From 4d840fd8174e4bff9f7790f8220df2d71dbfc64d Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Sat, 25 Feb 2023 23:19:45 +0100 Subject: [PATCH] Allow NULL as subfunction matcher This will match all arguments and discard them. This makes the bytecode for simple functions easier and will make it easier to construct simple function programmatically. --- src/bytecode.c | 4 +++ src/bytecode.h | 1 + src/compile.c | 10 +------ src/eval.c | 75 +++++++++++++++++++++++++++++++++++--------------- src/globals.c | 11 ++++++-- src/value.c | 4 ++- src/value.h | 2 +- 7 files changed, 71 insertions(+), 36 deletions(-) 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; };