mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 10:06:31 +00:00
finish runtime instrs
This commit is contained in:
parent
f077a16939
commit
161ea947d7
@ -10,28 +10,27 @@ enum class Op : uint32_t {
|
||||
Nop = 0,
|
||||
PushNull = 1,
|
||||
PushInt = 2,
|
||||
PushString = 3,
|
||||
PushArray = 4,
|
||||
PushStruct = 5,
|
||||
PushPtr = 6,
|
||||
Pop = 7,
|
||||
LoadLocal = 8,
|
||||
StoreLocal = 9,
|
||||
Call = 10,
|
||||
Return = 11,
|
||||
Jump = 12,
|
||||
JumpIfNotZero = 13,
|
||||
Add = 14,
|
||||
Subtract = 15,
|
||||
Multiply = 16,
|
||||
Divide = 17,
|
||||
Remainder = 18,
|
||||
Equal = 19,
|
||||
LessThan = 20,
|
||||
And = 21,
|
||||
Or = 22,
|
||||
Xor = 23,
|
||||
Not = 24,
|
||||
PushBool = 3,
|
||||
PushString = 4,
|
||||
PushPtr = 5,
|
||||
Pop = 6,
|
||||
LoadLocal = 7,
|
||||
StoreLocal = 8,
|
||||
Call = 9,
|
||||
Return = 10,
|
||||
Jump = 11,
|
||||
JumpIfFalse = 12,
|
||||
Add = 13,
|
||||
Subtract = 14,
|
||||
Multiply = 15,
|
||||
Divide = 16,
|
||||
Remainder = 17,
|
||||
Equal = 18,
|
||||
LessThan = 19,
|
||||
And = 20,
|
||||
Or = 21,
|
||||
Xor = 22,
|
||||
Not = 23,
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class Values;
|
||||
|
||||
struct Null { };
|
||||
struct Int {
|
||||
uint32_t value;
|
||||
int32_t value;
|
||||
};
|
||||
struct Bool {
|
||||
bool value;
|
||||
|
209
runtime/vm.cpp
209
runtime/vm.cpp
@ -1,14 +1,18 @@
|
||||
#include "vm.hpp"
|
||||
#include "arch.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace sliger;
|
||||
|
||||
void VM::run()
|
||||
{
|
||||
while (!done()) {
|
||||
auto op = eat_as_op();
|
||||
auto op = eat_op();
|
||||
switch (op) {
|
||||
case Op::Nop:
|
||||
// nothing
|
||||
@ -16,35 +20,184 @@ void VM::run()
|
||||
case Op::PushNull:
|
||||
this->stack.push_back(Null {});
|
||||
break;
|
||||
case Op::PushInt:
|
||||
if (done()) {
|
||||
std::cerr
|
||||
<< std::format("program malformed: missing int value");
|
||||
}
|
||||
this->stack.push_back(Null {});
|
||||
case Op::PushInt: {
|
||||
assert_program_has(1);
|
||||
auto value = eat_int32();
|
||||
this->stack.push_back(Int { value });
|
||||
break;
|
||||
case Op::PushString:
|
||||
case Op::PushArray:
|
||||
case Op::PushStruct:
|
||||
case Op::PushPtr:
|
||||
case Op::Pop:
|
||||
case Op::LoadLocal:
|
||||
case Op::StoreLocal:
|
||||
case Op::Call:
|
||||
case Op::Return:
|
||||
case Op::Jump:
|
||||
case Op::JumpIfNotZero:
|
||||
case Op::Add:
|
||||
case Op::Subtract:
|
||||
case Op::Multiply:
|
||||
case Op::Divide:
|
||||
case Op::Remainder:
|
||||
case Op::Equal:
|
||||
case Op::LessThan:
|
||||
case Op::And:
|
||||
case Op::Or:
|
||||
case Op::Xor:
|
||||
}
|
||||
case Op::PushBool: {
|
||||
assert_program_has(1);
|
||||
auto value = eat_int32();
|
||||
this->stack.push_back(Bool { .value = value != 0 });
|
||||
break;
|
||||
}
|
||||
case Op::PushString: {
|
||||
assert_program_has(1);
|
||||
auto string_length = eat_uint32();
|
||||
assert_program_has(string_length);
|
||||
auto value = std::string();
|
||||
for (uint32_t i = 0; i < string_length; ++i) {
|
||||
auto ch = eat_uint32();
|
||||
value.push_back(static_cast<char>(ch));
|
||||
}
|
||||
stack_push(String { .value = std::move(value) });
|
||||
break;
|
||||
}
|
||||
case Op::PushPtr: {
|
||||
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:
|
||||
assert_stack_has(1);
|
||||
auto value = !stack_pop().as_bool().value;
|
||||
stack_push(Bool { .value = value });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,15 @@
|
||||
#include "value.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace sliger {
|
||||
|
||||
class VM {
|
||||
public:
|
||||
VM(const std::vector<Op>& program)
|
||||
VM(const std::vector<uint32_t>& program)
|
||||
: program(program.data())
|
||||
, program_size(program.size())
|
||||
{
|
||||
@ -19,23 +21,80 @@ public:
|
||||
|
||||
inline void step() { this->pc += 1; }
|
||||
|
||||
inline auto eat_as_op() -> Op
|
||||
inline auto eat_op() -> Op
|
||||
{
|
||||
auto value = curr_as_op();
|
||||
step();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline auto curr_as_op() const -> Op
|
||||
{
|
||||
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 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:
|
||||
uint32_t pc = 0;
|
||||
const Op* program;
|
||||
uint32_t bp = 0;
|
||||
const uint32_t* program;
|
||||
size_t program_size;
|
||||
std::vector<Value> stack;
|
||||
std::vector<Value> pool_heap;
|
||||
|
43
src/arch.ts
43
src/arch.ts
@ -8,26 +8,25 @@ export const Ops = {
|
||||
Nop: 0,
|
||||
PushNull: 1,
|
||||
PushInt: 2,
|
||||
PushString: 3,
|
||||
PushArray: 4,
|
||||
PushStruct: 5,
|
||||
PushPtr: 6,
|
||||
Pop: 7,
|
||||
LoadLocal: 8,
|
||||
StoreLocal: 9,
|
||||
Call: 10,
|
||||
Return: 11,
|
||||
Jump: 12,
|
||||
JumpIfNotZero: 13,
|
||||
Add: 14,
|
||||
Subtract: 15,
|
||||
Multiply: 16,
|
||||
Divide: 17,
|
||||
Remainder: 18,
|
||||
Equal: 19,
|
||||
LessThan: 20,
|
||||
And: 21,
|
||||
Or: 22,
|
||||
Xor: 23,
|
||||
Not: 24,
|
||||
PushBool: 3,
|
||||
PushString: 4,
|
||||
PushPtr: 5,
|
||||
Pop: 6,
|
||||
LoadLocal: 7,
|
||||
StoreLocal: 8,
|
||||
Call: 9,
|
||||
Return: 10,
|
||||
Jump: 11,
|
||||
JumpIfTrue: 12,
|
||||
Add: 13,
|
||||
Subtract: 14,
|
||||
Multiply: 15,
|
||||
Divide: 16,
|
||||
Remainder: 17,
|
||||
Equal: 18,
|
||||
LessThan: 19,
|
||||
And: 20,
|
||||
Or: 21,
|
||||
Xor: 22,
|
||||
Not: 23,
|
||||
} as const;
|
||||
|
Loading…
Reference in New Issue
Block a user