bytecode: Add a function to dump bytecode
This also exposes it as a global function and removes the debug statements in the compiler.
This commit is contained in:
parent
1630314dc7
commit
41d0ee6132
4 changed files with 150 additions and 15 deletions
131
src/bytecode.c
131
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue