Expressions #7
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_); }
|
||||
|
||||
49
src/vm/vm.cc
49
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();
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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)) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user