Compare commits
2 Commits
ce91126cb1
...
3d89031748
Author | SHA1 | Date | |
---|---|---|---|
3d89031748 | |||
2fbccd0bc8 |
@ -63,7 +63,7 @@ auto compile_asm(const std::vector<AsmLine>& lines) -> std::vector<uint32_t>
|
||||
break;
|
||||
}
|
||||
case AsmLineType::Loc: {
|
||||
locs.insert_or_assign(std::get<Loc>(line.value).value, ip + 1);
|
||||
locs.insert_or_assign(std::get<Loc>(line.value).value, ip);
|
||||
break;
|
||||
}
|
||||
case AsmLineType::Ref: {
|
||||
@ -75,9 +75,15 @@ auto compile_asm(const std::vector<AsmLine>& lines) -> std::vector<uint32_t>
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < output.size(); ++i) {
|
||||
if (refs.contains(i)) {
|
||||
output.at(i) = static_cast<uint32_t>(locs.at(refs.at(i)));
|
||||
if (!refs.contains(i)) {
|
||||
continue;
|
||||
}
|
||||
if (!locs.contains(refs.at(i))) {
|
||||
std::cerr << std::format(
|
||||
"error: label \"{}\" used at {} not defined\n", refs.at(i), i);
|
||||
continue;
|
||||
}
|
||||
output.at(i) = static_cast<uint32_t>(locs.at(refs.at(i)));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@ -92,19 +98,23 @@ int main()
|
||||
// + a b
|
||||
// }
|
||||
//
|
||||
// let result = 0;
|
||||
// let i = 0;
|
||||
// loop {
|
||||
// if i >= 10 {
|
||||
// break;
|
||||
// fn main() {
|
||||
// let result = 0;
|
||||
// let i = 0;
|
||||
// loop {
|
||||
// if i >= 10 {
|
||||
// break;
|
||||
// }
|
||||
// result = add(result, 5);
|
||||
// i = + i 1;
|
||||
// }
|
||||
// result = add(result, 5);
|
||||
// result
|
||||
// }
|
||||
auto program_asm = std::vector<AsmLine> {
|
||||
// clang-format off
|
||||
SourceMap, 0, 0, 0,
|
||||
PushPtr, R("main"),
|
||||
Pop,
|
||||
Call, 0,
|
||||
PushPtr, R("_exit"),
|
||||
Jump,
|
||||
Pop,
|
||||
@ -112,15 +122,17 @@ int main()
|
||||
SourceMap, 19, 2, 5,
|
||||
Add,
|
||||
Return,
|
||||
L("main"),
|
||||
SourceMap, 28, 5, 1,
|
||||
PushInt, 0,
|
||||
PushInt, 0,
|
||||
SourceMap, 44, 6, 1,
|
||||
PushInt, 0,
|
||||
SourceMap, 55, 7, 1,
|
||||
L("1"),
|
||||
L("0"),
|
||||
SourceMap, 66, 8, 5,
|
||||
LoadLocal, 1,
|
||||
PushInt, 0,
|
||||
LoadLocal, 2,
|
||||
PushInt, 10,
|
||||
LessThan,
|
||||
Not,
|
||||
PushPtr, R("1"),
|
||||
@ -128,22 +140,25 @@ int main()
|
||||
SourceMap, 87, 9, 9,
|
||||
PushPtr, R("2"),
|
||||
Jump,
|
||||
L("1"),
|
||||
SourceMap, 104, 11, 5,
|
||||
LoadLocal, 0,
|
||||
LoadLocal, 1,
|
||||
PushInt, 5,
|
||||
PushPtr, R("add"),
|
||||
Call, 2,
|
||||
StoreLocal, 0,
|
||||
StoreLocal, 1,
|
||||
SourceMap, 133, 12, 5,
|
||||
LoadLocal, 1,
|
||||
LoadLocal, 2,
|
||||
PushInt, 1,
|
||||
Add,
|
||||
StoreLocal, 1,
|
||||
StoreLocal, 2,
|
||||
PushPtr, R("0"),
|
||||
Jump,
|
||||
L("2"),
|
||||
LoadLocal, 1,
|
||||
StoreLocal, 0,
|
||||
Pop,
|
||||
Pop,
|
||||
PushNull,
|
||||
Return,
|
||||
L("_exit"),
|
||||
SourceMap, 147, 15, 1
|
||||
@ -156,6 +171,7 @@ int main()
|
||||
.code_coverage = true,
|
||||
});
|
||||
vm.run_until_done();
|
||||
|
||||
vm.print_stack();
|
||||
std::cout << std::format("done\n{}\n", vm.stack_repr_string(4));
|
||||
auto flame_graph = vm.flame_graph_json();
|
||||
std::cout << std::format("flame graph: {}\n", flame_graph);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@ -50,6 +51,15 @@ struct Ptr {
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
template <ValueType op> struct ValueTypeToType { };
|
||||
template <> struct ValueTypeToType<ValueType::Null> { using Type = Null; };
|
||||
template <> struct ValueTypeToType<ValueType::Int> { using Type = Int; };
|
||||
template <> struct ValueTypeToType<ValueType::Bool> { using Type = Bool; };
|
||||
template <> struct ValueTypeToType<ValueType::String> { using Type = String; };
|
||||
template <> struct ValueTypeToType<ValueType::Ptr> { using Type = Ptr; };
|
||||
// clang-format on
|
||||
|
||||
class Value {
|
||||
public:
|
||||
Value(Null&& value)
|
||||
@ -80,120 +90,42 @@ public:
|
||||
|
||||
inline auto type() const -> ValueType { return m_type; };
|
||||
|
||||
inline auto as_null() -> Null&
|
||||
template <ValueType VT> inline auto as() -> ValueTypeToType<VT>::Type&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Null>(value);
|
||||
return std::get<typename ValueTypeToType<VT>::Type>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Null\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_null() const -> const Null&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Null>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Null\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
std::cerr << std::format("error: tried to unwrap {} as {}\n",
|
||||
value_type_to_string(this->m_type), value_type_to_string(VT));
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
inline auto as_int() -> Int&
|
||||
template <ValueType VT>
|
||||
inline auto as() const -> const ValueTypeToType<VT>::Type&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Int>(value);
|
||||
return std::get<typename ValueTypeToType<VT>::Type>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Int\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_int() const -> const Int&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Int>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Int\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
std::cerr << std::format("error: tried to unwrap {} as {}\n",
|
||||
value_type_to_string(this->m_type), value_type_to_string(VT));
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
inline auto as_bool() -> Bool&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Bool>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Bool\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_bool() const -> const Bool&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Bool>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Bool\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
inline auto as_null() -> Null& { return as<ValueType::Null>(); }
|
||||
inline auto as_int() -> Int& { return as<ValueType::Int>(); }
|
||||
inline auto as_bool() -> Bool& { return as<ValueType::Bool>(); }
|
||||
inline auto as_string() -> String& { return as<ValueType::String>(); }
|
||||
inline auto as_ptr() -> Ptr& { return as<ValueType::Ptr>(); }
|
||||
|
||||
inline auto as_string() -> String&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<String>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as String\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_string() const -> const String&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<String>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as String\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
inline auto as_ptr() -> Ptr&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Ptr>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Ptr\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_ptr() const -> const Ptr&
|
||||
{
|
||||
//
|
||||
try {
|
||||
return std::get<Ptr>(value);
|
||||
} catch (const std::bad_variant_access& ex) {
|
||||
std::cout << std::format("tried to unwrap {} as Ptr\n",
|
||||
value_type_to_string(this->m_type));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
inline auto as_null() const -> const Null& { return as<ValueType::Null>(); }
|
||||
inline auto as_int() const -> const Int& { return as<ValueType::Int>(); }
|
||||
inline auto as_bool() const -> const Bool& { return as<ValueType::Bool>(); }
|
||||
inline auto as_string() const -> const String& { return as<ValueType::String>(); }
|
||||
inline auto as_ptr() const -> const Ptr& { return as<ValueType::Ptr>(); }
|
||||
// clang-format on
|
||||
|
||||
inline auto to_string() const -> std::string
|
||||
{
|
||||
|
@ -4,11 +4,70 @@
|
||||
#include <cstdlib>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace sliger;
|
||||
|
||||
inline auto maybe_op_to_string(uint32_t value) -> std::string
|
||||
{
|
||||
switch (static_cast<Op>(value)) {
|
||||
case Op::Nop:
|
||||
return "Nop";
|
||||
case Op::PushNull:
|
||||
return "PushNull";
|
||||
case Op::PushInt:
|
||||
return "PushInt";
|
||||
case Op::PushBool:
|
||||
return "PushBool";
|
||||
case Op::PushString:
|
||||
return "PushString";
|
||||
case Op::PushPtr:
|
||||
return "PushPtr";
|
||||
case Op::Pop:
|
||||
return "Pop";
|
||||
case Op::LoadLocal:
|
||||
return "LoadLocal";
|
||||
case Op::StoreLocal:
|
||||
return "StoreLocal";
|
||||
case Op::Call:
|
||||
return "Call";
|
||||
case Op::Return:
|
||||
return "Return";
|
||||
case Op::Jump:
|
||||
return "Jump";
|
||||
case Op::JumpIfFalse:
|
||||
return "JumpIfFalse";
|
||||
case Op::Add:
|
||||
return "Add";
|
||||
case Op::Subtract:
|
||||
return "Subtract";
|
||||
case Op::Multiply:
|
||||
return "Multiply";
|
||||
case Op::Divide:
|
||||
return "Divide";
|
||||
case Op::Remainder:
|
||||
return "Remainder";
|
||||
case Op::Equal:
|
||||
return "Equal";
|
||||
case Op::LessThan:
|
||||
return "LessThan";
|
||||
case Op::And:
|
||||
return "And";
|
||||
case Op::Or:
|
||||
return "Or";
|
||||
case Op::Xor:
|
||||
return "Xor";
|
||||
case Op::Not:
|
||||
return "Not";
|
||||
case Op::SourceMap:
|
||||
return "SourceMap";
|
||||
default:
|
||||
return std::to_string(value);
|
||||
}
|
||||
}
|
||||
|
||||
void VM::run_until_done()
|
||||
{
|
||||
while (!done()) {
|
||||
@ -19,15 +78,15 @@ void VM::run_until_done()
|
||||
void VM::run_n_instructions(size_t amount)
|
||||
{
|
||||
for (size_t i = 0; !done() and i < amount; ++i) {
|
||||
|
||||
run_instruction();
|
||||
}
|
||||
}
|
||||
|
||||
void VM::run_instruction()
|
||||
{
|
||||
std::cout << "stack:\n";
|
||||
this->print_stack();
|
||||
std::cout << std::format("pc = {}\n", this->pc);
|
||||
std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc,
|
||||
maybe_op_to_string(this->program[this->pc]), stack_repr_string(4));
|
||||
auto op = eat_op();
|
||||
switch (op) {
|
||||
case Op::Nop:
|
||||
|
@ -156,11 +156,22 @@ public:
|
||||
return this->stack;
|
||||
}
|
||||
|
||||
inline void print_stack() const
|
||||
inline auto stack_repr_string(size_t max_items) const -> std::string
|
||||
{
|
||||
for (const auto& value : view_stack()) {
|
||||
std::cout << std::format(" {}\n", value.to_repr_string());
|
||||
auto result = std::string();
|
||||
result += "→";
|
||||
const auto& stack = view_stack();
|
||||
for (size_t i = 0; i < stack.size() and i < max_items; ++i) {
|
||||
if (i != 0) {
|
||||
result += " ";
|
||||
}
|
||||
result += std::format(
|
||||
"{:<11}", stack[stack.size() - i - 1].to_repr_string());
|
||||
}
|
||||
if (stack.size() >= max_items) {
|
||||
result += std::format(" ... + {}", stack.size() - max_items + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user