254 lines
6.2 KiB
C
254 lines
6.2 KiB
C
#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_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))
|
|
{
|
|
vec_t* target = ccm_from_tuple(ccm, ccm_target);
|
|
|
|
for (int i=0; i<param; i++)
|
|
{
|
|
CCM ccm_idx = ccm_pop(ccm);
|
|
int idx = ccm_from_num(ccm, ccm_idx);
|
|
|
|
if (idx < 0)
|
|
{
|
|
idx = target->size + 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));
|
|
} 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: {
|
|
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; i<param; i++)
|
|
{
|
|
CCM val = ccm_pop(ccm);
|
|
value_t* v = value_new_clone(ccm->values.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();
|
|
}
|
|
}
|
|
}
|