#include "vm.h" #include "lib/commons.h" #include "lib/mod.h" #include "lib/type.h" #include "lib/tysy.h" void vm_init(vm_t* vm, tysy_t* tysy, err_t* err) { assert(vm); vm->pc = 0; vm->bp = 0; vm->sp = 0; vm->tysy = tysy; vm->err = err; } void vm_free(vm_t* vm) { assert(vm); } void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value) { assert(vm); assert(value); param_t param = mod_push_new_value(mod, value); vm_push(vm, param); } void vm_push(vm_t* vm, param_t param) { assert(vm); assert(vm->sp + 1 < RZ_STACK_LIMIT); vm->stack[vm->sp] = param; vm->sp++; } param_t vm_pop(vm_t* vm) { assert(vm); assert(vm->sp > 0); param_t param = vm->stack[vm->sp - 1]; vm->sp--; return param; } size_t vm_stack_str(vm_t* vm, char* buffer, size_t size) { assert(vm); assert(buffer); size_t sz = 0; for (size_t i=0; isp; i++) { sz += snprintf(buffer + sz, size - sz, "| %d |\n", vm->stack[vm->sp - 1 - i]); } return sz; } int vm_exec_mod(vm_t* vm, mod_t* mod) { assert(vm); vm->pc = 0; while (vm->pc < mod->program.size) { int status = vm_exec_instr(vm, mod, mod->program.ops[vm->pc], mod->program.params[vm->pc]); if (status != 0) { return status; } } return 0; } int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) { assert(vm); switch (op) { case OP_PUSH: { if (vm->sp + 1 >= RZ_STACK_LIMIT) { fprintf(stderr, "Stack overflow\n"); abort(); } vm->stack[vm->sp] = param; vm->sp++; vm->pc++; } break; case OP_ASSERT: { param_t top = vm_pop(vm); value_t* value = mod->values.data[top]; if (value->type->kind != TYPE_BOOL) { vm_ensure_type(vm, value, TYPE_BOOL); vm->pc++; break; } if (!value->value.bool) { fprintf(stderr, "\33[31mASSERT\33[0m[:%d] assertion failed\n", value->line); return -1; } vm->pc++; } break; case OP_NE: case OP_EQ: { int l = vm_pop(vm); int r = vm_pop(vm); assert(l != -1); assert(r != -1); value_t* rhs = mod->values.data[l]; value_t* lhs = mod->values.data[r]; int same_type = lhs->type->kind == rhs->type->kind; int eq = value_eq(lhs, rhs); value_t* res = tysy_new_bool(vm->tysy, (op == OP_EQ ? (same_type && eq) : (!same_type || !eq)), rhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_LT: case OP_LE: case OP_GT: case OP_GE: { int r = vm_pop(vm); int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; value_t* rhs = mod->values.data[r]; vm_ensure_type(vm, lhs, TYPE_NUM); vm_ensure_type(vm, rhs, TYPE_NUM); int val = 0; switch (op) { case OP_LT: val = lhs->value.num < rhs->value.num; break; case OP_LE: val = lhs->value.num <= rhs->value.num; break; case OP_GT: val = lhs->value.num > rhs->value.num; break; case OP_GE: val = lhs->value.num >= rhs->value.num; break; default: break; } value_t* res = tysy_new_bool(vm->tysy, val, lhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MODULO: case OP_POW: { int r = vm_pop(vm); int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; value_t* rhs = mod->values.data[r]; vm_ensure_type(vm, lhs, TYPE_NUM); vm_ensure_type(vm, rhs, TYPE_NUM); double val = 0; switch (op) { case OP_ADD: val = lhs->value.num + rhs->value.num; break; case OP_SUB: val = lhs->value.num - rhs->value.num; break; case OP_MUL: val = lhs->value.num * rhs->value.num; break; case OP_DIV: val = lhs->value.num / rhs->value.num; break; case OP_MODULO: val = fmod(lhs->value.num, rhs->value.num); break; case OP_POW: val = powf(lhs->value.num, rhs->value.num); break; default: assert(0); break; } value_t* res = tysy_new_num(vm->tysy, val, lhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_STRCAT: { int r = vm_pop(vm); int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; value_t* rhs = mod->values.data[r]; vm_ensure_type(vm, lhs, TYPE_STR); vm_ensure_type(vm, rhs, TYPE_STR); str_t res; str_init(&res); str_append(&res, lhs->value.str); str_append(&res, rhs->value.str); value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line); str_free(&res); vm_push_new_value(vm, mod, value); vm->pc++; } break; case OP_STRDUP: { int r = vm_pop(vm); int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; value_t* rhs = mod->values.data[r]; if (lhs->type->kind != TYPE_NUM) { value_t* tmp = lhs; lhs = rhs; rhs = tmp; } vm_ensure_type(vm, lhs, TYPE_NUM); vm_ensure_type(vm, rhs, TYPE_STR); str_t res; str_init(&res); for (int i=0; i<(int) lhs->value.num; i++) { str_append(&res, rhs->value.str); } value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line); str_free(&res); vm_push_new_value(vm, mod, value); vm->pc++; } break; case OP_AND: case OP_OR: { int r = vm_pop(vm); int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; value_t* rhs = mod->values.data[r]; vm_ensure_type(vm, lhs, TYPE_BOOL); vm_ensure_type(vm, rhs, TYPE_BOOL); int val = 0; switch (op) { case OP_AND: val = lhs->value.bool && rhs->value.bool; break; case OP_OR: val = lhs->value.bool || rhs->value.bool; break; default: assert(0); break; } value_t* res = tysy_new_bool(vm->tysy, val, lhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_USUB: { int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; vm_ensure_type(vm, lhs, TYPE_NUM); double val = -lhs->value.num; value_t* res = tysy_new_num(vm->tysy, val, lhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_NOT: { int l = vm_pop(vm); value_t* lhs = mod->values.data[l]; vm_ensure_type(vm, lhs, TYPE_BOOL); int val = !lhs->value.bool; value_t* res = tysy_new_bool(vm->tysy, val, lhs->line); vm_push_new_value(vm, mod, res); vm->pc++; } break; case OP_BRT: case OP_BRF: { param_t p = vm_pop(vm); value_t* value = mod->values.data[p]; vm_ensure_type(vm, value, TYPE_BOOL); if (op == OP_BRT && value->value.bool) { vm->pc = param; } else if (op == OP_BRF && !value->value.bool) { vm->pc = param; } else { vm->pc++; } } break; case OP_BR: { vm->pc = param; } break; default: { fprintf(stderr, "Cannot execute unknown opcode '%s'.\n", OpcodeStr[op]); abort(); }; } return 0; } void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want) { assert(vm); assert(value); TypeKind got = value->type->kind; int line = value->line; if (got != want) { char msg[RZ_STR_LIMIT]; snprintf(msg, RZ_STR_LIMIT, "type mismatch: %s expected, got %s.", TypeKindStr[want] + strlen("TYPE_"), TypeKindStr[got] + strlen("TYPE_")); err_fatal(vm->err, msg, line); err_dump(vm->err); } }