From 0bc40cc5622fbb9147eb3c186cbd73045794699d Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 16:39:49 -0500 Subject: [PATCH] . --- src/assembler/assembler.hh | 2 +- src/vm/expr.cc | 54 +++++++++++++++++++++++++++++++++----- src/vm/expr.hh | 7 ++++- src/vm/tests.cc | 23 ++++++++++++++++ src/vm/value.cc | 15 +++++++++++ src/vm/value.hh | 5 +++- src/vm/vm.cc | 49 +++++++++++++++++++++++++++++++--- src/vm/vm.hh | 6 ++--- src/vm/vm_exceptions.hh | 4 +-- 9 files changed, 147 insertions(+), 18 deletions(-) diff --git a/src/assembler/assembler.hh b/src/assembler/assembler.hh index 00f87e5..eea7acf 100644 --- a/src/assembler/assembler.hh +++ b/src/assembler/assembler.hh @@ -12,7 +12,7 @@ namespace tyche::as { class Assembler { public: - explicit Assembler(std::string source) : lexer_(std::move(source)) {} + explicit Assembler(std::string source) : lexer_(std::move(source) + "\n") {} [[nodiscard]] ByteArray assemble(); diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 26878a7..89b1dab 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -1,18 +1,58 @@ #include "expr.hh" +#include + #include "vm_exceptions.hh" namespace tyche::vm { +std::function binary_ops[(size_t) BinaryOperationType::COUNT][(size_t) Type::COUNT][(size_t) Type::COUNT]; + +static int init_ = []() { + for (size_t i = 0; i < (size_t) BinaryOperationType::COUNT; ++i) + for (size_t j = 0; j < (size_t) Type::COUNT; ++j) + for (size_t k = 0; k < (size_t) Type::COUNT; ++k) + binary_ops[i][j][k] = [&i](Value const& a, Value const& b) -> Value { + throw VMInvalidOperation((BinaryOperationType) i, a.type(), b.type()); + }; + + // TODO - create macro +#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(Subtraction, 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(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()); }; + + BIN_OP(Inequality, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() != b.as_integer()); }; + + BIN_OP(LessThan, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() < b.as_integer()); }; + + BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() <= b.as_integer()); }; + + BIN_OP(GreaterThan, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() > b.as_integer()); }; + + 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(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()); }; + +#undef BIN_OP + + return 0; +}(); + Value binary_operation(Value const& a, Value const& b, BinaryOperationType op) { - // TODO - this is temporary code - - if (a.type() == Type::Integer && b.type() == Type::Integer && op == BinaryOperationType::Sum) { - return Value::CreateInteger(a.as_integer() + b.as_integer()); - } else { - throw VMInvalidOperation(op, a.type(), b.type()); - } + return binary_ops[(size_t) op][(size_t) a.type()][(size_t) b.type()](a, b); } } \ No newline at end of file diff --git a/src/vm/expr.hh b/src/vm/expr.hh index 539672e..83a307c 100644 --- a/src/vm/expr.hh +++ b/src/vm/expr.hh @@ -4,7 +4,12 @@ namespace tyche::vm { -enum class BinaryOperationType { Sum }; +enum class BinaryOperationType +{ + Sum, Subtraction, Multiplication, Division, IntegerDivision, Equality, Inequality, LessThan, LessThanOrEquals, + GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, + COUNT +}; Value binary_operation(Value const& a, Value const& b, BinaryOperationType op); diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 0d75fdf..c06daa4 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -3,6 +3,7 @@ #include "../bytecode/bytecodeprototype.hh" #include "../common/bytearray.hh" #include "../bytecode/bytecode.hh" +#include "../assembler/assembler.hh" #include "code.hh" #include "stack.hh" #include "vm.hh" @@ -92,6 +93,28 @@ TEST(VM, BasicCode) ASSERT_EQ(result, 5); } +TEST(VM, SumIntegers) +{ + ASSERT_EQ(VM().load_bytecode(as::Assembler(R"( +.func 0 + pushi 2 + pushi 3 + sum + ret + )").assemble()).call(0).to_integer(-1), 5); +} + +TEST(VM, SubtractIntegers) +{ + ASSERT_EQ(VM().load_bytecode(as::Assembler(R"( +.func 0 + pushi 2 + pushi 3 + sub + ret + )").assemble()).call(0).to_integer(-1), -1); +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/src/vm/value.cc b/src/vm/value.cc index 13f015e..535f78c 100644 --- a/src/vm/value.cc +++ b/src/vm/value.cc @@ -4,6 +4,21 @@ namespace tyche::vm { +std::string type_name(Type type) +{ + switch (type) { + case Type::Nil: return "nil"; + case Type::Integer: return "integer"; + case Type::Float: return "float"; + case Type::String: return "string"; + case Type::Array: return "array"; + case Type::Table: return "table"; + case Type::Function: return "function"; + case Type::NativePointer: return "native pointer"; + default: return "???"; + } +} + Type Value::type() const { return std::visit(overloaded { diff --git a/src/vm/value.hh b/src/vm/value.hh index 2592cd6..a052cb1 100644 --- a/src/vm/value.hh +++ b/src/vm/value.hh @@ -10,9 +10,10 @@ using FunctionId = uint32_t; enum class Type : uint8_t { - Nil = 0, Integer, Float, String, Array, Table, Function, NativePointer, + Nil = 0, Integer, Float, String, Array, Table, Function, NativePointer, COUNT }; +std::string type_name(Type type); class Value { struct Function { FunctionId f_id; }; @@ -26,6 +27,8 @@ public: 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); } + [[nodiscard]] Type type() const; [[nodiscard]] int32_t as_integer() const { return std::get(value_); } diff --git a/src/vm/vm.cc b/src/vm/vm.cc index 502fad8..a1a9d33 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -5,13 +5,14 @@ namespace tyche::vm { -void VM::load_bytecode(ByteArray const& ba) +VM& VM::load_bytecode(ByteArray const& ba) { FunctionId f_id = code_.import_bytecode(ba); stack_.push(Value::CreateFunctionId(f_id)); + return *this; } -void VM::call(size_t n_params) +VM& VM::call(size_t n_params) { // TODO - parameters @@ -24,6 +25,8 @@ void VM::call(size_t n_params) run_until_return(); // stack_.pop_fp(); loc_.pop(); + + return *this; } int32_t VM::to_integer(int index) const @@ -33,9 +36,10 @@ int32_t VM::to_integer(int index) const return i.as_integer(); } -void VM::push_integer(int32_t value) +VM& VM::push_integer(int32_t value) { stack_.push(Value::CreateInteger(value)); + return *this; } void VM::run_until_return() @@ -58,6 +62,45 @@ void VM::step() case Instruction::Sum: stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Sum)); break; + case Instruction::Subtract: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Subtraction)); + break; + case Instruction::Multiply: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Multiplication)); + break; + case Instruction::Divide: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Division)); + break; + case Instruction::DivideInt: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::IntegerDivision)); + break; + case Instruction::Equals: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Equality)); + break; + case Instruction::NotEquals: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Inequality)); + break; + case Instruction::LessThan: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::LessThan)); + break; + case Instruction::LessThanEq: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::LessThanOrEquals)); + break; + case Instruction::GreaterThan: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::GreaterThan)); + break; + case Instruction::GreaterThanEq: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::GreaterThanOrEquals)); + break; + case Instruction::And: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseAnd)); + break; + case Instruction::Or: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseOr)); + break; + case Instruction::Xor: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseXor)); + break; case Instruction::Return: { Value v = stack_.pop(); stack_.pop_fp(); diff --git a/src/vm/vm.hh b/src/vm/vm.hh index d989268..6ecd22a 100644 --- a/src/vm/vm.hh +++ b/src/vm/vm.hh @@ -9,13 +9,13 @@ namespace tyche::vm { class VM { public: - void load_bytecode(ByteArray const& ba); + VM& load_bytecode(ByteArray const& ba); - void call(size_t n_params); + VM& call(size_t n_params); [[nodiscard]] int32_t to_integer(int index) const; - void push_integer(int32_t value); + VM& push_integer(int32_t value); [[nodiscard]] std::string debug_stack() const { return stack_.debug(); } diff --git a/src/vm/vm_exceptions.hh b/src/vm/vm_exceptions.hh index 610f43b..7c2c1ed 100644 --- a/src/vm/vm_exceptions.hh +++ b/src/vm/vm_exceptions.hh @@ -29,7 +29,7 @@ public: class VMTypeError : public VMRuntimeError { public: - explicit VMTypeError(Type expected, Type found) : VMRuntimeError("Type error") {} // TODO - print types + explicit VMTypeError(Type expected, Type found) : VMRuntimeError("Type error (expected " + type_name(expected) + ", found " + type_name(found) + ")") {} }; class VMInvalidOpcode : public VMRuntimeError @@ -41,7 +41,7 @@ public: class VMInvalidOperation : public VMRuntimeError { public: - explicit VMInvalidOperation(BinaryOperationType op, Type type1, Type type2) : VMRuntimeError("Invalid binary operation") {} // TODO - print types + explicit VMInvalidOperation(BinaryOperationType op, Type type1, Type type2) : VMRuntimeError("Invalid binary operation for types " + type_name(type1) + " and " + type_name(type2)) {} }; }