#include "exec.h" void exec_init(struct exec* self) { assert(self); self->pc = 0; } void exec_free(struct exec* self) { assert(self); } void exec_prog(struct exec* self, struct moka* moka, struct prog* prog) { assert(self); assert(moka); assert(prog); self->pc = 0; while (self->pc < prog->instructions.size) { exec_instr(self, moka, prog, prog->instructions.data[self->pc]); } } void exec_instr(struct exec* self, struct moka* moka, struct prog* prog, struct instruction* instr) { assert(self); assert(moka); assert(instr); int param = instr->param; switch (instr->opcode) { case OP_CALL: { MOKA fun = moka_pop(moka); struct vec args; vec_init(&args); for (ssize_t i=0; iglobal_values.data[ moka_get_ref(moka, fun) ]; assert(val->type == TY_NATIVE); struct native* native = val->data.native; (native->fun)(moka, &args); vec_free(&args); self->pc++; } break; case OP_GLOBAL_LOAD: { moka_push_ref(moka, param, 0); self->pc++; } break; case OP_PUSH: { struct value* value = prog->values.data[param]; switch (value->type) { case TY_INT: { moka_push_int(moka, value->data.integer, value->line); } break; case TY_FLOAT: { moka_push_float(moka, value->data.real, value->line); } break; case TY_BOOL: { moka_push_bool(moka, value->data.boolean, value->line); } break; case TY_STRING: { moka_push_string(moka, value->data.str, value->line); } break; case TY_SYMBOL: { moka_push_symbol(moka, value->data.sym, value->line); } break; case TY_LAZY: { moka_push_lazy(moka, value->data.lazy, value->line); } break; default: { fprintf(stderr, "cannot push value of type <%s>\n", TypeKindStr[value->type] ); abort(); } break; } self->pc++; } break; default: { fprintf(stderr, "cannot execute opcode <%s>\n", OpcodeKindStr[instr->opcode]); abort(); } break; } }