From 161ea947d71942e428d34072d346c1518faa669d Mon Sep 17 00:00:00 2001 From: SimonFJ20 Date: Mon, 11 Nov 2024 15:31:54 +0100 Subject: [PATCH] finish runtime instrs --- runtime/arch.hpp | 43 +++++----- runtime/value.hpp | 2 +- runtime/vm.cpp | 209 +++++++++++++++++++++++++++++++++++++++------- runtime/vm.hpp | 67 ++++++++++++++- src/arch.ts | 43 +++++----- 5 files changed, 287 insertions(+), 77 deletions(-) diff --git a/runtime/arch.hpp b/runtime/arch.hpp index 411758e..317ed5b 100644 --- a/runtime/arch.hpp +++ b/runtime/arch.hpp @@ -10,28 +10,27 @@ enum class Op : uint32_t { Nop = 0, PushNull = 1, PushInt = 2, - PushString = 3, - PushArray = 4, - PushStruct = 5, - PushPtr = 6, - Pop = 7, - LoadLocal = 8, - StoreLocal = 9, - Call = 10, - Return = 11, - Jump = 12, - JumpIfNotZero = 13, - Add = 14, - Subtract = 15, - Multiply = 16, - Divide = 17, - Remainder = 18, - Equal = 19, - LessThan = 20, - And = 21, - Or = 22, - Xor = 23, - Not = 24, + PushBool = 3, + PushString = 4, + PushPtr = 5, + Pop = 6, + LoadLocal = 7, + StoreLocal = 8, + Call = 9, + Return = 10, + Jump = 11, + JumpIfFalse = 12, + Add = 13, + Subtract = 14, + Multiply = 15, + Divide = 16, + Remainder = 17, + Equal = 18, + LessThan = 19, + And = 20, + Or = 21, + Xor = 22, + Not = 23, }; } diff --git a/runtime/value.hpp b/runtime/value.hpp index 1f841f3..33b60a3 100644 --- a/runtime/value.hpp +++ b/runtime/value.hpp @@ -18,7 +18,7 @@ class Values; struct Null { }; struct Int { - uint32_t value; + int32_t value; }; struct Bool { bool value; diff --git a/runtime/vm.cpp b/runtime/vm.cpp index 3cba947..e3c7f07 100644 --- a/runtime/vm.cpp +++ b/runtime/vm.cpp @@ -1,14 +1,18 @@ #include "vm.hpp" #include "arch.hpp" +#include +#include #include #include +#include +#include using namespace sliger; void VM::run() { while (!done()) { - auto op = eat_as_op(); + auto op = eat_op(); switch (op) { case Op::Nop: // nothing @@ -16,35 +20,184 @@ void VM::run() case Op::PushNull: this->stack.push_back(Null {}); break; - case Op::PushInt: - if (done()) { - std::cerr - << std::format("program malformed: missing int value"); - } - this->stack.push_back(Null {}); + case Op::PushInt: { + assert_program_has(1); + auto value = eat_int32(); + this->stack.push_back(Int { value }); break; - case Op::PushString: - case Op::PushArray: - case Op::PushStruct: - case Op::PushPtr: - case Op::Pop: - case Op::LoadLocal: - case Op::StoreLocal: - case Op::Call: - case Op::Return: - case Op::Jump: - case Op::JumpIfNotZero: - case Op::Add: - case Op::Subtract: - case Op::Multiply: - case Op::Divide: - case Op::Remainder: - case Op::Equal: - case Op::LessThan: - case Op::And: - case Op::Or: - case Op::Xor: + } + 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 (auto i = arguments.size(); i >= 0; --i) { + auto argument = std::move(arguments.at(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; } } diff --git a/runtime/vm.hpp b/runtime/vm.hpp index eac7227..20758fb 100644 --- a/runtime/vm.hpp +++ b/runtime/vm.hpp @@ -4,13 +4,15 @@ #include "value.hpp" #include #include +#include +#include #include namespace sliger { class VM { public: - VM(const std::vector& program) + VM(const std::vector& program) : program(program.data()) , program_size(program.size()) { @@ -19,23 +21,80 @@ public: inline void step() { this->pc += 1; } - inline auto eat_as_op() -> Op + 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; - const Op* program; + uint32_t bp = 0; + const uint32_t* program; size_t program_size; std::vector stack; std::vector pool_heap; diff --git a/src/arch.ts b/src/arch.ts index eaa838c..77a73d7 100644 --- a/src/arch.ts +++ b/src/arch.ts @@ -8,26 +8,25 @@ export const Ops = { Nop: 0, PushNull: 1, PushInt: 2, - PushString: 3, - PushArray: 4, - PushStruct: 5, - PushPtr: 6, - Pop: 7, - LoadLocal: 8, - StoreLocal: 9, - Call: 10, - Return: 11, - Jump: 12, - JumpIfNotZero: 13, - Add: 14, - Subtract: 15, - Multiply: 16, - Divide: 17, - Remainder: 18, - Equal: 19, - LessThan: 20, - And: 21, - Or: 22, - Xor: 23, - Not: 24, + PushBool: 3, + PushString: 4, + PushPtr: 5, + Pop: 6, + LoadLocal: 7, + StoreLocal: 8, + Call: 9, + Return: 10, + Jump: 11, + JumpIfTrue: 12, + Add: 13, + Subtract: 14, + Multiply: 15, + Divide: 16, + Remainder: 17, + Equal: 18, + LessThan: 19, + And: 20, + Or: 21, + Xor: 22, + Not: 23, } as const;