finish runtime instrs

This commit is contained in:
SimonFJ20 2024-11-11 15:31:54 +01:00
parent f077a16939
commit 161ea947d7
5 changed files with 287 additions and 77 deletions

View File

@ -10,28 +10,27 @@ enum class Op : uint32_t {
Nop = 0, Nop = 0,
PushNull = 1, PushNull = 1,
PushInt = 2, PushInt = 2,
PushString = 3, PushBool = 3,
PushArray = 4, PushString = 4,
PushStruct = 5, PushPtr = 5,
PushPtr = 6, Pop = 6,
Pop = 7, LoadLocal = 7,
LoadLocal = 8, StoreLocal = 8,
StoreLocal = 9, Call = 9,
Call = 10, Return = 10,
Return = 11, Jump = 11,
Jump = 12, JumpIfFalse = 12,
JumpIfNotZero = 13, Add = 13,
Add = 14, Subtract = 14,
Subtract = 15, Multiply = 15,
Multiply = 16, Divide = 16,
Divide = 17, Remainder = 17,
Remainder = 18, Equal = 18,
Equal = 19, LessThan = 19,
LessThan = 20, And = 20,
And = 21, Or = 21,
Or = 22, Xor = 22,
Xor = 23, Not = 23,
Not = 24,
}; };
} }

View File

@ -18,7 +18,7 @@ class Values;
struct Null { }; struct Null { };
struct Int { struct Int {
uint32_t value; int32_t value;
}; };
struct Bool { struct Bool {
bool value; bool value;

View File

@ -1,14 +1,18 @@
#include "vm.hpp" #include "vm.hpp"
#include "arch.hpp" #include "arch.hpp"
#include <cstdint>
#include <cstdlib>
#include <format> #include <format>
#include <iostream> #include <iostream>
#include <utility>
#include <vector>
using namespace sliger; using namespace sliger;
void VM::run() void VM::run()
{ {
while (!done()) { while (!done()) {
auto op = eat_as_op(); auto op = eat_op();
switch (op) { switch (op) {
case Op::Nop: case Op::Nop:
// nothing // nothing
@ -16,35 +20,184 @@ void VM::run()
case Op::PushNull: case Op::PushNull:
this->stack.push_back(Null {}); this->stack.push_back(Null {});
break; break;
case Op::PushInt: case Op::PushInt: {
if (done()) { assert_program_has(1);
std::cerr auto value = eat_int32();
<< std::format("program malformed: missing int value"); this->stack.push_back(Int { value });
}
this->stack.push_back(Null {});
break; break;
case Op::PushString: }
case Op::PushArray: case Op::PushBool: {
case Op::PushStruct: assert_program_has(1);
case Op::PushPtr: auto value = eat_int32();
case Op::Pop: this->stack.push_back(Bool { .value = value != 0 });
case Op::LoadLocal: break;
case Op::StoreLocal: }
case Op::Call: case Op::PushString: {
case Op::Return: assert_program_has(1);
case Op::Jump: auto string_length = eat_uint32();
case Op::JumpIfNotZero: assert_program_has(string_length);
case Op::Add: auto value = std::string();
case Op::Subtract: for (uint32_t i = 0; i < string_length; ++i) {
case Op::Multiply: auto ch = eat_uint32();
case Op::Divide: value.push_back(static_cast<char>(ch));
case Op::Remainder: }
case Op::Equal: stack_push(String { .value = std::move(value) });
case Op::LessThan: break;
case Op::And: }
case Op::Or: case Op::PushPtr: {
case Op::Xor: assert_program_has(1);
auto value = eat_uint32();
this->stack.push_back(Ptr { value });
break;
}
case Op::Pop: {
assert_stack_has(1);
this->stack.pop_back();
break;
}
case Op::LoadLocal: {
auto loc = eat_uint32();
assert_fn_stack_has(loc);
auto value = fn_stack_at(loc);
stack_push(value);
break;
}
case Op::StoreLocal: {
auto loc = eat_uint32();
assert_fn_stack_has(loc + 1);
auto value = stack_pop();
fn_stack_at(loc) = value;
break;
}
case Op::Call: {
assert_program_has(1);
auto arg_count = eat_uint32();
assert_stack_has(arg_count + 1);
auto fn_ptr = stack_pop();
auto arguments = std::vector<Value>();
for (uint32_t i = 0; i < arg_count; ++i) {
auto argument = stack_pop();
arguments.push_back(argument);
}
stack_push(Ptr { .value = this->pc });
stack_push(Ptr { .value = this->bp });
for (auto i = arguments.size(); i >= 0; --i) {
auto argument = std::move(arguments.at(i));
arguments.pop_back();
stack_push(argument);
}
this->pc = fn_ptr.as_ptr().value;
break;
}
case Op::Return: {
assert_stack_has(3);
auto ret_val = stack_pop();
auto bp_val = stack_pop();
auto pc_val = stack_pop();
this->bp = bp_val.as_ptr().value;
stack_push(ret_val);
this->pc = pc_val.as_ptr().value;
break;
}
case Op::Jump: {
assert_stack_has(1);
auto addr = stack_pop();
this->pc = addr.as_ptr().value;
break;
}
case Op::JumpIfFalse: {
assert_stack_has(2);
auto cond = stack_pop();
auto addr = stack_pop();
if (cond.as_bool().value) {
this->pc = addr.as_ptr().value;
}
break;
}
case Op::Add: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left + right;
stack_push(Int { .value = value });
break;
}
case Op::Subtract: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left - right;
stack_push(Int { .value = value });
break;
}
case Op::Multiply: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left * right;
stack_push(Int { .value = value });
break;
}
case Op::Divide: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left / right;
stack_push(Int { .value = value });
break;
}
case Op::Remainder: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left % right;
stack_push(Int { .value = value });
break;
}
case Op::Equal: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left == right;
stack_push(Bool { .value = value });
break;
}
case Op::LessThan: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left < right;
stack_push(Bool { .value = value });
break;
}
case Op::And: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = left && right;
stack_push(Bool { .value = value });
break;
}
case Op::Or: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = left || right;
stack_push(Bool { .value = value });
break;
}
case Op::Xor: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = (left || !right) || (!left && right);
stack_push(Bool { .value = value });
break;
}
case Op::Not: case Op::Not:
assert_stack_has(1);
auto value = !stack_pop().as_bool().value;
stack_push(Bool { .value = value });
break; break;
} }
} }

