#include "vm.hpp" #include "arch.hpp" #include #include #include #include #include #include using namespace sliger; void VM::run() { while (!done()) { auto op = eat_op(); switch (op) { case Op::Nop: // nothing break; case Op::PushNull: this->stack.push_back(Null {}); break; case Op::PushInt: { assert_program_has(1); auto value = eat_int32(); this->stack.push_back(Int { value }); break; } case Op::PushBool: { assert_program_has(1); auto value = eat_int32(); this->stack.push_back(Bool { .value = value != 0 }); break; } case Op::PushString: { assert_program_has(1); auto string_length = eat_uint32(); assert_program_has(string_length); auto value = std::string(); for (uint32_t i = 0; i < string_length; ++i) { auto ch = eat_uint32(); value.push_back(static_cast(ch)); } stack_push(String { .value = std::move(value) }); break; } case Op::PushPtr: { assert_program_has(1); auto value = eat_uint32(); this->stack.push_back(Ptr { value }); break; } case Op::Pop: { assert_stack_has(1); this->stack.pop_back(); break; } case Op::LoadLocal: { auto loc = eat_uint32(); assert_fn_stack_has(loc); auto value = fn_stack_at(loc); stack_push(value); break; } case Op::StoreLocal: { auto loc = eat_uint32(); assert_fn_stack_has(loc + 1); auto value = stack_pop(); fn_stack_at(loc) = value; break; } case Op::Call: { assert_program_has(1); auto arg_count = eat_uint32(); assert_stack_has(arg_count + 1); auto fn_ptr = stack_pop(); auto arguments = std::vector(); for (uint32_t i = 0; i < arg_count; ++i) { auto argument = stack_pop(); arguments.push_back(argument); } stack_push(Ptr { .value = this->pc }); stack_push(Ptr { .value = this->bp }); for (size_t i = 0; i < arguments.size(); ++i) { auto argument = std::move(arguments.at(arguments.size() - 1 - i)); arguments.pop_back(); stack_push(argument); } this->pc = fn_ptr.as_ptr().value; break; } case Op::Return: { assert_stack_has(3); auto ret_val = stack_pop(); auto bp_val = stack_pop(); auto pc_val = stack_pop(); this->bp = bp_val.as_ptr().value; stack_push(ret_val); this->pc = pc_val.as_ptr().value; break; } case Op::Jump: { assert_stack_has(1); auto addr = stack_pop(); this->pc = addr.as_ptr().value; break; } case Op::JumpIfFalse: { assert_stack_has(2); auto cond = stack_pop(); auto addr = stack_pop(); if (cond.as_bool().value) { this->pc = addr.as_ptr().value; } break; } case Op::Add: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left + right; stack_push(Int { .value = value }); break; } case Op::Subtract: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left - right; stack_push(Int { .value = value }); break; } case Op::Multiply: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left * right; stack_push(Int { .value = value }); break; } case Op::Divide: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left / right; stack_push(Int { .value = value }); break; } case Op::Remainder: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left % right; stack_push(Int { .value = value }); break; } case Op::Equal: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left == right; stack_push(Bool { .value = value }); break; } case Op::LessThan: { assert_stack_has(2); auto right = stack_pop().as_int().value; auto left = stack_pop().as_int().value; auto value = left < right; stack_push(Bool { .value = value }); break; } case Op::And: { assert_stack_has(2); auto right = stack_pop().as_bool().value; auto left = stack_pop().as_bool().value; auto value = left && right; stack_push(Bool { .value = value }); break; } case Op::Or: { assert_stack_has(2); auto right = stack_pop().as_bool().value; auto left = stack_pop().as_bool().value; auto value = left || right; stack_push(Bool { .value = value }); break; } case Op::Xor: { assert_stack_has(2); auto right = stack_pop().as_bool().value; auto left = stack_pop().as_bool().value; auto value = (left || !right) || (!left && right); stack_push(Bool { .value = value }); break; } case Op::Not: assert_stack_has(1); auto value = !stack_pop().as_bool().value; stack_push(Bool { .value = value }); break; } } }