ccm/lib/exec.c

397 lines
10 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_LOCAL_STORE: {
CCM value = ccm_pop(ccm);
int addr = param;
ccm_set(ccm, value, addr);
ccm_push(ccm, value);
self->pc++;
} break;
case OP_LOCAL_LOAD: {
int addr = param;
CCM value = ccm_get(ccm, addr);
ccm_push(ccm, value);
self->pc++;
} break;
case OP_MK_ARRAY: {
vec_t* vec = malloc(sizeof(vec_t));
vec_init(vec);
for (int i=0; i<param; i++)
{
CCM element = ccm_pop(ccm);
vec_push(vec, ccm_to_value(ccm, element));
}
int line = 0;
if (vec->size > 0) {
line = ((value_t*) vec->data[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_ASTORE: {
int addr = ccm_pop(ccm);
CCM ccm_gaddr = ccm_get(ccm, addr);
int gaddr = ccm_from_ref(ccm, ccm_gaddr);
CCM ccm_target = ccm_load_global(ccm, gaddr);
value_t* target = ccm_to_value(ccm, ccm_target);
int indexes[param];
memset(indexes, 0, param * sizeof(int));
for (int i=0; i<param; i++) {
CCM ccm_idx = ccm_pop(ccm);
int idx = ccm_from_num(ccm, ccm_idx);
indexes[param - 1 - i] = idx;
}
for (int i=0; i<param-1; i++)
{
target = target->data.array->data[indexes[i]];
}
CCM ccm_expr = ccm_pop(ccm);
value_t* expr = ccm_to_value(ccm, ccm_expr);
target->data.array->data[indexes[param - 1]]
= expr;
ccm_push(ccm, ccm_expr);
self->pc++;
} break;
case OP_LEN: {
CCM ccm_value = ccm_pop(ccm);
value_t* value = ccm_to_value(ccm, ccm_value);
CCM ccm_res = 0;
if (value->type == TYPE_ARRAY)
{
ccm_res = ccm_to_num(
ccm,
value->data.array->size,
value->line
);
}
else if (value->type == TYPE_STR)
{
ccm_res = ccm_to_num(
ccm,
strlen(value->data.str),
value->line
);
}
ccm_push(ccm, ccm_res);
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 const 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; 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 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 {
value_t const* val = ccm_to_value(ccm, ccm_target);
err_push(&self->err, val->line,
"not an array");
return;
}
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;
}
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
);
} else {
ccm_push(ccm,
ccm_to_boolean(
ccm, 1,
((value_t*) values->data[0])->line
)
);
}
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_to_value(ccm, 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();
}
}
}