From bebaed19982935b1602c7120e14946603008f0f1 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 10:40:21 -0500 Subject: [PATCH 01/21] . --- TODO.md | 29 +++++++++++++++++++++++++---- doc/OPCODES | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/TODO.md b/TODO.md index fedadc1..f9c69d4 100644 --- a/TODO.md +++ b/TODO.md @@ -19,7 +19,7 @@ After some additional development: ## VM -- [ ] VM +- [x] VM - [x] Code - [x] Simple bytecode loader - [x] Output bytecode format @@ -29,10 +29,31 @@ After some additional development: - [x] Code execution (except functions) - [x] Functions - [x] Print stack - -- [ ] Assembler +- [x] Assembler +- [ ] VM execution + - [ ] Stack operations (nil, integer, float, string, function) + - [ ] Expressions + - [ ] Local/global variables + - [ ] Functions + - [ ] Constants + - [ ] Other operations + - [ ] Arrays + - [ ] Iteration + - [ ] Expressions + - [ ] Tables + - [ ] Iteration + - [ ] Metatables + - [ ] Expressions + - [ ] Control flow + - [ ] Compilation + - [ ] Error handling +- [ ] C++ API + - [ ] Run native code on VM + - [ ] Run tyche code from C++ + - [ ] C API After some additional development: - [ ] Bytecode loader - Combine multiple chunks - - Resolve function ids, constant ids, etc \ No newline at end of file + - Resolve function ids, constant ids, etc +- [ ] Upvalues \ No newline at end of file diff --git a/doc/OPCODES b/doc/OPCODES index ece0501..507e79a 100644 --- a/doc/OPCODES +++ b/doc/OPCODES @@ -37,7 +37,7 @@ Local variables: Function operations: a7 c7 e7 call [n_pars] Enter function on stack toplevel (passing n next stack values as parameters) -10 ret Leave a function (return value in stack) +10 ret Leave a function (return value in stack) 11 retn Leave a function (return nil) Table and array operations: -- 2.49.1 From 0bc40cc5622fbb9147eb3c186cbd73045794699d Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 16:39:49 -0500 Subject: [PATCH 02/21] . --- 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)) {} }; } -- 2.49.1 From 8f6d858a28a97ac41f3b1ab2ac8bb5e862fc4cb7 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 16:52:32 -0500 Subject: [PATCH 03/21] . --- doc/OPCODES | 15 +++--- src/common/bytearray.cc | 2 +- src/vm/code.cc | 1 + src/vm/expr.cc | 7 +++ src/vm/expr.hh | 2 +- src/vm/instruction.cc | 102 +++++++++++++++++++++------------------- src/vm/instruction.hh | 17 ++++--- src/vm/value.cc | 2 +- src/vm/vm.cc | 9 ++++ 9 files changed, 93 insertions(+), 64 deletions(-) diff --git a/doc/OPCODES b/doc/OPCODES index 507e79a..f809bae 100644 --- a/doc/OPCODES +++ b/doc/OPCODES @@ -65,17 +65,20 @@ Logical/arithmetic: 2b and Bitwise AND 2c or Bitwise OR 2d xor Bitwise XOR +2e pow Power +2f shl Shift left +30 shr Shift right Other value operations: -30 len Get table, array or string size -31 type Get type from value at the top of the stack +40 len Get table, array or string size +41 type Get type from value at the top of the stack b0 cast [type] Cast type to another type -32 ver Return VM version +42 ver Return VM version External code: -38 cmpl Compile code to assembly -39 asmbl Assemble code to bytecode format -3a load Load bytecode as function (will place function on stack) +48 cmpl Compile code to assembly +49 asmbl Assemble code to bytecode format +4a load Load bytecode as function (will place function on stack) Control flow: a8 c8 e8 bz [pc] Branch if zero diff --git a/src/common/bytearray.cc b/src/common/bytearray.cc index 2af83b2..39a4194 100644 --- a/src/common/bytearray.cc +++ b/src/common/bytearray.cc @@ -134,7 +134,7 @@ std::string ByteArray::hexdump() const { auto to_hex = [](uint32_t value, size_t n_chars) -> std::string { char buf[15]; - snprintf(buf, sizeof buf, (std::string("%0") + std::to_string(n_chars) + "X").c_str(), value); + snprintf(buf, sizeof buf, "%0*X", (int) n_chars, value); return { buf }; }; diff --git a/src/vm/code.cc b/src/vm/code.cc index d780fbc..ab3d9b3 100644 --- a/src/vm/code.cc +++ b/src/vm/code.cc @@ -44,6 +44,7 @@ Operation Code::operation(Location const& location) const .operator_ = bytecode_.get_code_int32(location.function_id, location.pc + 1), .next_location = { .function_id = location.function_id, .pc = location.pc + 5 }, }; + default: } throw std::logic_error("Should not get here"); diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 89b1dab..304a2eb 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -1,5 +1,6 @@ #include "expr.hh" +#include #include #include "vm_exceptions.hh" @@ -45,6 +46,12 @@ static int init_ = []() { 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(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()); }; + #undef BIN_OP return 0; diff --git a/src/vm/expr.hh b/src/vm/expr.hh index 83a307c..655a390 100644 --- a/src/vm/expr.hh +++ b/src/vm/expr.hh @@ -7,7 +7,7 @@ namespace tyche::vm { enum class BinaryOperationType { Sum, Subtraction, Multiplication, Division, IntegerDivision, Equality, Inequality, LessThan, LessThanOrEquals, - GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, + GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, Power, ShiftLeft, ShiftRight, COUNT }; diff --git a/src/vm/instruction.cc b/src/vm/instruction.cc index f719fb8..27ea8ce 100644 --- a/src/vm/instruction.cc +++ b/src/vm/instruction.cc @@ -5,54 +5,57 @@ namespace tyche::vm { -const std::unordered_map instruction_names = { - { "pushi", vm::Instruction::PushInt8 }, - { "pushc", vm::Instruction::PushConstant8 }, - { "pushz", vm::Instruction::PushZero }, - { "pusht", vm::Instruction::PushTrue }, - { "newa", vm::Instruction::NewArray }, - { "newt", vm::Instruction::NewTable }, - { "pop", vm::Instruction::Pop }, - { "dup", vm::Instruction::Duplicate }, - { "setl", vm::Instruction::SetLocal8 }, - { "getl", vm::Instruction::GetLocal8 }, - { "setg", vm::Instruction::SetGlobal8 }, - { "getl", vm::Instruction::GetGlobal8 }, - { "call8", vm::Instruction::Call8 }, - { "ret", vm::Instruction::Return }, - { "retn", vm::Instruction::ReturnNil }, - { "getkv", vm::Instruction::GetKeyValue }, - { "setkv", vm::Instruction::SetKeyValue }, - { "geta", vm::Instruction::GetArrayItem }, - { "seta", vm::Instruction::SetArrayItem }, - { "appnd", vm::Instruction::Append }, - { "next", vm::Instruction::Next }, - { "smt", vm::Instruction::SetMetatable }, - { "mt", vm::Instruction::GetMetatable }, - { "sum", vm::Instruction::Sum }, - { "sub", vm::Instruction::Subtract }, - { "mul", vm::Instruction::Multiply }, - { "div", vm::Instruction::Divide }, - { "idiv", vm::Instruction::DivideInt }, - { "eq", vm::Instruction::Equals }, - { "neq", vm::Instruction::NotEquals }, - { "lt", vm::Instruction::LessThan }, - { "lte", vm::Instruction::LessThanEq }, - { "gt", vm::Instruction::GreaterThan }, - { "gte", vm::Instruction::GreaterThanEq }, - { "and", vm::Instruction::And }, - { "or", vm::Instruction::Or }, - { "xor", vm::Instruction::Xor }, - { "len", vm::Instruction::Len }, - { "type", vm::Instruction::Type }, - { "cast", vm::Instruction::Cast }, - { "ver", vm::Instruction::Version }, - { "bz", vm::Instruction::BranchIfZero8 }, - { "bnz", vm::Instruction::BranchIfNotZero8 }, - { "jmp", vm::Instruction::Jump8 }, - { "cmpl", vm::Instruction::Compile }, - { "asmbl", vm::Instruction::Assemble }, - { "load", vm::Instruction::Load }, +const std::unordered_map instruction_names = { + { "pushi", Instruction::PushInt8 }, + { "pushc", Instruction::PushConstant8 }, + { "pushz", Instruction::PushZero }, + { "pusht", Instruction::PushTrue }, + { "newa", Instruction::NewArray }, + { "newt", Instruction::NewTable }, + { "pop", Instruction::Pop }, + { "dup", Instruction::Duplicate }, + { "setl", Instruction::SetLocal8 }, + { "getl", Instruction::GetLocal8 }, + { "setg", Instruction::SetGlobal8 }, + { "getl", Instruction::GetGlobal8 }, + { "call8", Instruction::Call8 }, + { "ret", Instruction::Return }, + { "retn", Instruction::ReturnNil }, + { "getkv", Instruction::GetKeyValue }, + { "setkv", Instruction::SetKeyValue }, + { "geta", Instruction::GetArrayItem }, + { "seta", Instruction::SetArrayItem }, + { "appnd", Instruction::Append }, + { "next", Instruction::Next }, + { "smt", Instruction::SetMetatable }, + { "mt", Instruction::GetMetatable }, + { "sum", Instruction::Sum }, + { "sub", Instruction::Subtract }, + { "mul", Instruction::Multiply }, + { "div", Instruction::Divide }, + { "idiv", Instruction::DivideInt }, + { "eq", Instruction::Equals }, + { "neq", Instruction::NotEquals }, + { "lt", Instruction::LessThan }, + { "lte", Instruction::LessThanEq }, + { "gt", Instruction::GreaterThan }, + { "gte", Instruction::GreaterThanEq }, + { "and", Instruction::And }, + { "or", Instruction::Or }, + { "xor", Instruction::Xor }, + { "pow", Instruction::Power }, + { "shl", Instruction::ShiftLeft }, + { "shr", Instruction::ShiftRight }, + { "len", Instruction::Len }, + { "type", Instruction::Type }, + { "cast", Instruction::Cast }, + { "ver", Instruction::Version }, + { "bz", Instruction::BranchIfZero8 }, + { "bnz", Instruction::BranchIfNotZero8 }, + { "jmp", Instruction::Jump8 }, + { "cmpl", Instruction::Compile }, + { "asmbl", Instruction::Assemble }, + { "load", Instruction::Load }, }; @@ -127,6 +130,9 @@ std::pair debug_instruction(Instruction inst, int oper) case Instruction::And: out = "and"; break; case Instruction::Or: out = "or"; break; case Instruction::Xor: out = "xor"; break; + case Instruction::Power: out = "pow"; break; + case Instruction::ShiftLeft: out = "shl"; break; + case Instruction::ShiftRight: out = "shr"; break; case Instruction::Len: out = "len"; break; case Instruction::Type: out = "type"; break; case Instruction::Cast: out = "cast"; break; diff --git a/src/vm/instruction.hh b/src/vm/instruction.hh index e87622a..a058751 100644 --- a/src/vm/instruction.hh +++ b/src/vm/instruction.hh @@ -74,12 +74,15 @@ enum class Instruction : uint8_t { And = 0x2b, Or = 0x2c, Xor = 0x2d, + Power = 0x2e, + ShiftLeft = 0x2f, + ShiftRight = 0x30, // other value operations - Len = 0x30, - Type = 0x31, - Cast = 0x32, - Version = 0x33, + Len = 0x40, + Type = 0x41, + Cast = 0x42, + Version = 0x43, // control flow BranchIfZero8 = 0xa8, @@ -93,9 +96,9 @@ enum class Instruction : uint8_t { Jump32 = 0xea, // external code - Compile = 0x38, - Assemble = 0x39, - Load = 0x3a, + Compile = 0x48, + Assemble = 0x49, + Load = 0x4a, }; std::pair debug_instruction(Instruction inst, int oper=0); diff --git a/src/vm/value.cc b/src/vm/value.cc index 535f78c..07523b4 100644 --- a/src/vm/value.cc +++ b/src/vm/value.cc @@ -15,7 +15,7 @@ std::string type_name(Type type) case Type::Table: return "table"; case Type::Function: return "function"; case Type::NativePointer: return "native pointer"; - default: return "???"; + case Type::COUNT: default: return "???"; } } diff --git a/src/vm/vm.cc b/src/vm/vm.cc index a1a9d33..b59cfb8 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -101,6 +101,15 @@ void VM::step() case Instruction::Xor: stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseXor)); break; + case Instruction::Power: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Power)); + break; + case Instruction::ShiftLeft: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::ShiftLeft)); + break; + case Instruction::ShiftRight: + stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::ShiftRight)); + break; case Instruction::Return: { Value v = stack_.pop(); stack_.pop_fp(); -- 2.49.1 From eed9196cd11b5564c64c4f8f849077928ff08138 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 16:55:36 -0500 Subject: [PATCH 04/21] . --- TODO.md | 3 +++ src/vm/tests.cc | 28 +++++++++++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/TODO.md b/TODO.md index f9c69d4..f1a2742 100644 --- a/TODO.md +++ b/TODO.md @@ -32,6 +32,9 @@ After some additional development: - [x] Assembler - [ ] VM execution - [ ] Stack operations (nil, integer, float, string, function) + - [ ] Integer + - [ ] Float + - [ ] String - [ ] Expressions - [ ] Local/global variables - [ ] Functions diff --git a/src/vm/tests.cc b/src/vm/tests.cc index c06daa4..61688fb 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -95,24 +95,18 @@ TEST(VM, BasicCode) 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); -} + auto test_op = [](int32_t op1, int32_t op2, std::string oper) { + return VM().load_bytecode(as::Assembler(std::format(R"( + .func 0 + pushi {} + pushi {} + {} + ret + )", op1, op2, oper)).assemble()).call(0).to_integer(-1); + }; -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); + ASSERT_EQ(test_op(2, 3, "sum"), 5); + ASSERT_EQ(test_op(2, 3, "sub"), -1); } int main(int argc, char** argv) -- 2.49.1 From 50db8b973843901d96f703ef1e4a606ae07cb13c Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 17:02:44 -0500 Subject: [PATCH 05/21] . --- src/vm/expr.cc | 2 ++ src/vm/tests.cc | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 304a2eb..2470f42 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -24,6 +24,8 @@ static int init_ = []() { 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(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()); }; diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 61688fb..4786b03 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -93,7 +93,7 @@ TEST(VM, BasicCode) ASSERT_EQ(result, 5); } -TEST(VM, SumIntegers) +TEST(VM, IntegerIntegerOperations) { auto test_op = [](int32_t op1, int32_t op2, std::string oper) { return VM().load_bytecode(as::Assembler(std::format(R"( @@ -107,6 +107,26 @@ TEST(VM, SumIntegers) ASSERT_EQ(test_op(2, 3, "sum"), 5); ASSERT_EQ(test_op(2, 3, "sub"), -1); + ASSERT_EQ(test_op(2, 3, "mul"), 6); + ASSERT_EQ(test_op(20, 3, "idiv"), 6); + ASSERT_EQ(test_op(2, 3, "eq"), 0); + ASSERT_EQ(test_op(2, 3, "neq"), 1); + ASSERT_EQ(test_op(2, 3, "lt"), 1); + ASSERT_EQ(test_op(2, 3, "lte"), 1); + ASSERT_EQ(test_op(3, 3, "lte"), 1); + ASSERT_EQ(test_op(4, 3, "lte"), 0); + ASSERT_EQ(test_op(2, 3, "gt"), 0); + ASSERT_EQ(test_op(2, 3, "gte"), 0); + ASSERT_EQ(test_op(3, 3, "gte"), 1); + ASSERT_EQ(test_op(4, 3, "gte"), 1); + ASSERT_EQ(test_op(2, 3, "and"), 2); + ASSERT_EQ(test_op(2, 3, "or"), 3); + ASSERT_EQ(test_op(2, 3, "xor"), 1); + ASSERT_EQ(test_op(2, 3, "pow"), 8); + ASSERT_EQ(test_op(2, 3, "shl"), 16); + ASSERT_EQ(test_op(30, 2, "shr"), 7); + + // TODO - div } int main(int argc, char** argv) -- 2.49.1 From 9e6d9c6212f78ead92d67dd5e0f3e647cd81232c Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 21:51:54 -0500 Subject: [PATCH 06/21] . --- .idea/tyche.iml | 2 -- src/assembler/assembler.cc | 2 +- src/vm/code.cc | 1 + src/vm/instruction.cc | 1 + src/vm/value.hh | 1 + 5 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 .idea/tyche.iml diff --git a/.idea/tyche.iml b/.idea/tyche.iml deleted file mode 100644 index 4c94235..0000000 --- a/.idea/tyche.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/assembler/assembler.cc b/src/assembler/assembler.cc index d189a26..babf196 100644 --- a/src/assembler/assembler.cc +++ b/src/assembler/assembler.cc @@ -70,7 +70,7 @@ ByteArray Assembler::assemble() case vm::OperandType::Int8: bp.functions.at(function_id).code.append_int8((int8_t) *oper); break; case vm::OperandType::Int16: bp.functions.at(function_id).code.append_int16((int16_t) *oper); break; case vm::OperandType::Int32: bp.functions.at(function_id).code.append_int32(*oper); break; - case vm::OperandType::NoOperand: default: + case vm::OperandType::NoOperand: default: break; } if (tt.type != TokenType::Enter) diff --git a/src/vm/code.cc b/src/vm/code.cc index ab3d9b3..96a2e11 100644 --- a/src/vm/code.cc +++ b/src/vm/code.cc @@ -45,6 +45,7 @@ Operation Code::operation(Location const& location) const .next_location = { .function_id = location.function_id, .pc = location.pc + 5 }, }; default: + break; } throw std::logic_error("Should not get here"); diff --git a/src/vm/instruction.cc b/src/vm/instruction.cc index 27ea8ce..f60f0b9 100644 --- a/src/vm/instruction.cc +++ b/src/vm/instruction.cc @@ -187,6 +187,7 @@ std::pair debug_instruction(bc::Bytecode const& bt, uint32_ case OperandType::Int32: return debug_instruction(inst, bt.get_code_int32(function_id, addr + 1)); default: + break; } return { "???", 1 }; diff --git a/src/vm/value.hh b/src/vm/value.hh index a052cb1..5d01d06 100644 --- a/src/vm/value.hh +++ b/src/vm/value.hh @@ -1,6 +1,7 @@ #ifndef TYCHE_VALUE_HH #define TYCHE_VALUE_HH +#include #include #include -- 2.49.1 From 5299ae9d636d4e8e63c223199f87cb4db63c8e52 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 22:04:21 -0500 Subject: [PATCH 07/21] . --- src/vm/expr.cc | 1 - src/vm/vm.cc | 52 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 2470f42..f81172a 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -17,7 +17,6 @@ static int init_ = []() { 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()); }; diff --git a/src/vm/vm.cc b/src/vm/vm.cc index b59cfb8..0918c53 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -53,6 +53,7 @@ void VM::run_until_return() void VM::step() { Operation op = code_.operation(loc_.top()); + Value a, b; switch (op.instruction) { case Instruction::PushInt8: case Instruction::PushInt16: @@ -60,55 +61,72 @@ void VM::step() push_integer(op.operator_); break; case Instruction::Sum: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Sum)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Sum)); break; case Instruction::Subtract: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Subtraction)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Subtraction)); break; case Instruction::Multiply: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Multiplication)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Multiplication)); break; case Instruction::Divide: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Division)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Division)); break; case Instruction::DivideInt: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::IntegerDivision)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::IntegerDivision)); break; case Instruction::Equals: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Equality)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Equality)); break; case Instruction::NotEquals: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Inequality)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Inequality)); break; case Instruction::LessThan: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::LessThan)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::LessThan)); break; case Instruction::LessThanEq: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::LessThanOrEquals)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::LessThanOrEquals)); break; case Instruction::GreaterThan: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::GreaterThan)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::GreaterThan)); break; case Instruction::GreaterThanEq: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::GreaterThanOrEquals)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::GreaterThanOrEquals)); break; case Instruction::And: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseAnd)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseAnd)); break; case Instruction::Or: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseOr)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseOr)); break; case Instruction::Xor: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::BitwiseXor)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseXor)); break; case Instruction::Power: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::Power)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::Power)); break; case Instruction::ShiftLeft: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::ShiftLeft)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::ShiftLeft)); break; case Instruction::ShiftRight: - stack_.push(binary_operation(stack_.pop(), stack_.pop(), BinaryOperationType::ShiftRight)); + a = stack_.pop(); b = stack_.pop(); + stack_.push(binary_operation(a, b, BinaryOperationType::ShiftRight)); break; case Instruction::Return: { Value v = stack_.pop(); -- 2.49.1 From 9c9d361fbb28d4ef6df5e731f5b2dfc010c4df7f Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 22:05:04 -0500 Subject: [PATCH 08/21] . --- TODO.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index f1a2742..7ed1aca 100644 --- a/TODO.md +++ b/TODO.md @@ -32,10 +32,13 @@ After some additional development: - [x] Assembler - [ ] VM execution - [ ] Stack operations (nil, integer, float, string, function) - - [ ] Integer + - [x] Integer - [ ] Float - [ ] String - [ ] Expressions + - [x] Integer + - [ ] Float + - [ ] String - [ ] Local/global variables - [ ] Functions - [ ] Constants -- 2.49.1 From de961d5d2c3d921a3fd00e805bc7b6cf20c0c310 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Fri, 1 May 2026 22:05:13 -0500 Subject: [PATCH 09/21] . --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 7ed1aca..108a86d 100644 --- a/TODO.md +++ b/TODO.md @@ -31,11 +31,11 @@ After some additional development: - [x] Print stack - [x] Assembler - [ ] VM execution - - [ ] Stack operations (nil, integer, float, string, function) + - [ ] Expressions - [x] Integer - [ ] Float - [ ] String - - [ ] Expressions + - [ ] Stack operations (nil, integer, float, string, function) - [x] Integer - [ ] Float - [ ] String -- 2.49.1 From a1dbc40961e19ae7cce4163e314fe013353380a2 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 08:19:20 -0500 Subject: [PATCH 10/21] . --- doc/OPCODES | 1 + src/vm/expr.cc | 2 + src/vm/expr.hh | 2 +- src/vm/instruction.cc | 2 + src/vm/instruction.hh | 1 + src/vm/tests.cc | 1 + src/vm/vm.cc | 105 +++++++++++++++--------------------------- 7 files changed, 44 insertions(+), 70 deletions(-) diff --git a/doc/OPCODES b/doc/OPCODES index f809bae..06676fb 100644 --- a/doc/OPCODES +++ b/doc/OPCODES @@ -68,6 +68,7 @@ Logical/arithmetic: 2e pow Power 2f shl Shift left 30 shr Shift right +31 mod Modulo Other value operations: 40 len Get table, array or string size diff --git a/src/vm/expr.cc b/src/vm/expr.cc index f81172a..e875725 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -53,6 +53,8 @@ static int init_ = []() { 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()); }; + #undef BIN_OP return 0; diff --git a/src/vm/expr.hh b/src/vm/expr.hh index 655a390..a0bc4dd 100644 --- a/src/vm/expr.hh +++ b/src/vm/expr.hh @@ -7,7 +7,7 @@ namespace tyche::vm { enum class BinaryOperationType { Sum, Subtraction, Multiplication, Division, IntegerDivision, Equality, Inequality, LessThan, LessThanOrEquals, - GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, Power, ShiftLeft, ShiftRight, + GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, Power, ShiftLeft, ShiftRight, Modulo, COUNT }; diff --git a/src/vm/instruction.cc b/src/vm/instruction.cc index f60f0b9..f739b0a 100644 --- a/src/vm/instruction.cc +++ b/src/vm/instruction.cc @@ -46,6 +46,7 @@ const std::unordered_map instruction_names = { { "pow", Instruction::Power }, { "shl", Instruction::ShiftLeft }, { "shr", Instruction::ShiftRight }, + { "mod", Instruction::Modulo }, { "len", Instruction::Len }, { "type", Instruction::Type }, { "cast", Instruction::Cast }, @@ -133,6 +134,7 @@ std::pair debug_instruction(Instruction inst, int oper) case Instruction::Power: out = "pow"; break; case Instruction::ShiftLeft: out = "shl"; break; case Instruction::ShiftRight: out = "shr"; break; + case Instruction::Modulo: out = "mod"; break; case Instruction::Len: out = "len"; break; case Instruction::Type: out = "type"; break; case Instruction::Cast: out = "cast"; break; diff --git a/src/vm/instruction.hh b/src/vm/instruction.hh index a058751..f603ff2 100644 --- a/src/vm/instruction.hh +++ b/src/vm/instruction.hh @@ -77,6 +77,7 @@ enum class Instruction : uint8_t { Power = 0x2e, ShiftLeft = 0x2f, ShiftRight = 0x30, + Modulo = 0x31, // other value operations Len = 0x40, diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 4786b03..eee5f25 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -125,6 +125,7 @@ TEST(VM, IntegerIntegerOperations) ASSERT_EQ(test_op(2, 3, "pow"), 8); ASSERT_EQ(test_op(2, 3, "shl"), 16); ASSERT_EQ(test_op(30, 2, "shr"), 7); + ASSERT_EQ(test_op(8, 3, "mod"), 2); // TODO - div } diff --git a/src/vm/vm.cc b/src/vm/vm.cc index 0918c53..1a602f4 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -52,82 +52,49 @@ void VM::run_until_return() void VM::step() { + Operation op = code_.operation(loc_.top()); - Value a, b; switch (op.instruction) { + + // + // stack management + // + case Instruction::PushInt8: case Instruction::PushInt16: case Instruction::PushInt32: push_integer(op.operator_); break; - case Instruction::Sum: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Sum)); - break; - case Instruction::Subtract: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Subtraction)); - break; - case Instruction::Multiply: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Multiplication)); - break; - case Instruction::Divide: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Division)); - break; - case Instruction::DivideInt: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::IntegerDivision)); - break; - case Instruction::Equals: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Equality)); - break; - case Instruction::NotEquals: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Inequality)); - break; - case Instruction::LessThan: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::LessThan)); - break; - case Instruction::LessThanEq: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::LessThanOrEquals)); - break; - case Instruction::GreaterThan: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::GreaterThan)); - break; - case Instruction::GreaterThanEq: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::GreaterThanOrEquals)); - break; - case Instruction::And: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseAnd)); - break; - case Instruction::Or: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseOr)); - break; - case Instruction::Xor: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::BitwiseXor)); - break; - case Instruction::Power: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::Power)); - break; - case Instruction::ShiftLeft: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::ShiftLeft)); - break; - case Instruction::ShiftRight: - a = stack_.pop(); b = stack_.pop(); - stack_.push(binary_operation(a, b, BinaryOperationType::ShiftRight)); - break; + + // + // logical/arithmetic + // + +#define BIN_OP(op) { Value a = stack_.pop(); Value b = stack_.pop(); stack_.push(binary_operation(a, b, BinaryOperationType::op)); } + case Instruction::Sum: BIN_OP(Sum) break; + case Instruction::Subtract: BIN_OP(Subtraction) break; + case Instruction::Multiply: BIN_OP(Multiplication) break; + case Instruction::Divide: BIN_OP(Division) break; + case Instruction::DivideInt: BIN_OP(IntegerDivision) break; + case Instruction::Equals: BIN_OP(Equality) break; + case Instruction::NotEquals: BIN_OP(Inequality) break; + case Instruction::LessThan: BIN_OP(LessThan) break; + case Instruction::LessThanEq: BIN_OP(LessThanOrEquals) break; + case Instruction::GreaterThan: BIN_OP(GreaterThan) break; + case Instruction::GreaterThanEq: BIN_OP(GreaterThanOrEquals) break; + case Instruction::And: BIN_OP(BitwiseAnd) break; + case Instruction::Or: BIN_OP(BitwiseOr) break; + case Instruction::Xor: BIN_OP(BitwiseXor) break; + case Instruction::Power: BIN_OP(Power) break; + case Instruction::ShiftLeft: BIN_OP(ShiftLeft) break; + case Instruction::ShiftRight: BIN_OP(ShiftRight) break; + case Instruction::Modulo: BIN_OP(Modulo) break; +#undef BIN_OP + + // + // function operations + // + case Instruction::Return: { Value v = stack_.pop(); stack_.pop_fp(); -- 2.49.1 From 728fc9d5713dbc339ba83278d16869af78d3908a Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 08:25:31 -0500 Subject: [PATCH 11/21] . --- src/vm/tests.cc | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/vm/tests.cc b/src/vm/tests.cc index eee5f25..aa62a2b 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -1,7 +1,6 @@ #include "gtest/gtest.h" #include "../bytecode/bytecodeprototype.hh" -#include "../common/bytearray.hh" #include "../bytecode/bytecode.hh" #include "../assembler/assembler.hh" #include "code.hh" @@ -93,6 +92,24 @@ TEST(VM, BasicCode) ASSERT_EQ(result, 5); } +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("pushc 0").to_float(-1), 3.14f); +} + TEST(VM, IntegerIntegerOperations) { auto test_op = [](int32_t op1, int32_t op2, std::string oper) { -- 2.49.1 From f16f2e0e8e8dd7fe201ed5d9d95bc46151b68549 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 08:30:33 -0500 Subject: [PATCH 12/21] . --- .gitignore | 2 ++ .idea/tyche.iml | 2 ++ src/vm/vm.cc | 13 +++++++++++++ src/vm/vm.hh | 2 ++ 4 files changed, 19 insertions(+) create mode 100644 .idea/tyche.iml diff --git a/.gitignore b/.gitignore index e257658..e820098 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ *.out *.app +cmake-build-*/ +build/ diff --git a/.idea/tyche.iml b/.idea/tyche.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/tyche.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/vm/vm.cc b/src/vm/vm.cc index 1a602f4..b8854b2 100644 --- a/src/vm/vm.cc +++ b/src/vm/vm.cc @@ -36,12 +36,25 @@ int32_t VM::to_integer(int index) const return i.as_integer(); } +float VM::to_float(int index) const +{ + Value i = stack_.at(index); + assert_type(i, Type::Float); + return i.as_float(); +} + VM& VM::push_integer(int32_t value) { stack_.push(Value::CreateInteger(value)); return *this; } +VM& VM::push_float(float value) +{ + stack_.push(Value::CreateFloat(value)); + return *this; +} + void VM::run_until_return() { size_t level = stack_.fp_level(); diff --git a/src/vm/vm.hh b/src/vm/vm.hh index 6ecd22a..e555bb6 100644 --- a/src/vm/vm.hh +++ b/src/vm/vm.hh @@ -14,8 +14,10 @@ public: VM& call(size_t n_params); [[nodiscard]] int32_t to_integer(int index) const; + [[nodiscard]] float to_float(int index) const; VM& push_integer(int32_t value); + VM& push_float(float value); [[nodiscard]] std::string debug_stack() const { return stack_.debug(); } -- 2.49.1 From 2e0d615ac5bc0613f5fcdbbef2ff8eb06ec253ed Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:02:52 -0500 Subject: [PATCH 13/21] . --- 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(); -- 2.49.1 From 344e3d3eb05d3ae5f99367ded8fa967a53beaf65 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:20:04 -0500 Subject: [PATCH 14/21] . --- .idea/tyche.iml | 2 +- src/vm/expr.cc | 73 ++++++++++++++++++++++++++++++++++++------------- src/vm/expr.hh | 6 ++-- 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/.idea/tyche.iml b/.idea/tyche.iml index f08604b..4c94235 100644 --- a/.idea/tyche.iml +++ b/.idea/tyche.iml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 1d32a88..06e1156 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -20,40 +20,75 @@ 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, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Sum, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Sum, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - 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(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - 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(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(Division, Integer, Integer) { return Value::createFloat((float) a.as_integer() / (float) b.as_integer()); }; + BIN_OP(Division, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - 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(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(Equality, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() == b.as_integer()); }; + BIN_OP(Equality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(Inequality, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() != b.as_integer()); }; + BIN_OP(Inequality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(LessThan, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() < b.as_integer()); }; + BIN_OP(LessThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() <= b.as_integer()); }; + BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(GreaterThan, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() > b.as_integer()); }; + BIN_OP(GreaterThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::CreateIntegerFromBool(a.as_integer() >= b.as_integer()); }; + BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(BitwiseAnd, Integer, Integer) { return Value::createInteger(a.as_integer() & b.as_integer()); }; + BIN_OP(Power, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - 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(Power, Integer, Integer) { return Value::createInteger((int32_t) powl(a.as_integer(), b.as_integer())); }; + BIN_OP(Modulo, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; + BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; 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(Modulo, 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(BitwiseXor, Integer, Integer) { return Value::createInteger(a.as_integer() ^ b.as_integer()); }; #undef BIN_OP diff --git a/src/vm/expr.hh b/src/vm/expr.hh index a0bc4dd..6250812 100644 --- a/src/vm/expr.hh +++ b/src/vm/expr.hh @@ -6,8 +6,10 @@ namespace tyche::vm { enum class BinaryOperationType { - Sum, Subtraction, Multiplication, Division, IntegerDivision, Equality, Inequality, LessThan, LessThanOrEquals, - GreaterThan, GreaterThanOrEquals, BitwiseAnd, BitwiseOr, BitwiseXor, Power, ShiftLeft, ShiftRight, Modulo, + Sum, Subtraction, Multiplication, Division, IntegerDivision, + Equality, Inequality, LessThan, LessThanOrEquals, + GreaterThan, GreaterThanOrEquals, Power, Modulo, + BitwiseAnd, BitwiseOr, BitwiseXor, ShiftLeft, ShiftRight, COUNT }; -- 2.49.1 From 3ff315fecc12381b614e4d3c7c279e2994e83dcd Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:21:30 -0500 Subject: [PATCH 15/21] . --- src/vm/expr.cc | 72 +++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 06e1156..39faf71 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -25,64 +25,64 @@ static int init_ = []() { BIN_OP(Sum, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Subtraction, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Subtraction, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Subtraction, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Subtraction, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Multiplication, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Multiplication, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Multiplication, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Multiplication, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Division, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Division, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Division, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Division, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(IntegerDivision, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(IntegerDivision, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(IntegerDivision, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(IntegerDivision, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Equality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Equality, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Equality, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Equality, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Inequality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Inequality, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Inequality, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Inequality, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(LessThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(LessThan, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(LessThan, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(LessThan, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(LessThanOrEquals, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(LessThanOrEquals, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(LessThanOrEquals, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(GreaterThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(GreaterThan, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(GreaterThan, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(GreaterThan, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(GreaterThanOrEquals, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(GreaterThanOrEquals, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(GreaterThanOrEquals, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Power, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Power, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Power, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Power, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; BIN_OP(Modulo, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Modulo, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; + BIN_OP(Modulo, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; + BIN_OP(Modulo, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; 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()); }; -- 2.49.1 From d4b4d5aab4ce1923316afff908437ff90bca3457 Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:23:39 -0500 Subject: [PATCH 16/21] . --- src/vm/expr.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 39faf71..56b04cc 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -24,25 +24,25 @@ static int init_ = []() { BIN_OP(Sum, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; BIN_OP(Sum, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - BIN_OP(Subtraction, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Subtraction, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Subtraction, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Subtraction, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Subtraction, Integer, Integer) { return Value::createInteger(a.as_integer() - b.as_integer()); }; + BIN_OP(Subtraction, Integer, Float) { return Value::createFloat((float) a.as_integer() - b.as_float()); }; + BIN_OP(Subtraction, Float, Integer) { return Value::createFloat(a.as_float() - (float) b.as_integer()); }; + BIN_OP(Subtraction, Float, Float) { return Value::createFloat(a.as_float() - b.as_float()); }; - BIN_OP(Multiplication, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Multiplication, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Multiplication, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Multiplication, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Multiplication, Integer, Integer) { return Value::createInteger(a.as_integer() * b.as_integer()); }; + BIN_OP(Multiplication, Integer, Float) { return Value::createFloat((float) a.as_integer() * b.as_float()); }; + BIN_OP(Multiplication, Float, Integer) { return Value::createFloat(a.as_float() * (float) b.as_integer()); }; + BIN_OP(Multiplication, Float, Float) { return Value::createFloat(a.as_float() * b.as_float()); }; - BIN_OP(Division, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Division, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Division, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Division, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Division, Integer, Integer) { return Value::createFloat((float) a.as_integer() / (float) b.as_integer()); }; + BIN_OP(Division, Integer, Float) { return Value::createFloat((float) a.as_integer() / b.as_float()); }; + BIN_OP(Division, Float, Integer) { return Value::createFloat(a.as_float() / (float) b.as_integer()); }; + BIN_OP(Division, Float, Float) { return Value::createFloat(a.as_float() / b.as_float()); }; - BIN_OP(IntegerDivision, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(IntegerDivision, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(IntegerDivision, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(IntegerDivision, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(IntegerDivision, Integer, Integer) { return Value::createInteger(a.as_integer() / b.as_integer()); }; + BIN_OP(IntegerDivision, Integer, Float) { return Value::createInteger(a.as_integer() / (int32_t) b.as_float()); }; + BIN_OP(IntegerDivision, Float, Integer) { return Value::createInteger((int32_t) a.as_float() / b.as_integer()); }; + BIN_OP(IntegerDivision, Float, Float) { return Value::createInteger((int32_t) a.as_float() / (int32_t) b.as_float()); }; BIN_OP(Equality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; BIN_OP(Equality, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; -- 2.49.1 From b03c7b41788a7700bce4ec6032f6a26a4dbc2feb Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:32:19 -0500 Subject: [PATCH 17/21] . --- src/vm/expr.cc | 62 +++++++++++++++++++++++-------------------------- src/vm/expr.hh | 2 ++ src/vm/value.hh | 2 +- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 56b04cc..a1c2fe8 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -44,46 +44,42 @@ static int init_ = []() { BIN_OP(IntegerDivision, Float, Integer) { return Value::createInteger((int32_t) a.as_float() / b.as_integer()); }; BIN_OP(IntegerDivision, Float, Float) { return Value::createInteger((int32_t) a.as_float() / (int32_t) b.as_float()); }; - BIN_OP(Equality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Equality, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Equality, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Equality, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Equality, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() == b.as_integer()); }; + BIN_OP(Equality, Integer, Float) { return Value::createIntegerFromBool(std::abs((float) a.as_integer() - b.as_float()) < FLOAT_EPSILON); }; + BIN_OP(Equality, Float, Integer) { return Value::createIntegerFromBool(std::abs(a.as_float() - (float) b.as_integer()) < FLOAT_EPSILON); }; + BIN_OP(Equality, Float, Float) { return Value::createIntegerFromBool(std::abs(a.as_float() - b.as_float()) < FLOAT_EPSILON); }; - BIN_OP(Inequality, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Inequality, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Inequality, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Inequality, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Inequality, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() != b.as_integer()); }; + BIN_OP(Inequality, Integer, Float) { return Value::createIntegerFromBool(std::abs((float) a.as_integer() - b.as_float()) >= FLOAT_EPSILON); }; + BIN_OP(Inequality, Float, Integer) { return Value::createIntegerFromBool(std::abs(a.as_float() - (float) b.as_integer()) >= FLOAT_EPSILON); }; + BIN_OP(Inequality, Float, Float) { return Value::createIntegerFromBool(std::abs(a.as_float() - b.as_float()) >= FLOAT_EPSILON); }; - BIN_OP(LessThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(LessThan, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(LessThan, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(LessThan, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(LessThan, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() < b.as_integer()); }; + BIN_OP(LessThan, Integer, Float) { return Value::createIntegerFromBool((float) a.as_integer() < b.as_float()); }; + BIN_OP(LessThan, Float, Integer) { return Value::createIntegerFromBool(a.as_float() < (float) b.as_integer()); }; + BIN_OP(LessThan, Float, Float) { return Value::createIntegerFromBool(a.as_float() < b.as_float()); }; - BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(LessThanOrEquals, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(LessThanOrEquals, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(LessThanOrEquals, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(LessThanOrEquals, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() <= b.as_integer()); }; + BIN_OP(LessThanOrEquals, Integer, Float) { return Value::createIntegerFromBool((float) a.as_integer() <= b.as_float()); }; + BIN_OP(LessThanOrEquals, Float, Integer) { return Value::createIntegerFromBool(a.as_float() <= (float) b.as_integer()); }; + BIN_OP(LessThanOrEquals, Float, Float) { return Value::createIntegerFromBool(a.as_float() <= b.as_float()); }; - BIN_OP(GreaterThan, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(GreaterThan, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(GreaterThan, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(GreaterThan, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(GreaterThan, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() > b.as_integer()); }; + BIN_OP(GreaterThan, Integer, Float) { return Value::createIntegerFromBool((float) a.as_integer() > b.as_float()); }; + BIN_OP(GreaterThan, Float, Integer) { return Value::createIntegerFromBool(a.as_float() > (float) b.as_integer()); }; + BIN_OP(GreaterThan, Float, Float) { return Value::createIntegerFromBool(a.as_float() > b.as_float()); }; - BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(GreaterThanOrEquals, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(GreaterThanOrEquals, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(GreaterThanOrEquals, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(GreaterThanOrEquals, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() >= b.as_integer()); }; + BIN_OP(GreaterThanOrEquals, Integer, Float) { return Value::createIntegerFromBool((float) a.as_integer() >= b.as_float()); }; + BIN_OP(GreaterThanOrEquals, Float, Integer) { return Value::createIntegerFromBool(a.as_float() >= (float) b.as_integer()); }; + BIN_OP(GreaterThanOrEquals, Float, Float) { return Value::createIntegerFromBool(a.as_float() >= b.as_float()); }; - BIN_OP(Power, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Power, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Power, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Power, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; - - BIN_OP(Modulo, Integer, Integer) { return Value::createInteger(a.as_integer() + b.as_integer()); }; - BIN_OP(Modulo, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; - BIN_OP(Modulo, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; - BIN_OP(Modulo, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Power, Integer, Integer) { return Value::createInteger((int32_t) powl(a.as_integer(), b.as_integer())); }; + BIN_OP(Power, Integer, Float) { return Value::createFloat(powf((float) a.as_integer(), b.as_float())); }; + BIN_OP(Power, Float, Integer) { return Value::createFloat(powf(a.as_float(), (float) b.as_integer())); }; + BIN_OP(Power, Float, Float) { return Value::createFloat(powf(a.as_float(), b.as_float())); }; + BIN_OP(Modulo, 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(BitwiseAnd, Integer, Integer) { return Value::createInteger(a.as_integer() & b.as_integer()); }; diff --git a/src/vm/expr.hh b/src/vm/expr.hh index 6250812..c1fb67f 100644 --- a/src/vm/expr.hh +++ b/src/vm/expr.hh @@ -13,6 +13,8 @@ enum class BinaryOperationType COUNT }; +constexpr float FLOAT_EPSILON = 0.000001f; + Value binary_operation(Value const& a, Value const& b, BinaryOperationType op); } diff --git a/src/vm/value.hh b/src/vm/value.hh index 5699cdb..0318ecd 100644 --- a/src/vm/value.hh +++ b/src/vm/value.hh @@ -28,7 +28,7 @@ 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); } + static Value createIntegerFromBool(bool b) { return createInteger(b ? 1 : 0); } [[nodiscard]] Type type() const; -- 2.49.1 From 044dfd6a241a4b11ffd23beacf08e72d1074573f Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:38:34 -0500 Subject: [PATCH 18/21] . --- src/vm/tests.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/vm/tests.cc b/src/vm/tests.cc index d06a3b0..0773f91 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -152,6 +152,47 @@ TEST(VM, IntegerIntegerOperations) ASSERT_FLOAT_EQ(run("pushi 3\n pushi 2\n div").to_float(-1), 1.5f); } +TEST(VM, IntegerFloatOperations) +{ + auto test_op = [](int32_t op1, float op2, std::string oper) -> VM { + return VM().load_bytecode(as::Assembler(std::format(R"( + .const + 0: {} + .func 0 + pushi {} + pushc {} + {} + ret + )", op2, op1, oper)).assemble()).call(0); + }; + + ASSERT_FLOAT_EQ(test_op(2, 3.5f, "sum").to_float(-1), 5.5f); + /* + ASSERT_EQ(test_op(2, 3, "sub"), -1); + ASSERT_EQ(test_op(2, 3, "mul"), 6); + ASSERT_EQ(test_op(20, 3, "idiv"), 6); + ASSERT_EQ(test_op(2, 3, "eq"), 0); + ASSERT_EQ(test_op(2, 3, "neq"), 1); + ASSERT_EQ(test_op(2, 3, "lt"), 1); + ASSERT_EQ(test_op(2, 3, "lte"), 1); + ASSERT_EQ(test_op(3, 3, "lte"), 1); + ASSERT_EQ(test_op(4, 3, "lte"), 0); + ASSERT_EQ(test_op(2, 3, "gt"), 0); + ASSERT_EQ(test_op(2, 3, "gte"), 0); + ASSERT_EQ(test_op(3, 3, "gte"), 1); + ASSERT_EQ(test_op(4, 3, "gte"), 1); + ASSERT_EQ(test_op(2, 3, "and"), 2); + ASSERT_EQ(test_op(2, 3, "or"), 3); + ASSERT_EQ(test_op(2, 3, "xor"), 1); + ASSERT_EQ(test_op(2, 3, "pow"), 8); + ASSERT_EQ(test_op(2, 3, "shl"), 16); + ASSERT_EQ(test_op(30, 2, "shr"), 7); + ASSERT_EQ(test_op(8, 3, "mod"), 2); + + ASSERT_FLOAT_EQ(run("pushi 3\n pushi 2\n div").to_float(-1), 1.5f); + */ +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); -- 2.49.1 From 4c7798f6724dbb63d9add5e8bdf7bc6dc60bf3be Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 09:51:43 -0500 Subject: [PATCH 19/21] . --- src/vm/expr.cc | 2 +- src/vm/tests.cc | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vm/expr.cc b/src/vm/expr.cc index a1c2fe8..11c7796 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -93,7 +93,7 @@ static int init_ = []() { Value binary_operation(Value const& a, Value const& b, BinaryOperationType op) { - return binary_ops[(size_t) op][(size_t) a.type()][(size_t) b.type()](a, b); + return binary_ops[(size_t) op][(size_t) b.type()][(size_t) a.type()](a, b); } } \ No newline at end of file diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 0773f91..867a084 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -154,19 +154,25 @@ TEST(VM, IntegerIntegerOperations) TEST(VM, IntegerFloatOperations) { - auto test_op = [](int32_t op1, float op2, std::string oper) -> VM { + auto test_op = [](int op1, std::string const& op2, std::string oper) -> VM { return VM().load_bytecode(as::Assembler(std::format(R"( .const 0: {} .func 0 pushi {} - pushc {} + pushc 0 {} ret )", op2, op1, oper)).assemble()).call(0); }; - ASSERT_FLOAT_EQ(test_op(2, 3.5f, "sum").to_float(-1), 5.5f); + ASSERT_FLOAT_EQ(test_op(2, "3.5", "sum").to_float(-1), 5.5f); + ASSERT_FLOAT_EQ(test_op(2, "3.5", "sub").to_float(-1), -1.5f); + ASSERT_FLOAT_EQ(test_op(2, "3.5", "mul").to_float(-1), 7.f); + ASSERT_FLOAT_EQ(test_op(20, "3.5", "idiv").to_integer(-1), 6); + ASSERT_FLOAT_EQ(test_op(20, "3.5", "div").to_float(-1), 5.7142859); + ASSERT_FLOAT_EQ(test_op(3, "3.5", "eq").to_integer(-1), 0); + ASSERT_FLOAT_EQ(test_op(3, "3.0", "eq").to_integer(-1), 1); /* ASSERT_EQ(test_op(2, 3, "sub"), -1); ASSERT_EQ(test_op(2, 3, "mul"), 6); -- 2.49.1 From 1d63645c32c56555ee287a2ef64adaffc33629ae Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 10:04:18 -0500 Subject: [PATCH 20/21] . --- TODO.md | 2 +- src/vm/tests.cc | 69 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index 5290a03..8afd260 100644 --- a/TODO.md +++ b/TODO.md @@ -37,7 +37,7 @@ After some additional development: - [x] String - [ ] Expressions - [x] Integer - - [ ] Float + - [x] Float - [ ] String - [ ] Local/global variables - [ ] Functions diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 867a084..102c447 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -173,30 +173,53 @@ TEST(VM, IntegerFloatOperations) ASSERT_FLOAT_EQ(test_op(20, "3.5", "div").to_float(-1), 5.7142859); ASSERT_FLOAT_EQ(test_op(3, "3.5", "eq").to_integer(-1), 0); ASSERT_FLOAT_EQ(test_op(3, "3.0", "eq").to_integer(-1), 1); - /* - ASSERT_EQ(test_op(2, 3, "sub"), -1); - ASSERT_EQ(test_op(2, 3, "mul"), 6); - ASSERT_EQ(test_op(20, 3, "idiv"), 6); - ASSERT_EQ(test_op(2, 3, "eq"), 0); - ASSERT_EQ(test_op(2, 3, "neq"), 1); - ASSERT_EQ(test_op(2, 3, "lt"), 1); - ASSERT_EQ(test_op(2, 3, "lte"), 1); - ASSERT_EQ(test_op(3, 3, "lte"), 1); - ASSERT_EQ(test_op(4, 3, "lte"), 0); - ASSERT_EQ(test_op(2, 3, "gt"), 0); - ASSERT_EQ(test_op(2, 3, "gte"), 0); - ASSERT_EQ(test_op(3, 3, "gte"), 1); - ASSERT_EQ(test_op(4, 3, "gte"), 1); - ASSERT_EQ(test_op(2, 3, "and"), 2); - ASSERT_EQ(test_op(2, 3, "or"), 3); - ASSERT_EQ(test_op(2, 3, "xor"), 1); - ASSERT_EQ(test_op(2, 3, "pow"), 8); - ASSERT_EQ(test_op(2, 3, "shl"), 16); - ASSERT_EQ(test_op(30, 2, "shr"), 7); - ASSERT_EQ(test_op(8, 3, "mod"), 2); +} - ASSERT_FLOAT_EQ(run("pushi 3\n pushi 2\n div").to_float(-1), 1.5f); - */ +TEST(VM, FloatIntegerOperations) +{ + auto test_op = [](std::string const& op1, int op2, std::string oper) -> VM { + return VM().load_bytecode(as::Assembler(std::format(R"( + .const + 0: {} + .func 0 + pushc 0 + pushi {} + {} + ret + )", op1, op2, oper)).assemble()).call(0); + }; + + ASSERT_FLOAT_EQ(test_op("3.5", 2, "sum").to_float(-1), 5.5f); + ASSERT_FLOAT_EQ(test_op("3.5", 2, "sub").to_float(-1), 1.5f); + ASSERT_FLOAT_EQ(test_op("3.5", 2, "mul").to_float(-1), 7.f); + ASSERT_FLOAT_EQ(test_op("3.5", 2, "idiv").to_integer(-1), 1); + ASSERT_FLOAT_EQ(test_op("3.5", 2, "div").to_float(-1), 1.75f); + ASSERT_FLOAT_EQ(test_op("3.5", 3, "eq").to_integer(-1), 0); + ASSERT_FLOAT_EQ(test_op("3.0", 3, "eq").to_integer(-1), 1); +} + +TEST(VM, FloatFloatOperations) +{ + auto test_op = [](std::string const& op1, std::string const& op2, std::string oper) -> VM { + return VM().load_bytecode(as::Assembler(std::format(R"( + .const + 0: {} + 1: {} + .func 0 + pushc 0 + pushc 1 + {} + ret + )", op1, op2, oper)).assemble()).call(0); + }; + + ASSERT_FLOAT_EQ(test_op("3.5", "2.2", "sum").to_float(-1), 5.7f); + ASSERT_FLOAT_EQ(test_op("3.5", "2.2", "sub").to_float(-1), 1.3f); + ASSERT_FLOAT_EQ(test_op("3.5", "2.2", "mul").to_float(-1), 7.7f); + ASSERT_FLOAT_EQ(test_op("3.5", "2.2", "idiv").to_integer(-1), 1); + ASSERT_FLOAT_EQ(test_op("4.5", "2.5", "div").to_float(-1), 1.8f); + ASSERT_FLOAT_EQ(test_op("3.2005", "3.2", "eq").to_integer(-1), 0); + ASSERT_FLOAT_EQ(test_op("3.2", "3.2", "eq").to_integer(-1), 1); } int main(int argc, char** argv) -- 2.49.1 From 3fce2d383cc656f393fd4217a81c3c628fb73d4a Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sat, 2 May 2026 15:06:31 -0500 Subject: [PATCH 21/21] . --- TODO.md | 6 +++--- src/vm/expr.cc | 21 ++++++++++++++++++--- src/vm/tests.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/vm/value.hh | 2 ++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/TODO.md b/TODO.md index 8afd260..e695e00 100644 --- a/TODO.md +++ b/TODO.md @@ -31,14 +31,14 @@ After some additional development: - [x] Print stack - [x] Assembler - [ ] VM execution - - [ ] Stack operations (nil, integer, float, string, function) + - [x] Stack operations (nil, integer, float, string, function) - [x] Integer - [x] Float - [x] String - - [ ] Expressions + - [x] Expressions - [x] Integer - [x] Float - - [ ] String + - [x] String - [ ] Local/global variables - [ ] Functions - [ ] Constants diff --git a/src/vm/expr.cc b/src/vm/expr.cc index 11c7796..67123ea 100644 --- a/src/vm/expr.cc +++ b/src/vm/expr.cc @@ -10,12 +10,24 @@ 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) + // every combination, except when explicit, return type error + 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()); }; + } + } + } + + // every equality/inequality, by default, return inequal + for (size_t j = 0; j < (size_t) Type::COUNT; ++j) { + for (size_t k = 0; k < (size_t) Type::COUNT; ++k) { + binary_ops[(size_t) BinaryOperationType::Equality][j][k] = [](Value const&, Value const&) { return Value::createFalse(); }; + binary_ops[(size_t) BinaryOperationType::Inequality][j][k] = [](Value const&, Value const&) { return Value::createTrue(); }; + } + } #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) @@ -23,6 +35,7 @@ static int init_ = []() { BIN_OP(Sum, Integer, Float) { return Value::createFloat((float) a.as_integer() + b.as_float()); }; BIN_OP(Sum, Float, Integer) { return Value::createFloat(a.as_float() + (float) b.as_integer()); }; BIN_OP(Sum, Float, Float) { return Value::createFloat(a.as_float() + b.as_float()); }; + BIN_OP(Sum, String, String) { return Value::createString(a.as_string() + b.as_string()); }; BIN_OP(Subtraction, Integer, Integer) { return Value::createInteger(a.as_integer() - b.as_integer()); }; BIN_OP(Subtraction, Integer, Float) { return Value::createFloat((float) a.as_integer() - b.as_float()); }; @@ -48,11 +61,13 @@ static int init_ = []() { BIN_OP(Equality, Integer, Float) { return Value::createIntegerFromBool(std::abs((float) a.as_integer() - b.as_float()) < FLOAT_EPSILON); }; BIN_OP(Equality, Float, Integer) { return Value::createIntegerFromBool(std::abs(a.as_float() - (float) b.as_integer()) < FLOAT_EPSILON); }; BIN_OP(Equality, Float, Float) { return Value::createIntegerFromBool(std::abs(a.as_float() - b.as_float()) < FLOAT_EPSILON); }; + BIN_OP(Equality, String, String) { return Value::createIntegerFromBool(a.as_string() == b.as_string()); }; BIN_OP(Inequality, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() != b.as_integer()); }; BIN_OP(Inequality, Integer, Float) { return Value::createIntegerFromBool(std::abs((float) a.as_integer() - b.as_float()) >= FLOAT_EPSILON); }; BIN_OP(Inequality, Float, Integer) { return Value::createIntegerFromBool(std::abs(a.as_float() - (float) b.as_integer()) >= FLOAT_EPSILON); }; BIN_OP(Inequality, Float, Float) { return Value::createIntegerFromBool(std::abs(a.as_float() - b.as_float()) >= FLOAT_EPSILON); }; + BIN_OP(Inequality, String, String) { return Value::createIntegerFromBool(a.as_string() != b.as_string()); }; BIN_OP(LessThan, Integer, Integer) { return Value::createIntegerFromBool(a.as_integer() < b.as_integer()); }; BIN_OP(LessThan, Integer, Float) { return Value::createIntegerFromBool((float) a.as_integer() < b.as_float()); }; diff --git a/src/vm/tests.cc b/src/vm/tests.cc index 102c447..b147cc7 100644 --- a/src/vm/tests.cc +++ b/src/vm/tests.cc @@ -222,6 +222,52 @@ TEST(VM, FloatFloatOperations) ASSERT_FLOAT_EQ(test_op("3.2", "3.2", "eq").to_integer(-1), 1); } +TEST(VM, StringString) +{ + ASSERT_EQ(run(R"( + .const + 0: "Hello" + 1: "World" + .func 0 + pushc 0 + pushc 1 + sum + ret + )").to_string(-1), "HelloWorld"); + + ASSERT_EQ(run(R"( + .const + 0: "Hello" + 1: "World" + .func 0 + pushc 0 + pushc 1 + eq + ret + )").to_integer(-1), 0); + + ASSERT_EQ(run(R"( + .const + 0: "Hello" + 1: "Hello" + .func 0 + pushc 0 + pushc 1 + eq + ret + )").to_integer(-1), 1); + + ASSERT_EQ(run(R"( + .const + 0: "Hello" + .func 0 + pushc 0 + pushi 1 + eq + ret + )").to_integer(-1), 0); +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/src/vm/value.hh b/src/vm/value.hh index 0318ecd..65c98ce 100644 --- a/src/vm/value.hh +++ b/src/vm/value.hh @@ -28,6 +28,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 createFalse() { return createInteger(0); } + static Value createTrue() { return createInteger(1); } static Value createIntegerFromBool(bool b) { return createInteger(b ? 1 : 0); } [[nodiscard]] Type type() const; -- 2.49.1