finish runtime instrs
This commit is contained in:
parent
f077a16939
commit
161ea947d7
@ -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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
209
runtime/vm.cpp
209
runtime/vm.cpp
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
43
src/arch.ts
43
src/arch.ts
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user