From 2e0d615ac5bc0613f5fcdbbef2ff8eb06ec253ed Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:02:52 -0500 Subject: [PATCH] . --- TODO.md | 8 +++--- src/vm/code.hh | 2 ++ src/vm/expr.cc | 24 ++++++++-------- src/vm/instruction.cc | 6 ++++ src/vm/instruction.hh | 3 ++ src/vm/stack.cc | 8 ++++++ src/vm/stack.hh | 1 + src/vm/tests.cc | 45 ++++++++++++++++------------- src/vm/value.hh | 12 ++++---- src/vm/vm.cc | 66 ++++++++++++++++++++++++++++++++++++++----- src/vm/vm.hh | 20 +++++++++++-- 11 files changed, 143 insertions(+), 52 deletions(-) diff --git a/TODO.md b/TODO.md index 108a86d..5290a03 100644 --- a/TODO.md +++ b/TODO.md @@ -31,11 +31,11 @@ After some additional development: - [x] Print stack - [x] Assembler - [ ] VM execution - - [ ] Expressions - - [x] Integer - - [ ] Float - - [ ] String - [ ] Stack operations (nil, integer, float, string, function) + - [x] Integer + - [x] Float + - [x] String + - [ ] Expressions - [x] Integer - [ ] Float - [ ] String diff --git a/src/vm/code.hh b/src/vm/code.hh index 1c4710b..e4c9b87 100644 --- a/src/vm/code.hh +++ b/src/vm/code.hh @@ -23,6 +23,8 @@ public: [[nodiscard]] Operation operation(Location const& location) const; + [[nodiscard]] bc::Bytecode const& bytecode() const { return bytecode_; } + private: bc::Bytecode bytecode_; }; diff --git a/src/vm/expr.cc b/src/vm/expr.cc index e875725..1d32a88 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -19,15 +19,15 @@ static int init_ = []() { #define BIN_OP(op, t1, t2) binary_ops[(size_t) BinaryOperationType::op][(size_t) Type::t1][(size_t) Type::t2] = [](Value const& b, Value const& a) - BIN_OP(Sum, Integer, Integer) { return Value::CreateInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(Sum, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Subtraction, Integer, Integer) { return Value::CreateInteger(a.as_integer() - b.as_integer()); }; + BIN_OP(Subtraction, Integer, Integer) { return Value::createInteger(a.as_integer() - b.as_integer()); }; - BIN_OP(Multiplication, Integer, Integer) { return Value::CreateInteger(a.as_integer() * b.as_integer()); }; + BIN_OP(Multiplication, Integer, Integer) { return Value::createInteger(a.as_integer() * b.as_integer()); }; - BIN_OP(Division, Integer, Integer) { return Value::CreateFloat((float) a.as_integer() / (float) b.as_integer()); }; + BIN_OP(Division, Integer, Integer) { return Value::createFloat((float) a.as_integer() / (float) b.as_integer()); }; - BIN_OP(IntegerDivision, Integer, Integer) { return Value::CreateInteger(a.as_integer() / b.as_integer()); }; + BIN_OP(IntegerDivision, Integer, Integer) { return Value::createInteger(a.as_integer() / b.as_integer()); }; BIN_OP(Equality, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() == b.as_integer()); }; @@ -41,19 +41,19 @@ static int init_ = []() { BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() >= b.as_integer()); }; - BIN_OP(BitwiseAnd, Integer, Integer) { return Value::CreateInteger(a.as_integer() & b.as_integer()); }; + BIN_OP(BitwiseAnd, Integer, Integer) { return Value::createInteger(a.as_integer() & b.as_integer()); }; - BIN_OP(BitwiseOr, Integer, Integer) { return Value::CreateInteger(a.as_integer() | b.as_integer()); }; + BIN_OP(BitwiseOr, Integer, Integer) { return Value::createInteger(a.as_integer() | b.as_integer()); }; - BIN_OP(BitwiseXor, Integer, Integer) { return Value::CreateInteger(a.as_integer() ^ b.as_integer()); }; + BIN_OP(BitwiseXor, Integer, Integer) { return Value::createInteger(a.as_integer() ^ b.as_integer()); }; - BIN_OP(Power, Integer, Integer) { return Value::CreateInteger((int32_t) powl(a.as_integer(), b.as_integer())); }; + BIN_OP(Power, Integer, Integer) { return Value::createInteger((int32_t) powl(a.as_integer(), b.as_integer())); }; - BIN_OP(ShiftLeft, Integer, Integer) { return Value::CreateInteger(a.as_integer() << b.as_integer()); }; + BIN_OP(ShiftLeft, Integer, Integer) { return Value::createInteger(a.as_integer() << b.as_integer()); }; - BIN_OP(ShiftRight, Integer, Integer) { return Value::CreateInteger(a.as_integer() >> b.as_integer()); }; + BIN_OP(ShiftRight, Integer, Integer) { return Value::createInteger(a.as_integer() >> b.as_integer()); }; - BIN_OP(Modulo, Integer, Integer) { return Value::CreateInteger(a.as_integer() % b.as_integer()); }; + BIN_OP(Modulo, Integer, Integer) { return Value::createInteger(a.as_integer() % b.as_integer()); }; #undef BIN_OP diff --git a/src/vm/instruction.cc b/src/vm/instruction.cc index f739b0a..90fa77a 100644 --- a/src/vm/instruction.cc +++ b/src/vm/instruction.cc @@ -10,6 +10,7 @@ const std::unordered_map instruction_names = { { "pushc", Instruction::PushConstant8 }, { "pushz", Instruction::PushZero }, { "pusht", Instruction::PushTrue }, + { "pushf", Instruction::PushFunction8 }, { "newa", Instruction::NewArray }, { "newt", Instruction::NewTable }, { "pop", Instruction::Pop }, @@ -76,6 +77,11 @@ std::pair debug_instruction(Instruction inst, int oper) case Instruction::PushConstant32: out = "pushc"; break; + case Instruction::PushFunction8: + case Instruction::PushFunction16: + case Instruction::PushFunction32: + out = "pushf"; + break; case Instruction::PushZero: out = "pushz"; break; case Instruction::PushTrue: out = "pusht"; break; case Instruction::NewArray: out = "newa"; break; diff --git a/src/vm/instruction.hh b/src/vm/instruction.hh index f603ff2..78023ad 100644 --- a/src/vm/instruction.hh +++ b/src/vm/instruction.hh @@ -21,6 +21,9 @@ enum class Instruction : uint8_t { PushConstant8 = 0xa1, PushConstant16 = 0xc1, PushConstant32 = 0xe1, + PushFunction8 = 0xa2, + PushFunction16 = 0xc2, + PushFunction32 = 0xe2, PushZero = 0x00, PushTrue = 0x01, NewArray = 0x02, diff --git a/src/vm/stack.cc b/src/vm/stack.cc index 801b9fa..b9240e7 100644 --- a/src/vm/stack.cc +++ b/src/vm/stack.cc @@ -24,6 +24,14 @@ Value Stack::pop() return v; } +Value Stack::peek() const +{ + if (stack_.size() <= fps_.top()) + throw VMStackUnderflow(); + + return stack_.back(); +} + Value Stack::at(int pos) const { try { diff --git a/src/vm/stack.hh b/src/vm/stack.hh index 96d04e9..b17fcd1 100644 --- a/src/vm/stack.hh +++ b/src/vm/stack.hh @@ -14,6 +14,7 @@ public: void push(Value const& value); Value pop(); + [[nodiscard]] Value peek() const; [[nodiscard]] Value at(int pos) const; [[nodiscard]] size_t size() const; diff --git a/src/vm/tests.cc b/src/vm/tests.cc index aa62a2b..d06a3b0 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -11,6 +11,17 @@ using namespace tyche; using namespace tyche::bc; using namespace tyche::vm; +static VM run(std::string oper) { + return VM().load_bytecode(as::Assembler(std::format(R"( + .const + 0: 3.14 + 1: "Hello world" + .func 0 + {} + ret + )", oper)).assemble()).call(0); +} + TEST(Code, ImportSingleAndDebug) { BytecodePrototype bp; @@ -35,9 +46,9 @@ TEST(Code, ImportSingleAndDebug) TEST(Stack, PushPullGet) { Stack stack; - stack.push(Value::CreateInteger(10)); - stack.push(Value::CreateInteger(20)); - stack.push(Value::CreateInteger(30)); + stack.push(Value::createInteger(10)); + stack.push(Value::createInteger(20)); + stack.push(Value::createInteger(30)); ASSERT_EQ(stack.size(), 3); ASSERT_EQ(stack.at(0).as_integer(), 10); @@ -49,12 +60,12 @@ TEST(Stack, PushPullGet) TEST(Stack, FramePointer) { Stack stack; - stack.push(Value::CreateInteger(10)); - stack.push(Value::CreateInteger(20)); + stack.push(Value::createInteger(10)); + stack.push(Value::createInteger(20)); stack.push_fp(); - stack.push(Value::CreateInteger(30)); - stack.push(Value::CreateInteger(40)); - stack.push(Value::CreateInteger(50)); + stack.push(Value::createInteger(30)); + stack.push(Value::createInteger(40)); + stack.push(Value::createInteger(50)); ASSERT_EQ(stack.size(), 3); ASSERT_EQ(stack.at(0).as_integer(), 30); @@ -94,20 +105,14 @@ TEST(VM, BasicCode) TEST(VM, StackOperations) { - auto run = [](std::string oper) { - return VM().load_bytecode(as::Assembler(std::format(R"( - .const - 0: 3.14 - 1: "Hello world" - .func 0 - {} - ret - )", oper)).assemble()).call(0); - }; - ASSERT_EQ(run("pushi 5000").to_integer(-1), 5000); ASSERT_EQ(run("pushi -5000").to_integer(-1), -5000); + ASSERT_FLOAT_EQ(run("pushi 5000").to_float(-1), 5000.f); ASSERT_FLOAT_EQ(run("pushc 0").to_float(-1), 3.14f); + ASSERT_EQ(run("pushc 0").to_integer(-1), 3); + ASSERT_EQ(run("pushc 1").to_string(-1), "Hello world"); + ASSERT_TRUE(run("pushf 0").is_function(-1)); + ASSERT_EQ(run("pushi 2\n pushi 3\n pop").to_integer(-1), 2); } TEST(VM, IntegerIntegerOperations) @@ -144,7 +149,7 @@ TEST(VM, IntegerIntegerOperations) ASSERT_EQ(test_op(30, 2, "shr"), 7); ASSERT_EQ(test_op(8, 3, "mod"), 2); - // TODO - div + ASSERT_FLOAT_EQ(run("pushi 3\n pushi 2\n div").to_float(-1), 1.5f); } int main(int argc, char** argv) diff --git a/src/vm/value.hh b/src/vm/value.hh index 5d01d06..5699cdb 100644 --- a/src/vm/value.hh +++ b/src/vm/value.hh @@ -22,13 +22,13 @@ class Value { public: Value() : value_(std::monostate()) {} - static Value CreateNil() { return Value(std::monostate()); } - static Value CreateInteger(int32_t v) { return Value(v); } - static Value CreateFloat(float f) { return Value(f); } - static Value CreateString(std::string const& str) { return Value(str); } - static Value CreateFunctionId(FunctionId f_id) { return Value(Function { f_id }); } + static Value createNil() { return Value(std::monostate()); } + static Value createInteger(int32_t v) { return Value(v); } + static Value createFloat(float f) { return Value(f); } + static Value createString(std::string const& str) { return Value(str); } + static Value createFunctionId(FunctionId f_id) { return Value(Function { f_id }); } - static Value CreateIntegerFromBool(bool b) { return CreateInteger(b ? 1 : 0); } + static Value CreateIntegerFromBool(bool b) { return createInteger(b ? 1 : 0); } [[nodiscard]] Type type() const; diff --git a/src/vm/vm.cc b/src/vm/vm.cc index b8854b2..d3408dd 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -8,7 +8,7 @@ namespace tyche::vm { VM& VM::load_bytecode(ByteArray const& ba) { FunctionId f_id = code_.import_bytecode(ba); - stack_.push(Value::CreateFunctionId(f_id)); + stack_.push(Value::createFunctionId(f_id)); return *this; } @@ -32,26 +32,51 @@ VM& VM::call(size_t n_params) int32_t VM::to_integer(int index) const { Value i = stack_.at(index); - assert_type(i, Type::Integer); - return i.as_integer(); + if (i.type() == Type::Integer) + return i.as_integer(); + if (i.type() == Type::Float) + return (int32_t) i.as_float(); + throw VMTypeError(Type::Integer, i.type()); } float VM::to_float(int index) const +{ + Value f = stack_.at(index); + if (f.type() == Type::Float) + return f.as_float(); + if (f.type() == Type::Integer) + return (float) f.as_integer(); + throw VMTypeError(Type::Float, f.type()); +} + +std::string VM::to_string(int index) const { Value i = stack_.at(index); - assert_type(i, Type::Float); - return i.as_float(); + assert_type(i, Type::String); + return i.as_string(); +} + +VM& VM::push_nil() +{ + stack_.push(Value::createNil()); + return *this; } VM& VM::push_integer(int32_t value) { - stack_.push(Value::CreateInteger(value)); + stack_.push(Value::createInteger(value)); return *this; } VM& VM::push_float(float value) { - stack_.push(Value::CreateFloat(value)); + stack_.push(Value::createFloat(value)); + return *this; +} + +VM& VM::push_string(std::string const& str) +{ + stack_.push(Value::createString(str)); return *this; } @@ -79,6 +104,33 @@ void VM::step() push_integer(op.operator_); break; + case Instruction::PushConstant8: + case Instruction::PushConstant16: + case Instruction::PushConstant32: { + auto cnst = code_.bytecode().get_constant(op.operator_); + if (auto f = std::get_if(&cnst)) + push_float(*f); + else if (auto s = std::get_if(&cnst)) + push_string(*s); + else + throw std::logic_error("Shouldn't get here"); + break; + } + + case Instruction::PushFunction8: + case Instruction::PushFunction16: + case Instruction::PushFunction32: + stack_.push(Value::createFunctionId(op.operator_)); + break; + + case Instruction::Pop: + stack_.pop(); + break; + + case Instruction::Duplicate: + stack_.push(stack_.peek()); + break; + // // logical/arithmetic // diff --git a/src/vm/vm.hh b/src/vm/vm.hh index e555bb6..4477e41 100644 --- a/src/vm/vm.hh +++ b/src/vm/vm.hh @@ -13,13 +13,27 @@ public: VM& call(size_t n_params); - [[nodiscard]] int32_t to_integer(int index) const; - [[nodiscard]] float to_float(int index) const; + [[nodiscard]] bool is_nil(int index) const { return stack_.at(index).type() == Type::Nil; } + [[nodiscard]] bool is_integer(int index) const { return stack_.at(index).type() == Type::Integer; } + [[nodiscard]] bool is_float(int index) const { return stack_.at(index).type() == Type::Float; } + [[nodiscard]] bool is_string(int index) const { return stack_.at(index).type() == Type::String; } + [[nodiscard]] bool is_array(int index) const { return stack_.at(index).type() == Type::Array; } + [[nodiscard]] bool is_table(int index) const { return stack_.at(index).type() == Type::Table; } + [[nodiscard]] bool is_function(int index) const { return stack_.at(index).type() == Type::Function; } + [[nodiscard]] bool is_native_pointer(int index) const { return stack_.at(index).type() == Type::NativePointer; } + [[nodiscard]] size_t stack_sz() const { return stack_.size(); } + + VM& push_nil(); VM& push_integer(int32_t value); VM& push_float(float value); + VM& push_string(std::string const& string); - [[nodiscard]] std::string debug_stack() const { return stack_.debug(); } + [[nodiscard]] int32_t to_integer(int index) const; + [[nodiscard]] float to_float(int index) const; + [[nodiscard]] std::string to_string(int index) const; + + [[nodiscard]] std::string debug_stack() const { return stack_.debug(); } private: void run_until_return();