#include #include "apfl.h" #include "alloc.h" #include "bytecode.h" #include "gc.h" struct instruction_list * apfl_instructions_new(struct gc *gc, int line) { struct instruction_list *ilist = apfl_gc_new_instructions(gc); if (ilist == NULL) { return NULL; } *ilist = (struct instruction_list) { .instructions = NULL, .len = 0, .cap = 0, .line = line, }; return ilist; } void apfl_instructions_deinit(struct apfl_allocator allocator, struct instruction_list *ilist) { FREE_LIST(allocator, ilist->instructions, ilist->cap); } #define GET_ARGUMENT(ilist, i, arg) \ do { \ if (i >= ilist->len) { \ return; \ } \ arg = ilist->instructions[++i]; \ } while (0) void apfl_gc_instructions_traverse(struct instruction_list *ilist, gc_visitor cb, void *opaque) { union instruction_or_arg arg; for (size_t i = 0; i < ilist->len; i++) { 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: case INSN_LIST: case INSN_SET_LINE: case INSN_GET_BY_INDEX_KEEP: case INSN_MATCHER_SET_VAL: i++; 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(ilist, i, arg); cb(opaque, GC_OBJECT_FROM(arg.string, GC_TYPE_STRING)); break; case INSN_FUNC: GET_ARGUMENT(ilist, i, arg); cb(opaque, GC_OBJECT_FROM(arg.body, GC_TYPE_INSTRUCTIONS)); break; case INSN_MATCHER_LOAD: GET_ARGUMENT(ilist, i, arg); cb(opaque, GC_OBJECT_FROM(arg.matcher, GC_TYPE_MATCHER_INSTRUCTIONS)); break; case INSN_VAR_SET_FROM_MATCHER: case INSN_VAR_SET_LOCAL_FROM_MATCHER: GET_ARGUMENT(ilist, i, arg); cb(opaque, GC_OBJECT_FROM(arg.string, GC_TYPE_STRING)); i++; break; } } } const char * apfl_instruction_to_string(enum instruction insn) { switch (insn) { case INSN_NIL: return "INSN_NIL"; case INSN_TRUE: return "INSN_TRUE"; case INSN_FALSE: return "INSN_FALSE"; case INSN_NUMBER: return "INSN_NUMBER"; case INSN_STRING: return "INSN_STRING"; case INSN_LIST: return "INSN_LIST"; case INSN_LIST_APPEND: return "INSN_LIST_APPEND"; case INSN_LIST_EXPAND_INTO: return "INSN_LIST_EXPAND_INTO"; case INSN_DICT: return "INSN_DICT"; case INSN_DICT_APPEND_KVPAIR: return "INSN_DICT_APPEND_KVPAIR"; case INSN_GET_MEMBER: return "INSN_GET_MEMBER"; case INSN_VAR_GET: return "INSN_VAR_GET"; case INSN_VAR_SET: return "INSN_VAR_SET"; case INSN_VAR_SET_LOCAL: return "INSN_VAR_SET_LOCAL"; case INSN_VAR_NEW: return "INSN_VAR_NEW"; case INSN_VAR_NEW_LOCAL: return "INSN_VAR_NEW_LOCAL"; case INSN_MOVE_TO_LOCAL_VAR: return "INSN_MOVE_TO_LOCAL_VAR"; case INSN_NEXT_LINE: return "INSN_NEXT_LINE"; case INSN_SET_LINE: return "INSN_SET_LINE"; case INSN_GET_BY_INDEX_KEEP: return "INSN_GET_BY_INDEX_KEEP"; case INSN_DROP: return "INSN_DROP"; case INSN_CALL: return "INSN_CALL"; case INSN_FUNC: return "INSN_FUNC"; case INSN_MATCHER_LOAD: return "INSN_MATCHER_LOAD"; case INSN_MATCHER_SET_VAL: return "INSN_MATCHER_SET_VAL"; case INSN_MATCHER_MUST_MATCH: return "INSN_MATCHER_MUST_MATCH"; case INSN_MATCHER_DROP: return "INSN_MATCHER_DROP"; case INSN_VAR_SET_FROM_MATCHER: return "INSN_VAR_SET_FROM_MATCHER"; case INSN_VAR_SET_LOCAL_FROM_MATCHER: return "INSN_VAR_SET_LOCAL_FROM_MATCHER"; } return "??"; } const char * apfl_matcher_instruction_to_string(enum matcher_instruction insn) { switch (insn) { case MATCHER_IGNORE: return "MATCHER_IGNORE"; case MATCHER_CAPTURE: return "MATCHER_CAPTURE"; case MATCHER_CHECK_CONST: return "MATCHER_CHECK_CONST"; case MATCHER_CHECK_PRED: return "MATCHER_CHECK_PRED"; case MATCHER_ENTER_LIST: return "MATCHER_ENTER_LIST"; case MATCHER_LEAVE_LIST: return "MATCHER_LEAVE_LIST"; case MATCHER_CONTINUE_FROM_END: return "MATCHER_CONTINUE_FROM_END"; case MATCHER_REMAINDING: return "MATCHER_REMAINDING"; } return "??"; } struct matcher_instruction_list * apfl_matcher_instructions_new(struct gc *gc) { struct matcher_instruction_list *milist = apfl_gc_new_matcher_instructions(gc); if (milist == NULL) { return NULL; } *milist = (struct matcher_instruction_list) { .instructions = NULL, .len = 0, .cap = 0, .capture_count = 0, .value_count = 0, }; return milist; } void apfl_matcher_instructions_deinit(struct apfl_allocator allocator, struct matcher_instruction_list *milist) { FREE_LIST(allocator, milist->instructions, milist->cap); }