112 lines
2.7 KiB
C
112 lines
2.7 KiB
C
|
|
#include <assert.h>
|
||
|
|
|
||
|
|
#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:
|
||
|
|
break;
|
||
|
|
case INSN_NUMBER:
|
||
|
|
case INSN_LIST:
|
||
|
|
case INSN_SET_LINE:
|
||
|
|
i++;
|
||
|
|
break;
|
||
|
|
case INSN_STRING:
|
||
|
|
case INSN_VAR_GET:
|
||
|
|
case INSN_VAR_SET:
|
||
|
|
case INSN_VAR_NEW:
|
||
|
|
GET_ARGUMENT(ilist, i, arg);
|
||
|
|
cb(opaque, GC_OBJECT_FROM(arg.string, GC_TYPE_STRING));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
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_NEW:
|
||
|
|
return "INSN_VAR_NEW";
|
||
|
|
case INSN_NEXT_LINE:
|
||
|
|
return "INSN_NEXT_LINE";
|
||
|
|
case INSN_SET_LINE:
|
||
|
|
return "INSN_SET_LINE";
|
||
|
|
}
|
||
|
|
|
||
|
|
return "??";
|
||
|
|
}
|