From 41d0ee613224976e2d348ab4ffd0c6e32d3ba7c2 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Thu, 28 Jul 2022 20:49:29 +0200 Subject: [PATCH] bytecode: Add a function to dump bytecode This also exposes it as a global function and removes the debug statements in the compiler. --- src/bytecode.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ src/bytecode.h | 2 + src/compile.c | 16 +----- src/globals.c | 16 ++++++ 4 files changed, 150 insertions(+), 15 deletions(-) diff --git a/src/bytecode.c b/src/bytecode.c index 4654185..4996fae 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -4,6 +4,7 @@ #include "alloc.h" #include "bytecode.h" +#include "format.h" #include "gc.h" struct instruction_list * @@ -206,3 +207,133 @@ apfl_matcher_instructions_deinit(struct apfl_allocator allocator, struct matcher { FREE_LIST(allocator, milist->instructions, milist->cap); } + +static bool +bytecode_dump_milist(unsigned indent, struct apfl_format_writer w, struct matcher_instruction_list *milist) +{ + for (size_t i = 0; i < milist->len; i++) { + FMT_TRY(apfl_format_put_indent(w, indent)); + FMT_TRY(apfl_format_put_string(w, apfl_matcher_instruction_to_string(milist->instructions[i].instruction))); + + switch (milist->instructions[i].instruction) { + case MATCHER_IGNORE: + case MATCHER_ENTER_LIST: + case MATCHER_LEAVE_LIST: + case MATCHER_CONTINUE_FROM_END: + case MATCHER_REMAINDING: + break; + case MATCHER_CAPTURE: + case MATCHER_CHECK_CONST: + case MATCHER_CHECK_PRED: + if (i >= milist->len) { + FMT_TRY(apfl_format_put_string(w, "Bytecode corrupted")); + return false; + } + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_int(w, (int)milist->instructions[++i].index)); + break; + } + + FMT_TRY(apfl_format_put_char(w, '\n')); + } + + return true; +} + +#define GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg) \ + do { \ + if (i >= ilist->len) { \ + FMT_TRY(apfl_format_put_string(w, "Bytecode corrupted")); \ + return false; \ + } \ + arg = ilist->instructions[++i]; \ + } while (0) + +static bool +bytecode_dump_ilist(unsigned indent, struct apfl_format_writer w, struct instruction_list *ilist) +{ + union instruction_or_arg arg; + + for (size_t i = 0; i < ilist->len; i++) { + FMT_TRY(apfl_format_put_indent(w, indent)); + FMT_TRY(apfl_format_put_string(w, apfl_instruction_to_string(ilist->instructions[i].instruction))); + + switch (ilist->instructions[i].instruction) { + case INSN_NIL: + case INSN_TRUE: + case INSN_FALSE: + case INSN_LIST_APPEND: + case INSN_LIST_EXPAND_INTO: + case INSN_DICT: + case INSN_DICT_APPEND_KVPAIR: + case INSN_GET_MEMBER: + case INSN_NEXT_LINE: + case INSN_DROP: + case INSN_CALL: + case INSN_MATCHER_MUST_MATCH: + case INSN_MATCHER_DROP: + break; + case INSN_NUMBER: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_number(w, arg.number)); + break; + case INSN_LIST: + case INSN_SET_LINE: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_int(w, (int)arg.count)); + break; + case INSN_GET_BY_INDEX_KEEP: + case INSN_MATCHER_SET_VAL: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_int(w, (int)arg.index)); + break; + case INSN_STRING: + case INSN_VAR_GET: + case INSN_VAR_SET: + case INSN_VAR_SET_LOCAL: + case INSN_VAR_NEW: + case INSN_VAR_NEW_LOCAL: + case INSN_MOVE_TO_LOCAL_VAR: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_string(w, *arg.string)); + break; + case INSN_FUNC: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ilist{\n")); + FMT_TRY(bytecode_dump_ilist(indent+1, w, arg.body)); + FMT_TRY(apfl_format_put_indent(w, indent)); + FMT_TRY(apfl_format_put_string(w, "}")); + break; + case INSN_MATCHER_LOAD: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " milist{\n")); + FMT_TRY(bytecode_dump_milist(indent+1, w, arg.matcher)); + FMT_TRY(apfl_format_put_indent(w, indent)); + FMT_TRY(apfl_format_put_string(w, "}")); + break; + case INSN_VAR_SET_FROM_MATCHER: + case INSN_VAR_SET_LOCAL_FROM_MATCHER: + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_string(w, " ")); + FMT_TRY(apfl_format_put_string(w, *arg.string)); + FMT_TRY(apfl_format_put_string(w, ", ")); + GET_ARGUMENT_FOR_DUMP(w, ilist, i, arg); + FMT_TRY(apfl_format_put_int(w, (int)arg.index)); + break; + } + + FMT_TRY(apfl_format_put_char(w, '\n')); + } + + return true; +} + +bool +apfl_bytecode_dump(struct apfl_format_writer w, struct instruction_list *ilist) +{ + return bytecode_dump_ilist(0, w, ilist); +} diff --git a/src/bytecode.h b/src/bytecode.h index 7092944..d4ee9f1 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -94,6 +94,8 @@ void apfl_gc_instructions_traverse(struct instruction_list *, gc_visitor, void * struct matcher_instruction_list *apfl_matcher_instructions_new(struct gc *); void apfl_matcher_instructions_deinit(struct apfl_allocator, struct matcher_instruction_list *); +bool apfl_bytecode_dump(struct apfl_format_writer, struct instruction_list *); + #ifdef __cplusplus } #endif diff --git a/src/compile.c b/src/compile.c index ce2d5c8..5253e35 100644 --- a/src/compile.c +++ b/src/compile.c @@ -9,14 +9,6 @@ #include "resizable.h" #include "strings.h" -#define DEBUG_COMPILING 0 - -#if DEBUG_COMPILING -# define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__); -#else -# define DEBUG_LOG(...) -#endif - struct compiler { struct gc *gc; struct apfl_error error; @@ -63,9 +55,7 @@ ilist_ensure_cap(struct compiler *compiler, struct instruction_list *ilist, size ilist->instructions[ilist->len] = (union instruction_or_arg) { \ .member = data, \ }; \ - ilist->len++; \ - \ - DEBUG_LOG("ilist %p " dbgfmt "\n", (void *)ilist, __VA_ARGS__); + ilist->len++; static void ilist_put_insn(struct instruction_list *ilist, enum instruction instruction) @@ -132,8 +122,6 @@ milist_put_insn(struct matcher_instruction_list *milist, enum matcher_instructio .instruction = instruction, }; milist->len++; - - DEBUG_LOG("milist %p: put_insn: %s\n", (void *)milist, apfl_matcher_instruction_to_string(instruction)); } static void @@ -146,8 +134,6 @@ milist_put_index(struct matcher_instruction_list *milist, size_t index) .index = index, }; milist->len++; - - DEBUG_LOG("milist %p: put_index: %d\n", (void *)milist, (int)index); } static bool diff --git a/src/globals.c b/src/globals.c index 312e583..b696988 100644 --- a/src/globals.c +++ b/src/globals.c @@ -3,6 +3,7 @@ #include "apfl.h" +#include "bytecode.h" #include "context.h" #include "globals.h" #include "scope.h" @@ -175,6 +176,20 @@ dump(apfl_ctx ctx) TRY_FORMAT(ctx, apfl_debug_print_val(ctx, -1, w)); } +static void +disasm(apfl_ctx ctx) +{ + struct apfl_format_writer w = apfl_format_file_writer(stdout); + apfl_get_list_member_by_index(ctx, 0, 0); + apfl_drop(ctx, 0); + struct apfl_value value = apfl_stack_must_get(ctx, -1); + if (value.type != VALUE_FUNC) { + apfl_raise_const_error(ctx, APFL_RESULT_ERR, apfl_messages.wrong_type); + } + + TRY_FORMAT(ctx, apfl_bytecode_dump(w, value.func->body)); +} + static const struct global_def globals[] = { {"if", impl_if}, {"==", impl_eq}, @@ -184,6 +199,7 @@ static const struct global_def globals[] = { {"/", impl_div}, {"print", print}, {"dump", dump}, + {"disasm", disasm}, {NULL, NULL}, };