#include "exec.h" #include "bytecode.h" void exec_init(exec_t* self) { assert(self); self->pc = 0; err_init(&self->err); } void exec_free(exec_t* self) { assert(self); err_free(&self->err); } void exec_module(exec_t* self, module_t* module) { assert(self); assert(module); self->pc = 0; while (self->pc < module->prog.instrs.size) { if (!err_is_ok(&self->err)) { return; } instr_t const* instr = module->prog.instrs.data[self->pc]; exec_instr(self, module, instr->opcode, instr->param); } } void exec_instr(exec_t* self, module_t* module, Opcode op, int param) { assert(self); ccm_t* ccm = &module->ccm; switch (op) { case OP_INDEX: { CCM ccm_target = ccm_pop(ccm); vec_t* target = ccm_from_tuple(ccm, ccm_target); value_t* result = NULL; for (int i=0; isize + idx; } if (idx < 0 || idx >= (ssize_t) target->size) { assert(target->size > 0); err_push(&self->err, ((value_t*)target->data[0])->line, "index out of bounds"); return; } value_t* val = target->data[idx]; if (i == param - 1) { result = val; } else { target = val->data.tuple; } } ccm_push(ccm, ccm_from_value(ccm, result)); self->pc++; } break; case OP_NOT: { ccm_not(ccm); self->pc++; } break; case OP_IN: { ccm_in(ccm); self->pc++; } break; case OP_BR: { self->pc = param; } break; case OP_BRF: { CCM value = ccm_pop(ccm); int val = ccm_from_boolean(ccm, value); if (val) { self->pc++; } else { self->pc = param; } } break; case OP_ASSERT_NE: case OP_ASSERT_EQ: { CCM val = ccm_pop(ccm); vec_t* values = ccm_from_tuple(ccm, val); assert(values->size == 2); int oracle = 1; if (op == OP_ASSERT_NE) { oracle = 0; } if (value_equals(values->data[0], values->data[1]) == !oracle) { char lhs[CCM_STRLEN]; value_str(values->data[0], lhs, CCM_STRLEN); char rhs[CCM_STRLEN]; value_str(values->data[1], rhs, CCM_STRLEN); char const* operator = oracle ? "==" : "!="; err_push( &self->err, ((value_t*) values->data[0])->line, "assertion failed: <%s> %s <%s>", lhs, operator, rhs ); } self->pc++; } break; case OP_PUSH: { CCM value = (CCM) module->prog.constants.data[param]; ccm_push(ccm, value); self->pc++; } break; case OP_POP: { ccm_pop(ccm); self->pc++; } break; case OP_ADD: { ccm_add(ccm); self->pc++; } break; case OP_SUB: { ccm_sub(ccm); self->pc++; } break; case OP_USUB: { ccm_usub(ccm); self->pc++; } break; case OP_MUL: { ccm_mul(ccm); self->pc++; } break; case OP_DIV: { ccm_div(ccm); self->pc++; } break; case OP_MOD: { ccm_mod(ccm); self->pc++; } break; case OP_POW: { ccm_pow(ccm); self->pc++; } break; case OP_MK_TUPLE: { vec_t* values = malloc(sizeof(vec_t)); vec_init(values); int line = -1; for (int i=0; ivalues.data[val]); vec_push(values, v); if (line == -1) { line = v->line; } } CCM value = ccm_to_tuple(ccm, values, line); ccm_push(ccm, value); self->pc++; } break; default: { fprintf(stderr, "cannot exec opcode '%s'", OpcodeStr[op]); abort(); } } }