#include "VM.hpp" #include "src/Program.hpp" namespace zn { /*explicit*/ VM::VM(Program& program) { m_pc = 0; Frame f = {program, {}}; m_frames.push_back(f); } /*virtual*/ VM::~VM() { } void VM::execute(Program& program) { m_pc = 0; while (m_pc < program.size()) { auto instr = program.instr(m_pc); execute(program, instr.opcode, instr.param); } } void VM::execute(Program& program, Opcode opcode, int param) { switch (opcode) { case OPCODE_LOAD_CONST: { push(param); m_pc++; } break; case OPCODE_LOAD_LOCAL: { auto constant = frame().locals[to_vm_addr(param)]; push(program.add_constant(constant)); m_pc++; } break; case OPCODE_POP: { pop(); m_pc++; } break; case OPCODE_CALL_NATIVE: { std::vector> args; for (int i=0; i(*fun_ref->value()); auto fun = std::get> (m_globals[ref]); assert(fun); auto result = fun->call(args); int addr = m_frames.back().program.add_constant(result); push(addr); m_pc++; } break; default: { std::cerr << "cannot execute opcode '" << OpcodeStr[opcode] << "'" << std::endl; abort(); } break; } } std::string VM::string() const { std::stringstream ss; ss << "======== VM Stack ========\n"; size_t addr = 0; for (int val: m_stack) { ss << addr << " " << val << "\n"; addr++; } return ss.str(); } size_t VM::store_local(int index, std::shared_ptr constant) { frame().locals.push_back(constant); size_t addr = frame().locals.size() - 1; m_addr_mapping[index] = addr; return addr; } std::shared_ptr VM::load_local(int index) const { size_t addr = to_vm_addr(index); assert(addr < m_frames.back().locals.size()); return m_frames.back().locals[addr]; } size_t VM::store_global(global_var_t var) { m_globals.push_back(var); return m_globals.size() - 1; } size_t VM::to_vm_addr(int user_addr) const { return m_addr_mapping.at(user_addr); } int VM::to_user_addr(size_t vm_addr) const { for (auto const& entry: m_addr_mapping) { if (entry.second == vm_addr) { return entry.first; } } std::cerr << "cannot find user addr of '" << vm_addr << "'" << std::endl; abort(); } Frame& VM::frame() { return m_frames.back(); } void VM::push(int value) { m_stack.push_back(value); } int VM::pop() { assert(m_stack.size() > 0); int value = m_stack.back(); m_stack.pop_back(); return value; } }