View File

@ -4,13 +4,15 @@
#include "value.hpp" #include "value.hpp"
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <format>
#include <iostream>
#include <vector> #include <vector>
namespace sliger { namespace sliger {
class VM { class VM {
public: public:
VM(const std::vector<Op>& program) VM(const std::vector<uint32_t>& program)
: program(program.data()) : program(program.data())
, program_size(program.size()) , program_size(program.size())
{ {
@ -19,23 +21,80 @@ public:
inline void step() { this->pc += 1; } inline void step() { this->pc += 1; }
inline auto eat_as_op() -> Op inline auto eat_op() -> Op
{ {
auto value = curr_as_op(); auto value = curr_as_op();
step(); step();
return value; return value;
} }
inline auto curr_as_op() const -> Op inline auto curr_as_op() const -> Op
{ {
return static_cast<Op>(this->program[this->pc]); return static_cast<Op>(this->program[this->pc]);
} }
inline auto eat_int32() -> int32_t
{
auto value = curr_as_int32();
step();
return value;
}
inline auto curr_as_int32() const -> int32_t
{
return static_cast<int32_t>(this->program[this->pc]);
}
inline auto eat_uint32() -> uint32_t
{
auto value = curr_as_uint32();
step();
return value;
}
inline auto curr_as_uint32() const -> uint32_t
{
return this->program[this->pc];
}
inline auto done() const -> bool { return this->pc >= this->program_size; } inline auto done() const -> bool { return this->pc >= this->program_size; }
inline auto fn_stack_at(size_t idx) -> Value&
{
return this->stack.at(this->bp + idx);
}
inline void assert_fn_stack_has(size_t count)
{
if (this->stack.size() - this->bp < count) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
inline void assert_stack_has(size_t count)
{
if (this->stack.size() < count) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
inline void stack_push(Value&& value) { this->stack.push_back(value); }
inline void stack_push(Value& value) { this->stack.push_back(value); }
inline auto stack_pop() -> Value
{
auto value = this->stack.at(this->stack.size() - 1);
this->stack.pop_back();
return value;
}
inline auto assert_program_has(size_t count)
{
if (this->pc + count >= program_size) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
private: private:
uint32_t pc = 0; uint32_t pc = 0;
const Op* program; uint32_t bp = 0;
const uint32_t* program;
size_t program_size; size_t program_size;
std::vector<Value> stack; std::vector<Value> stack;
std::vector<Value> pool_heap; std::vector<Value> pool_heap;

View File

@ -8,26 +8,25 @@ export const Ops = {
Nop: 0, Nop: 0,
PushNull: 1, PushNull: 1,
PushInt: 2, PushInt: 2,
PushString: 3, PushBool: 3,
PushArray: 4, PushString: 4,
PushStruct: 5, PushPtr: 5,
PushPtr: 6, Pop: 6,
Pop: 7, LoadLocal: 7,
LoadLocal: 8, StoreLocal: 8,
StoreLocal: 9, Call: 9,
Call: 10, Return: 10,
Return: 11, Jump: 11,
Jump: 12, JumpIfTrue: 12,
JumpIfNotZero: 13, Add: 13,
Add: 14, Subtract: 14,
Subtract: 15, Multiply: 15,
Multiply: 16, Divide: 16,
Divide: 17, Remainder: 17,
Remainder: 18, Equal: 18,
Equal: 19, LessThan: 19,
LessThan: 20, And: 20,
And: 21, Or: 21,
Or: 22, Xor: 22,
Xor: 23, Not: 23,
Not: 24,
} as const; } as const;