#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_MK_ARRAY: { vec_t* vec = malloc(sizeof(vec_t)); vec_init(vec); for (int i=0; idata[0])->line; size_t addr = ccm_store_global( ccm, ccm_to_array(ccm, vec, line) ); ccm_push(ccm, ccm_to_ref(ccm, addr, line)); self->pc++; } break; case OP_EQ: { ccm_eq(ccm); self->pc++; } break; case OP_LT: { ccm_lt(ccm); self->pc++; } break; case OP_GT: { ccm_gt(ccm); self->pc++; } break; case OP_INDEX: { CCM ccm_target = ccm_pop(ccm); value_t* result = NULL; if (ccm_is_str(ccm, ccm_target)) { int line = ((value_t*)ccm->values.data[ccm_target])->line ; if (param != 1) { err_push(&self->err, line, "index out of bounds"); return; } char const* target = ccm_from_str(ccm, ccm_target); size_t size = strlen(target); CCM ccm_idx = ccm_pop(ccm); int idx = ccm_from_num(ccm, ccm_idx); if (idx < 0) { idx = size + idx; } if (idx < 0 || idx >= (ssize_t) size) { assert(size > 0); err_push(&self->err, line, "index out of bounds"); return; } char buf[2] = {target[idx], '\0'}; ccm_push(ccm, ccm_to_str(ccm, buf, line)); } else if (ccm_is_tuple(ccm, ccm_target) || ccm_is_ref(ccm, ccm_target)) { vec_t* target; if (ccm_is_tuple(ccm, ccm_target)) { target = ccm_from_tuple(ccm, ccm_target); } else { target = ccm_to_value(ccm, ccm_target)->data.array; } 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 if (ccm_is_tuple(ccm, ccm_target) ) { target = val->data.tuple; } else if (ccm_is_ref(ccm, ccm_target)) { target = val->data.array; } else { assert(0); } } CCM ccm_result = ccm_from_value(ccm, result); if (ccm_is_array(ccm, ccm_result)) { CCM ref = ccm_to_ref(ccm, ccm_store_global(ccm, ccm_result), result->line); ccm_push(ccm, ref); } else { ccm_push(ccm, ccm_result); } } else { assert(0); } 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: { // TODO: bug here // [1] == [1] -> OK // assert_eq ([1], [1]) -> Failed 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; } value_t* val_lhs = values->data[0]; value_t* val_rhs = values->data[1]; if (val_lhs->type == TYPE_REF) { CCM c = ccm_add_value(ccm, val_lhs); value_t* myval = ccm_to_value(ccm, c); val_lhs = myval; } if (val_rhs->type == TYPE_REF) { CCM c = ccm_add_value(ccm, val_rhs); value_t* myval = ccm_to_value(ccm, c); val_rhs = myval; } if (value_equals(val_lhs, val_rhs) == !oracle) { char lhs[CCM_STRLEN]; value_str(val_lhs, lhs, CCM_STRLEN); char rhs[CCM_STRLEN]; value_str(val_rhs, 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; iline; } } 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(); } } }