#pragma once #include "arch.hpp" #include "value.hpp" #include #include #include #include #include namespace sliger { class VM { public: VM(const std::vector& program) : program(program.data()) , program_size(program.size()) { } void run(); inline void step() { this->pc += 1; } inline auto eat_op() -> Op { auto value = curr_as_op(); step(); return value; } inline auto curr_as_op() const -> Op { return static_cast(this->program[this->pc]); } inline auto eat_int32() -> int32_t { auto value = curr_as_int32(); step(); return value; } inline auto curr_as_int32() const -> int32_t { return static_cast(this->program[this->pc]); } inline auto eat_uint32() -> uint32_t { auto value = curr_as_uint32(); step(); return value; } inline auto curr_as_uint32() const -> uint32_t { return this->program[this->pc]; } inline auto done() const -> bool { return this->pc >= this->program_size; } inline auto fn_stack_at(size_t idx) -> Value& { return this->stack.at(this->bp + idx); } inline void assert_fn_stack_has(size_t count) { if (this->stack.size() - this->bp < count) { std::cerr << std::format("stack underflow"); std::exit(1); } } inline void assert_stack_has(size_t count) { if (this->stack.size() < count) { std::cerr << std::format("stack underflow"); std::exit(1); } } inline void stack_push(Value&& value) { this->stack.push_back(value); } inline void stack_push(Value& value) { this->stack.push_back(value); } inline auto stack_pop() -> Value { auto value = this->stack.at(this->stack.size() - 1); this->stack.pop_back(); return value; } inline auto assert_program_has(size_t count) { if (this->pc + count >= program_size) { std::cerr << std::format("stack underflow"); std::exit(1); } } private: uint32_t pc = 0; uint32_t bp = 0; const uint32_t* program; size_t program_size; std::vector stack; std::vector pool_heap; }; }