diff --git a/src/bytecode.c b/src/bytecode.c index 3459f05..123d92a 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -83,6 +83,7 @@ apfl_gc_instructions_traverse(struct instruction_list *ilist, gc_visitor cb, voi cb(opaque, GC_OBJECT_FROM(arg.string, GC_TYPE_STRING)); break; case INSN_FUNC_ADD_SUBFUNC: + case INSN_FUNC_ADD_SUBFUNC_ANYARGS: GET_ARGUMENT(ilist, i, arg); cb(opaque, GC_OBJECT_FROM(arg.body, GC_TYPE_INSTRUCTIONS)); break; @@ -181,6 +182,8 @@ apfl_instruction_to_string(enum instruction insn) return "INSN_FUNC"; case INSN_FUNC_ADD_SUBFUNC: return "INSN_FUNC_ADD_SUBFUNC"; + case INSN_FUNC_ADD_SUBFUNC_ANYARGS: + return "INSN_FUNC_ADD_SUBFUNC_ANYARGS"; case INSN_FUNC_SET_NAME: return "INSN_FUNC_SET_NAME"; case INSN_MATCHER_PUSH: @@ -360,6 +363,7 @@ apfl_bytecode_dump(unsigned indent, struct apfl_io_writer w, struct instruction_ FMT_TRY(apfl_io_write_string(w, *arg.string)); break; case INSN_FUNC_ADD_SUBFUNC: + case INSN_FUNC_ADD_SUBFUNC_ANYARGS: GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); FMT_TRY(apfl_io_write_string(w, " ilist{\n")); FMT_TRY(apfl_bytecode_dump(indent+1, w, arg.body)); diff --git a/src/bytecode.h b/src/bytecode.h index 5d47bd4..3694aa7 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -64,6 +64,7 @@ enum instruction { INSN_CALL, // ( func list -- value ) INSN_FUNC, // ( -- func ), arg: count INSN_FUNC_ADD_SUBFUNC, // ( func -- func' ), arg: body; pops a matcher from the matcher stack + INSN_FUNC_ADD_SUBFUNC_ANYARGS, // ( func -- func' ), arg: body INSN_FUNC_SET_NAME, // ( func -- func' ), arg: string INSN_MATCHER_PUSH, // ( -- ), arg: matcher; pushes a matcher onto the matcher stack INSN_MATCHER_SET_VAL, // ( val -- ), arg: index diff --git a/src/compile.c b/src/compile.c index bf4d46b..5b47a99 100644 --- a/src/compile.c +++ b/src/compile.c @@ -716,20 +716,12 @@ compile_simple_func_inner( struct instruction_list *body_ilist = NULL; MALLOC_FAIL_IF_NULL(compiler, (body_ilist = tmp_ilist(compiler, line, ilist->filename))); - struct matcher_instruction_list *milist = NULL; - MALLOC_FAIL_IF_NULL(compiler, (milist = tmp_milist(compiler))); - - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_IGNORE); // Ignore all arguments - TRY(compile_body(compiler, func, body_ilist)); TRY(ilist_ensure_cap(compiler, ilist, 6)); ilist_put_insn(ilist, INSN_FUNC); ilist_put_count(ilist, 1); - ilist_put_insn(ilist, INSN_MATCHER_PUSH); - ilist_put_matcher(ilist, milist); - ilist_put_insn(ilist, INSN_FUNC_ADD_SUBFUNC); + ilist_put_insn(ilist, INSN_FUNC_ADD_SUBFUNC_ANYARGS); ilist_put_body(ilist, body_ilist); if (name != NULL) { diff --git a/src/eval.c b/src/eval.c index bfb4e20..ddfc1ec 100644 --- a/src/eval.c +++ b/src/eval.c @@ -298,8 +298,12 @@ func(apfl_ctx ctx, struct func_call_stack_entry *cse, size_t count) } static void -func_add_subfunc(apfl_ctx ctx, struct func_call_stack_entry *cse, struct instruction_list *body) -{ +func_add_subfunc( + apfl_ctx ctx, + struct func_call_stack_entry *cse, + struct instruction_list *body, + bool with_matcher +) { // TODO: Better error messsages struct apfl_value value = apfl_stack_must_get(ctx, -1); @@ -307,11 +311,17 @@ func_add_subfunc(apfl_ctx ctx, struct func_call_stack_entry *cse, struct instruc apfl_raise_const_error(ctx, apfl_messages.corrupted_bytecode); } - if (!apfl_func_add_subfunc(value.func, body, matcher_stack_top(ctx, cse))) { + if (!apfl_func_add_subfunc( + value.func, + body, + with_matcher ? matcher_stack_top(ctx, cse) : NULL + )) { apfl_raise_const_error(ctx, apfl_messages.corrupted_bytecode); } - matcher_stack_drop(ctx, cse); + if (with_matcher) { + matcher_stack_drop(ctx, cse); + } } static void @@ -665,7 +675,11 @@ evaluate(apfl_ctx ctx, struct func_call_stack_entry *cse) goto continue_loop; case INSN_FUNC_ADD_SUBFUNC: must_get_argument(ctx, pc, ilist, &arg); - func_add_subfunc(ctx, cse, arg.body); + func_add_subfunc(ctx, cse, arg.body, true); + goto continue_loop; + case INSN_FUNC_ADD_SUBFUNC_ANYARGS: + must_get_argument(ctx, pc, ilist, &arg); + func_add_subfunc(ctx, cse, arg.body, false); goto continue_loop; case INSN_FUNC_SET_NAME: must_get_argument(ctx, pc, ilist, &arg); @@ -1300,6 +1314,32 @@ matcher_stack_new(void) }; } +static void +dispatch_accept(struct call_stack_entry *cse) +{ + assert(cse->type == APFL_CSE_FUNCTION_DISPATCH); + struct func_dispatch_call_stack_entry *fd_cse = &cse->func_dispatch; + + struct function *function = fd_cse->function; + + struct subfunction *subfunction = &function->subfunctions[fd_cse->subfunc]; + + // Replace the current CSE with a function CSE + cse->type = APFL_CSE_FUNCTION; + cse->stack.len = 0; + cse->func = (struct func_call_stack_entry) { + .pc = 0, + .instructions = subfunction->body, + .scopes = fd_cse->scopes, + .execution_line = subfunction->body->line, + .matcher_stack = matcher_stack_new(), + .returning_from_matcher = false, + .matcher_result = false, + .function = function, + .subfunction_index = fd_cse->subfunc, + }; +} + static void dispatch(apfl_ctx ctx, struct call_stack_entry *cse) { @@ -1310,23 +1350,7 @@ dispatch(apfl_ctx ctx, struct call_stack_entry *cse) if (fd_cse->returning_from_matcher) { if (fd_cse->matcher_result) { - struct subfunction *subfunction = &function->subfunctions[fd_cse->subfunc]; - - // Replace the current CSE with a function CSE - cse->type = APFL_CSE_FUNCTION; - cse->stack.len = 0; - cse->func = (struct func_call_stack_entry) { - .pc = 0, - .instructions = subfunction->body, - .scopes = fd_cse->scopes, - .execution_line = subfunction->body->line, - .matcher_stack = matcher_stack_new(), - .returning_from_matcher = false, - .matcher_result = false, - .function = function, - .subfunction_index = fd_cse->subfunc, - }; - + dispatch_accept(cse); return; } @@ -1338,6 +1362,13 @@ dispatch(apfl_ctx ctx, struct call_stack_entry *cse) apfl_raise_const_error(ctx, apfl_messages.no_matching_subfunction); } + struct matcher *matcher = function->subfunctions[fd_cse->subfunc].matcher; + + if (matcher == NULL) { + dispatch_accept(cse); + return; + } + // matcher_init_matching consumes the value on the top of the stack, we need // to copy the value for further subfunctions. apfl_copy(ctx, -1); diff --git a/src/globals.c b/src/globals.c index dde1b4d..13ef4e8 100644 --- a/src/globals.c +++ b/src/globals.c @@ -248,9 +248,14 @@ disasm(apfl_ctx ctx) TRY_FORMAT(ctx, apfl_io_write_string(w, "Subfunction #")); TRY_FORMAT(ctx, apfl_format_put_number(w, (int)i)); TRY_FORMAT(ctx, apfl_io_write_string(w, "\n")); - TRY_FORMAT(ctx, apfl_format_put_indent(w, 1)); - TRY_FORMAT(ctx, apfl_io_write_string(w, "Matcher\n")); - TRY_FORMAT(ctx, apfl_bytecode_dump_matcher(2, w, subfunction->matcher->instructions)); + if (subfunction->matcher == NULL) { + TRY_FORMAT(ctx, apfl_format_put_indent(w, 1)); + TRY_FORMAT(ctx, apfl_io_write_string(w, "No matcher (matches everything)\n")); + } else { + TRY_FORMAT(ctx, apfl_format_put_indent(w, 1)); + TRY_FORMAT(ctx, apfl_io_write_string(w, "Matcher\n")); + TRY_FORMAT(ctx, apfl_bytecode_dump_matcher(2, w, subfunction->matcher->instructions)); + } TRY_FORMAT(ctx, apfl_format_put_indent(w, 1)); TRY_FORMAT(ctx, apfl_io_write_string(w, "Instructions\n")); TRY_FORMAT(ctx, apfl_bytecode_dump(2, w, subfunction->body)); diff --git a/src/value.c b/src/value.c index 5f114de..f30963d 100644 --- a/src/value.c +++ b/src/value.c @@ -852,7 +852,9 @@ apfl_gc_func_traverse(struct function* function, gc_visitor cb, void *opaque) for (size_t i = 0; i < function->subfunctions_len; i++) { struct subfunction *sub = &function->subfunctions[i]; cb(opaque, GC_OBJECT_FROM(sub->body, GC_TYPE_INSTRUCTIONS)); - cb(opaque, GC_OBJECT_FROM(sub->matcher, GC_TYPE_MATCHER)); + if (sub->matcher != NULL) { + cb(opaque, GC_OBJECT_FROM(sub->matcher, GC_TYPE_MATCHER)); + } } cb(opaque, GC_OBJECT_FROM(function->scope, GC_TYPE_SCOPE)); if (function->name != NULL) { diff --git a/src/value.h b/src/value.h index b8487d0..281c8e4 100644 --- a/src/value.h +++ b/src/value.h @@ -43,7 +43,7 @@ struct dict_header { }; struct subfunction { - struct matcher *matcher; + struct matcher *matcher; // Can be NULL, in which case all arguments are accepted but discarded struct instruction_list *body; };