This commit is contained in:
Andre Wagner
2026-05-01 16:39:49 -05:00
parent bebaed1998
commit 0bc40cc562
9 changed files with 147 additions and 18 deletions

View File

@@ -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();

View File

@@ -1,18 +1,58 @@
#include "expr.hh"
#include <functional>
#include "vm_exceptions.hh"
namespace tyche::vm {
std::function<Value(Value const&, Value const&)> 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);
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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<int32_t>(value_); }

View File

@@ -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();

View File

@@ -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(); }

View File

@@ -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)) {}
};
}