From 55c54fa0a3c3317bc698e823ca53bd30d6638898 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 11:23:35 +0200 Subject: [PATCH 01/10] Logic: Maintain the frame stack in the interpreter --- src/lang/interpreter.cc | 173 +++++++++++++++++++++------------------- src/rt/objects.h | 36 +-------- src/rt/region.h | 6 ++ src/rt/rt.cc | 14 +--- src/rt/rt.h | 8 +- 5 files changed, 106 insertions(+), 131 deletions(-) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index f28dbaf..5a2f00b 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -39,22 +39,55 @@ struct ExecReturn { // Interpreter/state // ============================================== struct InterpreterFrame { - std::vector stack; trieste::NodeIt ip; trieste::Node body; - // Used for sanity checks objects::DynObject *frame; + std::vector stack; + + ~InterpreterFrame() { + objects::remove_reference(frame, frame); + } }; class Interpreter { objects::UI* ui; std::vector frame_stack; - // This is the top level stack - std::vector stack; + + InterpreterFrame *push_stack_frame(trieste::Node body) { + objects::DynObject * parent_obj = nullptr; + if (!frame_stack.empty()) { + parent_obj = frame_stack.back()->frame; + } + + auto frame = new InterpreterFrame { body->begin(), body, objects::make_frame(parent_obj), {} }; + frame_stack.push_back(frame); + return frame; + } + InterpreterFrame *pop_stack_frame() { + auto frame = frame_stack.back(); + frame_stack.pop_back(); + delete frame; + + if (frame_stack.empty()) { + return nullptr; + } else { + return frame_stack.back(); + } + } + InterpreterFrame *parent_stack_frame() { + return frame_stack[frame_stack.size() - 2]; + } + + std::vector& stack() { + return frame_stack.back()->stack; + } + objects::DynObject *frame() { + return frame_stack.back()->frame; + } objects::DynObject* pop(char const* data_info) { - auto v = stack.back(); - stack.pop_back(); + auto v = stack().back(); + stack().pop_back(); std::cout << "pop " << v << " (" << data_info << ")" << std::endl; return v; } @@ -68,7 +101,7 @@ class Interpreter { std::cout << node->location().view() << std::endl << std::endl; // Mermaid output - std::vector edges{{nullptr, "?", objects::get_frame()}}; + std::vector edges{{nullptr, "?", frame()}}; ui->output(edges, std::string(node->location().view())); // Continue @@ -95,7 +128,7 @@ class Interpreter { } else if (payload == KeyIter) { auto v = pop("iterator source"); obj = objects::make_iter(v); - remove_reference(objects::get_frame(), v); + remove_reference(frame(), v); } else if (payload == Proto) { obj = objects::make_object(); // RC transferred @@ -107,42 +140,40 @@ class Interpreter { assert(false && "CreateObject has to specify a value"); } - stack.push_back(obj); + stack().push_back(obj); std::cout << "push " << obj << std::endl; return ExecNext {}; } if (node == Null) { - stack.push_back(nullptr); + stack().push_back(nullptr); std::cout << "push nullptr" << std::endl; return ExecNext {}; } if (node == LoadFrame) { - auto frame = objects::get_frame(); std::string field{node->location().view()}; - auto v = objects::get(frame, field); - objects::add_reference(frame, v); - stack.push_back(v); + auto v = objects::get(frame(), field); + objects::add_reference(frame(), v); + stack().push_back(v); std::cout << "push " << v << std::endl; return ExecNext {}; } if (node == StoreFrame) { - auto frame = objects::get_frame(); auto v = pop("value to store"); std::string field{node->location().view()}; - auto v2 = objects::set(frame, field, v); - remove_reference(frame, v2); + auto v2 = objects::set(frame(), field, v); + remove_reference(frame(), v2); return ExecNext {}; } if (node == LoadField) { - assert(stack.size() >= 2 && "the stack is too small"); + assert(stack().size() >= 2 && "the stack is too small"); auto k = pop("lookup-key"); auto v = pop("lookup-value"); @@ -153,11 +184,11 @@ class Interpreter { } auto v2 = objects::get(v, k); - stack.push_back(v2); + stack().push_back(v2); std::cout << "push " << v2 << std::endl; - objects::add_reference(objects::get_frame(), v2); - objects::remove_reference(objects::get_frame(), k); - objects::remove_reference(objects::get_frame(), v); + objects::add_reference(frame(), v2); + objects::remove_reference(frame(), k); + objects::remove_reference(frame(), v); return ExecNext {}; } @@ -167,9 +198,9 @@ class Interpreter { auto k = pop("lookup-key"); auto v2 = pop("lookup-value"); auto v3 = objects::set(v2, k, v); - move_reference(objects::get_frame(), v2, v); - remove_reference(objects::get_frame(), k); - remove_reference(objects::get_frame(), v2); + move_reference(frame(), v2, v); + remove_reference(frame(), k); + remove_reference(frame(), v2); remove_reference(v2, v3); return ExecNext {}; } @@ -178,7 +209,7 @@ class Interpreter { { auto v = pop("region source"); objects::create_region(v); - remove_reference(objects::get_frame(), v); + remove_reference(frame(), v); return ExecNext {}; } @@ -186,7 +217,7 @@ class Interpreter { { auto v = pop("object to freeze"); objects::freeze(v); - remove_reference(objects::get_frame(), v); + remove_reference(frame(), v); return ExecNext {}; } @@ -206,14 +237,13 @@ class Interpreter { } else { result = "False"; } - auto frame = objects::get_frame(); - auto v = objects::get(frame, result); - objects::add_reference(frame, v); - stack.push_back(v); + auto v = objects::get(frame(), result); + objects::add_reference(frame(), v); + stack().push_back(v); std::cout << "push " << v << " (" << result << ")"<< std::endl; - remove_reference(objects::get_frame(), a); - remove_reference(objects::get_frame(), b); + remove_reference(frame(), a); + remove_reference(frame(), b); return ExecNext {}; } @@ -225,9 +255,9 @@ class Interpreter { if (node == JumpFalse) { auto v = pop("jump condition"); - auto false_obj = objects::get(objects::get_frame(), "False"); + auto false_obj = objects::get(frame(), "False"); auto jump = (v == false_obj); - remove_reference(objects::get_frame(), v); + remove_reference(frame(), v); if (jump) { return ExecJump { node->location() }; } else { @@ -240,18 +270,18 @@ class Interpreter { auto it = pop("iterator"); auto obj = objects::value::iter_next(it); - remove_reference(objects::get_frame(), it); + remove_reference(frame(), it); - stack.push_back(obj); + stack().push_back(obj); std::cout << "push " << obj << " (next from iter)" << std::endl; return ExecNext {}; } if (node == ClearStack) { - if (!stack.empty()) { - while (!stack.empty()) { - remove_reference(objects::get_frame(), stack.back()); - stack.pop_back(); + if (!stack().empty()) { + while (!stack().empty()) { + remove_reference(frame(), stack().back()); + stack().pop_back(); } } return ExecNext {}; @@ -261,7 +291,7 @@ class Interpreter { auto func = pop("function"); auto arg_ctn = std::stoul(std::string(node->location().view())); auto action = ExecFunc { objects::value::get_bytecode(func)->body , arg_ctn }; - remove_reference(objects::get_frame(), func); + remove_reference(frame(), func); return action; } @@ -284,73 +314,54 @@ class Interpreter { Interpreter(objects::UI* ui_): ui(ui_) {} void run(trieste::Node main) { - // Push the main frame, to later clear the locally defined functions and vars - objects::push_frame(); - - auto it = main->begin(); - auto body = main; + auto frame = push_stack_frame(main); - while (it != body->end()) { - const auto action = run_stmt(*it); + while (frame) { + const auto action = run_stmt(*frame->ip); if (std::holds_alternative(action)) { - it++; + frame->ip++; } else if (std::holds_alternative(action)) { auto jump = std::get(action); - auto label_node = body->look(jump.target); + auto label_node = frame->body->look(jump.target); assert(label_node.size() == 1); - it = body->find(label_node[0]); + frame->ip = frame->body->find(label_node[0]); // Skip the label node - it++; + frame->ip++; } else if (std::holds_alternative(action)) { auto func = std::get(action); - // Make sure the stored it, continues after the call - it++; + // Make sure the stored ip, continues after the call + frame->ip++; - // Store the current frame - auto parent_frame = new InterpreterFrame { std::move(stack), it, body, objects::get_frame() }; - frame_stack.push_back(parent_frame); - objects::push_frame(); + frame = push_stack_frame(func.body); + auto parent_frame = parent_stack_frame(); // Setup the new frame - body = func.body; - it = body->begin(); - stack = {}; for (size_t i = 0; i < func.arg_ctn; i++) { - stack.push_back(parent_frame->stack.back()); + frame->stack.push_back(parent_frame->stack.back()); parent_frame->stack.pop_back(); } } else if (std::holds_alternative(action)) { - it = body->end(); + frame->ip = frame->body->end(); } else { assert(false && "unhandled statement action"); } - if (it == body->end() && !frame_stack.empty()) { - // Handle frame stack poping - auto frame = frame_stack.back(); - frame_stack.pop_back(); - objects::pop_frame(); - - assert(frame->frame == objects::get_frame() && "the interpreter and object frames need to be synced"); - - it = frame->ip; - body = frame->body; - stack = frame->stack; - delete frame; - + if (frame->ip == frame->body->end()) { if (std::holds_alternative(action)) { auto return_ = std::get(action); if (return_.value.has_value()) { - stack.push_back(return_.value.value()); + auto parent = parent_stack_frame(); + auto value = return_.value.value(); + objects::move_reference(frame->frame, parent->frame, value); + parent->stack.push_back(value); } } + + frame = pop_stack_frame(); } } - - // Pop the main frame, to clear local functions and variables - objects::pop_frame(); } }; diff --git a/src/rt/objects.h b/src/rt/objects.h index a9f2e89..43f179a 100644 --- a/src/rt/objects.h +++ b/src/rt/objects.h @@ -14,7 +14,6 @@ #include "nop.h" #include "region.h" #include "rt.h" -#include "tagged_pointer.h" #include "../lang/interpreter.h" namespace objects { @@ -40,12 +39,7 @@ class DynObject { template friend void visit(Edge, Pre, Post); - thread_local static std::vector frame_stack; - - // Represents the region of specific object. Uses small pointers to - // encode special regions. - using RegionPointer = utils::TaggedPointer; - + thread_local static RegionPointer local_region; // TODO: Not concurrency safe inline static size_t count{0}; @@ -214,22 +208,6 @@ class DynObject { return nullptr; } - inline static void push_frame(DynObject* frame) { - frame_stack.push_back(frame); - } - - // Place holder for the frame object. Used in various places if we don't have - // an entry point. - inline static DynObject *frame() { - return frame_stack.back(); - } - - inline static void pop_frame() { - auto frame = frame_stack.back(); - frame_stack.pop_back(); - remove_reference(frame_stack.back(), frame); - } - void freeze() { // TODO SCC algorithm visit(this, [](Edge e) { @@ -348,15 +326,8 @@ class DynObject { static size_t get_count() { return count; } - static void set_local_region(Region *r) { frame()->region = {r}; } - static Region *get_local_region() { - auto frame = DynObject::frame(); - if (frame->region) { - return frame->region.get_ptr(); - } - - return frame->get(ParentField)->get_local_region(); + return local_region; } static std::set get_objects() { return all_objects; } @@ -541,11 +512,10 @@ inline void visit(Edge e, Pre pre, Post post) { } } - template inline void visit(DynObject* start, Pre pre, Post post) { - visit(Edge{DynObject::frame(), "", start}, pre, post); + visit(Edge{nullptr, "", start}, pre, post); } } // namespace objects diff --git a/src/rt/region.h b/src/rt/region.h index 843133a..50b47b4 100644 --- a/src/rt/region.h +++ b/src/rt/region.h @@ -4,6 +4,7 @@ #include #include "output.h" +#include "tagged_pointer.h" namespace objects { class DynObject; @@ -185,4 +186,9 @@ struct Region { collecting = false; } }; + +// Represents the region of specific object. Uses small pointers to +// encode special regions. +using RegionPointer = utils::TaggedPointer; + } // namespace objects \ No newline at end of file diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 6c48bf5..1a3d285 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -19,17 +19,12 @@ DynObject *make_object(std::string value) { } DynObject *make_object() { return new DynObject(); } -thread_local std::vector DynObject::frame_stack = { FrameObject::create_first_stack() }; - -void push_frame() { - auto parent = DynObject::frame(); - DynObject::push_frame(new FrameObject(parent)); -} -DynObject *get_frame() { return DynObject::frame(); } -void pop_frame() { - DynObject::pop_frame(); +DynObject *make_frame(DynObject *parent) { + return new FrameObject(parent); } +thread_local RegionPointer DynObject::local_region = new Region(); + void freeze(DynObject *obj) { obj->freeze(); } void create_region(DynObject *object) { object->create_region(); } @@ -83,7 +78,6 @@ void move_reference(DynObject *src, DynObject *dst, DynObject *target) { } size_t pre_run() { - objects::DynObject::set_local_region(new Region()); std::cout << "Running test..." << std::endl; return objects::DynObject::get_count(); } diff --git a/src/rt/rt.h b/src/rt/rt.h index 7f02667..6d4995a 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -20,13 +20,7 @@ DynObject *make_func(verona::interpreter::Bytecode *body); DynObject *make_iter(DynObject *iter_src); DynObject *make_object(std::string str_value); DynObject *make_object(); - -/// @brief This pushes a new frame onto the frame stack -void push_frame(); -/// @brief Returns the current frame at the top of the frame stack. -DynObject *get_frame(); -/// @brief This pops the current frame. -void pop_frame(); +DynObject *make_frame(DynObject *parent); void freeze(DynObject *obj); void create_region(DynObject *objects); From a65e58e0ba3894247ed71961c3ca07bbf20a43a4 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 13:01:52 +0200 Subject: [PATCH 02/10] Refactoring: Add `rt::env` namespace and `rt/objects` folder --- src/lang/interpreter.cc | 2 +- src/rt/env.h | 107 ++++++++++++++++++++ src/rt/mermaid.h | 2 +- src/rt/{objects.h => objects/dyn_object.h} | 108 +-------------------- src/rt/{ => objects}/region.h | 4 +- src/rt/rt.cc | 29 +++--- src/rt/rt.h | 2 +- src/{rt => utils}/nop.h | 0 src/{rt => utils}/tagged_pointer.h | 0 9 files changed, 131 insertions(+), 123 deletions(-) create mode 100644 src/rt/env.h rename src/rt/{objects.h => objects/dyn_object.h} (80%) rename src/rt/{ => objects}/region.h (98%) rename src/{rt => utils}/nop.h (100%) rename src/{rt => utils}/tagged_pointer.h (100%) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index 5a2f00b..590387a 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -124,7 +124,7 @@ class Interpreter { if (payload == Dictionary) { obj = objects::make_object(); } else if (payload == String) { - obj = objects::make_object(std::string(payload->location().view())); + obj = objects::make_str(std::string(payload->location().view())); } else if (payload == KeyIter) { auto v = pop("iterator source"); obj = objects::make_iter(v); diff --git a/src/rt/env.h b/src/rt/env.h new file mode 100644 index 0000000..c9c2abe --- /dev/null +++ b/src/rt/env.h @@ -0,0 +1,107 @@ +#include "objects/dyn_object.h" +#include "rt.h" + +namespace rt::env { + +// The prototype object for functions +// TODO put some stuff in here? +objects::DynObject framePrototypeObject{nullptr, true}; + +class FrameObject : public objects::DynObject { + FrameObject() : objects::DynObject(&framePrototypeObject, true) {} +public: + FrameObject(objects::DynObject* parent_frame) : objects::DynObject(&framePrototypeObject) { + if (parent_frame) { + auto old_value = this->set(objects::ParentField, parent_frame); + objects::add_reference(this, parent_frame); + assert(!old_value); + } + } + + static FrameObject* create_first_stack() { + return new FrameObject(); + } +}; + +// The prototype object for functions +// TODO put some stuff in here? +objects::DynObject funcPrototypeObject{nullptr, true}; +// The prototype object for bytecode functions +// TODO put some stuff in here? +objects::DynObject bytecodeFuncPrototypeObject{&funcPrototypeObject, true}; + +class FuncObject : public objects::DynObject { +public: + FuncObject(objects::DynObject* prototype_, bool global = false) : objects::DynObject(prototype_, global) {} +}; + +class BytecodeFuncObject : public FuncObject { + verona::interpreter::Bytecode *body; +public: + BytecodeFuncObject(verona::interpreter::Bytecode *body_) : FuncObject(&bytecodeFuncPrototypeObject), body(body_) {} + ~BytecodeFuncObject() { + verona::interpreter::delete_bytecode(this->body); + this->body = nullptr; + } + + verona::interpreter::Bytecode* get_bytecode() { + return this->body; + } +}; + + +// The prototype object for strings +// TODO put some stuff in here? +objects::DynObject stringPrototypeObject{nullptr, true}; + +class StringObject : public objects::DynObject { + std::string value; + +public: + StringObject(std::string value_) + : objects::DynObject(&stringPrototypeObject), value(value_) {} + + std::string get_name() { + return value; + } + + std::string as_key() { + return value; + } + + objects::DynObject* is_primitive() { + return this; + } +}; + +// The prototype object for iterators +// TODO put some stuff in here? +objects::DynObject keyIterPrototypeObject{nullptr, true}; + +class KeyIterObject : public objects::DynObject { + std::map::iterator iter; + std::map::iterator iter_end; + + public: + KeyIterObject(std::map &fields) + : objects::DynObject(&keyIterPrototypeObject), iter(fields.begin()), iter_end(fields.end()) {} + + objects::DynObject* iter_next() { + objects::DynObject *obj = nullptr; + if (this->iter != this->iter_end) { + obj = objects::make_str(this->iter->first); + this->iter++; + } + + return obj; + } + + std::string get_name() { + return "<iterator>"; + } + + objects::DynObject* is_primitive() { + return this; + } +}; +} // namespace rt::env diff --git a/src/rt/mermaid.h b/src/rt/mermaid.h index fc6ddbc..6898647 100644 --- a/src/rt/mermaid.h +++ b/src/rt/mermaid.h @@ -5,7 +5,7 @@ #include #include -#include "objects.h" +#include "objects/dyn_object.h" namespace objects { diff --git a/src/rt/objects.h b/src/rt/objects/dyn_object.h similarity index 80% rename from src/rt/objects.h rename to src/rt/objects/dyn_object.h index 43f179a..5d55090 100644 --- a/src/rt/objects.h +++ b/src/rt/objects/dyn_object.h @@ -11,10 +11,10 @@ #include #include -#include "nop.h" +#include "../../utils/nop.h" #include "region.h" -#include "rt.h" -#include "../lang/interpreter.h" +#include "../rt.h" +#include "../../lang/interpreter.h" namespace objects { constexpr uintptr_t ImmutableTag{1}; @@ -60,7 +60,6 @@ class DynObject { bool is_local_object() { return region.get_ptr() == get_local_region(); } - static void remove_region_reference(Region *src, Region *target) { if (src == target) { std::cout << "Same region, no need to do anything" << std::endl; @@ -333,107 +332,6 @@ class DynObject { static std::set get_objects() { return all_objects; } }; -// The prototype object for strings -// TODO put some stuff in here? -DynObject stringPrototypeObject{nullptr, true}; - -class StringObject : public DynObject { - std::string value; - -public: - StringObject(std::string value_) - : DynObject(&stringPrototypeObject), value(value_) {} - - std::string get_name() { - return value; - } - - std::string as_key() { - return value; - } - - DynObject* is_primitive() { - return this; - } -}; - -// The prototype object for iterators -// TODO put some stuff in here? -DynObject keyIterPrototypeObject{nullptr, true}; - -class KeyIterObject : public DynObject { - std::map::iterator iter; - std::map::iterator iter_end; - - public: - KeyIterObject(std::map &fields) - : DynObject(&keyIterPrototypeObject), iter(fields.begin()), iter_end(fields.end()) {} - - DynObject* iter_next() { - DynObject *obj = nullptr; - if (this->iter != this->iter_end) { - obj = make_object(this->iter->first); - this->iter++; - } - - return obj; - } - - std::string get_name() { - return "<iterator>"; - } - - DynObject* is_primitive() { - return this; - } -}; - -// The prototype object for functions -// TODO put some stuff in here? -DynObject funcPrototypeObject{nullptr, true}; -// The prototype object for bytecode functions -// TODO put some stuff in here? -DynObject bytecodeFuncPrototypeObject{&funcPrototypeObject, true}; - -class FuncObject : public DynObject { -public: - FuncObject(DynObject* prototype_, bool global = false) : DynObject(prototype_, global) {} -}; - -class BytecodeFuncObject : public FuncObject { - verona::interpreter::Bytecode *body; -public: - BytecodeFuncObject(verona::interpreter::Bytecode *body_) : FuncObject(&bytecodeFuncPrototypeObject), body(body_) {} - ~BytecodeFuncObject() { - verona::interpreter::delete_bytecode(this->body); - this->body = nullptr; - } - - verona::interpreter::Bytecode* get_bytecode() { - return this->body; - } -}; - -// The prototype object for functions -// TODO put some stuff in here? -DynObject framePrototypeObject{nullptr, true}; - -class FrameObject : public DynObject { - FrameObject() : DynObject(&framePrototypeObject, true) {} -public: - FrameObject(DynObject* parent_frame) : DynObject(&framePrototypeObject) { - if (parent_frame) { - auto old_value = this->set(ParentField, parent_frame); - objects::add_reference(this, parent_frame); - assert(!old_value); - } - } - - static FrameObject* create_first_stack() { - return new FrameObject(); - } -}; - void destruct(DynObject *obj) { // Called from the region destructor. // Remove all references to other objects. diff --git a/src/rt/region.h b/src/rt/objects/region.h similarity index 98% rename from src/rt/region.h rename to src/rt/objects/region.h index 50b47b4..b8d53fb 100644 --- a/src/rt/region.h +++ b/src/rt/objects/region.h @@ -3,8 +3,8 @@ #include #include -#include "output.h" -#include "tagged_pointer.h" +#include "../output.h" +#include "../../utils/tagged_pointer.h" namespace objects { class DynObject; diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 1a3d285..c3cec9e 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -3,24 +3,27 @@ #include #include "mermaid.h" -#include "objects.h" +#include "objects/dyn_object.h" #include "rt.h" +#include "env.h" namespace objects { DynObject *make_func(verona::interpreter::Bytecode *body) { - return new BytecodeFuncObject(body); + return new rt::env::BytecodeFuncObject(body); } DynObject *make_iter(DynObject *iter_src) { - return new KeyIterObject(iter_src->fields); + return new rt::env::KeyIterObject(iter_src->fields); } -DynObject *make_object(std::string value) { - return new StringObject(value); +DynObject *make_str(std::string value) { + return new rt::env::StringObject(value); +} +DynObject *make_object() { + return new DynObject(); } -DynObject *make_object() { return new DynObject(); } DynObject *make_frame(DynObject *parent) { - return new FrameObject(parent); + return new rt::env::FrameObject(parent); } thread_local RegionPointer DynObject::local_region = new Region(); @@ -35,10 +38,10 @@ DynObject *get(DynObject *obj, std::string key) { std::string get_key(DynObject* key) { // TODO Add some checking. This is need to lookup the correct function in the prototype chain. - if (key->get_prototype() != &stringPrototypeObject) { + if (key->get_prototype() != &rt::env::stringPrototypeObject) { error("Key must be a string."); } - StringObject *str_key = reinterpret_cast(key); + rt::env::StringObject *str_key = reinterpret_cast(key); return str_key->as_key(); } @@ -116,16 +119,16 @@ void post_run(size_t initial_count, UI& ui) { namespace value { DynObject *iter_next(DynObject *iter) { assert(!iter->is_immutable()); - if (iter->get_prototype() != &objects::keyIterPrototypeObject) { + if (iter->get_prototype() != &rt::env::keyIterPrototypeObject) { error("Object is not an iterator."); } - return reinterpret_cast(iter)->iter_next(); + return reinterpret_cast(iter)->iter_next(); } verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func) { - if (func->get_prototype() == &objects::bytecodeFuncPrototypeObject) { - return reinterpret_cast(func)->get_bytecode(); + if (func->get_prototype() == &rt::env::bytecodeFuncPrototypeObject) { + return reinterpret_cast(func)->get_bytecode(); } else { error("Object is not a function."); return {}; diff --git a/src/rt/rt.h b/src/rt/rt.h index 6d4995a..a84741d 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -18,7 +18,7 @@ struct Edge { DynObject *make_func(verona::interpreter::Bytecode *body); DynObject *make_iter(DynObject *iter_src); -DynObject *make_object(std::string str_value); +DynObject *make_str(std::string str_value); DynObject *make_object(); DynObject *make_frame(DynObject *parent); diff --git a/src/rt/nop.h b/src/utils/nop.h similarity index 100% rename from src/rt/nop.h rename to src/utils/nop.h diff --git a/src/rt/tagged_pointer.h b/src/utils/tagged_pointer.h similarity index 100% rename from src/rt/tagged_pointer.h rename to src/utils/tagged_pointer.h From 5ea4e76b640adae10052928197969bcbb3127a3b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 13:31:11 +0200 Subject: [PATCH 03/10] Refactoring: Add `rt::ui` namespace --- CMakeLists.txt | 2 +- src/lang/interpreter.cc | 8 +++---- src/rt/objects/dyn_object.h | 15 ++++++------ src/rt/objects/region.h | 6 ++--- src/rt/objects/visit.h | 13 ++++++++++ src/rt/output.h | 11 --------- src/rt/rt.cc | 13 +++++----- src/rt/rt.h | 22 +++-------------- src/rt/ui.h | 23 ++++++++++++++++++ src/rt/{mermaid.h => ui/mermaid.cc} | 37 ++++++++++++++--------------- 10 files changed, 79 insertions(+), 71 deletions(-) create mode 100644 src/rt/objects/visit.h delete mode 100644 src/rt/output.h create mode 100644 src/rt/ui.h rename src/rt/{mermaid.h => ui/mermaid.cc} (74%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1a1a0b..20841f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ set (TRIESTE_ENABLE_TESTING OFF) FetchContent_MakeAvailable_ExcludeFromAll(trieste) set(CMAKE_CXX_STANDARD 20) -add_library(rt OBJECT src/rt/rt.cc) +add_library(rt OBJECT src/rt/rt.cc src/rt/ui/mermaid.cc) add_library(lang OBJECT src/lang/lang.cc src/lang/interpreter.cc) target_link_libraries(lang PRIVATE trieste::trieste) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index 590387a..3422340 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -50,7 +50,7 @@ struct InterpreterFrame { }; class Interpreter { - objects::UI* ui; + rt::ui::UI* ui; std::vector frame_stack; InterpreterFrame *push_stack_frame(trieste::Node body) { @@ -311,7 +311,7 @@ class Interpreter { } public: - Interpreter(objects::UI* ui_): ui(ui_) {} + Interpreter(rt::ui::UI* ui_): ui(ui_) {} void run(trieste::Node main) { auto frame = push_stack_frame(main); @@ -365,7 +365,7 @@ class Interpreter { } }; -class UI : public objects::UI +class UI : public rt::ui::UI { bool interactive; std::string path; @@ -381,7 +381,7 @@ class UI : public objects::UI out << "```" << std::endl; out << message << std::endl; out << "```" << std::endl; - objects::mermaid(edges, out); + rt::ui::mermaid(edges, out); if (interactive) { out.close(); std::cout << "Press a key!" << std::endl; diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index 5d55090..c81d8a4 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -11,8 +11,9 @@ #include #include -#include "../../utils/nop.h" +#include "visit.h" #include "region.h" +#include "../../utils/nop.h" #include "../rt.h" #include "../../lang/interpreter.h" @@ -33,7 +34,7 @@ inline void visit(DynObject* start, Pre pre, Post post = {}); class DynObject { friend class Reference; friend DynObject* make_iter(DynObject *obj); - friend void mermaid(std::vector &roots, std::ostream &out); + friend void rt::ui::mermaid(std::vector &roots, std::ostream &out); friend void destruct(DynObject *obj); friend void dealloc(DynObject *obj); template @@ -183,7 +184,7 @@ class DynObject { // that we don't track for leaks, otherwise, we need to check if the // RC is zero. if (change_rc(0) != 0 && matched != 0) { - error("Object still has references"); + rt::ui::error("Object still has references"); } auto r = get_region(this); @@ -246,7 +247,7 @@ class DynObject { [[nodiscard]] DynObject *set(std::string name, DynObject *value) { if (is_immutable()) { - error("Cannot mutate immutable object"); + rt::ui::error("Cannot mutate immutable object"); } DynObject *old = fields[name]; fields[name] = value; @@ -256,7 +257,7 @@ class DynObject { // The caller must provide an rc for value. [[nodiscard]] DynObject* set_prototype(DynObject* value) { if (is_immutable()) { - error("Cannot mutate immutable object"); + rt::ui::error("Cannot mutate immutable object"); } DynObject* old = prototype; prototype = value; @@ -332,7 +333,7 @@ class DynObject { static std::set get_objects() { return all_objects; } }; -void destruct(DynObject *obj) { +inline void destruct(DynObject *obj) { // Called from the region destructor. // Remove all references to other objects. // If in the same region, then just remove the RC, but don't try to collect @@ -361,7 +362,7 @@ void destruct(DynObject *obj) { } } -void dealloc(DynObject *obj) { +inline void dealloc(DynObject *obj) { // Called from the region destructor. // So remove from region if in one. // This ensures we don't try to remove it from the set that is being iterated. diff --git a/src/rt/objects/region.h b/src/rt/objects/region.h index b8d53fb..a588e82 100644 --- a/src/rt/objects/region.h +++ b/src/rt/objects/region.h @@ -3,7 +3,7 @@ #include #include -#include "../output.h" +#include "../ui.h" #include "../../utils/tagged_pointer.h" namespace objects { @@ -125,13 +125,13 @@ struct Region { // Check if already parented to another region. if (r->parent != nullptr) - error("Region already has a parent: Creating region DAG not supported!"); + rt::ui::error("Region already has a parent: Creating region DAG not supported!"); // Prevent creating a cycle auto ancestors = p->parent; while (ancestors != nullptr) { if (ancestors == r) - error("Cycle created in region hierarchy"); + rt::ui::error("Cycle created in region hierarchy"); ancestors = ancestors->parent; } diff --git a/src/rt/objects/visit.h b/src/rt/objects/visit.h new file mode 100644 index 0000000..346f51e --- /dev/null +++ b/src/rt/objects/visit.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace objects { +class DynObject; + +struct Edge { + DynObject *src; + std::string key; + DynObject *target; +}; +} diff --git a/src/rt/output.h b/src/rt/output.h deleted file mode 100644 index ee861a3..0000000 --- a/src/rt/output.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -namespace objects { - [[noreturn]] inline void error(const std::string &msg) { - std::cerr << "Error: " << msg << std::endl; - std::exit(1); - } -} \ No newline at end of file diff --git a/src/rt/rt.cc b/src/rt/rt.cc index c3cec9e..1554112 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -2,7 +2,6 @@ #include #include -#include "mermaid.h" #include "objects/dyn_object.h" #include "rt.h" #include "env.h" @@ -39,7 +38,7 @@ DynObject *get(DynObject *obj, std::string key) { std::string get_key(DynObject* key) { // TODO Add some checking. This is need to lookup the correct function in the prototype chain. if (key->get_prototype() != &rt::env::stringPrototypeObject) { - error("Key must be a string."); + rt::ui::error("Key must be a string."); } rt::env::StringObject *str_key = reinterpret_cast(key); return str_key->as_key(); @@ -60,10 +59,10 @@ DynObject *set(DynObject *obj, DynObject *key, DynObject *value) { // TODO [[nodiscard]] DynObject *set_prototype(DynObject *obj, DynObject *proto) { if (proto->is_primitive() != nullptr) { - error("Cannot set a primitive as a prototype."); + rt::ui::error("Cannot set a primitive as a prototype."); } if (obj->is_primitive() != nullptr) { - error("Cannot set a prototype on a primitive object."); + rt::ui::error("Cannot set a prototype on a primitive object."); } return obj->set_prototype(proto); } @@ -85,7 +84,7 @@ size_t pre_run() { return objects::DynObject::get_count(); } -void post_run(size_t initial_count, UI& ui) { +void post_run(size_t initial_count, rt::ui::UI& ui) { std::cout << "Test complete - checking for cycles in local region..." << std::endl; if (objects::DynObject::get_count() != initial_count) { @@ -120,7 +119,7 @@ namespace value { DynObject *iter_next(DynObject *iter) { assert(!iter->is_immutable()); if (iter->get_prototype() != &rt::env::keyIterPrototypeObject) { - error("Object is not an iterator."); + rt::ui::error("Object is not an iterator."); } return reinterpret_cast(iter)->iter_next(); @@ -130,7 +129,7 @@ namespace value { if (func->get_prototype() == &rt::env::bytecodeFuncPrototypeObject) { return reinterpret_cast(func)->get_bytecode(); } else { - error("Object is not a function."); + rt::ui::error("Object is not a function."); return {}; } } diff --git a/src/rt/rt.h b/src/rt/rt.h index a84741d..cb3c07d 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -2,19 +2,12 @@ #include #include -#include -#include #include "../lang/interpreter.h" +#include "objects/visit.h" +#include "ui.h" namespace objects { -class DynObject; - -struct Edge { - DynObject *src; - std::string key; - DynObject *target; -}; DynObject *make_func(verona::interpreter::Bytecode *body); DynObject *make_iter(DynObject *iter_src); @@ -36,17 +29,8 @@ void add_reference(DynObject *src, DynObject *target); void remove_reference(DynObject *src, DynObject *target); void move_reference(DynObject *src, DynObject *dst, DynObject *target); -size_t get_object_count(); - -struct UI -{ - virtual void output(std::vector &, std::string ) {} -}; - size_t pre_run(); -void post_run(size_t count, UI& ui); - -void mermaid(std::vector &roots, std::ostream &out); +void post_run(size_t count, rt::ui::UI& ui); namespace value { DynObject *iter_next(DynObject *iter); diff --git a/src/rt/ui.h b/src/rt/ui.h new file mode 100644 index 0000000..12ccfeb --- /dev/null +++ b/src/rt/ui.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +#include "objects/visit.h" + +namespace rt::ui { +class UI +{ +public: + virtual void output(std::vector &, std::string ) {} +}; + +void mermaid(std::vector &roots, std::ostream &out); + +[[noreturn]] inline void error(const std::string &msg) { +std::cerr << "Error: " << msg << std::endl; +std::exit(1); +} +} // namespace rt::ui diff --git a/src/rt/mermaid.h b/src/rt/ui/mermaid.cc similarity index 74% rename from src/rt/mermaid.h rename to src/rt/ui/mermaid.cc index 6898647..58f2d88 100644 --- a/src/rt/mermaid.h +++ b/src/rt/ui/mermaid.cc @@ -1,24 +1,23 @@ -#pragma once - #include #include #include #include -#include "objects/dyn_object.h" +#include "../ui.h" +#include "../objects/dyn_object.h" -namespace objects { +namespace rt::ui { -void mermaid(std::vector &roots, std::ostream &out) { +void mermaid(std::vector &roots, std::ostream &out) { // Give a nice id to each object. - std::map visited; + std::map visited; // Keep track of all the objects in a region. - std::map> region_strings; + std::map> region_strings; // Keep track of the immutable objects. std::vector immutable_objects; // // Add frame as local region - // visited[DynObject::frame()] = 0; - // region_strings[DynObject::get_local_region()] = {0}; + // visited[objects::DynObject::frame()] = 0; + // region_strings[objects::DynObject::get_local_region()] = {0}; // Add nullptr as immutable visited[nullptr] = 0; immutable_objects.push_back(0); @@ -30,10 +29,10 @@ void mermaid(std::vector &roots, std::ostream &out) { bool unreachable = false; - auto explore = [&](Edge e) { - DynObject *dst = e.target; + auto explore = [&](objects::Edge e) { + objects::DynObject *dst = e.target; std::string key = e.key; - DynObject *src = e.src; + objects::DynObject *src = e.src; if (src != nullptr) { out << " id" << visited[src] << " -->|" << key << "| "; } @@ -49,7 +48,7 @@ void mermaid(std::vector &roots, std::ostream &out) { out << " ]" << (unreachable ? ":::unreachable" : "") << std::endl; - auto region = DynObject::get_region(dst); + auto region = objects::DynObject::get_region(dst); if (region != nullptr) { region_strings[region].push_back(curr_id); } @@ -61,13 +60,13 @@ void mermaid(std::vector &roots, std::ostream &out) { }; // Output all reachable edges for (auto &root : roots) { - visit({root.src, root.key, root.target}, explore); + objects::visit({root.src, root.key, root.target}, explore); } // Output the unreachable parts of the graph unreachable = true; - for (auto &root : DynObject::all_objects) { - visit({nullptr, "", root}, explore); + for (auto &root : objects::DynObject::all_objects) { + objects::visit({nullptr, "", root}, explore); } // Output any region parent edges. @@ -82,7 +81,7 @@ void mermaid(std::vector &roots, std::ostream &out) { for (auto [region, objects] : region_strings) { out << "subgraph "; - if (region == DynObject::get_local_region()) { + if (region == objects::DynObject::get_local_region()) { out << "local region" << std::endl; } else { out << std::endl; @@ -106,10 +105,10 @@ void mermaid(std::vector &roots, std::ostream &out) { out << "end" << std::endl; // Output object count as very useful. - out << "subgraph Count " << DynObject::get_count() << std::endl; + out << "subgraph Count " << objects::DynObject::get_count() << std::endl; out << "end" << std::endl; out << "classDef unreachable stroke:red,stroke-width:2px" << std::endl; // Footer (end of mermaid graph) out << "```" << std::endl; } -} // namespace objects \ No newline at end of file +} // namespace rt::ui \ No newline at end of file From 7ea2ac7eb96c705da72b564c2cfd3dfc8562c348 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 13:44:28 +0200 Subject: [PATCH 04/10] Refactoring: Delete unused `./src/api.h` --- src/api.h | 169 ------------------------------------------------------ 1 file changed, 169 deletions(-) delete mode 100644 src/api.h diff --git a/src/api.h b/src/api.h deleted file mode 100644 index cea5fa9..0000000 --- a/src/api.h +++ /dev/null @@ -1,169 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "rt/rt.h" - -namespace api { -using namespace objects; - -class Reference; - -class Object { - friend class Reference; - friend void - mermaid(std::initializer_list> roots); - - DynObject *value; - - Object(DynObject *object) : value(object) {} - - void copy(DynObject *new_object) { - add_reference(get_frame(), new_object); - auto old_object = value; - value = new_object; - remove_reference(get_frame(), old_object); - } - - void move(DynObject *new_value) { - auto old_value = value; - value = new_value; - remove_reference(get_frame(), old_value); - } - -public: - Object() : value(nullptr) {} - - Object(Object &other) : value(other.value) { - add_reference(get_frame(), value); - } - - Object(Object &&other) : value(other.value) { other.value = nullptr; } - - Object &operator=(Object &other) { - copy(other.value); - return *this; - } - - Object &operator=(Object &&other) { - move(other.value); - return *this; - } - - Object &operator=(std::nullptr_t) { - move(nullptr); - return *this; - } - - Object &operator=(Reference &other); - Object &operator=(Reference &&other); - - static Object create(std::string name) { return make_object(name); } - - Reference operator[](std::string name); - - ~Object() { - remove_reference(get_frame(), value); - } - - void freeze() { objects::freeze(value); } - - void create_region() { objects::create_region(value); } -}; - -class Reference { - friend class Object; - std::string key; - DynObject *src; - - void copy(DynObject *new_object) { - add_reference(src, new_object); - auto old = objects::set(src, key, new_object); - remove_reference(src, old); - } - - DynObject *get() { return objects::get(src, key); } - - Reference(std::string name, DynObject *object) : key(name), src(object) {} - -public: - Reference &operator=(Object &other) { - copy(other.value); - return *this; - } - - Reference &operator=(Object &&other) { - auto old_value = objects::set(src, key, other.value); - move_reference(get_frame(), src, other.value); - remove_reference(src, old_value); - // move semantics. - other.value = nullptr; - return *this; - } - - Reference &operator=(Reference &other) { - copy(other.get()); - return *this; - } - - Reference &operator=(Reference &&other) { - copy(other.get()); - return *this; - } - - Reference &operator=(std::nullptr_t) { - auto old_value = objects::set(src, key, nullptr); - remove_reference(src, old_value); - return *this; - } - - Reference operator[](std::string name) { return {name, objects::get(src, key)}; } -}; - -Reference Object::operator[](std::string name) { - return Reference(name, value); -} - -Object &Object::operator=(Reference &other) { - copy(other.get()); - return *this; -} - -Object &Object::operator=(Reference &&other) { - copy(other.get()); - return *this; -} - -struct UI : objects::UI -{ - void output(std::vector &edges, std::string message) { - std::ofstream out("mermaid.md"); - objects::mermaid(edges, out); - std::cout << message << std::endl; - std::cout << "Press a key!" << std::endl; - getchar(); - } -}; - -void mermaid(std::initializer_list> roots) { - UI ui; - std::vector edges; - for (auto &root : roots) { - edges.push_back( - {get_frame(), root.first, root.second.value}); - } - - ui.output(edges, ""); -} - -template void run(F &&f) { - UI ui; - size_t initial_count = objects::pre_run(); - f(); - objects::post_run(initial_count, ui); -}; -} // namespace api \ No newline at end of file From 35e3a4462883b7051f1d497507f7af1b1aa47c37 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 14:18:18 +0200 Subject: [PATCH 05/10] Refactoring: Move the runtime into the `rt` namespace --- src/lang/interpreter.cc | 102 ++++++++++++++++++------------------ src/rt/env.h | 4 +- src/rt/objects/dyn_object.h | 21 +++----- src/rt/objects/region.h | 8 +-- src/rt/objects/visit.h | 11 +++- src/rt/rt.cc | 94 ++++++++++++++++----------------- src/rt/rt.h | 40 +++++++------- 7 files changed, 138 insertions(+), 142 deletions(-) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index 3422340..fb9eaba 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -32,7 +32,7 @@ struct ExecFunc { size_t arg_ctn; }; struct ExecReturn { - std::optional value; + std::optional value; }; // ============================================== @@ -41,11 +41,11 @@ struct ExecReturn { struct InterpreterFrame { trieste::NodeIt ip; trieste::Node body; - objects::DynObject *frame; - std::vector stack; + rt::objects::DynObject *frame; + std::vector stack; ~InterpreterFrame() { - objects::remove_reference(frame, frame); + rt::remove_reference(frame, frame); } }; @@ -54,12 +54,12 @@ class Interpreter { std::vector frame_stack; InterpreterFrame *push_stack_frame(trieste::Node body) { - objects::DynObject * parent_obj = nullptr; + rt::objects::DynObject * parent_obj = nullptr; if (!frame_stack.empty()) { parent_obj = frame_stack.back()->frame; } - auto frame = new InterpreterFrame { body->begin(), body, objects::make_frame(parent_obj), {} }; + auto frame = new InterpreterFrame { body->begin(), body, rt::make_frame(parent_obj), {} }; frame_stack.push_back(frame); return frame; } @@ -78,14 +78,14 @@ class Interpreter { return frame_stack[frame_stack.size() - 2]; } - std::vector& stack() { + std::vector& stack() { return frame_stack.back()->stack; } - objects::DynObject *frame() { + rt::objects::DynObject *frame() { return frame_stack.back()->frame; } - objects::DynObject* pop(char const* data_info) { + rt::objects::DynObject* pop(char const* data_info) { auto v = stack().back(); stack().pop_back(); std::cout << "pop " << v << " (" << data_info << ")" << std::endl; @@ -101,7 +101,7 @@ class Interpreter { std::cout << node->location().view() << std::endl << std::endl; // Mermaid output - std::vector edges{{nullptr, "?", frame()}}; + std::vector edges{{nullptr, "?", frame()}}; ui->output(edges, std::string(node->location().view())); // Continue @@ -117,25 +117,25 @@ class Interpreter { std::cout << "Op: " << node->type().str() << std::endl; if (node == CreateObject) { - objects::DynObject *obj = nullptr; - + rt::objects::DynObject *obj = nullptr; + assert(!node->empty() && "CreateObject has to specify the type of data"); auto payload = node->at(0); if (payload == Dictionary) { - obj = objects::make_object(); + obj = rt::make_object(); } else if (payload == String) { - obj = objects::make_str(std::string(payload->location().view())); + obj = rt::make_str(std::string(payload->location().view())); } else if (payload == KeyIter) { auto v = pop("iterator source"); - obj = objects::make_iter(v); - remove_reference(frame(), v); + obj = rt::make_iter(v); + rt::remove_reference(frame(), v); } else if (payload == Proto) { - obj = objects::make_object(); + obj = rt::make_object(); // RC transferred - objects::set_prototype(obj, pop("prototype source")); + rt::set_prototype(obj, pop("prototype source")); } else if (payload == Func) { assert(payload->size() == 1 && "CreateObject: A bytecode function requires a body node"); - obj = objects::make_func(new Bytecode { payload->at(0) }); + obj = rt::make_func(new Bytecode { payload->at(0) }); } else { assert(false && "CreateObject has to specify a value"); } @@ -155,8 +155,8 @@ class Interpreter { if (node == LoadFrame) { std::string field{node->location().view()}; - auto v = objects::get(frame(), field); - objects::add_reference(frame(), v); + auto v = rt::get(frame(), field); + rt::add_reference(frame(), v); stack().push_back(v); std::cout << "push " << v << std::endl; return ExecNext {}; @@ -166,8 +166,8 @@ class Interpreter { { auto v = pop("value to store"); std::string field{node->location().view()}; - auto v2 = objects::set(frame(), field, v); - remove_reference(frame(), v2); + auto v2 = rt::set(frame(), field, v); + rt::remove_reference(frame(), v2); return ExecNext {}; } @@ -183,12 +183,12 @@ class Interpreter { std::abort(); } - auto v2 = objects::get(v, k); + auto v2 = rt::get(v, k); stack().push_back(v2); std::cout << "push " << v2 << std::endl; - objects::add_reference(frame(), v2); - objects::remove_reference(frame(), k); - objects::remove_reference(frame(), v); + rt::add_reference(frame(), v2); + rt::remove_reference(frame(), k); + rt::remove_reference(frame(), v); return ExecNext {}; } @@ -197,27 +197,27 @@ class Interpreter { auto v = pop("value to store"); auto k = pop("lookup-key"); auto v2 = pop("lookup-value"); - auto v3 = objects::set(v2, k, v); - move_reference(frame(), v2, v); - remove_reference(frame(), k); - remove_reference(frame(), v2); - remove_reference(v2, v3); + auto v3 = rt::set(v2, k, v); + rt::move_reference(frame(), v2, v); + rt::remove_reference(frame(), k); + rt::remove_reference(frame(), v2); + rt::remove_reference(v2, v3); return ExecNext {}; } if (node == CreateRegion) { auto v = pop("region source"); - objects::create_region(v); - remove_reference(frame(), v); + rt::create_region(v); + rt::remove_reference(frame(), v); return ExecNext {}; } if (node == FreezeObject) { auto v = pop("object to freeze"); - objects::freeze(v); - remove_reference(frame(), v); + rt::freeze(v); + rt::remove_reference(frame(), v); return ExecNext {}; } @@ -237,13 +237,13 @@ class Interpreter { } else { result = "False"; } - auto v = objects::get(frame(), result); - objects::add_reference(frame(), v); + auto v = rt::get(frame(), result); + rt::add_reference(frame(), v); stack().push_back(v); std::cout << "push " << v << " (" << result << ")"<< std::endl; - remove_reference(frame(), a); - remove_reference(frame(), b); + rt::remove_reference(frame(), a); + rt::remove_reference(frame(), b); return ExecNext {}; } @@ -255,9 +255,9 @@ class Interpreter { if (node == JumpFalse) { auto v = pop("jump condition"); - auto false_obj = objects::get(frame(), "False"); + auto false_obj = rt::get(frame(), "False"); auto jump = (v == false_obj); - remove_reference(frame(), v); + rt::remove_reference(frame(), v); if (jump) { return ExecJump { node->location() }; } else { @@ -269,8 +269,8 @@ class Interpreter { { auto it = pop("iterator"); - auto obj = objects::value::iter_next(it); - remove_reference(frame(), it); + auto obj = rt::iter_next(it); + rt::remove_reference(frame(), it); stack().push_back(obj); std::cout << "push " << obj << " (next from iter)" << std::endl; @@ -280,7 +280,7 @@ class Interpreter { if (node == ClearStack) { if (!stack().empty()) { while (!stack().empty()) { - remove_reference(frame(), stack().back()); + rt::remove_reference(frame(), stack().back()); stack().pop_back(); } } @@ -290,8 +290,8 @@ class Interpreter { if (node == Call) { auto func = pop("function"); auto arg_ctn = std::stoul(std::string(node->location().view())); - auto action = ExecFunc { objects::value::get_bytecode(func)->body , arg_ctn }; - remove_reference(frame(), func); + auto action = ExecFunc { rt::get_bytecode(func)->body , arg_ctn }; + rt::remove_reference(frame(), func); return action; } @@ -354,7 +354,7 @@ class Interpreter { if (return_.value.has_value()) { auto parent = parent_stack_frame(); auto value = return_.value.value(); - objects::move_reference(frame->frame, parent->frame, value); + rt::move_reference(frame->frame, parent->frame, value); parent->stack.push_back(value); } } @@ -377,7 +377,7 @@ class UI : public rt::ui::UI out.open(path); } - void output(std::vector &edges, std::string message) { + void output(std::vector &edges, std::string message) { out << "```" << std::endl; out << message << std::endl; out << "```" << std::endl; @@ -392,13 +392,13 @@ class UI : public rt::ui::UI }; void start(trieste::Node main_body, bool interactive) { - size_t initial = objects::pre_run(); + size_t initial = rt::pre_run(); UI ui(interactive); Interpreter inter(&ui); inter.run(main_body); - objects::post_run(initial, ui); + rt::post_run(initial, ui); } } // namespace verona::interpreter \ No newline at end of file diff --git a/src/rt/env.h b/src/rt/env.h index c9c2abe..8f6d55c 100644 --- a/src/rt/env.h +++ b/src/rt/env.h @@ -13,7 +13,7 @@ class FrameObject : public objects::DynObject { FrameObject(objects::DynObject* parent_frame) : objects::DynObject(&framePrototypeObject) { if (parent_frame) { auto old_value = this->set(objects::ParentField, parent_frame); - objects::add_reference(this, parent_frame); + add_reference(this, parent_frame); assert(!old_value); } } @@ -89,7 +89,7 @@ class KeyIterObject : public objects::DynObject { objects::DynObject* iter_next() { objects::DynObject *obj = nullptr; if (this->iter != this->iter_end) { - obj = objects::make_str(this->iter->first); + obj = make_str(this->iter->first); this->iter++; } diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index c81d8a4..75196fc 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -13,27 +13,18 @@ #include "visit.h" #include "region.h" -#include "../../utils/nop.h" #include "../rt.h" #include "../../lang/interpreter.h" -namespace objects { +namespace rt::objects { constexpr uintptr_t ImmutableTag{1}; const std::string PrototypeField{" proto "}; const std::string ParentField{" parent "}; -using NopDO = utils::Nop; - -template -inline void visit(Edge e, Pre pre, Post post = {}); - -template -inline void visit(DynObject* start, Pre pre, Post post = {}); - // Representation of objects class DynObject { friend class Reference; - friend DynObject* make_iter(DynObject *obj); + friend objects::DynObject* rt::make_iter(objects::DynObject *obj); friend void rt::ui::mermaid(std::vector &roots, std::ostream &out); friend void destruct(DynObject *obj); friend void dealloc(DynObject *obj); @@ -184,7 +175,7 @@ class DynObject { // that we don't track for leaks, otherwise, we need to check if the // RC is zero. if (change_rc(0) != 0 && matched != 0) { - rt::ui::error("Object still has references"); + ui::error("Object still has references"); } auto r = get_region(this); @@ -247,7 +238,7 @@ class DynObject { [[nodiscard]] DynObject *set(std::string name, DynObject *value) { if (is_immutable()) { - rt::ui::error("Cannot mutate immutable object"); + ui::error("Cannot mutate immutable object"); } DynObject *old = fields[name]; fields[name] = value; @@ -257,7 +248,7 @@ class DynObject { // The caller must provide an rc for value. [[nodiscard]] DynObject* set_prototype(DynObject* value) { if (is_immutable()) { - rt::ui::error("Cannot mutate immutable object"); + ui::error("Cannot mutate immutable object"); } DynObject* old = prototype; prototype = value; @@ -417,4 +408,4 @@ inline void visit(DynObject* start, Pre pre, Post post) visit(Edge{nullptr, "", start}, pre, post); } -} // namespace objects +} // namespace rtobjects diff --git a/src/rt/objects/region.h b/src/rt/objects/region.h index a588e82..5fa3e45 100644 --- a/src/rt/objects/region.h +++ b/src/rt/objects/region.h @@ -6,7 +6,7 @@ #include "../ui.h" #include "../../utils/tagged_pointer.h" -namespace objects { +namespace rt::objects { class DynObject; void destruct(DynObject *obj); @@ -125,13 +125,13 @@ struct Region { // Check if already parented to another region. if (r->parent != nullptr) - rt::ui::error("Region already has a parent: Creating region DAG not supported!"); + ui::error("Region already has a parent: Creating region DAG not supported!"); // Prevent creating a cycle auto ancestors = p->parent; while (ancestors != nullptr) { if (ancestors == r) - rt::ui::error("Cycle created in region hierarchy"); + ui::error("Cycle created in region hierarchy"); ancestors = ancestors->parent; } @@ -191,4 +191,4 @@ struct Region { // encode special regions. using RegionPointer = utils::TaggedPointer; -} // namespace objects \ No newline at end of file +} // namespace rt::objects \ No newline at end of file diff --git a/src/rt/objects/visit.h b/src/rt/objects/visit.h index 346f51e..a04de97 100644 --- a/src/rt/objects/visit.h +++ b/src/rt/objects/visit.h @@ -1,8 +1,9 @@ #pragma once #include +#include "../../utils/nop.h" -namespace objects { +namespace rt::objects { class DynObject; struct Edge { @@ -10,4 +11,12 @@ struct Edge { std::string key; DynObject *target; }; + +using NopDO = utils::Nop; + +template +inline void visit(Edge e, Pre pre, Post post = {}); + +template +inline void visit(DynObject* start, Pre pre, Post post = {}); } diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 1554112..cca957e 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -6,77 +6,77 @@ #include "rt.h" #include "env.h" -namespace objects { +namespace rt { -DynObject *make_func(verona::interpreter::Bytecode *body) { - return new rt::env::BytecodeFuncObject(body); +objects::DynObject *make_func(verona::interpreter::Bytecode *body) { + return new env::BytecodeFuncObject(body); } -DynObject *make_iter(DynObject *iter_src) { - return new rt::env::KeyIterObject(iter_src->fields); +objects::DynObject *make_iter(objects::DynObject *iter_src) { + return new env::KeyIterObject(iter_src->fields); } -DynObject *make_str(std::string value) { - return new rt::env::StringObject(value); +objects::DynObject *make_str(std::string value) { + return new env::StringObject(value); } -DynObject *make_object() { - return new DynObject(); +objects::DynObject *make_object() { + return new objects::DynObject(); } -DynObject *make_frame(DynObject *parent) { - return new rt::env::FrameObject(parent); +objects::DynObject *make_frame(objects::DynObject *parent) { + return new env::FrameObject(parent); } -thread_local RegionPointer DynObject::local_region = new Region(); +thread_local objects::RegionPointer objects::DynObject::local_region = new Region(); -void freeze(DynObject *obj) { obj->freeze(); } +void freeze(objects::DynObject *obj) { obj->freeze(); } -void create_region(DynObject *object) { object->create_region(); } +void create_region(objects::DynObject *object) { object->create_region(); } -DynObject *get(DynObject *obj, std::string key) { +objects::DynObject *get(objects::DynObject *obj, std::string key) { return obj->get(key); } -std::string get_key(DynObject* key) { +std::string get_key(objects::DynObject* key) { // TODO Add some checking. This is need to lookup the correct function in the prototype chain. - if (key->get_prototype() != &rt::env::stringPrototypeObject) { - rt::ui::error("Key must be a string."); + if (key->get_prototype() != &env::stringPrototypeObject) { + ui::error("Key must be a string."); } - rt::env::StringObject *str_key = reinterpret_cast(key); + env::StringObject *str_key = reinterpret_cast(key); return str_key->as_key(); } -DynObject *get(DynObject *obj, DynObject *key) { +objects::DynObject *get(objects::DynObject *obj, objects::DynObject *key) { return get(obj, get_key(key)); } -DynObject *set(DynObject *obj, std::string key, DynObject *value) { +objects::DynObject *set(objects::DynObject *obj, std::string key, objects::DynObject *value) { return obj->set(key, value); } -DynObject *set(DynObject *obj, DynObject *key, DynObject *value) { +objects::DynObject *set(objects::DynObject *obj, objects::DynObject *key, objects::DynObject *value) { return set(obj, get_key(key), value); } // TODO [[nodiscard]] -DynObject *set_prototype(DynObject *obj, DynObject *proto) { +objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *proto) { if (proto->is_primitive() != nullptr) { - rt::ui::error("Cannot set a primitive as a prototype."); + ui::error("Cannot set a primitive as a prototype."); } if (obj->is_primitive() != nullptr) { - rt::ui::error("Cannot set a prototype on a primitive object."); + ui::error("Cannot set a prototype on a primitive object."); } return obj->set_prototype(proto); } -void add_reference(DynObject *src, DynObject *target) { - DynObject::add_reference(src, target); +void add_reference(objects::DynObject *src, objects::DynObject *target) { + objects::DynObject::add_reference(src, target); } -void remove_reference(DynObject *src, DynObject *target) { - DynObject::remove_reference(src, target); +void remove_reference(objects::DynObject *src, objects::DynObject *target) { + objects::DynObject::remove_reference(src, target); } -void move_reference(DynObject *src, DynObject *dst, DynObject *target) { - DynObject::move_reference(src, dst, target); +void move_reference(objects::DynObject *src, objects::DynObject *dst, objects::DynObject *target) { + objects::DynObject::move_reference(src, dst, target); } size_t pre_run() { @@ -84,7 +84,7 @@ size_t pre_run() { return objects::DynObject::get_count(); } -void post_run(size_t initial_count, rt::ui::UI& ui) { +void post_run(size_t initial_count, ui::UI& ui) { std::cout << "Test complete - checking for cycles in local region..." << std::endl; if (objects::DynObject::get_count() != initial_count) { @@ -115,24 +115,22 @@ void post_run(size_t initial_count, rt::ui::UI& ui) { } } -namespace value { - DynObject *iter_next(DynObject *iter) { - assert(!iter->is_immutable()); - if (iter->get_prototype() != &rt::env::keyIterPrototypeObject) { - rt::ui::error("Object is not an iterator."); - } - - return reinterpret_cast(iter)->iter_next(); +objects::DynObject *iter_next(objects::DynObject *iter) { + assert(!iter->is_immutable()); + if (iter->get_prototype() != &env::keyIterPrototypeObject) { + ui::error("Object is not an iterator."); } - verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func) { - if (func->get_prototype() == &rt::env::bytecodeFuncPrototypeObject) { - return reinterpret_cast(func)->get_bytecode(); - } else { - rt::ui::error("Object is not a function."); - return {}; - } + return reinterpret_cast(iter)->iter_next(); +} + +verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func) { + if (func->get_prototype() == &env::bytecodeFuncPrototypeObject) { + return reinterpret_cast(func)->get_bytecode(); + } else { + ui::error("Object is not a function."); + return {}; } } -} // namespace objects +} // namespace rt diff --git a/src/rt/rt.h b/src/rt/rt.h index cb3c07d..411f70d 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -7,34 +7,32 @@ #include "objects/visit.h" #include "ui.h" -namespace objects { +namespace rt { -DynObject *make_func(verona::interpreter::Bytecode *body); -DynObject *make_iter(DynObject *iter_src); -DynObject *make_str(std::string str_value); -DynObject *make_object(); -DynObject *make_frame(DynObject *parent); +objects::DynObject *make_func(verona::interpreter::Bytecode *body); +objects::DynObject *make_iter(objects::DynObject *iter_src); +objects::DynObject *make_str(std::string str_value); +objects::DynObject *make_object(); +objects::DynObject *make_frame(objects::DynObject *parent); -void freeze(DynObject *obj); -void create_region(DynObject *objects); +void freeze(objects::DynObject *obj); +void create_region(objects::DynObject *objects); -DynObject *get(DynObject *src, std::string key); -DynObject *get(DynObject *src, DynObject *key); -DynObject *set(DynObject *dst, std::string key, DynObject *value); -DynObject *set(DynObject *dst, DynObject *key, DynObject *value); +objects::DynObject *get(objects::DynObject *src, std::string key); +objects::DynObject *get(objects::DynObject *src, objects::DynObject *key); +objects::DynObject *set(objects::DynObject *dst, std::string key, objects::DynObject *value); +objects::DynObject *set(objects::DynObject *dst, objects::DynObject *key, objects::DynObject *value); -DynObject *set_prototype(DynObject *obj, DynObject *proto); +objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *proto); -void add_reference(DynObject *src, DynObject *target); -void remove_reference(DynObject *src, DynObject *target); -void move_reference(DynObject *src, DynObject *dst, DynObject *target); +void add_reference(objects::DynObject *src, objects::DynObject *target); +void remove_reference(objects::DynObject *src, objects::DynObject *target); +void move_reference(objects::DynObject *src, objects::DynObject *dst, objects::DynObject *target); size_t pre_run(); void post_run(size_t count, rt::ui::UI& ui); -namespace value { - DynObject *iter_next(DynObject *iter); - verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func); -} +objects::DynObject *iter_next(objects::DynObject *iter); +verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func); -} // namespace objects +} // namespace rt From 8cb33eac67070164b06b07b7f6fd3202da01f2cd Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 15:08:40 +0200 Subject: [PATCH 06/10] Refactoring: Split `lang.cc` into pass files --- CMakeLists.txt | 11 +- src/lang/interpreter.h | 18 - src/lang/lang.cc | 735 +--------------------------------- src/lang/lang.h | 97 +++++ src/lang/passes/bytecode.cc | 137 +++++++ src/lang/passes/call_stmts.cc | 28 ++ src/lang/passes/flatten.cc | 171 ++++++++ src/lang/passes/grouping.cc | 133 ++++++ src/lang/passes/parse.cc | 183 +++++++++ 9 files changed, 763 insertions(+), 750 deletions(-) create mode 100644 src/lang/lang.h create mode 100644 src/lang/passes/bytecode.cc create mode 100644 src/lang/passes/call_stmts.cc create mode 100644 src/lang/passes/flatten.cc create mode 100644 src/lang/passes/grouping.cc create mode 100644 src/lang/passes/parse.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 20841f9..3910a28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,16 @@ set(CMAKE_CXX_STANDARD 20) add_library(rt OBJECT src/rt/rt.cc src/rt/ui/mermaid.cc) -add_library(lang OBJECT src/lang/lang.cc src/lang/interpreter.cc) +add_library( + lang OBJECT + src/lang/lang.cc + src/lang/interpreter.cc + src/lang/passes/parse.cc + src/lang/passes/grouping.cc + src/lang/passes/call_stmts.cc + src/lang/passes/flatten.cc + src/lang/passes/bytecode.cc +) target_link_libraries(lang PRIVATE trieste::trieste) add_executable(verona_dyn src/main.cc) diff --git a/src/lang/interpreter.h b/src/lang/interpreter.h index a714c7d..b12e164 100644 --- a/src/lang/interpreter.h +++ b/src/lang/interpreter.h @@ -1,25 +1,7 @@ #pragma once -#include -#include - -namespace objects { - struct UI; - class DynObject; -} - namespace verona::interpreter { struct Bytecode; void delete_bytecode(Bytecode* bytecode); } - -namespace verona::interpreter { -/// @brief This executes the the given function body with the given stack. -/// The frame should be pushed and poped by the function callee. It's recommendable -/// to have a print at the start and end of the function body. -/// -/// The stack holds the arguments in reverse order of their definition. They have to -/// be popped of in order. -std::optional run_body(Bytecode *body, std::vector &stack, objects::UI* ui); -} // namespace verona::interpreter diff --git a/src/lang/lang.cc b/src/lang/lang.cc index b092a4a..0e86fe4 100644 --- a/src/lang/lang.cc +++ b/src/lang/lang.cc @@ -1,739 +1,12 @@ -#include "bytecode.h" +#include + #include "trieste/driver.h" -#include "trieste/trieste.h" #include "interpreter.h" -#include -#define TAB_SIZE 4 +#include "lang.h" using namespace trieste; -inline const TokenDef Ident{"ident", trieste::flag::print}; -inline const TokenDef Assign{"assign"}; -inline const TokenDef Create{"create"}; -inline const TokenDef For{"for"}; -inline const TokenDef If{"if"}; -inline const TokenDef Else{"else"}; -inline const TokenDef Block{"block"}; -inline const TokenDef Empty{"empty"}; -inline const TokenDef Drop{"drop"}; -inline const TokenDef Freeze{"freeze"}; -inline const TokenDef Region{"region"}; -inline const TokenDef Lookup{"lookup"}; -inline const TokenDef Parens{"parens"}; - -inline const TokenDef Op{"op"}; -inline const TokenDef Rhs{"rhs"}; -inline const TokenDef Lhs{"lhs"}; -inline const TokenDef Key{"key"}; -inline const TokenDef Value{"value"}; - -namespace verona::wf { -using namespace trieste::wf; - -inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze | Drop | Null | String | Create | Parens; -inline const auto parse_groups = Group | Assign | If | Else | Block | For | Func | List | Return; - -inline const auto parser = - (Top <<= File) - | (File <<= parse_groups++) - | (Assign <<= Group++) - | (If <<= Group * Eq * Group) - | (Else <<= Group * Group) - | (Group <<= (parse_tokens | Block | List)++) - | (Block <<= (parse_tokens | parse_groups)++) - | (Eq <<= Group * Group) - | (Lookup <<= Group) - | (For <<= Group * List * Group * Group) - | (List <<= Group++) - | (Parens <<= (Group | List)++) - | (Func <<= Group * Group * Group) - | (Return <<= Group++) - ; - -inline const auto lv = Ident | Lookup; -inline const auto rv = lv | Empty | Null | String | Create | Call; -inline const auto cmp_values = Ident | Lookup | Null; -inline const auto key = Ident | Lookup | String; - -inline const auto grouping = - (Top <<= File) - | (File <<= Body) - | (Body <<= Block) - | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call)++) - | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) - | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) - | (Region <<= Ident) - | (Freeze <<= Ident) - | (Create <<= Ident) - | (If <<= Eq * Block * Block) - | (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) - | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Func <<= Ident * Params * Body) - | (Call <<= (Op >>= key) * List) - | (ReturnValue <<= rv) - | (List <<= rv++) - | (Params <<= Ident++) - ; -inline const auto stmt_prints = - grouping - | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call | ClearStack | Print)++); -} // namespace verona::wf - -struct Indent { - size_t indent; - Token toc; -}; - -trieste::Parse parser() { - Parse p{depth::file, verona::wf::parser}; - - auto indent = std::make_shared>(); - indent->push_back({0, File}); - - auto update_indent = [indent](detail::Make& m, size_t this_indent) { - m.term({Assign, Return}); - - if (this_indent > indent->back().indent) { - std::cout << "this_indent " << this_indent << std::endl; - std::cout << "indent->back().indent " << indent->back().indent << std::endl; - m.error("unexpected indention"); - } - - while (this_indent < indent->back().indent) { - m.term({Block, Group, indent->back().toc}); - indent->pop_back(); - } - - if (this_indent != indent->back().indent) { - m.error("unexpected indention"); - } - }; - - p("start", - { - // Empty lines should be ignored - "[ \\t]*\\r?\\n" >> [](auto &) {}, - - // Line comment - "(?:#[^\\n]*)" >> [](auto &) {}, - - // Indention - " +" >> [update_indent](auto &m) { - if (m.match().len % TAB_SIZE != 0) { - m.error("unexpected indention"); - } - auto this_indent = m.match().len / TAB_SIZE; - update_indent(m, this_indent); - m.mode("contents"); - }, - - "\\t*" >> [update_indent](auto &m) { - auto this_indent = m.match().len; - update_indent(m, this_indent); - m.mode("contents"); - }, - }); - - p( - "contents", - { - // Indentation - "\\r?\\n" >> [](auto &m) { - m.mode("start"); - }, - - "[[:blank:]]+" >> [](auto &) {}, - - // Line comment - "(?:#[^\\n\\r]*)" >> [](auto &) {}, - - "def" >> [](auto &m) { - m.seq(Func); - }, - "\\(" >> [](auto &m) { - m.push(Parens); - }, - "\\)" >> [](auto &m) { - m.term({List, Parens}); - m.extend(Parens); - }, - "return" >> [](auto &m) { - m.seq(Return); - }, - - "for" >> [](auto &m) { - m.seq(For); - }, - "in" >> [](auto &m) { - // In should always be in a list from the identifiers. - m.term({List}); - }, - "," >> [](auto &m) { - m.seq(List); - }, - - "if" >> [](auto &m) { - m.seq(If); - }, - "else" >> [](auto &m) { - m.seq(Else); - }, - ":" >> [indent](auto &m) { - // Exit conditionals expressions. - m.term({Eq}); - - Token toc = Empty; - if (m.in(If)) { - toc = If; - } else if (m.in(Else)) { - toc = Else; - } else if (m.in(For)) { - toc = For; - } else if (m.in(Func)) { - toc = Func; - } else { - m.error("unexpected colon"); - return; - } - assert(toc != Empty); - - auto current_indent = indent->back().indent; - auto next_indent = current_indent + 1; - indent->push_back({next_indent, toc}); - - if (m.in(Group)) { - m.pop(Group); - } - - m.push(Block); - }, - "drop" >> [](auto &m) { m.add(Drop); }, - "create" >> [](auto &m) { m.add(Create); }, - "freeze" >> [](auto &m) { m.add(Freeze); }, - "region" >> [](auto &m) { m.add(Region); }, - "None" >> [](auto &m) { m.add(Null); }, - "[0-9A-Za-z_]+" >> [](auto &m) { m.add(Ident); }, - "\\[" >> [](auto &m) { - m.push(Lookup); - }, - "\\]" >> [](auto &m) { - m.term({Lookup}); - }, - "\\.([0-9A-Za-z_]+)" >> [](auto &m) { - m.push(Lookup); - m.add(String, 1); - m.term({Lookup}); - }, - "\"([^\\n\"]+)\"" >> [](auto &m) { m.add(String, 1); }, - "==" >> [](auto &m) { m.seq(Eq); }, - "=" >> [](auto &m) { m.seq(Assign); }, - "{}" >> [](auto &m) { m.add(Empty); }, - }); - - p.done([update_indent](auto &m) { - update_indent(m, 0); - }); - - return p; -} - -auto LV = T(Ident, Lookup); -auto RV = T(Empty, Ident, Lookup, Null, String, Create, Call); -auto CMP_V = T(Ident, Lookup, Null); -auto KEY = T(Ident, Lookup, String); - -Node create_print(size_t line, std::string text) { - std::stringstream ss; - ss << "Line " << line << ": " << text; - return NodeDef::create(Print, ss.str()); -} -Node create_print(Node from, std::string text) { - auto [line, col] = from->location().linecol(); - return create_print(line + 1, text); -} -Node create_print(Node from) { - return create_print(from, std::string(from->location().view())); -} -Node create_from(Token def, Node from) { - return NodeDef::create(def, from->location()); -} -std::string expr_header(Node expr) { - auto expr_str = expr->location().view(); - return std::string(expr_str.substr(0, expr_str.find(":") + 1)); -} - -PassDef grouping() { - PassDef p{ - "grouping", - verona::wf::grouping, - dir::bottomup, - { - // Normalize so that all expressions are inside bodies and blocks. - T(File) << (--T(Body) * Any++[File]) >> - [](auto& _) { return File << (Body << (Block << _[File])); }, - - In(Group) * LV[Lhs] * (T(Lookup)[Lookup] << (T(Group) << KEY[Rhs])) >> - [](auto &_) { return Lookup << _[Lhs] << _(Rhs); }, - - T(Group) << ((T(Region)[Region] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Region)->extend(_(Ident)->location()); - return _(Region) << _(Ident); - }, - - T(Group) << ((T(Freeze)[Freeze] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Freeze)->extend(_(Ident)->location()); - return _(Freeze) << _(Ident); - }, - - T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >> - [](auto &_) { - return Assign << _(Lhs) << Null; - }, - // function(arg, arg) - --In(Func) * ( - T(Group)[Group] << ( - (T(Ident)[Ident]) * - (T(Parens)[Parens] << (~T(List)[List])) * - End)) >> - [](auto &_) { - auto list = _(List); - if (!list) { - list = create_from(List, _(Parens)); - } - - return create_from(Call, _(Group)) - << _(Ident) - << list; - }, - - T(Group) << ((T(Create)[Create] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Create)->extend(_(Ident)->location()); - return Group << (_(Create) << _(Ident)); - }, - - T(Assign) << ((T(Group) << LV[Lhs] * End) * - ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> - [](auto &_) { return Assign << _[Lhs] << _[Rhs]; }, - T(Eq) << ((T(Group) << CMP_V[Lhs] * End) * - (T(Group) << CMP_V[Rhs] * End) * End) >> - [](auto &_) { return Eq << _[Lhs] << _[Rhs]; }, - - (T(If) << (T(Group) * T(Eq)[Eq] * (T(Group) << T(Block)[Block]))) >> - [](auto &_) { - return If << _(Eq) << _(Block); - }, - (T(Else) << (T(Group) * (T(Group) << T(Block)[Block]))) >> - [](auto &_) { - return Else << _(Block); - }, - (T(If)[If] << (T(Eq) * T(Block) * End)) * (T(Else) << T(Block)[Block]) >> - [](auto &_) { - return _(If) << _(Block); - }, - (T(If)[If] << (T(Eq) * T(Block) * End)) * (--T(Else)) >> - [](auto &_) { - // This adds an empty else block, if no else was written - return _(If) << Block; - }, - - In(List) * (T(Group) << (RV[Rhs] * End)) >> [](auto &_) { - return _(Rhs); - }, - - T(For)[For] << ( - (T(Group)) * - (T(List) << (T(Ident)[Key] * T(Ident)[Value] * End)) * - (T(Group) << (LV[Op] * End)) * - (T(Group) << (T(Block)[Block] * End)) * - End) >> - [](auto &_) { - // This function only has a block for now, as a lowering pass still needs to - // do some modifications until it's a "full" body. - return create_from(For, _(For)) - << _(Key) - << _(Value) - << _(Op) - << _(Block); - }, - - T(Func)[Func] << ( - (T(Group) << End) * - (T(Group) << ( - (T(Ident)[Ident]) * - (T(Parens)[Parens] << (~(T(List) << T(Ident)++[List]))) * - End)) * - (T(Group) << T(Block)[Block]) * - End) >> - [](auto &_) { - return create_from(Func, _(Func)) - << _(Ident) - << (create_from(Params, _(Parens)) << _[List]) - << (Body << _(Block)); - }, - - T(Return)[Return] << ( - (T(Group) << End) * - End) >> - [](auto &_) { - return create_from(Return, _(Return)); - }, - T(Return)[Return] << ( - (T(Group) << End) * - (T(Group) << (RV[Rhs] * End)) * - End) >> - [](auto &_) { - return create_from(ReturnValue, _(Return)) << _(Rhs); - }, - - }}; - - - return p; -} - -PassDef stmt_prints() { - PassDef p{ - "stmt_prints", - verona::wf::stmt_prints, - dir::bottomup | dir::once, - { - In(Block) * T(Call)[Call] >> - [](auto &_) { - return Seq - << _(Call) - << ClearStack - << create_print(_(Call)); - }, - } - }; - - return p; -} - -Node return_ident() { - return Ident ^ "return"; -} - -inline const TokenDef Compile{"compile"}; - -namespace verona::wf { -using namespace trieste::wf; -inline const trieste::wf::Wellformed flatten = - (Top <<= File) - | (File <<= Body) - | (Body <<= (Freeze | Region | Assign | Eq | Neq | Label | Jump | JumpFalse | - Print | StoreFrame | LoadFrame | CreateObject | Ident | IterNext | - Create | StoreField | Lookup | String | Call | Return | ReturnValue | - ClearStack)++) - | (CreateObject <<= (KeyIter | String | Dictionary | Func)) - | (Func <<= Compile) - | (Compile <<= Body) - | (Create <<= Ident) - | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) - | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) - | (Region <<= Ident) - | (Freeze <<= Ident) - | (Call <<= (Op >>= key) * List) - | (List <<= rv++) - | (Params <<= Ident++) - | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Label <<= Ident)[Ident]; - ; -} // namespace verona::wf - -int g_jump_label_counter = 0; -std::string new_jump_label() -{ - g_jump_label_counter += 1; - return "label_"+std::to_string(g_jump_label_counter); -} - -int g_iter_name = 0; -std::string new_iter_name() -{ - g_iter_name += 1; - return "_iter_"+std::to_string(g_iter_name); -} - -PassDef flatten() { - return { - "flatten", - verona::wf::flatten, - dir::bottomup, - { - In(Body) * (T(Block) << Any++[Block]) >> - [](auto &_) { - return Seq << _[Block]; - }, - T(If)[If] << (T(Eq)[Op] * (T(Block) << Any++[Lhs]) * (T(Block) << Any++[Rhs])) >> - [](auto &_) { - auto else_label = new_jump_label(); - auto join_label = new_jump_label(); - - auto if_head = expr_header(_(If)); - - return Seq << _(Op) - << (JumpFalse ^ else_label) - // Then block - << create_print(_(If), if_head + " (True)") - << _[Lhs] - << (Jump ^ join_label) - // Else block - << ((Label ^ "else:") << (Ident ^ else_label)) - << create_print(_(If), if_head + " (False)") - << _[Rhs] - // Join - << (Label << (Ident ^ join_label)) - ; - }, - T(For)[For] << ( - T(Ident)[Key] * - T(Ident)[Value] * - LV[Op] * - (T(Block) << Any++[Block]) * - End) >> - [](auto &_) { - auto it_name = new_iter_name(); - - auto start_label = new_jump_label(); - auto break_label = new_jump_label(); - - auto for_head = expr_header(_(For)); - - return Seq - // Prelude - << clone(_(Op)) - << (CreateObject << KeyIter) - << (StoreFrame ^ it_name) - << (Ident ^ it_name) - << (String ^ "source") - << _(Op) - << (StoreField) - << create_print(_(For), "create " + it_name) - << ((Label ^ "start:") << (Ident ^ start_label)) - // key = iter++ - << (Ident ^ it_name) - << (IterNext) - << create_from(StoreFrame, _(Key)) - // While (key != null) - << (Neq - << create_from(Ident, _(Key)) - << Null) - << (JumpFalse ^ break_label) - // value = it.source.key - << (Lookup - << (Lookup - << (Ident ^ it_name) - << (String ^ "source")) - << create_from(Ident, _(Key))) - << create_from(StoreFrame, _(Value)) - << create_print(_(For), for_head + " (Next)") - // Block - << _[Block] - // Final cleanup - << (Jump ^ start_label) - << ((Label ^ "break:") << (Ident ^ break_label)) - << create_print(_(For), for_head + " (Break)") - << ((Assign ^ ("drop " + std::string(_(Value)->location().view()))) << create_from(Ident, _(Value)) << Null) - << ((Assign ^ ("drop " + it_name)) << (Ident ^ it_name) << Null); - }, - - T(Func)[Func] << ( - T(Ident)[Ident] * - T(Params)[Params] * - (T(Body)[Body] << Any++[Block])* - End) >> - [](auto &_) { - auto func_head = expr_header(_(Func)); - - // Function setup - Node body = Body; - Node args = _(Params); - for (auto it = args->begin(); it != args->end(); it++) { - body << create_from(StoreFrame, *it); - } - body << create_print(_(Func), func_head + " (Enter)"); - - // Function body - auto block = _[Block]; - for (auto stmt : block) { - if (stmt == ReturnValue) { - body << (create_from(Assign, stmt) << return_ident() << stmt->at(0)); - body << (LoadFrame ^ "return"); - body << create_from(ReturnValue, stmt); - } else if (stmt == Return) { - body << create_print(stmt); - body << stmt; - } else { - body << stmt; - } - } - body << create_print(_(Func), func_head + " (Exit)"); - - // Function cleanup - return Seq - << (CreateObject << (Func << (Compile << body))) - << (StoreFrame ^ _(Ident)) - << create_print(_(Func), func_head); - }, - } - }; -} - -inline const TokenDef Prelude{"prelude"}; -inline const TokenDef Postlude{"postlude"}; - -namespace verona::wf { -using namespace trieste::wf; -inline const trieste::wf::Wellformed bytecode = - empty | (Body <<= (LoadFrame | StoreFrame | LoadField | StoreField | Drop | Null | - CreateObject | CreateRegion | FreezeObject | IterNext | Print | - Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue | - ClearStack)++) - | (CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) - | (Top <<= Body) - | (Func <<= Body) - | (Label <<= Ident)[Ident]; -} // namespace verona::wf - -PassDef bytecode() { - PassDef p{"bytecode", - verona::wf::bytecode, - dir::topdown, - { - T(File) << T(Body)[Body] >> - [](auto &_) { - return Body - << Prelude - << (Compile << *_[Body]) - << Postlude; - }, - T(Compile) << (T(Body)[Body] << Any++[Block]) >> - [](auto &_) { - return create_from(Body, _(Body)) << (Compile << _[Block]); - }, - - T(Prelude) >> - [](auto &) { - return Seq - << (CreateObject << (String ^ "True")) - << (StoreFrame ^ "True") - << (LoadFrame ^ "True") - << FreezeObject - << (CreateObject << (String ^ "False")) - << (StoreFrame ^ "False") - << (LoadFrame ^ "False") - << FreezeObject - << create_print(0, "prelude"); - }, - T(Postlude) >> - [](auto &) { - return Seq - << Null - << (StoreFrame ^ "True") - << Null - << (StoreFrame ^ "False") - << create_print(0, "postlude"); - }, - - T(Compile) << (Any[Lhs] * (Any * Any++)[Rhs]) >> - [](auto &_) { - return Seq << (Compile << _[Lhs]) - << (Compile << _[Rhs]); - }, - - // The node doesn't require additional processing and should be copied - T(Compile) << T( - Null, Label, Print, Jump, JumpFalse, CreateObject, - StoreFrame, LoadFrame, IterNext, StoreField, Return, - ReturnValue, ClearStack)[Op] >> - [](auto &_) -> Node { return _(Op); }, - - T(Compile) << (T(Eq, Neq)[Op] << (Any[Lhs] * Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _(Lhs)) - << (Compile << _(Rhs)) - << _(Op)->type(); - }, - - T(Compile) << (T(Ident)[Ident]) >> - [](auto &_) { return create_from(LoadFrame, _(Ident)); }, - - T(Compile) << (T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) >> - [](auto &_) { - return Seq << (Compile << _[Op]) - << (Compile << _[Key]) - << create_from(LoadField, _(Lookup)); - }, - - T(Compile) << (T(Assign)[Op] << (T(Ident)[Ident] * Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _[Rhs]) - << create_from(StoreFrame, _(Ident)) - << create_print(_(Op)); - }, - - T(Compile) << (T(Assign)[Assign] << (( - T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) * - Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _[Op]) - << (Compile << _[Key]) - << (Compile << _[Rhs]) - << create_from(StoreField, _(Lookup)) - << create_print(_(Assign)); - }, - - T(Compile) << (T(Freeze)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << FreezeObject - << create_print(_(Op)); - }, - - T(Compile) << (T(Create)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << (CreateObject << Proto); - }, - - T(Compile) << (T(Region)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << CreateRegion - << create_print(_(Op)); - }, - - T(Compile) << ( - T(Call)[Call] << ( - KEY[Op] * - (T(List) << Any++[List]) * - End)) >> - [](auto &_) { - // The print is done by the called function - return Seq - << (Compile << _[List]) - << (Compile << _(Op)) - << (Call ^ std::to_string(_[List].size())); - }, - - T(Compile) << End >> - [](auto &) -> Node { return {}; }, - - T(Compile) << (T(Empty)) >> - [](auto &) -> Node { return CreateObject << Dictionary; }, - T(Compile) << (T(String)[String]) >> - [](auto &_) -> Node { return CreateObject << _(String); }, - - }}; - return p; -} - std::pair>> extract_bytecode_pass() { auto result = std::make_shared>(); PassDef p{ @@ -767,7 +40,7 @@ struct CLIOptions : trieste::Options int load_trieste(int argc, char **argv) { CLIOptions options; auto [extract_bytecode, result] = extract_bytecode_pass(); - trieste::Reader reader{"verona_dyn", {grouping(), stmt_prints(), flatten(), bytecode(), extract_bytecode}, parser()}; + trieste::Reader reader{"verona_dyn", {grouping(), call_stmts(), flatten(), bytecode(), extract_bytecode}, parser()}; trieste::Driver driver{reader, &options}; auto build_res = driver.run(argc, argv); diff --git a/src/lang/lang.h b/src/lang/lang.h new file mode 100644 index 0000000..00d6224 --- /dev/null +++ b/src/lang/lang.h @@ -0,0 +1,97 @@ +#pragma once + +#include "trieste/trieste.h" + +#include "bytecode.h" + +using namespace trieste; + +#define TAB_SIZE 4 + +inline const TokenDef Ident{"ident", trieste::flag::print}; +inline const TokenDef Assign{"assign"}; +inline const TokenDef Create{"create"}; +inline const TokenDef For{"for"}; +inline const TokenDef If{"if"}; +inline const TokenDef Else{"else"}; +inline const TokenDef Block{"block"}; +inline const TokenDef Empty{"empty"}; +inline const TokenDef Drop{"drop"}; +inline const TokenDef Freeze{"freeze"}; +inline const TokenDef Region{"region"}; +inline const TokenDef Lookup{"lookup"}; +inline const TokenDef Parens{"parens"}; + +inline const TokenDef Op{"op"}; +inline const TokenDef Rhs{"rhs"}; +inline const TokenDef Lhs{"lhs"}; +inline const TokenDef Key{"key"}; +inline const TokenDef Value{"value"}; +inline const TokenDef Compile{"compile"}; + +namespace verona::wf { +inline const auto lv = Ident | Lookup; +inline const auto rv = lv | Empty | Null | String | Create | Call; +inline const auto cmp_values = Ident | Lookup | Null; +inline const auto key = Ident | Lookup | String; + +inline const auto grouping = + (Top <<= File) + | (File <<= Body) + | (Body <<= Block) + | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call)++) + | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) + | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) + | (Region <<= Ident) + | (Freeze <<= Ident) + | (Create <<= Ident) + | (If <<= Eq * Block * Block) + | (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) + | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) + | (Func <<= Ident * Params * Body) + | (Call <<= (Op >>= key) * List) + | (ReturnValue <<= rv) + | (List <<= rv++) + | (Params <<= Ident++) + ; + +inline const trieste::wf::Wellformed bytecode = + (Top <<= Body) + | (Body <<= (LoadFrame | StoreFrame | LoadField | StoreField | Drop | Null | + CreateObject | CreateRegion | FreezeObject | IterNext | Print | + Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue | + ClearStack)++) + | (CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) + | (Func <<= Body) + | (Label <<= Ident)[Ident]; +} + +inline const auto LV = T(Ident, Lookup); +inline const auto RV = T(Empty, Ident, Lookup, Null, String, Create, Call); +inline const auto CMP_V = T(Ident, Lookup, Null); +inline const auto KEY = T(Ident, Lookup, String); + +// Parsing && AST construction +Parse parser(); +PassDef grouping(); + +// Lowering && Bytecode +PassDef call_stmts(); +PassDef flatten(); +PassDef bytecode(); + +inline Node create_print(size_t line, std::string text) { + std::stringstream ss; + ss << "Line " << line << ": " << text; + return NodeDef::create(Print, ss.str()); +} +inline Node create_print(Node from, std::string text) { + auto [line, col] = from->location().linecol(); + return create_print(line + 1, text); +} +inline Node create_print(Node from) { + return create_print(from, std::string(from->location().view())); +} +inline Node create_from(Token def, Node from) { + return NodeDef::create(def, from->location()); +} diff --git a/src/lang/passes/bytecode.cc b/src/lang/passes/bytecode.cc new file mode 100644 index 0000000..f4db699 --- /dev/null +++ b/src/lang/passes/bytecode.cc @@ -0,0 +1,137 @@ +#include "../lang.h" + +inline const TokenDef Prelude{"prelude"}; +inline const TokenDef Postlude{"postlude"}; + +PassDef bytecode() { + PassDef p{"bytecode", + verona::wf::bytecode, + dir::topdown, + { + T(File) << T(Body)[Body] >> + [](auto &_) { + return Body + << Prelude + << (Compile << *_[Body]) + << Postlude; + }, + T(Compile) << (T(Body)[Body] << Any++[Block]) >> + [](auto &_) { + return create_from(Body, _(Body)) << (Compile << _[Block]); + }, + + T(Prelude) >> + [](auto &) { + return Seq + << (CreateObject << (String ^ "True")) + << (StoreFrame ^ "True") + << (LoadFrame ^ "True") + << FreezeObject + << (CreateObject << (String ^ "False")) + << (StoreFrame ^ "False") + << (LoadFrame ^ "False") + << FreezeObject + << create_print(0, "prelude"); + }, + T(Postlude) >> + [](auto &) { + return Seq + << Null + << (StoreFrame ^ "True") + << Null + << (StoreFrame ^ "False") + << create_print(0, "postlude"); + }, + + T(Compile) << (Any[Lhs] * (Any * Any++)[Rhs]) >> + [](auto &_) { + return Seq << (Compile << _[Lhs]) + << (Compile << _[Rhs]); + }, + + // The node doesn't require additional processing and should be copied + T(Compile) << T( + Null, Label, Print, Jump, JumpFalse, CreateObject, + StoreFrame, LoadFrame, IterNext, StoreField, Return, + ReturnValue, ClearStack)[Op] >> + [](auto &_) -> Node { return _(Op); }, + + T(Compile) << (T(Eq, Neq)[Op] << (Any[Lhs] * Any[Rhs])) >> + [](auto &_) { + return Seq << (Compile << _(Lhs)) + << (Compile << _(Rhs)) + << _(Op)->type(); + }, + + T(Compile) << (T(Ident)[Ident]) >> + [](auto &_) { return create_from(LoadFrame, _(Ident)); }, + + T(Compile) << (T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) >> + [](auto &_) { + return Seq << (Compile << _[Op]) + << (Compile << _[Key]) + << create_from(LoadField, _(Lookup)); + }, + + T(Compile) << (T(Assign)[Op] << (T(Ident)[Ident] * Any[Rhs])) >> + [](auto &_) { + return Seq << (Compile << _[Rhs]) + << create_from(StoreFrame, _(Ident)) + << create_print(_(Op)); + }, + + T(Compile) << (T(Assign)[Assign] << (( + T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) * + Any[Rhs])) >> + [](auto &_) { + return Seq << (Compile << _[Op]) + << (Compile << _[Key]) + << (Compile << _[Rhs]) + << create_from(StoreField, _(Lookup)) + << create_print(_(Assign)); + }, + + T(Compile) << (T(Freeze)[Op] << T(Ident)[Ident]) >> + [](auto &_) { + return Seq << (Compile << _[Ident]) + << FreezeObject + << create_print(_(Op)); + }, + + T(Compile) << (T(Create)[Op] << T(Ident)[Ident]) >> + [](auto &_) { + return Seq << (Compile << _[Ident]) + << (CreateObject << Proto); + }, + + T(Compile) << (T(Region)[Op] << T(Ident)[Ident]) >> + [](auto &_) { + return Seq << (Compile << _[Ident]) + << CreateRegion + << create_print(_(Op)); + }, + + T(Compile) << ( + T(Call)[Call] << ( + KEY[Op] * + (T(List) << Any++[List]) * + End)) >> + [](auto &_) { + // The print is done by the called function + return Seq + << (Compile << _[List]) + << (Compile << _(Op)) + << (Call ^ std::to_string(_[List].size())); + }, + + T(Compile) << End >> + [](auto &) -> Node { return {}; }, + + T(Compile) << (T(Empty)) >> + [](auto &) -> Node { return CreateObject << Dictionary; }, + T(Compile) << (T(String)[String]) >> + [](auto &_) -> Node { return CreateObject << _(String); }, + + }}; + return p; +} diff --git a/src/lang/passes/call_stmts.cc b/src/lang/passes/call_stmts.cc new file mode 100644 index 0000000..dc762f2 --- /dev/null +++ b/src/lang/passes/call_stmts.cc @@ -0,0 +1,28 @@ +#include "../lang.h" + +namespace verona::wf { +using namespace trieste::wf; + +inline const auto call_stmts = + grouping + | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call | ClearStack | Print)++); +} + +PassDef call_stmts() { + PassDef p{ + "call_stmts", + verona::wf::call_stmts, + dir::bottomup | dir::once, + { + In(Block) * T(Call)[Call] >> + [](auto &_) { + return Seq + << _(Call) + << ClearStack + << create_print(_(Call)); + }, + } + }; + + return p; +} diff --git a/src/lang/passes/flatten.cc b/src/lang/passes/flatten.cc new file mode 100644 index 0000000..7842acb --- /dev/null +++ b/src/lang/passes/flatten.cc @@ -0,0 +1,171 @@ +#include "../lang.h" + +namespace verona::wf { +using namespace trieste::wf; +inline const trieste::wf::Wellformed flatten = + (Top <<= File) + | (File <<= Body) + | (Body <<= (Freeze | Region | Assign | Eq | Neq | Label | Jump | JumpFalse | + Print | StoreFrame | LoadFrame | CreateObject | Ident | IterNext | + Create | StoreField | Lookup | String | Call | Return | ReturnValue | + ClearStack)++) + | (CreateObject <<= (KeyIter | String | Dictionary | Func)) + | (Func <<= Compile) + | (Compile <<= Body) + | (Create <<= Ident) + | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) + | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) + | (Region <<= Ident) + | (Freeze <<= Ident) + | (Call <<= (Op >>= key) * List) + | (List <<= rv++) + | (Params <<= Ident++) + | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) + | (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) + | (Label <<= Ident)[Ident]; + ; +} // namespace verona::wf + +int g_jump_label_counter = 0; +std::string new_jump_label() +{ + g_jump_label_counter += 1; + return "label_"+std::to_string(g_jump_label_counter); +} + +int g_iter_name = 0; +std::string new_iter_name() +{ + g_iter_name += 1; + return "_iter_"+std::to_string(g_iter_name); +} + +std::string expr_header(Node expr) { + auto expr_str = expr->location().view(); + return std::string(expr_str.substr(0, expr_str.find(":") + 1)); +} + +PassDef flatten() { + return { + "flatten", + verona::wf::flatten, + dir::bottomup, + { + In(Body) * (T(Block) << Any++[Block]) >> + [](auto &_) { + return Seq << _[Block]; + }, + T(If)[If] << (T(Eq)[Op] * (T(Block) << Any++[Lhs]) * (T(Block) << Any++[Rhs])) >> + [](auto &_) { + auto else_label = new_jump_label(); + auto join_label = new_jump_label(); + + auto if_head = expr_header(_(If)); + + return Seq << _(Op) + << (JumpFalse ^ else_label) + // Then block + << create_print(_(If), if_head + " (True)") + << _[Lhs] + << (Jump ^ join_label) + // Else block + << ((Label ^ "else:") << (Ident ^ else_label)) + << create_print(_(If), if_head + " (False)") + << _[Rhs] + // Join + << (Label << (Ident ^ join_label)) + ; + }, + T(For)[For] << ( + T(Ident)[Key] * + T(Ident)[Value] * + LV[Op] * + (T(Block) << Any++[Block]) * + End) >> + [](auto &_) { + auto it_name = new_iter_name(); + + auto start_label = new_jump_label(); + auto break_label = new_jump_label(); + + auto for_head = expr_header(_(For)); + + return Seq + // Prelude + << clone(_(Op)) + << (CreateObject << KeyIter) + << (StoreFrame ^ it_name) + << (Ident ^ it_name) + << (String ^ "source") + << _(Op) + << (StoreField) + << create_print(_(For), "create " + it_name) + << ((Label ^ "start:") << (Ident ^ start_label)) + // key = iter++ + << (Ident ^ it_name) + << (IterNext) + << create_from(StoreFrame, _(Key)) + // While (key != null) + << (Neq + << create_from(Ident, _(Key)) + << Null) + << (JumpFalse ^ break_label) + // value = it.source.key + << (Lookup + << (Lookup + << (Ident ^ it_name) + << (String ^ "source")) + << create_from(Ident, _(Key))) + << create_from(StoreFrame, _(Value)) + << create_print(_(For), for_head + " (Next)") + // Block + << _[Block] + // Final cleanup + << (Jump ^ start_label) + << ((Label ^ "break:") << (Ident ^ break_label)) + << create_print(_(For), for_head + " (Break)") + << ((Assign ^ ("drop " + std::string(_(Value)->location().view()))) << create_from(Ident, _(Value)) << Null) + << ((Assign ^ ("drop " + it_name)) << (Ident ^ it_name) << Null); + }, + + T(Func)[Func] << ( + T(Ident)[Ident] * + T(Params)[Params] * + (T(Body)[Body] << Any++[Block])* + End) >> + [](auto &_) { + auto func_head = expr_header(_(Func)); + + // Function setup + Node body = Body; + Node args = _(Params); + for (auto it = args->begin(); it != args->end(); it++) { + body << create_from(StoreFrame, *it); + } + body << create_print(_(Func), func_head + " (Enter)"); + + // Function body + auto block = _[Block]; + for (auto stmt : block) { + if (stmt == ReturnValue) { + body << (create_from(Assign, stmt) << (Ident ^ "return") << stmt->at(0)); + body << (LoadFrame ^ "return"); + body << create_from(ReturnValue, stmt); + } else if (stmt == Return) { + body << create_print(stmt); + body << stmt; + } else { + body << stmt; + } + } + body << create_print(_(Func), func_head + " (Exit)"); + + // Function cleanup + return Seq + << (CreateObject << (Func << (Compile << body))) + << (StoreFrame ^ _(Ident)) + << create_print(_(Func), func_head); + }, + } + }; +} diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc new file mode 100644 index 0000000..d89c99b --- /dev/null +++ b/src/lang/passes/grouping.cc @@ -0,0 +1,133 @@ +#include "../lang.h" + +PassDef grouping() { + PassDef p{ + "grouping", + verona::wf::grouping, + dir::bottomup, + { + // Normalize so that all expressions are inside bodies and blocks. + T(File) << (--T(Body) * Any++[File]) >> + [](auto& _) { return File << (Body << (Block << _[File])); }, + + In(Group) * LV[Lhs] * (T(Lookup)[Lookup] << (T(Group) << KEY[Rhs])) >> + [](auto &_) { return Lookup << _[Lhs] << _(Rhs); }, + + T(Group) << ((T(Region)[Region] << End) * T(Ident)[Ident] * End) >> + [](auto &_) { + _(Region)->extend(_(Ident)->location()); + return _(Region) << _(Ident); + }, + + T(Group) << ((T(Freeze)[Freeze] << End) * T(Ident)[Ident] * End) >> + [](auto &_) { + _(Freeze)->extend(_(Ident)->location()); + return _(Freeze) << _(Ident); + }, + + T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >> + [](auto &_) { + return Assign << _(Lhs) << Null; + }, + // function(arg, arg) + --In(Func) * ( + T(Group)[Group] << ( + (T(Ident)[Ident]) * + (T(Parens)[Parens] << (~T(List)[List])) * + End)) >> + [](auto &_) { + auto list = _(List); + if (!list) { + list = create_from(List, _(Parens)); + } + + return create_from(Call, _(Group)) + << _(Ident) + << list; + }, + + T(Group) << ((T(Create)[Create] << End) * T(Ident)[Ident] * End) >> + [](auto &_) { + _(Create)->extend(_(Ident)->location()); + return Group << (_(Create) << _(Ident)); + }, + + T(Assign) << ((T(Group) << LV[Lhs] * End) * + ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> + [](auto &_) { return Assign << _[Lhs] << _[Rhs]; }, + T(Eq) << ((T(Group) << CMP_V[Lhs] * End) * + (T(Group) << CMP_V[Rhs] * End) * End) >> + [](auto &_) { return Eq << _[Lhs] << _[Rhs]; }, + + (T(If) << (T(Group) * T(Eq)[Eq] * (T(Group) << T(Block)[Block]))) >> + [](auto &_) { + return If << _(Eq) << _(Block); + }, + (T(Else) << (T(Group) * (T(Group) << T(Block)[Block]))) >> + [](auto &_) { + return Else << _(Block); + }, + (T(If)[If] << (T(Eq) * T(Block) * End)) * (T(Else) << T(Block)[Block]) >> + [](auto &_) { + return _(If) << _(Block); + }, + (T(If)[If] << (T(Eq) * T(Block) * End)) * (--T(Else)) >> + [](auto &_) { + // This adds an empty else block, if no else was written + return _(If) << Block; + }, + + In(List) * (T(Group) << (RV[Rhs] * End)) >> [](auto &_) { + return _(Rhs); + }, + + T(For)[For] << ( + (T(Group)) * + (T(List) << (T(Ident)[Key] * T(Ident)[Value] * End)) * + (T(Group) << (LV[Op] * End)) * + (T(Group) << (T(Block)[Block] * End)) * + End) >> + [](auto &_) { + // This function only has a block for now, as a lowering pass still needs to + // do some modifications until it's a "full" body. + return create_from(For, _(For)) + << _(Key) + << _(Value) + << _(Op) + << _(Block); + }, + + T(Func)[Func] << ( + (T(Group) << End) * + (T(Group) << ( + (T(Ident)[Ident]) * + (T(Parens)[Parens] << (~(T(List) << T(Ident)++[List]))) * + End)) * + (T(Group) << T(Block)[Block]) * + End) >> + [](auto &_) { + return create_from(Func, _(Func)) + << _(Ident) + << (create_from(Params, _(Parens)) << _[List]) + << (Body << _(Block)); + }, + + T(Return)[Return] << ( + (T(Group) << End) * + End) >> + [](auto &_) { + return create_from(Return, _(Return)); + }, + T(Return)[Return] << ( + (T(Group) << End) * + (T(Group) << (RV[Rhs] * End)) * + End) >> + [](auto &_) { + return create_from(ReturnValue, _(Return)) << _(Rhs); + }, + + }}; + + + return p; +} diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc new file mode 100644 index 0000000..13cc771 --- /dev/null +++ b/src/lang/passes/parse.cc @@ -0,0 +1,183 @@ +#include "../lang.h" + +namespace verona::wf { +using namespace trieste::wf; + +inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze | Drop | Null | String | Create | Parens; +inline const auto parse_groups = Group | Assign | If | Else | Block | For | Func | List | Return; + +inline const auto parser = + (Top <<= File) + | (File <<= parse_groups++) + | (Assign <<= Group++) + | (If <<= Group * Eq * Group) + | (Else <<= Group * Group) + | (Group <<= (parse_tokens | Block | List)++) + | (Block <<= (parse_tokens | parse_groups)++) + | (Eq <<= Group * Group) + | (Lookup <<= Group) + | (For <<= Group * List * Group * Group) + | (List <<= Group++) + | (Parens <<= (Group | List)++) + | (Func <<= Group * Group * Group) + | (Return <<= Group++) + ; +} + +struct Indent { + size_t indent; + Token toc; +}; + +trieste::Parse parser() { + Parse p{depth::file, verona::wf::parser}; + + auto indent = std::make_shared>(); + indent->push_back({0, File}); + + auto update_indent = [indent](detail::Make& m, size_t this_indent) { + m.term({Assign, Return}); + + if (this_indent > indent->back().indent) { + std::cout << "this_indent " << this_indent << std::endl; + std::cout << "indent->back().indent " << indent->back().indent << std::endl; + m.error("unexpected indention"); + } + + while (this_indent < indent->back().indent) { + m.term({Block, Group, indent->back().toc}); + indent->pop_back(); + } + + if (this_indent != indent->back().indent) { + m.error("unexpected indention"); + } + }; + + p("start", + { + // Empty lines should be ignored + "[ \\t]*\\r?\\n" >> [](auto &) {}, + + // Line comment + "(?:#[^\\n]*)" >> [](auto &) {}, + + // Indention + " +" >> [update_indent](auto &m) { + if (m.match().len % TAB_SIZE != 0) { + m.error("unexpected indention"); + } + auto this_indent = m.match().len / TAB_SIZE; + update_indent(m, this_indent); + m.mode("contents"); + }, + + "\\t*" >> [update_indent](auto &m) { + auto this_indent = m.match().len; + update_indent(m, this_indent); + m.mode("contents"); + }, + }); + + p( + "contents", + { + // Indentation + "\\r?\\n" >> [](auto &m) { + m.mode("start"); + }, + + "[[:blank:]]+" >> [](auto &) {}, + + // Line comment + "(?:#[^\\n\\r]*)" >> [](auto &) {}, + + "def" >> [](auto &m) { + m.seq(Func); + }, + "\\(" >> [](auto &m) { + m.push(Parens); + }, + "\\)" >> [](auto &m) { + m.term({List, Parens}); + m.extend(Parens); + }, + "return" >> [](auto &m) { + m.seq(Return); + }, + + "for" >> [](auto &m) { + m.seq(For); + }, + "in" >> [](auto &m) { + // In should always be in a list from the identifiers. + m.term({List}); + }, + "," >> [](auto &m) { + m.seq(List); + }, + + "if" >> [](auto &m) { + m.seq(If); + }, + "else" >> [](auto &m) { + m.seq(Else); + }, + ":" >> [indent](auto &m) { + // Exit conditionals expressions. + m.term({Eq}); + + Token toc = Empty; + if (m.in(If)) { + toc = If; + } else if (m.in(Else)) { + toc = Else; + } else if (m.in(For)) { + toc = For; + } else if (m.in(Func)) { + toc = Func; + } else { + m.error("unexpected colon"); + return; + } + assert(toc != Empty); + + auto current_indent = indent->back().indent; + auto next_indent = current_indent + 1; + indent->push_back({next_indent, toc}); + + if (m.in(Group)) { + m.pop(Group); + } + + m.push(Block); + }, + "drop" >> [](auto &m) { m.add(Drop); }, + "create" >> [](auto &m) { m.add(Create); }, + "freeze" >> [](auto &m) { m.add(Freeze); }, + "region" >> [](auto &m) { m.add(Region); }, + "None" >> [](auto &m) { m.add(Null); }, + "[0-9A-Za-z_]+" >> [](auto &m) { m.add(Ident); }, + "\\[" >> [](auto &m) { + m.push(Lookup); + }, + "\\]" >> [](auto &m) { + m.term({Lookup}); + }, + "\\.([0-9A-Za-z_]+)" >> [](auto &m) { + m.push(Lookup); + m.add(String, 1); + m.term({Lookup}); + }, + "\"([^\\n\"]+)\"" >> [](auto &m) { m.add(String, 1); }, + "==" >> [](auto &m) { m.seq(Eq); }, + "=" >> [](auto &m) { m.seq(Assign); }, + "{}" >> [](auto &m) { m.add(Empty); }, + }); + + p.done([update_indent](auto &m) { + update_indent(m, 0); + }); + + return p; +} From 224112f012d8b74c50a8cab6bd2efa9fd6b7e692 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 15:46:50 +0200 Subject: [PATCH 07/10] Logic: Make `True` & `False` global objects --- src/lang/interpreter.cc | 19 +++++++++---------- src/lang/passes/bytecode.cc | 31 +------------------------------ src/rt/env.h | 7 +++++-- src/rt/rt.cc | 7 +++++++ src/rt/rt.h | 3 +++ 5 files changed, 25 insertions(+), 42 deletions(-) diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index fb9eaba..b202f9e 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -231,16 +231,17 @@ class Interpreter { bool_result = !bool_result; } - std::string result; + const char* result_str; + rt::objects::DynObject* result; if (bool_result) { - result = "True"; + result = rt::get_true(); + result_str = "true"; } else { - result = "False"; + result = rt::get_false(); + result_str = "false"; } - auto v = rt::get(frame(), result); - rt::add_reference(frame(), v); - stack().push_back(v); - std::cout << "push " << v << " (" << result << ")"<< std::endl; + stack().push_back(result); + std::cout << "push " << result << " (" << result_str << ")" << std::endl; rt::remove_reference(frame(), a); rt::remove_reference(frame(), b); @@ -255,9 +256,7 @@ class Interpreter { if (node == JumpFalse) { auto v = pop("jump condition"); - auto false_obj = rt::get(frame(), "False"); - auto jump = (v == false_obj); - rt::remove_reference(frame(), v); + auto jump = (v == rt::get_false()); if (jump) { return ExecJump { node->location() }; } else { diff --git a/src/lang/passes/bytecode.cc b/src/lang/passes/bytecode.cc index f4db699..a59606e 100644 --- a/src/lang/passes/bytecode.cc +++ b/src/lang/passes/bytecode.cc @@ -1,8 +1,5 @@ #include "../lang.h" -inline const TokenDef Prelude{"prelude"}; -inline const TokenDef Postlude{"postlude"}; - PassDef bytecode() { PassDef p{"bytecode", verona::wf::bytecode, @@ -10,39 +7,13 @@ PassDef bytecode() { { T(File) << T(Body)[Body] >> [](auto &_) { - return Body - << Prelude - << (Compile << *_[Body]) - << Postlude; + return Body << (Compile << *_[Body]); }, T(Compile) << (T(Body)[Body] << Any++[Block]) >> [](auto &_) { return create_from(Body, _(Body)) << (Compile << _[Block]); }, - T(Prelude) >> - [](auto &) { - return Seq - << (CreateObject << (String ^ "True")) - << (StoreFrame ^ "True") - << (LoadFrame ^ "True") - << FreezeObject - << (CreateObject << (String ^ "False")) - << (StoreFrame ^ "False") - << (LoadFrame ^ "False") - << FreezeObject - << create_print(0, "prelude"); - }, - T(Postlude) >> - [](auto &) { - return Seq - << Null - << (StoreFrame ^ "True") - << Null - << (StoreFrame ^ "False") - << create_print(0, "postlude"); - }, - T(Compile) << (Any[Lhs] * (Any * Any++)[Rhs]) >> [](auto &_) { return Seq << (Compile << _[Lhs]) diff --git a/src/rt/env.h b/src/rt/env.h index 8f6d55c..91299ba 100644 --- a/src/rt/env.h +++ b/src/rt/env.h @@ -58,8 +58,8 @@ class StringObject : public objects::DynObject { std::string value; public: - StringObject(std::string value_) - : objects::DynObject(&stringPrototypeObject), value(value_) {} + StringObject(std::string value_, bool global = false) + : objects::DynObject(&stringPrototypeObject, global), value(value_) {} std::string get_name() { return value; @@ -74,6 +74,9 @@ class StringObject : public objects::DynObject { } }; +StringObject TrueObject{"True", true}; +StringObject FalseObject{"False", true}; + // The prototype object for iterators // TODO put some stuff in here? objects::DynObject keyIterPrototypeObject{nullptr, true}; diff --git a/src/rt/rt.cc b/src/rt/rt.cc index cca957e..7d9e50d 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -67,6 +67,13 @@ objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *p return obj->set_prototype(proto); } +objects::DynObject *get_true() { + return &env::TrueObject; +} +objects::DynObject *get_false() { + return &env::FalseObject; +} + void add_reference(objects::DynObject *src, objects::DynObject *target) { objects::DynObject::add_reference(src, target); } diff --git a/src/rt/rt.h b/src/rt/rt.h index 411f70d..1f82b03 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -25,6 +25,9 @@ objects::DynObject *set(objects::DynObject *dst, objects::DynObject *key, object objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *proto); +objects::DynObject *get_true(); +objects::DynObject *get_false(); + void add_reference(objects::DynObject *src, objects::DynObject *target); void remove_reference(objects::DynObject *src, objects::DynObject *target); void move_reference(objects::DynObject *src, objects::DynObject *dst, objects::DynObject *target); From 5e4a70a1ba414fd6b45911cf878c63389ddd752a Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 16:21:36 +0200 Subject: [PATCH 08/10] Logic: Add text to prototypes and escape string in mermaid --- src/rt/env.h | 36 +++++++++++++++++++++--------------- src/rt/objects/dyn_object.h | 4 ++-- src/rt/ui/mermaid.cc | 22 ++++++++++++++++++++-- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/rt/env.h b/src/rt/env.h index 91299ba..6aa35ae 100644 --- a/src/rt/env.h +++ b/src/rt/env.h @@ -3,9 +3,19 @@ namespace rt::env { -// The prototype object for functions -// TODO put some stuff in here? -objects::DynObject framePrototypeObject{nullptr, true}; +class PrototypeObject : public objects::DynObject { + std::string name; +public: + PrototypeObject(std::string name_, objects::DynObject *prototype = nullptr) : objects::DynObject(prototype, true), name(name_) {} + + std::string get_name() { + std::stringstream stream; + stream << "[" << name << "]"; + return stream.str(); + } +}; + +PrototypeObject framePrototypeObject{"Frame"}; class FrameObject : public objects::DynObject { FrameObject() : objects::DynObject(&framePrototypeObject, true) {} @@ -23,12 +33,8 @@ class FrameObject : public objects::DynObject { } }; -// The prototype object for functions -// TODO put some stuff in here? -objects::DynObject funcPrototypeObject{nullptr, true}; -// The prototype object for bytecode functions -// TODO put some stuff in here? -objects::DynObject bytecodeFuncPrototypeObject{&funcPrototypeObject, true}; +PrototypeObject funcPrototypeObject{"Function"}; +PrototypeObject bytecodeFuncPrototypeObject{"BytecodeFunction", &funcPrototypeObject}; class FuncObject : public objects::DynObject { public: @@ -50,9 +56,7 @@ class BytecodeFuncObject : public FuncObject { }; -// The prototype object for strings -// TODO put some stuff in here? -objects::DynObject stringPrototypeObject{nullptr, true}; +PrototypeObject stringPrototypeObject{"String"}; class StringObject : public objects::DynObject { std::string value; @@ -62,7 +66,9 @@ class StringObject : public objects::DynObject { : objects::DynObject(&stringPrototypeObject, global), value(value_) {} std::string get_name() { - return value; + std::stringstream stream; + stream << "\"" << value << "\""; + return stream.str(); } std::string as_key() { @@ -79,7 +85,7 @@ StringObject FalseObject{"False", true}; // The prototype object for iterators // TODO put some stuff in here? -objects::DynObject keyIterPrototypeObject{nullptr, true}; +PrototypeObject keyIterPrototypeObject{"KeyIterator"}; class KeyIterObject : public objects::DynObject { std::map::iterator iter; @@ -100,7 +106,7 @@ class KeyIterObject : public objects::DynObject { } std::string get_name() { - return "<iterator>"; + return ""; } objects::DynObject* is_primitive() { diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index 75196fc..86ad5f4 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -18,8 +18,8 @@ namespace rt::objects { constexpr uintptr_t ImmutableTag{1}; -const std::string PrototypeField{" proto "}; -const std::string ParentField{" parent "}; +const std::string PrototypeField{"__proto__"}; +const std::string ParentField{"__parent__"}; // Representation of objects class DynObject { diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 58f2d88..0a329db 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -8,6 +8,24 @@ namespace rt::ui { +void replace(std::string& text, std::string from, std::string replace) { + size_t pos = 0; + while ((pos = text.find(from, pos)) != std::string::npos) { + text.replace(pos, from.length(), replace); + pos += replace.length(); // Move past the last replaced position + } +} + +std::string escape(std::string text) { + replace(text, "[", "#91;"); + replace(text, "]", "#93;"); + replace(text, "_", "#95;"); + replace(text, "<", "#60;"); + replace(text, ">", "#62;"); + replace(text, "\"", "#34;"); + return text; +} + void mermaid(std::vector &roots, std::ostream &out) { // Give a nice id to each object. std::map visited; @@ -34,7 +52,7 @@ void mermaid(std::vector &roots, std::ostream &out) { std::string key = e.key; objects::DynObject *src = e.src; if (src != nullptr) { - out << " id" << visited[src] << " -->|" << key << "| "; + out << " id" << visited[src] << " -->|" << escape(key) << "| "; } if (visited.find(dst) != visited.end()) { out << "id" << visited[dst] << std::endl; @@ -43,7 +61,7 @@ void mermaid(std::vector &roots, std::ostream &out) { auto curr_id = id++; visited[dst] = curr_id; out << "id" << curr_id << "[ "; - out << dst->get_name(); + out << escape(dst->get_name()); out << "
rc=" << dst->rc; out << " ]" << (unreachable ? ":::unreachable" : "") << std::endl; From 531754777e7e8cd6331d176249f75b9089f6eb07 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Mon, 7 Oct 2024 16:27:59 +0200 Subject: [PATCH 09/10] Clang format --- src/lang/bytecode.h | 1 - src/lang/interpreter.cc | 743 +++++++++++++++++++--------------- src/lang/interpreter.h | 7 +- src/lang/lang.cc | 35 +- src/lang/lang.h | 73 ++-- src/lang/passes/bytecode.cc | 179 ++++---- src/lang/passes/call_stmts.cc | 41 +- src/lang/passes/flatten.cc | 265 ++++++------ src/lang/passes/grouping.cc | 201 ++++----- src/lang/passes/parse.cc | 184 ++++----- src/main.cc | 4 +- src/rt/env.h | 198 +++++---- src/rt/objects/dyn_object.h | 686 +++++++++++++++++-------------- src/rt/objects/region.h | 346 ++++++++-------- src/rt/objects/visit.h | 29 +- src/rt/rt.cc | 299 ++++++++------ src/rt/rt.h | 73 ++-- src/rt/ui.h | 30 +- src/rt/ui/mermaid.cc | 241 ++++++----- src/utils/nop.h | 8 +- src/utils/tagged_pointer.h | 36 +- 21 files changed, 1955 insertions(+), 1724 deletions(-) diff --git a/src/lang/bytecode.h b/src/lang/bytecode.h index c1f9a77..c40b897 100644 --- a/src/lang/bytecode.h +++ b/src/lang/bytecode.h @@ -37,4 +37,3 @@ inline const trieste::TokenDef Jump{"jump", trieste::flag::print}; inline const trieste::TokenDef JumpFalse{"jump_false", trieste::flag::print}; inline const trieste::TokenDef Print("print", trieste::flag::print); inline const trieste::TokenDef IterNext("iter_next"); - diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index b202f9e..7391383 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -1,403 +1,476 @@ -#include "bytecode.h" #include "../rt/rt.h" +#include "bytecode.h" #include "trieste/trieste.h" #include -#include #include #include +#include -namespace verona::interpreter { - -// ============================================== -// Public UI -// ============================================== -struct Bytecode { - trieste::Node body; -}; - -void delete_bytecode(Bytecode* bytecode) { - delete bytecode; -} - -// ============================================== -// Statement Effects -// ============================================== -struct ExecNext {}; -struct ExecJump { - trieste::Location target; -}; -struct ExecFunc { - trieste::Node body; - size_t arg_ctn; -}; -struct ExecReturn { - std::optional value; -}; - -// ============================================== -// Interpreter/state -// ============================================== -struct InterpreterFrame { - trieste::NodeIt ip; - trieste::Node body; - rt::objects::DynObject *frame; - std::vector stack; - - ~InterpreterFrame() { - rt::remove_reference(frame, frame); - } -}; - -class Interpreter { - rt::ui::UI* ui; - std::vector frame_stack; - - InterpreterFrame *push_stack_frame(trieste::Node body) { - rt::objects::DynObject * parent_obj = nullptr; - if (!frame_stack.empty()) { - parent_obj = frame_stack.back()->frame; - } +namespace verona::interpreter +{ - auto frame = new InterpreterFrame { body->begin(), body, rt::make_frame(parent_obj), {} }; - frame_stack.push_back(frame); - return frame; - } - InterpreterFrame *pop_stack_frame() { - auto frame = frame_stack.back(); - frame_stack.pop_back(); - delete frame; - - if (frame_stack.empty()) { - return nullptr; - } else { - return frame_stack.back(); - } - } - InterpreterFrame *parent_stack_frame() { - return frame_stack[frame_stack.size() - 2]; + // ============================================== + // Public UI + // ============================================== + struct Bytecode + { + trieste::Node body; + }; + + void delete_bytecode(Bytecode* bytecode) + { + delete bytecode; } - std::vector& stack() { - return frame_stack.back()->stack; - } - rt::objects::DynObject *frame() { - return frame_stack.back()->frame; - } - - rt::objects::DynObject* pop(char const* data_info) { - auto v = stack().back(); - stack().pop_back(); - std::cout << "pop " << v << " (" << data_info << ")" << std::endl; - return v; - } + // ============================================== + // Statement Effects + // ============================================== + struct ExecNext + {}; + struct ExecJump + { + trieste::Location target; + }; + struct ExecFunc + { + trieste::Node body; + size_t arg_ctn; + }; + struct ExecReturn + { + std::optional value; + }; + + // ============================================== + // Interpreter/state + // ============================================== + struct InterpreterFrame + { + trieste::NodeIt ip; + trieste::Node body; + rt::objects::DynObject* frame; + std::vector stack; + + ~InterpreterFrame() + { + rt::remove_reference(frame, frame); + } + }; - std::variant run_stmt(trieste::Node& node) { - // ========================================== - // Operators that shouldn't be printed - // ========================================== - if (node == Print) { - // Console output - std::cout << node->location().view() << std::endl << std::endl; + class Interpreter + { + rt::ui::UI* ui; + std::vector frame_stack; - // Mermaid output - std::vector edges{{nullptr, "?", frame()}}; - ui->output(edges, std::string(node->location().view())); + InterpreterFrame* push_stack_frame(trieste::Node body) + { + rt::objects::DynObject* parent_obj = nullptr; + if (!frame_stack.empty()) + { + parent_obj = frame_stack.back()->frame; + } - // Continue - return ExecNext {}; - } - if (node == Label) { - return ExecNext {}; + auto frame = new InterpreterFrame{ + body->begin(), body, rt::make_frame(parent_obj), {}}; + frame_stack.push_back(frame); + return frame; } - - // ========================================== - // Operators that should be printed - // ========================================== - std::cout << "Op: " << node->type().str() << std::endl; - if (node == CreateObject) + InterpreterFrame* pop_stack_frame() { - rt::objects::DynObject *obj = nullptr; - - assert(!node->empty() && "CreateObject has to specify the type of data"); - auto payload = node->at(0); - if (payload == Dictionary) { - obj = rt::make_object(); - } else if (payload == String) { - obj = rt::make_str(std::string(payload->location().view())); - } else if (payload == KeyIter) { - auto v = pop("iterator source"); - obj = rt::make_iter(v); - rt::remove_reference(frame(), v); - } else if (payload == Proto) { - obj = rt::make_object(); - // RC transferred - rt::set_prototype(obj, pop("prototype source")); - } else if (payload == Func) { - assert(payload->size() == 1 && "CreateObject: A bytecode function requires a body node"); - obj = rt::make_func(new Bytecode { payload->at(0) }); - } else { - assert(false && "CreateObject has to specify a value"); - } + auto frame = frame_stack.back(); + frame_stack.pop_back(); + delete frame; - stack().push_back(obj); - std::cout << "push " << obj << std::endl; - return ExecNext {}; + if (frame_stack.empty()) + { + return nullptr; + } + else + { + return frame_stack.back(); + } } - - if (node == Null) + InterpreterFrame* parent_stack_frame() { - stack().push_back(nullptr); - std::cout << "push nullptr" << std::endl; - return ExecNext {}; + return frame_stack[frame_stack.size() - 2]; } - if (node == LoadFrame) + std::vector& stack() { - std::string field{node->location().view()}; - auto v = rt::get(frame(), field); - rt::add_reference(frame(), v); - stack().push_back(v); - std::cout << "push " << v << std::endl; - return ExecNext {}; + return frame_stack.back()->stack; + } + rt::objects::DynObject* frame() + { + return frame_stack.back()->frame; } - if (node == StoreFrame) + rt::objects::DynObject* pop(char const* data_info) { - auto v = pop("value to store"); - std::string field{node->location().view()}; - auto v2 = rt::set(frame(), field, v); - rt::remove_reference(frame(), v2); - return ExecNext {}; + auto v = stack().back(); + stack().pop_back(); + std::cout << "pop " << v << " (" << data_info << ")" << std::endl; + return v; } - if (node == LoadField) + std::variant + run_stmt(trieste::Node& node) { - assert(stack().size() >= 2 && "the stack is too small"); - auto k = pop("lookup-key"); - auto v = pop("lookup-value"); - - if (!v) { - std::cerr << std::endl; - std::cerr << "Error: Tried to access a field on `None`" << std::endl; - std::abort(); + // ========================================== + // Operators that shouldn't be printed + // ========================================== + if (node == Print) + { + // Console output + std::cout << node->location().view() << std::endl << std::endl; + + // Mermaid output + std::vector edges{{nullptr, "?", frame()}}; + ui->output(edges, std::string(node->location().view())); + + // Continue + return ExecNext{}; + } + if (node == Label) + { + return ExecNext{}; } - auto v2 = rt::get(v, k); - stack().push_back(v2); - std::cout << "push " << v2 << std::endl; - rt::add_reference(frame(), v2); - rt::remove_reference(frame(), k); - rt::remove_reference(frame(), v); - return ExecNext {}; - } + // ========================================== + // Operators that should be printed + // ========================================== + std::cout << "Op: " << node->type().str() << std::endl; + if (node == CreateObject) + { + rt::objects::DynObject* obj = nullptr; + + assert( + !node->empty() && "CreateObject has to specify the type of data"); + auto payload = node->at(0); + if (payload == Dictionary) + { + obj = rt::make_object(); + } + else if (payload == String) + { + obj = rt::make_str(std::string(payload->location().view())); + } + else if (payload == KeyIter) + { + auto v = pop("iterator source"); + obj = rt::make_iter(v); + rt::remove_reference(frame(), v); + } + else if (payload == Proto) + { + obj = rt::make_object(); + // RC transferred + rt::set_prototype(obj, pop("prototype source")); + } + else if (payload == Func) + { + assert( + payload->size() == 1 && + "CreateObject: A bytecode function requires a body node"); + obj = rt::make_func(new Bytecode{payload->at(0)}); + } + else + { + assert(false && "CreateObject has to specify a value"); + } - if (node == StoreField) - { - auto v = pop("value to store"); - auto k = pop("lookup-key"); - auto v2 = pop("lookup-value"); - auto v3 = rt::set(v2, k, v); - rt::move_reference(frame(), v2, v); - rt::remove_reference(frame(), k); - rt::remove_reference(frame(), v2); - rt::remove_reference(v2, v3); - return ExecNext {}; - } + stack().push_back(obj); + std::cout << "push " << obj << std::endl; + return ExecNext{}; + } - if (node == CreateRegion) - { - auto v = pop("region source"); - rt::create_region(v); - rt::remove_reference(frame(), v); - return ExecNext {}; - } + if (node == Null) + { + stack().push_back(nullptr); + std::cout << "push nullptr" << std::endl; + return ExecNext{}; + } - if (node == FreezeObject) - { - auto v = pop("object to freeze"); - rt::freeze(v); - rt::remove_reference(frame(), v); - return ExecNext {}; - } + if (node == LoadFrame) + { + std::string field{node->location().view()}; + auto v = rt::get(frame(), field); + rt::add_reference(frame(), v); + stack().push_back(v); + std::cout << "push " << v << std::endl; + return ExecNext{}; + } - if (node == Eq || node == Neq) - { - auto b = pop("Rhs"); - auto a = pop("Lhs"); + if (node == StoreFrame) + { + auto v = pop("value to store"); + std::string field{node->location().view()}; + auto v2 = rt::set(frame(), field, v); + rt::remove_reference(frame(), v2); + return ExecNext{}; + } - auto bool_result = (a == b); - if (node == Neq) { - bool_result = !bool_result; + if (node == LoadField) + { + assert(stack().size() >= 2 && "the stack is too small"); + auto k = pop("lookup-key"); + auto v = pop("lookup-value"); + + if (!v) + { + std::cerr << std::endl; + std::cerr << "Error: Tried to access a field on `None`" << std::endl; + std::abort(); + } + + auto v2 = rt::get(v, k); + stack().push_back(v2); + std::cout << "push " << v2 << std::endl; + rt::add_reference(frame(), v2); + rt::remove_reference(frame(), k); + rt::remove_reference(frame(), v); + return ExecNext{}; } - const char* result_str; - rt::objects::DynObject* result; - if (bool_result) { - result = rt::get_true(); - result_str = "true"; - } else { - result = rt::get_false(); - result_str = "false"; + if (node == StoreField) + { + auto v = pop("value to store"); + auto k = pop("lookup-key"); + auto v2 = pop("lookup-value"); + auto v3 = rt::set(v2, k, v); + rt::move_reference(frame(), v2, v); + rt::remove_reference(frame(), k); + rt::remove_reference(frame(), v2); + rt::remove_reference(v2, v3); + return ExecNext{}; } - stack().push_back(result); - std::cout << "push " << result << " (" << result_str << ")" << std::endl; - rt::remove_reference(frame(), a); - rt::remove_reference(frame(), b); - return ExecNext {}; - } + if (node == CreateRegion) + { + auto v = pop("region source"); + rt::create_region(v); + rt::remove_reference(frame(), v); + return ExecNext{}; + } - if (node == Jump) - { - return ExecJump { node->location() }; - } + if (node == FreezeObject) + { + auto v = pop("object to freeze"); + rt::freeze(v); + rt::remove_reference(frame(), v); + return ExecNext{}; + } - if (node == JumpFalse) - { - auto v = pop("jump condition"); - auto jump = (v == rt::get_false()); - if (jump) { - return ExecJump { node->location() }; - } else { - return ExecNext {}; + if (node == Eq || node == Neq) + { + auto b = pop("Rhs"); + auto a = pop("Lhs"); + + auto bool_result = (a == b); + if (node == Neq) + { + bool_result = !bool_result; + } + + const char* result_str; + rt::objects::DynObject* result; + if (bool_result) + { + result = rt::get_true(); + result_str = "true"; + } + else + { + result = rt::get_false(); + result_str = "false"; + } + stack().push_back(result); + std::cout << "push " << result << " (" << result_str << ")" + << std::endl; + + rt::remove_reference(frame(), a); + rt::remove_reference(frame(), b); + return ExecNext{}; } - } - if (node == IterNext) - { - auto it = pop("iterator"); + if (node == Jump) + { + return ExecJump{node->location()}; + } - auto obj = rt::iter_next(it); - rt::remove_reference(frame(), it); + if (node == JumpFalse) + { + auto v = pop("jump condition"); + auto jump = (v == rt::get_false()); + if (jump) + { + return ExecJump{node->location()}; + } + else + { + return ExecNext{}; + } + } - stack().push_back(obj); - std::cout << "push " << obj << " (next from iter)" << std::endl; - return ExecNext {}; - } + if (node == IterNext) + { + auto it = pop("iterator"); + + auto obj = rt::iter_next(it); + rt::remove_reference(frame(), it); - if (node == ClearStack) { - if (!stack().empty()) { - while (!stack().empty()) { - rt::remove_reference(frame(), stack().back()); - stack().pop_back(); + stack().push_back(obj); + std::cout << "push " << obj << " (next from iter)" << std::endl; + return ExecNext{}; + } + + if (node == ClearStack) + { + if (!stack().empty()) + { + while (!stack().empty()) + { + rt::remove_reference(frame(), stack().back()); + stack().pop_back(); + } } + return ExecNext{}; } - return ExecNext {}; - } - if (node == Call) { - auto func = pop("function"); - auto arg_ctn = std::stoul(std::string(node->location().view())); - auto action = ExecFunc { rt::get_bytecode(func)->body , arg_ctn }; - rt::remove_reference(frame(), func); - return action; - } + if (node == Call) + { + auto func = pop("function"); + auto arg_ctn = std::stoul(std::string(node->location().view())); + auto action = ExecFunc{rt::get_bytecode(func)->body, arg_ctn}; + rt::remove_reference(frame(), func); + return action; + } - if (node == Return) { - return ExecReturn {}; - } + if (node == Return) + { + return ExecReturn{}; + } + + if (node == ReturnValue) + { + auto value = pop("return value"); + // RC is transfered to the stack of the parent frame + return ExecReturn{value}; + } - if (node == ReturnValue) { - auto value = pop("return value"); - // RC is transfered to the stack of the parent frame - return ExecReturn { value }; + std::cerr << "unhandled bytecode" << std::endl; + node->str(std::cerr); + std::abort(); } - std::cerr << "unhandled bytecode" << std::endl; - node->str(std::cerr); - std::abort(); - } + public: + Interpreter(rt::ui::UI* ui_) : ui(ui_) {} + + void run(trieste::Node main) + { + auto frame = push_stack_frame(main); + + while (frame) + { + const auto action = run_stmt(*frame->ip); -public: - Interpreter(rt::ui::UI* ui_): ui(ui_) {} - - void run(trieste::Node main) { - auto frame = push_stack_frame(main); - - while (frame) { - const auto action = run_stmt(*frame->ip); - - if (std::holds_alternative(action)) { - frame->ip++; - } else if (std::holds_alternative(action)) { - auto jump = std::get(action); - auto label_node = frame->body->look(jump.target); - assert(label_node.size() == 1); - frame->ip = frame->body->find(label_node[0]); - // Skip the label node - frame->ip++; - } else if (std::holds_alternative(action)) { - auto func = std::get(action); - - // Make sure the stored ip, continues after the call - frame->ip++; - - frame = push_stack_frame(func.body); - auto parent_frame = parent_stack_frame(); - - // Setup the new frame - for (size_t i = 0; i < func.arg_ctn; i++) { - frame->stack.push_back(parent_frame->stack.back()); - parent_frame->stack.pop_back(); + if (std::holds_alternative(action)) + { + frame->ip++; } - } else if (std::holds_alternative(action)) { - frame->ip = frame->body->end(); - } else { - assert(false && "unhandled statement action"); - } + else if (std::holds_alternative(action)) + { + auto jump = std::get(action); + auto label_node = frame->body->look(jump.target); + assert(label_node.size() == 1); + frame->ip = frame->body->find(label_node[0]); + // Skip the label node + frame->ip++; + } + else if (std::holds_alternative(action)) + { + auto func = std::get(action); + + // Make sure the stored ip, continues after the call + frame->ip++; - if (frame->ip == frame->body->end()) { - if (std::holds_alternative(action)) { - auto return_ = std::get(action); - if (return_.value.has_value()) { - auto parent = parent_stack_frame(); - auto value = return_.value.value(); - rt::move_reference(frame->frame, parent->frame, value); - parent->stack.push_back(value); + frame = push_stack_frame(func.body); + auto parent_frame = parent_stack_frame(); + + // Setup the new frame + for (size_t i = 0; i < func.arg_ctn; i++) + { + frame->stack.push_back(parent_frame->stack.back()); + parent_frame->stack.pop_back(); } } + else if (std::holds_alternative(action)) + { + frame->ip = frame->body->end(); + } + else + { + assert(false && "unhandled statement action"); + } - frame = pop_stack_frame(); + if (frame->ip == frame->body->end()) + { + if (std::holds_alternative(action)) + { + auto return_ = std::get(action); + if (return_.value.has_value()) + { + auto parent = parent_stack_frame(); + auto value = return_.value.value(); + rt::move_reference(frame->frame, parent->frame, value); + parent->stack.push_back(value); + } + } + + frame = pop_stack_frame(); + } } } - } -}; + }; -class UI : public rt::ui::UI -{ - bool interactive; - std::string path; - std::ofstream out; - -public: - UI(bool interactive_) : interactive(interactive_) { - path = "mermaid.md"; - out.open(path); - } + class UI : public rt::ui::UI + { + bool interactive; + std::string path; + std::ofstream out; - void output(std::vector &edges, std::string message) { - out << "```" << std::endl; - out << message << std::endl; - out << "```" << std::endl; - rt::ui::mermaid(edges, out); - if (interactive) { - out.close(); - std::cout << "Press a key!" << std::endl; - getchar(); + public: + UI(bool interactive_) : interactive(interactive_) + { + path = "mermaid.md"; out.open(path); } - } -}; -void start(trieste::Node main_body, bool interactive) { - size_t initial = rt::pre_run(); + void output(std::vector& edges, std::string message) + { + out << "```" << std::endl; + out << message << std::endl; + out << "```" << std::endl; + rt::ui::mermaid(edges, out); + if (interactive) + { + out.close(); + std::cout << "Press a key!" << std::endl; + getchar(); + out.open(path); + } + } + }; + + void start(trieste::Node main_body, bool interactive) + { + size_t initial = rt::pre_run(); - UI ui(interactive); - Interpreter inter(&ui); - inter.run(main_body); + UI ui(interactive); + Interpreter inter(&ui); + inter.run(main_body); - rt::post_run(initial, ui); -} + rt::post_run(initial, ui); + } -} // namespace verona::interpreter \ No newline at end of file +} // namespace verona::interpreter diff --git a/src/lang/interpreter.h b/src/lang/interpreter.h index b12e164..4227bd9 100644 --- a/src/lang/interpreter.h +++ b/src/lang/interpreter.h @@ -1,7 +1,8 @@ #pragma once -namespace verona::interpreter { - struct Bytecode; +namespace verona::interpreter +{ + struct Bytecode; - void delete_bytecode(Bytecode* bytecode); + void delete_bytecode(Bytecode* bytecode); } diff --git a/src/lang/lang.cc b/src/lang/lang.cc index 0e86fe4..4155039 100644 --- a/src/lang/lang.cc +++ b/src/lang/lang.cc @@ -1,20 +1,16 @@ -#include +#include "lang.h" -#include "trieste/driver.h" #include "interpreter.h" +#include "trieste/driver.h" -#include "lang.h" +#include using namespace trieste; -std::pair>> extract_bytecode_pass() { +std::pair>> extract_bytecode_pass() +{ auto result = std::make_shared>(); - PassDef p{ - "interpreter", - verona::wf::bytecode, - dir::topdown | dir::once, - {} - }; + PassDef p{"interpreter", verona::wf::bytecode, dir::topdown | dir::once, {}}; p.post(trieste::Top, [result](Node n) { *result = n->at(0); return 0; @@ -23,7 +19,8 @@ std::pair>> extract_bytecode_pass() return {p, result}; } -namespace verona::interpreter { +namespace verona::interpreter +{ void start(trieste::Node main_body, bool interactive); } @@ -31,20 +28,26 @@ struct CLIOptions : trieste::Options { bool iterative = false; - void configure(CLI::App &app) + void configure(CLI::App& app) { - app.add_flag("-i,--interactive", iterative, "Run the interpreter iteratively"); + app.add_flag( + "-i,--interactive", iterative, "Run the interpreter iteratively"); } }; -int load_trieste(int argc, char **argv) { +int load_trieste(int argc, char** argv) +{ CLIOptions options; auto [extract_bytecode, result] = extract_bytecode_pass(); - trieste::Reader reader{"verona_dyn", {grouping(), call_stmts(), flatten(), bytecode(), extract_bytecode}, parser()}; + trieste::Reader reader{ + "verona_dyn", + {grouping(), call_stmts(), flatten(), bytecode(), extract_bytecode}, + parser()}; trieste::Driver driver{reader, &options}; auto build_res = driver.run(argc, argv); - if (build_res == 0 && result->has_value()) { + if (build_res == 0 && result->has_value()) + { verona::interpreter::start(result->value(), options.iterative); } return build_res; diff --git a/src/lang/lang.h b/src/lang/lang.h index 00d6224..d33ad1d 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -1,8 +1,7 @@ #pragma once -#include "trieste/trieste.h" - #include "bytecode.h" +#include "trieste/trieste.h" using namespace trieste; @@ -29,41 +28,33 @@ inline const TokenDef Key{"key"}; inline const TokenDef Value{"value"}; inline const TokenDef Compile{"compile"}; -namespace verona::wf { -inline const auto lv = Ident | Lookup; -inline const auto rv = lv | Empty | Null | String | Create | Call; -inline const auto cmp_values = Ident | Lookup | Null; -inline const auto key = Ident | Lookup | String; +namespace verona::wf +{ + inline const auto lv = Ident | Lookup; + inline const auto rv = lv | Empty | Null | String | Create | Call; + inline const auto cmp_values = Ident | Lookup | Null; + inline const auto key = Ident | Lookup | String; -inline const auto grouping = - (Top <<= File) - | (File <<= Body) - | (Body <<= Block) - | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call)++) - | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) - | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) - | (Region <<= Ident) - | (Freeze <<= Ident) - | (Create <<= Ident) - | (If <<= Eq * Block * Block) - | (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) - | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Func <<= Ident * Params * Body) - | (Call <<= (Op >>= key) * List) - | (ReturnValue <<= rv) - | (List <<= rv++) - | (Params <<= Ident++) - ; + inline const auto grouping = (Top <<= File) | (File <<= Body) | + (Body <<= Block) | + (Block <<= + (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | + Call)++) | + (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | + (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) | (Region <<= Ident) | + (Freeze <<= Ident) | (Create <<= Ident) | (If <<= Eq * Block * Block) | + (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) | + (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | + (Func <<= Ident * Params * Body) | (Call <<= (Op >>= key) * List) | + (ReturnValue <<= rv) | (List <<= rv++) | (Params <<= Ident++); -inline const trieste::wf::Wellformed bytecode = - (Top <<= Body) - | (Body <<= (LoadFrame | StoreFrame | LoadField | StoreField | Drop | Null | - CreateObject | CreateRegion | FreezeObject | IterNext | Print | - Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue | - ClearStack)++) - | (CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) - | (Func <<= Body) - | (Label <<= Ident)[Ident]; + inline const trieste::wf::Wellformed bytecode = (Top <<= Body) | + (Body <<= + (LoadFrame | StoreFrame | LoadField | StoreField | Drop | Null | + CreateObject | CreateRegion | FreezeObject | IterNext | Print | Eq | Neq | + Jump | JumpFalse | Label | Call | Return | ReturnValue | ClearStack)++) | + (CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) | + (Func <<= Body) | (Label <<= Ident)[Ident]; } inline const auto LV = T(Ident, Lookup); @@ -80,18 +71,22 @@ PassDef call_stmts(); PassDef flatten(); PassDef bytecode(); -inline Node create_print(size_t line, std::string text) { +inline Node create_print(size_t line, std::string text) +{ std::stringstream ss; ss << "Line " << line << ": " << text; return NodeDef::create(Print, ss.str()); } -inline Node create_print(Node from, std::string text) { +inline Node create_print(Node from, std::string text) +{ auto [line, col] = from->location().linecol(); return create_print(line + 1, text); } -inline Node create_print(Node from) { +inline Node create_print(Node from) +{ return create_print(from, std::string(from->location().view())); } -inline Node create_from(Token def, Node from) { +inline Node create_from(Token def, Node from) +{ return NodeDef::create(def, from->location()); } diff --git a/src/lang/passes/bytecode.cc b/src/lang/passes/bytecode.cc index a59606e..42f95f2 100644 --- a/src/lang/passes/bytecode.cc +++ b/src/lang/passes/bytecode.cc @@ -1,108 +1,105 @@ #include "../lang.h" -PassDef bytecode() { - PassDef p{"bytecode", - verona::wf::bytecode, - dir::topdown, - { - T(File) << T(Body)[Body] >> - [](auto &_) { - return Body << (Compile << *_[Body]); - }, - T(Compile) << (T(Body)[Body] << Any++[Block]) >> - [](auto &_) { - return create_from(Body, _(Body)) << (Compile << _[Block]); - }, +PassDef bytecode() +{ + PassDef p{ + "bytecode", + verona::wf::bytecode, + dir::topdown, + { + T(File) << T(Body)[Body] >> + [](auto& _) { return Body << (Compile << *_[Body]); }, + T(Compile) << (T(Body)[Body] << Any++[Block]) >> + [](auto& _) { + return create_from(Body, _(Body)) << (Compile << _[Block]); + }, - T(Compile) << (Any[Lhs] * (Any * Any++)[Rhs]) >> - [](auto &_) { - return Seq << (Compile << _[Lhs]) - << (Compile << _[Rhs]); - }, + T(Compile) << (Any[Lhs] * (Any * Any++)[Rhs]) >> + [](auto& _) { + return Seq << (Compile << _[Lhs]) << (Compile << _[Rhs]); + }, - // The node doesn't require additional processing and should be copied - T(Compile) << T( - Null, Label, Print, Jump, JumpFalse, CreateObject, - StoreFrame, LoadFrame, IterNext, StoreField, Return, - ReturnValue, ClearStack)[Op] >> - [](auto &_) -> Node { return _(Op); }, + // The node doesn't require additional processing and should be copied + T(Compile) << T( + Null, + Label, + Print, + Jump, + JumpFalse, + CreateObject, + StoreFrame, + LoadFrame, + IterNext, + StoreField, + Return, + ReturnValue, + ClearStack)[Op] >> + [](auto& _) -> Node { return _(Op); }, - T(Compile) << (T(Eq, Neq)[Op] << (Any[Lhs] * Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _(Lhs)) - << (Compile << _(Rhs)) - << _(Op)->type(); - }, + T(Compile) << (T(Eq, Neq)[Op] << (Any[Lhs] * Any[Rhs])) >> + [](auto& _) { + return Seq << (Compile << _(Lhs)) << (Compile << _(Rhs)) + << _(Op)->type(); + }, - T(Compile) << (T(Ident)[Ident]) >> - [](auto &_) { return create_from(LoadFrame, _(Ident)); }, + T(Compile) << (T(Ident)[Ident]) >> + [](auto& _) { return create_from(LoadFrame, _(Ident)); }, - T(Compile) << (T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) >> - [](auto &_) { - return Seq << (Compile << _[Op]) - << (Compile << _[Key]) - << create_from(LoadField, _(Lookup)); - }, + T(Compile) << (T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) >> + [](auto& _) { + return Seq << (Compile << _[Op]) << (Compile << _[Key]) + << create_from(LoadField, _(Lookup)); + }, - T(Compile) << (T(Assign)[Op] << (T(Ident)[Ident] * Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _[Rhs]) - << create_from(StoreFrame, _(Ident)) - << create_print(_(Op)); - }, + T(Compile) << (T(Assign)[Op] << (T(Ident)[Ident] * Any[Rhs])) >> + [](auto& _) { + return Seq << (Compile << _[Rhs]) << create_from(StoreFrame, _(Ident)) + << create_print(_(Op)); + }, - T(Compile) << (T(Assign)[Assign] << (( - T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) * - Any[Rhs])) >> - [](auto &_) { - return Seq << (Compile << _[Op]) - << (Compile << _[Key]) - << (Compile << _[Rhs]) - << create_from(StoreField, _(Lookup)) - << create_print(_(Assign)); - }, + T(Compile) + << (T(Assign)[Assign] + << ((T(Lookup)[Lookup] << (Any[Op] * Any[Key] * End)) * + Any[Rhs])) >> + [](auto& _) { + return Seq << (Compile << _[Op]) << (Compile << _[Key]) + << (Compile << _[Rhs]) + << create_from(StoreField, _(Lookup)) + << create_print(_(Assign)); + }, - T(Compile) << (T(Freeze)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << FreezeObject - << create_print(_(Op)); - }, + T(Compile) << (T(Freeze)[Op] << T(Ident)[Ident]) >> + [](auto& _) { + return Seq << (Compile << _[Ident]) << FreezeObject + << create_print(_(Op)); + }, - T(Compile) << (T(Create)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << (CreateObject << Proto); - }, + T(Compile) << (T(Create)[Op] << T(Ident)[Ident]) >> + [](auto& _) { + return Seq << (Compile << _[Ident]) << (CreateObject << Proto); + }, - T(Compile) << (T(Region)[Op] << T(Ident)[Ident]) >> - [](auto &_) { - return Seq << (Compile << _[Ident]) - << CreateRegion - << create_print(_(Op)); - }, - - T(Compile) << ( - T(Call)[Call] << ( - KEY[Op] * - (T(List) << Any++[List]) * - End)) >> - [](auto &_) { - // The print is done by the called function - return Seq - << (Compile << _[List]) - << (Compile << _(Op)) - << (Call ^ std::to_string(_[List].size())); - }, + T(Compile) << (T(Region)[Op] << T(Ident)[Ident]) >> + [](auto& _) { + return Seq << (Compile << _[Ident]) << CreateRegion + << create_print(_(Op)); + }, - T(Compile) << End >> - [](auto &) -> Node { return {}; }, + T(Compile) + << (T(Call)[Call] << (KEY[Op] * (T(List) << Any++[List]) * End)) >> + [](auto& _) { + // The print is done by the called function + return Seq << (Compile << _[List]) << (Compile << _(Op)) + << (Call ^ std::to_string(_[List].size())); + }, - T(Compile) << (T(Empty)) >> - [](auto &) -> Node { return CreateObject << Dictionary; }, - T(Compile) << (T(String)[String]) >> - [](auto &_) -> Node { return CreateObject << _(String); }, + T(Compile) << End >> [](auto&) -> Node { return {}; }, - }}; + T(Compile) << (T(Empty)) >> + [](auto&) -> Node { return CreateObject << Dictionary; }, + T(Compile) << (T(String)[String]) >> + [](auto& _) -> Node { return CreateObject << _(String); }, + + }}; return p; } diff --git a/src/lang/passes/call_stmts.cc b/src/lang/passes/call_stmts.cc index dc762f2..2e3d59f 100644 --- a/src/lang/passes/call_stmts.cc +++ b/src/lang/passes/call_stmts.cc @@ -1,28 +1,25 @@ #include "../lang.h" -namespace verona::wf { -using namespace trieste::wf; +namespace verona::wf +{ + using namespace trieste::wf; -inline const auto call_stmts = - grouping - | (Block <<= (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call | ClearStack | Print)++); + inline const auto call_stmts = grouping | + (Block <<= + (Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call | + ClearStack | Print)++); } -PassDef call_stmts() { - PassDef p{ - "call_stmts", - verona::wf::call_stmts, - dir::bottomup | dir::once, - { - In(Block) * T(Call)[Call] >> - [](auto &_) { - return Seq - << _(Call) - << ClearStack - << create_print(_(Call)); - }, - } - }; - - return p; +PassDef call_stmts() +{ + return { + "call_stmts", + verona::wf::call_stmts, + dir::bottomup | dir::once, + { + In(Block) * T(Call)[Call] >> + [](auto& _) { + return Seq << _(Call) << ClearStack << create_print(_(Call)); + }, + }}; } diff --git a/src/lang/passes/flatten.cc b/src/lang/passes/flatten.cc index 7842acb..3beb5c2 100644 --- a/src/lang/passes/flatten.cc +++ b/src/lang/passes/flatten.cc @@ -1,171 +1,160 @@ #include "../lang.h" -namespace verona::wf { -using namespace trieste::wf; -inline const trieste::wf::Wellformed flatten = - (Top <<= File) - | (File <<= Body) - | (Body <<= (Freeze | Region | Assign | Eq | Neq | Label | Jump | JumpFalse | - Print | StoreFrame | LoadFrame | CreateObject | Ident | IterNext | - Create | StoreField | Lookup | String | Call | Return | ReturnValue | - ClearStack)++) - | (CreateObject <<= (KeyIter | String | Dictionary | Func)) - | (Func <<= Compile) - | (Compile <<= Body) - | (Create <<= Ident) - | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) - | (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) - | (Region <<= Ident) - | (Freeze <<= Ident) - | (Call <<= (Op >>= key) * List) - | (List <<= rv++) - | (Params <<= Ident++) - | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) - | (Label <<= Ident)[Ident]; - ; +namespace verona::wf +{ + using namespace trieste::wf; + inline const trieste::wf::Wellformed flatten = (Top <<= File) | + (File <<= Body) | + (Body <<= + (Freeze | Region | Assign | Eq | Neq | Label | Jump | JumpFalse | Print | + StoreFrame | LoadFrame | CreateObject | Ident | IterNext | Create | + StoreField | Lookup | String | Call | Return | ReturnValue | + ClearStack)++) | + (CreateObject <<= (KeyIter | String | Dictionary | Func)) | + (Func <<= Compile) | (Compile <<= Body) | (Create <<= Ident) | + (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | + (Lookup <<= (Lhs >>= lv) * (Rhs >>= key)) | (Region <<= Ident) | + (Freeze <<= Ident) | (Call <<= (Op >>= key) * List) | (List <<= rv++) | + (Params <<= Ident++) | + (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | + (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | + (Label <<= Ident)[Ident]; + ; } // namespace verona::wf int g_jump_label_counter = 0; std::string new_jump_label() { g_jump_label_counter += 1; - return "label_"+std::to_string(g_jump_label_counter); + return "label_" + std::to_string(g_jump_label_counter); } int g_iter_name = 0; std::string new_iter_name() { g_iter_name += 1; - return "_iter_"+std::to_string(g_iter_name); + return "_iter_" + std::to_string(g_iter_name); } -std::string expr_header(Node expr) { +std::string expr_header(Node expr) +{ auto expr_str = expr->location().view(); return std::string(expr_str.substr(0, expr_str.find(":") + 1)); } -PassDef flatten() { +PassDef flatten() +{ return { - "flatten", - verona::wf::flatten, - dir::bottomup, - { - In(Body) * (T(Block) << Any++[Block]) >> - [](auto &_) { - return Seq << _[Block]; - }, - T(If)[If] << (T(Eq)[Op] * (T(Block) << Any++[Lhs]) * (T(Block) << Any++[Rhs])) >> - [](auto &_) { - auto else_label = new_jump_label(); - auto join_label = new_jump_label(); + "flatten", + verona::wf::flatten, + dir::bottomup, + { + In(Body) * (T(Block) << Any++[Block]) >> + [](auto& _) { return Seq << _[Block]; }, + T(If)[If] + << (T(Eq)[Op] * (T(Block) << Any++[Lhs]) * + (T(Block) << Any++[Rhs])) >> + [](auto& _) { + auto else_label = new_jump_label(); + auto join_label = new_jump_label(); - auto if_head = expr_header(_(If)); + auto if_head = expr_header(_(If)); - return Seq << _(Op) - << (JumpFalse ^ else_label) - // Then block - << create_print(_(If), if_head + " (True)") - << _[Lhs] - << (Jump ^ join_label) - // Else block - << ((Label ^ "else:") << (Ident ^ else_label)) - << create_print(_(If), if_head + " (False)") - << _[Rhs] - // Join - << (Label << (Ident ^ join_label)) - ; + return Seq << _(Op) + << (JumpFalse ^ else_label) + // Then block + << create_print(_(If), if_head + " (True)") << _[Lhs] + << (Jump ^ join_label) + // Else block + << ((Label ^ "else:") << (Ident ^ else_label)) + << create_print(_(If), if_head + " (False)") + << _[Rhs] + // Join + << (Label << (Ident ^ join_label)); }, - T(For)[For] << ( - T(Ident)[Key] * - T(Ident)[Value] * - LV[Op] * - (T(Block) << Any++[Block]) * - End) >> - [](auto &_) { - auto it_name = new_iter_name(); + T(For)[For] + << (T(Ident)[Key] * T(Ident)[Value] * LV[Op] * + (T(Block) << Any++[Block]) * End) >> + [](auto& _) { + auto it_name = new_iter_name(); - auto start_label = new_jump_label(); - auto break_label = new_jump_label(); + auto start_label = new_jump_label(); + auto break_label = new_jump_label(); - auto for_head = expr_header(_(For)); + auto for_head = expr_header(_(For)); - return Seq - // Prelude - << clone(_(Op)) - << (CreateObject << KeyIter) - << (StoreFrame ^ it_name) - << (Ident ^ it_name) - << (String ^ "source") - << _(Op) - << (StoreField) - << create_print(_(For), "create " + it_name) - << ((Label ^ "start:") << (Ident ^ start_label)) - // key = iter++ - << (Ident ^ it_name) - << (IterNext) - << create_from(StoreFrame, _(Key)) - // While (key != null) - << (Neq - << create_from(Ident, _(Key)) - << Null) - << (JumpFalse ^ break_label) - // value = it.source.key - << (Lookup - << (Lookup - << (Ident ^ it_name) - << (String ^ "source")) - << create_from(Ident, _(Key))) - << create_from(StoreFrame, _(Value)) - << create_print(_(For), for_head + " (Next)") - // Block - << _[Block] - // Final cleanup - << (Jump ^ start_label) - << ((Label ^ "break:") << (Ident ^ break_label)) - << create_print(_(For), for_head + " (Break)") - << ((Assign ^ ("drop " + std::string(_(Value)->location().view()))) << create_from(Ident, _(Value)) << Null) - << ((Assign ^ ("drop " + it_name)) << (Ident ^ it_name) << Null); - }, + return Seq + // Prelude + << clone(_(Op)) << (CreateObject << KeyIter) + << (StoreFrame ^ it_name) << (Ident ^ it_name) + << (String ^ "source") << _(Op) << (StoreField) + << create_print(_(For), "create " + it_name) + << ((Label ^ "start:") << (Ident ^ start_label)) + // key = iter++ + << (Ident ^ it_name) << (IterNext) + << create_from(StoreFrame, _(Key)) + // While (key != null) + << (Neq << create_from(Ident, _(Key)) << Null) + << (JumpFalse ^ break_label) + // value = it.source.key + << (Lookup << (Lookup << (Ident ^ it_name) << (String ^ "source")) + << create_from(Ident, _(Key))) + << create_from(StoreFrame, _(Value)) + << create_print(_(For), for_head + " (Next)") + // Block + << _[Block] + // Final cleanup + << (Jump ^ start_label) + << ((Label ^ "break:") << (Ident ^ break_label)) + << create_print(_(For), for_head + " (Break)") + << ((Assign ^ ("drop " + std::string(_(Value)->location().view()))) + << create_from(Ident, _(Value)) << Null) + << ((Assign ^ ("drop " + it_name)) << (Ident ^ it_name) << Null); + }, - T(Func)[Func] << ( - T(Ident)[Ident] * - T(Params)[Params] * - (T(Body)[Body] << Any++[Block])* - End) >> - [](auto &_) { - auto func_head = expr_header(_(Func)); + T(Func)[Func] + << (T(Ident)[Ident] * T(Params)[Params] * + (T(Body)[Body] << Any++[Block]) * End) >> + [](auto& _) { + auto func_head = expr_header(_(Func)); - // Function setup - Node body = Body; - Node args = _(Params); - for (auto it = args->begin(); it != args->end(); it++) { - body << create_from(StoreFrame, *it); - } - body << create_print(_(Func), func_head + " (Enter)"); + // Function setup + Node body = Body; + Node args = _(Params); + for (auto it = args->begin(); it != args->end(); it++) + { + body << create_from(StoreFrame, *it); + } + body << create_print(_(Func), func_head + " (Enter)"); - // Function body - auto block = _[Block]; - for (auto stmt : block) { - if (stmt == ReturnValue) { - body << (create_from(Assign, stmt) << (Ident ^ "return") << stmt->at(0)); - body << (LoadFrame ^ "return"); - body << create_from(ReturnValue, stmt); - } else if (stmt == Return) { - body << create_print(stmt); - body << stmt; - } else { - body << stmt; - } + // Function body + auto block = _[Block]; + for (auto stmt : block) + { + if (stmt == ReturnValue) + { + body + << (create_from(Assign, stmt) + << (Ident ^ "return") << stmt->at(0)); + body << (LoadFrame ^ "return"); + body << create_from(ReturnValue, stmt); + } + else if (stmt == Return) + { + body << create_print(stmt); + body << stmt; } - body << create_print(_(Func), func_head + " (Exit)"); + else + { + body << stmt; + } + } + body << create_print(_(Func), func_head + " (Exit)"); - // Function cleanup - return Seq - << (CreateObject << (Func << (Compile << body))) - << (StoreFrame ^ _(Ident)) - << create_print(_(Func), func_head); - }, - } - }; + // Function cleanup + return Seq << (CreateObject << (Func << (Compile << body))) + << (StoreFrame ^ _(Ident)) + << create_print(_(Func), func_head); + }, + }}; } diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index d89c99b..38bb55d 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -1,133 +1,110 @@ #include "../lang.h" -PassDef grouping() { +PassDef grouping() +{ PassDef p{ - "grouping", - verona::wf::grouping, - dir::bottomup, - { - // Normalize so that all expressions are inside bodies and blocks. - T(File) << (--T(Body) * Any++[File]) >> - [](auto& _) { return File << (Body << (Block << _[File])); }, + "grouping", + verona::wf::grouping, + dir::bottomup, + { + // Normalize so that all expressions are inside bodies and blocks. + T(File) << (--T(Body) * Any++[File]) >> + [](auto& _) { return File << (Body << (Block << _[File])); }, - In(Group) * LV[Lhs] * (T(Lookup)[Lookup] << (T(Group) << KEY[Rhs])) >> - [](auto &_) { return Lookup << _[Lhs] << _(Rhs); }, + In(Group) * LV[Lhs] * (T(Lookup)[Lookup] << (T(Group) << KEY[Rhs])) >> + [](auto& _) { return Lookup << _[Lhs] << _(Rhs); }, - T(Group) << ((T(Region)[Region] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Region)->extend(_(Ident)->location()); - return _(Region) << _(Ident); - }, + T(Group) << ((T(Region)[Region] << End) * T(Ident)[Ident] * End) >> + [](auto& _) { + _(Region)->extend(_(Ident)->location()); + return _(Region) << _(Ident); + }, - T(Group) << ((T(Freeze)[Freeze] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Freeze)->extend(_(Ident)->location()); - return _(Freeze) << _(Ident); - }, + T(Group) << ((T(Freeze)[Freeze] << End) * T(Ident)[Ident] * End) >> + [](auto& _) { + _(Freeze)->extend(_(Ident)->location()); + return _(Freeze) << _(Ident); + }, - T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >> - [](auto &_) { - return Assign << _(Lhs) << Null; - }, - // function(arg, arg) - --In(Func) * ( - T(Group)[Group] << ( - (T(Ident)[Ident]) * - (T(Parens)[Parens] << (~T(List)[List])) * - End)) >> - [](auto &_) { - auto list = _(List); - if (!list) { - list = create_from(List, _(Parens)); - } + T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >> + [](auto& _) { return Assign << _(Lhs) << Null; }, + // function(arg, arg) + --In(Func) * + (T(Group)[Group] + << ((T(Ident)[Ident]) * (T(Parens)[Parens] << (~T(List)[List])) * + End)) >> + [](auto& _) { + auto list = _(List); + if (!list) + { + list = create_from(List, _(Parens)); + } - return create_from(Call, _(Group)) - << _(Ident) - << list; - }, + return create_from(Call, _(Group)) << _(Ident) << list; + }, - T(Group) << ((T(Create)[Create] << End) * T(Ident)[Ident] * End) >> - [](auto &_) { - _(Create)->extend(_(Ident)->location()); - return Group << (_(Create) << _(Ident)); - }, + T(Group) << ((T(Create)[Create] << End) * T(Ident)[Ident] * End) >> + [](auto& _) { + _(Create)->extend(_(Ident)->location()); + return Group << (_(Create) << _(Ident)); + }, - T(Assign) << ((T(Group) << LV[Lhs] * End) * - ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> - [](auto &_) { return Assign << _[Lhs] << _[Rhs]; }, - T(Eq) << ((T(Group) << CMP_V[Lhs] * End) * - (T(Group) << CMP_V[Rhs] * End) * End) >> - [](auto &_) { return Eq << _[Lhs] << _[Rhs]; }, + T(Assign) + << ((T(Group) << LV[Lhs] * End) * + ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> + [](auto& _) { return Assign << _[Lhs] << _[Rhs]; }, + T(Eq) + << ((T(Group) << CMP_V[Lhs] * End) * (T(Group) << CMP_V[Rhs] * End) * + End) >> + [](auto& _) { return Eq << _[Lhs] << _[Rhs]; }, - (T(If) << (T(Group) * T(Eq)[Eq] * (T(Group) << T(Block)[Block]))) >> - [](auto &_) { - return If << _(Eq) << _(Block); - }, - (T(Else) << (T(Group) * (T(Group) << T(Block)[Block]))) >> - [](auto &_) { - return Else << _(Block); - }, - (T(If)[If] << (T(Eq) * T(Block) * End)) * (T(Else) << T(Block)[Block]) >> - [](auto &_) { - return _(If) << _(Block); - }, - (T(If)[If] << (T(Eq) * T(Block) * End)) * (--T(Else)) >> - [](auto &_) { - // This adds an empty else block, if no else was written - return _(If) << Block; - }, + (T(If) << (T(Group) * T(Eq)[Eq] * (T(Group) << T(Block)[Block]))) >> + [](auto& _) { return If << _(Eq) << _(Block); }, + (T(Else) << (T(Group) * (T(Group) << T(Block)[Block]))) >> + [](auto& _) { return Else << _(Block); }, + (T(If)[If] << (T(Eq) * T(Block) * End)) * (T(Else) << T(Block)[Block]) >> + [](auto& _) { return _(If) << _(Block); }, + (T(If)[If] << (T(Eq) * T(Block) * End)) * (--T(Else)) >> + [](auto& _) { + // This adds an empty else block, if no else was written + return _(If) << Block; + }, - In(List) * (T(Group) << (RV[Rhs] * End)) >> [](auto &_) { - return _(Rhs); - }, + In(List) * (T(Group) << (RV[Rhs] * End)) >> + [](auto& _) { return _(Rhs); }, - T(For)[For] << ( - (T(Group)) * + T(For)[For] + << ((T(Group)) * (T(List) << (T(Ident)[Key] * T(Ident)[Value] * End)) * (T(Group) << (LV[Op] * End)) * - (T(Group) << (T(Block)[Block] * End)) * - End) >> - [](auto &_) { - // This function only has a block for now, as a lowering pass still needs to - // do some modifications until it's a "full" body. - return create_from(For, _(For)) - << _(Key) - << _(Value) - << _(Op) - << _(Block); - }, - - T(Func)[Func] << ( - (T(Group) << End) * - (T(Group) << ( - (T(Ident)[Ident]) * - (T(Parens)[Parens] << (~(T(List) << T(Ident)++[List]))) * - End)) * - (T(Group) << T(Block)[Block]) * - End) >> - [](auto &_) { - return create_from(Func, _(Func)) - << _(Ident) - << (create_from(Params, _(Parens)) << _[List]) - << (Body << _(Block)); - }, + (T(Group) << (T(Block)[Block] * End)) * End) >> + [](auto& _) { + // This function only has a block for now, as a lowering pass still + // needs to do some modifications until it's a "full" body. + return create_from(For, _(For)) + << _(Key) << _(Value) << _(Op) << _(Block); + }, - T(Return)[Return] << ( - (T(Group) << End) * - End) >> - [](auto &_) { - return create_from(Return, _(Return)); - }, - T(Return)[Return] << ( - (T(Group) << End) * - (T(Group) << (RV[Rhs] * End)) * - End) >> - [](auto &_) { - return create_from(ReturnValue, _(Return)) << _(Rhs); - }, + T(Func)[Func] + << ((T(Group) << End) * + (T(Group) + << ((T(Ident)[Ident]) * + (T(Parens)[Parens] << (~(T(List) << T(Ident)++[List]))) * + End)) * + (T(Group) << T(Block)[Block]) * End) >> + [](auto& _) { + return create_from(Func, _(Func)) + << _(Ident) << (create_from(Params, _(Parens)) << _[List]) + << (Body << _(Block)); + }, - }}; + T(Return)[Return] << ((T(Group) << End) * End) >> + [](auto& _) { return create_from(Return, _(Return)); }, + T(Return)[Return] + << ((T(Group) << End) * (T(Group) << (RV[Rhs] * End)) * End) >> + [](auto& _) { return create_from(ReturnValue, _(Return)) << _(Rhs); }, + }}; return p; } diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index 13cc771..3cc5090 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -1,35 +1,31 @@ #include "../lang.h" -namespace verona::wf { -using namespace trieste::wf; - -inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze | Drop | Null | String | Create | Parens; -inline const auto parse_groups = Group | Assign | If | Else | Block | For | Func | List | Return; - -inline const auto parser = - (Top <<= File) - | (File <<= parse_groups++) - | (Assign <<= Group++) - | (If <<= Group * Eq * Group) - | (Else <<= Group * Group) - | (Group <<= (parse_tokens | Block | List)++) - | (Block <<= (parse_tokens | parse_groups)++) - | (Eq <<= Group * Group) - | (Lookup <<= Group) - | (For <<= Group * List * Group * Group) - | (List <<= Group++) - | (Parens <<= (Group | List)++) - | (Func <<= Group * Group * Group) - | (Return <<= Group++) - ; +namespace verona::wf +{ + using namespace trieste::wf; + + inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze | + Drop | Null | String | Create | Parens; + inline const auto parse_groups = + Group | Assign | If | Else | Block | For | Func | List | Return; + + inline const auto parser = (Top <<= File) | (File <<= parse_groups++) | + (Assign <<= Group++) | (If <<= Group * Eq * Group) | + (Else <<= Group * Group) | (Group <<= (parse_tokens | Block | List)++) | + (Block <<= (parse_tokens | parse_groups)++) | (Eq <<= Group * Group) | + (Lookup <<= Group) | (For <<= Group * List * Group * Group) | + (List <<= Group++) | (Parens <<= (Group | List)++) | + (Func <<= Group * Group * Group) | (Return <<= Group++); } -struct Indent { +struct Indent +{ size_t indent; Token toc; }; -trieste::Parse parser() { +trieste::Parse parser() +{ Parse p{depth::file, verona::wf::parser}; auto indent = std::make_shared>(); @@ -38,33 +34,39 @@ trieste::Parse parser() { auto update_indent = [indent](detail::Make& m, size_t this_indent) { m.term({Assign, Return}); - if (this_indent > indent->back().indent) { + if (this_indent > indent->back().indent) + { std::cout << "this_indent " << this_indent << std::endl; - std::cout << "indent->back().indent " << indent->back().indent << std::endl; + std::cout << "indent->back().indent " << indent->back().indent + << std::endl; m.error("unexpected indention"); } - while (this_indent < indent->back().indent) { + while (this_indent < indent->back().indent) + { m.term({Block, Group, indent->back().toc}); indent->pop_back(); } - if (this_indent != indent->back().indent) { + if (this_indent != indent->back().indent) + { m.error("unexpected indention"); } }; p("start", { - // Empty lines should be ignored - "[ \\t]*\\r?\\n" >> [](auto &) {}, + // Empty lines should be ignored + "[ \\t]*\\r?\\n" >> [](auto&) {}, - // Line comment - "(?:#[^\\n]*)" >> [](auto &) {}, + // Line comment + "(?:#[^\\n]*)" >> [](auto&) {}, - // Indention - " +" >> [update_indent](auto &m) { - if (m.match().len % TAB_SIZE != 0) { + // Indention + " +" >> + [update_indent](auto& m) { + if (m.match().len % TAB_SIZE != 0) + { m.error("unexpected indention"); } auto this_indent = m.match().len / TAB_SIZE; @@ -72,71 +74,67 @@ trieste::Parse parser() { m.mode("contents"); }, - "\\t*" >> [update_indent](auto &m) { + "\\t*" >> + [update_indent](auto& m) { auto this_indent = m.match().len; update_indent(m, this_indent); m.mode("contents"); }, }); - p( - "contents", + p("contents", { - // Indentation - "\\r?\\n" >> [](auto &m) { - m.mode("start"); - }, + // Indentation + "\\r?\\n" >> [](auto& m) { m.mode("start"); }, - "[[:blank:]]+" >> [](auto &) {}, + "[[:blank:]]+" >> [](auto&) {}, - // Line comment - "(?:#[^\\n\\r]*)" >> [](auto &) {}, + // Line comment + "(?:#[^\\n\\r]*)" >> [](auto&) {}, - "def" >> [](auto &m) { - m.seq(Func); - }, - "\\(" >> [](auto &m) { - m.push(Parens); - }, - "\\)" >> [](auto &m) { + "def" >> [](auto& m) { m.seq(Func); }, + "\\(" >> [](auto& m) { m.push(Parens); }, + "\\)" >> + [](auto& m) { m.term({List, Parens}); m.extend(Parens); }, - "return" >> [](auto &m) { - m.seq(Return); - }, + "return" >> [](auto& m) { m.seq(Return); }, - "for" >> [](auto &m) { - m.seq(For); - }, - "in" >> [](auto &m) { + "for" >> [](auto& m) { m.seq(For); }, + "in" >> + [](auto& m) { // In should always be in a list from the identifiers. m.term({List}); }, - "," >> [](auto &m) { - m.seq(List); - }, + "," >> [](auto& m) { m.seq(List); }, - "if" >> [](auto &m) { - m.seq(If); - }, - "else" >> [](auto &m) { - m.seq(Else); - }, - ":" >> [indent](auto &m) { + "if" >> [](auto& m) { m.seq(If); }, + "else" >> [](auto& m) { m.seq(Else); }, + ":" >> + [indent](auto& m) { // Exit conditionals expressions. m.term({Eq}); Token toc = Empty; - if (m.in(If)) { + if (m.in(If)) + { toc = If; - } else if (m.in(Else)) { + } + else if (m.in(Else)) + { toc = Else; - } else if (m.in(For)) { + } + else if (m.in(For)) + { toc = For; - } else if (m.in(Func)) { + } + else if (m.in(Func)) + { toc = Func; - } else { + } + else + { m.error("unexpected colon"); return; } @@ -146,38 +144,34 @@ trieste::Parse parser() { auto next_indent = current_indent + 1; indent->push_back({next_indent, toc}); - if (m.in(Group)) { + if (m.in(Group)) + { m.pop(Group); } m.push(Block); }, - "drop" >> [](auto &m) { m.add(Drop); }, - "create" >> [](auto &m) { m.add(Create); }, - "freeze" >> [](auto &m) { m.add(Freeze); }, - "region" >> [](auto &m) { m.add(Region); }, - "None" >> [](auto &m) { m.add(Null); }, - "[0-9A-Za-z_]+" >> [](auto &m) { m.add(Ident); }, - "\\[" >> [](auto &m) { - m.push(Lookup); - }, - "\\]" >> [](auto &m) { - m.term({Lookup}); - }, - "\\.([0-9A-Za-z_]+)" >> [](auto &m) { + "drop" >> [](auto& m) { m.add(Drop); }, + "create" >> [](auto& m) { m.add(Create); }, + "freeze" >> [](auto& m) { m.add(Freeze); }, + "region" >> [](auto& m) { m.add(Region); }, + "None" >> [](auto& m) { m.add(Null); }, + "[0-9A-Za-z_]+" >> [](auto& m) { m.add(Ident); }, + "\\[" >> [](auto& m) { m.push(Lookup); }, + "\\]" >> [](auto& m) { m.term({Lookup}); }, + "\\.([0-9A-Za-z_]+)" >> + [](auto& m) { m.push(Lookup); m.add(String, 1); m.term({Lookup}); }, - "\"([^\\n\"]+)\"" >> [](auto &m) { m.add(String, 1); }, - "==" >> [](auto &m) { m.seq(Eq); }, - "=" >> [](auto &m) { m.seq(Assign); }, - "{}" >> [](auto &m) { m.add(Empty); }, + "\"([^\\n\"]+)\"" >> [](auto& m) { m.add(String, 1); }, + "==" >> [](auto& m) { m.seq(Eq); }, + "=" >> [](auto& m) { m.seq(Assign); }, + "{}" >> [](auto& m) { m.add(Empty); }, }); - p.done([update_indent](auto &m) { - update_indent(m, 0); - }); + p.done([update_indent](auto& m) { update_indent(m, 0); }); return p; } diff --git a/src/main.cc b/src/main.cc index 47fa1e8..4a22e1d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -2,9 +2,9 @@ * This file contains a model implementation of region tracking. */ -int load_trieste(int argc, char **argv); +int load_trieste(int argc, char** argv); -int main(int argc, char **argv) +int main(int argc, char** argv) { return load_trieste(argc, argv); } diff --git a/src/rt/env.h b/src/rt/env.h index 6aa35ae..1a2f01e 100644 --- a/src/rt/env.h +++ b/src/rt/env.h @@ -1,103 +1,135 @@ #include "objects/dyn_object.h" #include "rt.h" -namespace rt::env { - -class PrototypeObject : public objects::DynObject { - std::string name; -public: - PrototypeObject(std::string name_, objects::DynObject *prototype = nullptr) : objects::DynObject(prototype, true), name(name_) {} - - std::string get_name() { - std::stringstream stream; - stream << "[" << name << "]"; - return stream.str(); - } -}; - -PrototypeObject framePrototypeObject{"Frame"}; - -class FrameObject : public objects::DynObject { - FrameObject() : objects::DynObject(&framePrototypeObject, true) {} -public: - FrameObject(objects::DynObject* parent_frame) : objects::DynObject(&framePrototypeObject) { - if (parent_frame) { - auto old_value = this->set(objects::ParentField, parent_frame); - add_reference(this, parent_frame); - assert(!old_value); +namespace rt::env +{ + + class PrototypeObject : public objects::DynObject + { + std::string name; + + public: + PrototypeObject(std::string name_, objects::DynObject* prototype = nullptr) + : objects::DynObject(prototype, true), name(name_) + {} + + std::string get_name() + { + std::stringstream stream; + stream << "[" << name << "]"; + return stream.str(); } - } + }; - static FrameObject* create_first_stack() { - return new FrameObject(); - } -}; + PrototypeObject framePrototypeObject{"Frame"}; -PrototypeObject funcPrototypeObject{"Function"}; -PrototypeObject bytecodeFuncPrototypeObject{"BytecodeFunction", &funcPrototypeObject}; + class FrameObject : public objects::DynObject + { + FrameObject() : objects::DynObject(&framePrototypeObject, true) {} -class FuncObject : public objects::DynObject { -public: - FuncObject(objects::DynObject* prototype_, bool global = false) : objects::DynObject(prototype_, global) {} -}; + public: + FrameObject(objects::DynObject* parent_frame) + : objects::DynObject(&framePrototypeObject) + { + if (parent_frame) + { + auto old_value = this->set(objects::ParentField, parent_frame); + add_reference(this, parent_frame); + assert(!old_value); + } + } -class BytecodeFuncObject : public FuncObject { - verona::interpreter::Bytecode *body; -public: - BytecodeFuncObject(verona::interpreter::Bytecode *body_) : FuncObject(&bytecodeFuncPrototypeObject), body(body_) {} - ~BytecodeFuncObject() { - verona::interpreter::delete_bytecode(this->body); - this->body = nullptr; - } + static FrameObject* create_first_stack() + { + return new FrameObject(); + } + }; - verona::interpreter::Bytecode* get_bytecode() { - return this->body; - } -}; + PrototypeObject funcPrototypeObject{"Function"}; + PrototypeObject bytecodeFuncPrototypeObject{ + "BytecodeFunction", &funcPrototypeObject}; + class FuncObject : public objects::DynObject + { + public: + FuncObject(objects::DynObject* prototype_, bool global = false) + : objects::DynObject(prototype_, global) + {} + }; -PrototypeObject stringPrototypeObject{"String"}; + class BytecodeFuncObject : public FuncObject + { + verona::interpreter::Bytecode* body; -class StringObject : public objects::DynObject { - std::string value; + public: + BytecodeFuncObject(verona::interpreter::Bytecode* body_) + : FuncObject(&bytecodeFuncPrototypeObject), body(body_) + {} + ~BytecodeFuncObject() + { + verona::interpreter::delete_bytecode(this->body); + this->body = nullptr; + } -public: - StringObject(std::string value_, bool global = false) - : objects::DynObject(&stringPrototypeObject, global), value(value_) {} + verona::interpreter::Bytecode* get_bytecode() + { + return this->body; + } + }; - std::string get_name() { - std::stringstream stream; - stream << "\"" << value << "\""; - return stream.str(); - } + PrototypeObject stringPrototypeObject{"String"}; - std::string as_key() { - return value; - } + class StringObject : public objects::DynObject + { + std::string value; - objects::DynObject* is_primitive() { - return this; - } -}; + public: + StringObject(std::string value_, bool global = false) + : objects::DynObject(&stringPrototypeObject, global), value(value_) + {} + + std::string get_name() + { + std::stringstream stream; + stream << "\"" << value << "\""; + return stream.str(); + } -StringObject TrueObject{"True", true}; -StringObject FalseObject{"False", true}; + std::string as_key() + { + return value; + } -// The prototype object for iterators -// TODO put some stuff in here? -PrototypeObject keyIterPrototypeObject{"KeyIterator"}; + objects::DynObject* is_primitive() + { + return this; + } + }; -class KeyIterObject : public objects::DynObject { - std::map::iterator iter; - std::map::iterator iter_end; + StringObject TrueObject{"True", true}; + StringObject FalseObject{"False", true}; - public: - KeyIterObject(std::map &fields) - : objects::DynObject(&keyIterPrototypeObject), iter(fields.begin()), iter_end(fields.end()) {} + // The prototype object for iterators + // TODO put some stuff in here? + PrototypeObject keyIterPrototypeObject{"KeyIterator"}; - objects::DynObject* iter_next() { - objects::DynObject *obj = nullptr; - if (this->iter != this->iter_end) { + class KeyIterObject : public objects::DynObject + { + std::map::iterator iter; + std::map::iterator iter_end; + + public: + KeyIterObject(std::map& fields) + : objects::DynObject(&keyIterPrototypeObject), + iter(fields.begin()), + iter_end(fields.end()) + {} + + objects::DynObject* iter_next() + { + objects::DynObject* obj = nullptr; + if (this->iter != this->iter_end) + { obj = make_str(this->iter->first); this->iter++; } @@ -105,12 +137,14 @@ class KeyIterObject : public objects::DynObject { return obj; } - std::string get_name() { + std::string get_name() + { return ""; } - objects::DynObject* is_primitive() { + objects::DynObject* is_primitive() + { return this; } -}; + }; } // namespace rt::env diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index 86ad5f4..5306e53 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -1,278 +1,312 @@ #pragma once +#include "../../lang/interpreter.h" +#include "../rt.h" +#include "region.h" +#include "visit.h" + #include #include -#include #include #include #include #include +#include #include #include #include -#include "visit.h" -#include "region.h" -#include "../rt.h" -#include "../../lang/interpreter.h" - -namespace rt::objects { -constexpr uintptr_t ImmutableTag{1}; -const std::string PrototypeField{"__proto__"}; -const std::string ParentField{"__parent__"}; - -// Representation of objects -class DynObject { - friend class Reference; - friend objects::DynObject* rt::make_iter(objects::DynObject *obj); - friend void rt::ui::mermaid(std::vector &roots, std::ostream &out); - friend void destruct(DynObject *obj); - friend void dealloc(DynObject *obj); - template - friend void visit(Edge, Pre, Post); - - thread_local static RegionPointer local_region; - - // TODO: Not concurrency safe - inline static size_t count{0}; - // TODO: Not concurrency safe - inline static std::set all_objects{}; - - size_t rc{1}; - RegionPointer region{nullptr}; - DynObject* prototype{nullptr}; +namespace rt::objects +{ + constexpr uintptr_t ImmutableTag{1}; + const std::string PrototypeField{"__proto__"}; + const std::string ParentField{"__parent__"}; - std::map fields{}; + // Representation of objects + class DynObject + { + friend class Reference; + friend objects::DynObject* rt::make_iter(objects::DynObject* obj); + friend void + rt::ui::mermaid(std::vector& roots, std::ostream& out); + friend void destruct(DynObject* obj); + friend void dealloc(DynObject* obj); + template + friend void visit(Edge, Pre, Post); + + thread_local static RegionPointer local_region; + + // TODO: Not concurrency safe + inline static size_t count{0}; + // TODO: Not concurrency safe + inline static std::set all_objects{}; + + size_t rc{1}; + RegionPointer region{nullptr}; + DynObject* prototype{nullptr}; + + std::map fields{}; + + static Region* get_region(DynObject* obj) + { + if ((obj == nullptr) || obj->is_immutable()) + return nullptr; + return obj->region.get_ptr(); + } - static Region *get_region(DynObject *obj) { - if ((obj == nullptr) || obj->is_immutable()) - return nullptr; - return obj->region.get_ptr(); - } + bool is_local_object() + { + return region.get_ptr() == get_local_region(); + } - bool is_local_object() { return region.get_ptr() == get_local_region(); } + static void remove_region_reference(Region* src, Region* target) + { + if (src == target) + { + std::cout << "Same region, no need to do anything" << std::endl; + return; + } - static void remove_region_reference(Region *src, Region *target) { - if (src == target) { - std::cout << "Same region, no need to do anything" << std::endl; - return; - } + // Handle immutable case + if (target == nullptr) + return; - // Handle immutable case - if (target == nullptr) - return; + if (src == get_local_region()) + { + Region::dec_lrc(target); + return; + } - if (src == get_local_region()) { - Region::dec_lrc(target); + assert(target->parent == src); + Region::dec_prc(target); return; } - assert(target->parent == src); - Region::dec_prc(target); - return; - } + static void add_region_reference(Region* src_region, DynObject* target) + { + if (target->is_immutable()) + return; - static void add_region_reference(Region *src_region, DynObject *target) { - if (target->is_immutable()) - return; + auto target_region = get_region(target); + if (src_region == target_region) + return; - auto target_region = get_region(target); - if (src_region == target_region) - return; + if (src_region == get_local_region()) + { + Region::inc_lrc(target_region); + return; + } - if (src_region == get_local_region()) { - Region::inc_lrc(target_region); - return; - } + if (target_region == get_local_region()) + { + target->add_to_region(src_region); + return; + } - if (target_region == get_local_region()) { - target->add_to_region(src_region); - return; + Region::set_parent(target_region, src_region); } - Region::set_parent(target_region, src_region); - } + size_t change_rc(signed delta) + { + std::cout << "Change RC: " << get_name() << " " << rc << " + " << delta + << std::endl; + if (!is_immutable()) + { + assert(delta == 0 || rc != 0); + rc += delta; + // Check not underflowing. + assert(rc >> 62 == 0); + return rc; + } - size_t change_rc(signed delta) { - std::cout << "Change RC: " << get_name() << " " << rc << " + " << delta - << std::endl; - if (!is_immutable()) { - assert(delta == 0 || rc != 0); - rc += delta; - // Check not underflowing. - assert(rc >> 62 == 0); - return rc; + // TODO Follow SCC chain to the root. + // Have to use atomic as this can be called from multiple threads. + return std::atomic_ref(rc).fetch_add(delta, std::memory_order_relaxed) + + delta; } - // TODO Follow SCC chain to the root. - // Have to use atomic as this can be called from multiple threads. - return std::atomic_ref(rc).fetch_add(delta, std::memory_order_relaxed) + - delta; - } - - void add_to_region(Region *r) { - size_t internal_references{0}; - size_t rc_of_added_objects{0}; - visit(this, [&](Edge e) { - auto obj = e.target; - if (obj == nullptr || obj->is_immutable()) + void add_to_region(Region* r) + { + size_t internal_references{0}; + size_t rc_of_added_objects{0}; + visit(this, [&](Edge e) { + auto obj = e.target; + if (obj == nullptr || obj->is_immutable()) + return false; + + if (obj->is_local_object()) + { + std::cout << "Adding object to region: " << obj->get_name() + << " rc = " << obj->rc << std::endl; + rc_of_added_objects += obj->rc; + internal_references++; + obj->region = {r}; + get_local_region()->objects.erase(obj); + r->objects.insert(obj); + return true; + } + + auto obj_region = get_region(obj); + if (obj_region == r) + { + std::cout << "Adding internal reference to object: " + << obj->get_name() << std::endl; + internal_references++; + return false; + } + + Region::set_parent(obj_region, r); + Region::dec_lrc(obj_region); return false; + }); + r->local_reference_count += rc_of_added_objects - internal_references; + + std::cout << "Added " << rc_of_added_objects - internal_references + << " to LRC of region" << std::endl; + std::cout << "Region LRC: " << r->local_reference_count << std::endl; + std::cout << "Internal references found: " << internal_references + << std::endl; + } - if (obj->is_local_object()) { - std::cout << "Adding object to region: " << obj->get_name() - << " rc = " << obj->rc << std::endl; - rc_of_added_objects += obj->rc; - internal_references++; - obj->region = {r}; - get_local_region()->objects.erase(obj); - r->objects.insert(obj); - return true; + public: + // prototype is borrowed, the caller does not need to provide an RC. + DynObject(DynObject* prototype_ = nullptr, bool global = false) + : prototype(prototype_) + { + if (!global) + { + count++; + all_objects.insert(this); + auto local_region = get_local_region(); + region = local_region; + local_region->objects.insert(this); } + if (prototype != nullptr) + prototype->change_rc(1); + std::cout << "Allocate: " << get_name() << std::endl; + } - auto obj_region = get_region(obj); - if (obj_region == r) { - std::cout << "Adding internal reference to object: " << obj->get_name() - << std::endl; - internal_references++; - return false; + // TODO This should use prototype lookup for the destructor. + virtual ~DynObject() + { + // Erase from set of all objects, and remove count if found. + auto matched = all_objects.erase(this); + count -= matched; + + // If it wasn't in the all_objects set, then it was a special object + // that we don't track for leaks, otherwise, we need to check if the + // RC is zero. + if (change_rc(0) != 0 && matched != 0) + { + ui::error("Object still has references"); } - Region::set_parent(obj_region, r); - Region::dec_lrc(obj_region); - return false; - }); - r->local_reference_count += rc_of_added_objects - internal_references; - - std::cout << "Added " << rc_of_added_objects - internal_references - << " to LRC of region" << std::endl; - std::cout << "Region LRC: " << r->local_reference_count << std::endl; - std::cout << "Internal references found: " << internal_references - << std::endl; - } + auto r = get_region(this); + if (!is_immutable() && r != nullptr) + r->objects.erase(this); -public: - // prototype is borrowed, the caller does not need to provide an RC. - DynObject(DynObject* prototype_ = nullptr, bool global = false) : prototype(prototype_) { - if (!global) { - count++; - all_objects.insert(this); - auto local_region = get_local_region(); - region = local_region; - local_region->objects.insert(this); + std::cout << "Deallocate: " << get_name() << std::endl; } - if (prototype != nullptr) - prototype->change_rc(1); - std::cout << "Allocate: " << get_name() << std::endl; - } - // TODO This should use prototype lookup for the destructor. - virtual ~DynObject() { - // Erase from set of all objects, and remove count if found. - auto matched = all_objects.erase(this); - count -= matched; - - // If it wasn't in the all_objects set, then it was a special object - // that we don't track for leaks, otherwise, we need to check if the - // RC is zero. - if (change_rc(0) != 0 && matched != 0) { - ui::error("Object still has references"); + /// @brief The string representation of this value to + /// TODO remove virtual once we have primitive functions. + virtual std::string get_name() + { + std::stringstream stream; + stream << this; + return stream.str(); } - auto r = get_region(this); - if (!is_immutable() && r != nullptr) - r->objects.erase(this); - - std::cout << "Deallocate: " << get_name() << std::endl; - } - - /// @brief The string representation of this value to - /// TODO remove virtual once we have primitive functions. - virtual std::string get_name() - { - std::stringstream stream; - stream << this; - return stream.str(); - } - - /// TODO remove virtual once we have primitive functions. - virtual DynObject* is_primitive() { - return nullptr; - } - - void freeze() { - // TODO SCC algorithm - visit(this, [](Edge e) { - auto obj = e.target; - if (obj->is_immutable()) - return false; - - auto r = get_region(obj); - if (r != nullptr) - { - get_region(obj)->objects.erase(obj); - } - obj->region.set_tag(ImmutableTag); - return true; - }); - } - + /// TODO remove virtual once we have primitive functions. + virtual DynObject* is_primitive() + { + return nullptr; + } - bool is_immutable() { return region.get_tag() == ImmutableTag; } + void freeze() + { + // TODO SCC algorithm + visit(this, [](Edge e) { + auto obj = e.target; + if (obj->is_immutable()) + return false; + + auto r = get_region(obj); + if (r != nullptr) + { + get_region(obj)->objects.erase(obj); + } + obj->region.set_tag(ImmutableTag); + return true; + }); + } - [[nodiscard]] DynObject *get(std::string name) { - auto result = fields.find(name); - if (result != fields.end()) - return result->second; + bool is_immutable() + { + return region.get_tag() == ImmutableTag; + } - if (name == PrototypeField) - return prototype; + [[nodiscard]] DynObject* get(std::string name) + { + auto result = fields.find(name); + if (result != fields.end()) + return result->second; - // Search the prototype chain. - // TODO make this iterative. - if (prototype != nullptr) - return prototype->get(name); + if (name == PrototypeField) + return prototype; - // No field or prototype chain found. - return nullptr; - } + // Search the prototype chain. + // TODO make this iterative. + if (prototype != nullptr) + return prototype->get(name); - [[nodiscard]] DynObject *set(std::string name, DynObject *value) { - if (is_immutable()) { - ui::error("Cannot mutate immutable object"); + // No field or prototype chain found. + return nullptr; } - DynObject *old = fields[name]; - fields[name] = value; - return old; - } - // The caller must provide an rc for value. - [[nodiscard]] DynObject* set_prototype(DynObject* value) { - if (is_immutable()) { - ui::error("Cannot mutate immutable object"); + [[nodiscard]] DynObject* set(std::string name, DynObject* value) + { + if (is_immutable()) + { + ui::error("Cannot mutate immutable object"); + } + DynObject* old = fields[name]; + fields[name] = value; + return old; } - DynObject* old = prototype; - prototype = value; - return old; - } - DynObject* get_prototype() { - return prototype; - } + // The caller must provide an rc for value. + [[nodiscard]] DynObject* set_prototype(DynObject* value) + { + if (is_immutable()) + { + ui::error("Cannot mutate immutable object"); + } + DynObject* old = prototype; + prototype = value; + return old; + } + DynObject* get_prototype() + { + return prototype; + } - static void add_reference(DynObject *src, DynObject *target) { - if (target == nullptr) - return; + static void add_reference(DynObject* src, DynObject* target) + { + if (target == nullptr) + return; - target->change_rc(1); + target->change_rc(1); - auto src_region = get_region(src); - add_region_reference(src_region, target); - } + auto src_region = get_region(src); + add_region_reference(src_region, target); + } - static void remove_reference(DynObject *src_initial, - DynObject *old_dst_initial) { - visit( + static void + remove_reference(DynObject* src_initial, DynObject* old_dst_initial) + { + visit( {src_initial, "", old_dst_initial}, [&](Edge e) { if (e.target == nullptr) @@ -285,127 +319,149 @@ class DynObject { remove_region_reference(get_region(e.src), get_region(e.target)); return result; }, - [&](DynObject *obj) { delete obj; }); + [&](DynObject* obj) { delete obj; }); - Region::collect(); - } - - static void move_reference(DynObject *src, DynObject *dst, - DynObject *target) { - if (target == nullptr || target->is_immutable()) - return; + Region::collect(); + } - auto src_region = get_region(src); - auto dst_region = get_region(dst); + static void + move_reference(DynObject* src, DynObject* dst, DynObject* target) + { + if (target == nullptr || target->is_immutable()) + return; - if (src_region == dst_region) - return; + auto src_region = get_region(src); + auto dst_region = get_region(dst); - auto target_region = get_region(target); + if (src_region == dst_region) + return; - add_region_reference(dst_region, target); - // Note that target_region and get_region(target) are not necessarily the same. - remove_region_reference(src_region, target_region); - } + auto target_region = get_region(target); - void create_region() { - Region *r = new Region(); - add_to_region(r); - // Add root reference as external. - r->local_reference_count++; - } + add_region_reference(dst_region, target); + // Note that target_region and get_region(target) are not necessarily the + // same. + remove_region_reference(src_region, target_region); + } - static size_t get_count() { return count; } + void create_region() + { + Region* r = new Region(); + add_to_region(r); + // Add root reference as external. + r->local_reference_count++; + } - static Region *get_local_region() { - return local_region; - } + static size_t get_count() + { + return count; + } - static std::set get_objects() { return all_objects; } -}; + static Region* get_local_region() + { + return local_region; + } -inline void destruct(DynObject *obj) { - // Called from the region destructor. - // Remove all references to other objects. - // If in the same region, then just remove the RC, but don't try to collect - // as the whole region is being torndown including any potential cycles. - auto same_region = [](DynObject *src, DynObject *target) { - return DynObject::get_region(src) == DynObject::get_region(target); + static std::set get_objects() + { + return all_objects; + } }; - for (auto &[key, field] : obj->fields) { - if (field == nullptr) - continue; - if (same_region(obj,field)) { - // Same region just remove the rc, but don't try to collect. - field->change_rc(-1); - continue; + + inline void destruct(DynObject* obj) + { + // Called from the region destructor. + // Remove all references to other objects. + // If in the same region, then just remove the RC, but don't try to collect + // as the whole region is being torndown including any potential cycles. + auto same_region = [](DynObject* src, DynObject* target) { + return DynObject::get_region(src) == DynObject::get_region(target); + }; + for (auto& [key, field] : obj->fields) + { + if (field == nullptr) + continue; + if (same_region(obj, field)) + { + // Same region just remove the rc, but don't try to collect. + field->change_rc(-1); + continue; + } + + auto old_value = obj->set(key, nullptr); + remove_reference(obj, old_value); } - auto old_value = obj->set(key, nullptr); - remove_reference(obj, old_value); + if (same_region(obj, obj->prototype)) + { + obj->prototype->change_rc(-1); + } + else + { + auto old_value = obj->set_prototype(nullptr); + remove_reference(obj, old_value); + } } - if (same_region(obj, obj->prototype)) { - obj->prototype->change_rc(-1); - } else { - auto old_value = obj->set_prototype(nullptr); - remove_reference(obj, old_value); + inline void dealloc(DynObject* obj) + { + // Called from the region destructor. + // So remove from region if in one. + // This ensures we don't try to remove it from the set that is being + // iterated. + obj->region = nullptr; + delete obj; } -} -inline void dealloc(DynObject *obj) { - // Called from the region destructor. - // So remove from region if in one. - // This ensures we don't try to remove it from the set that is being iterated. - obj->region = nullptr; - delete obj; -} - -template -inline void visit(Edge e, Pre pre, Post post) { - if (!pre(e)) - return; + template + inline void visit(Edge e, Pre pre, Post post) + { + if (!pre(e)) + return; - constexpr bool HasPost = !std::is_same_v; - constexpr uintptr_t POST{1}; + constexpr bool HasPost = !std::is_same_v; + constexpr uintptr_t POST{1}; - std::vector, std::string>> stack; + std::vector, std::string>> stack; - auto visit_object = [&](DynObject *obj) { - if (obj == nullptr) - return; - if constexpr (HasPost) - stack.push_back({{obj, POST}, ""}); - // TODO This will need to depend on the type of object. - for (auto &[key, field] : obj->fields) - stack.push_back({obj, key}); - if (obj->prototype != nullptr) - stack.push_back({obj, PrototypeField}); - }; + auto visit_object = [&](DynObject* obj) { + if (obj == nullptr) + return; + if constexpr (HasPost) + stack.push_back({{obj, POST}, ""}); + // TODO This will need to depend on the type of object. + for (auto& [key, field] : obj->fields) + stack.push_back({obj, key}); + if (obj->prototype != nullptr) + stack.push_back({obj, PrototypeField}); + }; - visit_object(e.target); + visit_object(e.target); - while (!stack.empty()) { - auto [obj, key] = stack.back(); - auto obj_ptr = obj.get_ptr(); - stack.pop_back(); + while (!stack.empty()) + { + auto [obj, key] = stack.back(); + auto obj_ptr = obj.get_ptr(); + stack.pop_back(); - if (HasPost && obj.get_tag() == POST) { - post(obj_ptr); - continue; - } + if (HasPost && obj.get_tag() == POST) + { + post(obj_ptr); + continue; + } - DynObject *next = obj_ptr->get(key); - if (pre({obj_ptr, key, next})) { - visit_object(next); + DynObject* next = obj_ptr->get(key); + if (pre({obj_ptr, key, next})) + { + visit_object(next); + } } } -} -template -inline void visit(DynObject* start, Pre pre, Post post) -{ - visit(Edge{nullptr, "", start}, pre, post); -} + template + inline void visit(DynObject* start, Pre pre, Post post) + { + visit(Edge{nullptr, "", start}, pre, post); + } -} // namespace rtobjects +} // namespace rt::objects diff --git a/src/rt/objects/region.h b/src/rt/objects/region.h index 5fa3e45..cbb82e2 100644 --- a/src/rt/objects/region.h +++ b/src/rt/objects/region.h @@ -1,194 +1,210 @@ #pragma once -#include -#include - -#include "../ui.h" #include "../../utils/tagged_pointer.h" +#include "../ui.h" -namespace rt::objects { -class DynObject; - -void destruct(DynObject *obj); -void dealloc(DynObject *obj); - -// Represents the region of objects -struct Region { - - static inline thread_local std::vector to_collect{}; - // The local reference count is the number of references to objects in the region from local region. - // Using non-zero LRC for subregions ensures we cannot send a region if a - // subregion has references into it. Using zero and non-zero means we reduce - // the number of updates. - size_t local_reference_count{0}; - - // For nested regions, this points at the owning region. - // This guarantees that the regions for trees. - Region *parent{nullptr}; - - // The parent reference count is the number of references to the region from - // the parent region. In classic Verona we considered this as 0 or 1, but by - // tracking dynamically we can allow multiple references. - size_t parent_reference_count{0}; +#include +#include - // The number of direct subregions, whose LRC is non-zero - size_t sub_region_reference_count{0}; +namespace rt::objects +{ + class DynObject; - // The objects in this region. - // TODO: make this more efficient. - std::set objects{}; + void destruct(DynObject* obj); + void dealloc(DynObject* obj); - size_t combined_lrc() + // Represents the region of objects + struct Region { - return local_reference_count + sub_region_reference_count; - } - - static void action(Region *r) { - if ((r->local_reference_count == 0) && (r->parent == nullptr)) { - // TODO, this can be hooked to perform delayed operations like send. - // Needs to check for sub_region_reference_count for send, but not deallocate. + static inline thread_local std::vector to_collect{}; + // The local reference count is the number of references to objects in the + // region from local region. Using non-zero LRC for subregions ensures we + // cannot send a region if a subregion has references into it. Using zero + // and non-zero means we reduce the number of updates. + size_t local_reference_count{0}; + + // For nested regions, this points at the owning region. + // This guarantees that the regions for trees. + Region* parent{nullptr}; + + // The parent reference count is the number of references to the region from + // the parent region. In classic Verona we considered this as 0 or 1, but + // by tracking dynamically we can allow multiple references. + size_t parent_reference_count{0}; + + // The number of direct subregions, whose LRC is non-zero + size_t sub_region_reference_count{0}; + + // The objects in this region. + // TODO: make this more efficient. + std::set objects{}; + + size_t combined_lrc() + { + return local_reference_count + sub_region_reference_count; + } - to_collect.push_back(r); - std::cout << "Collecting region: " << r << std::endl; + static void action(Region* r) + { + if ((r->local_reference_count == 0) && (r->parent == nullptr)) + { + // TODO, this can be hooked to perform delayed operations like send. + // Needs to check for sub_region_reference_count for send, but not + // deallocate. + + to_collect.push_back(r); + std::cout << "Collecting region: " << r << std::endl; + } } - } - - static void dec_lrc(Region *r) { - assert(r->local_reference_count != 0); - r->local_reference_count--; - // Edge triggered LRC for parent. - if(r->combined_lrc() == 0) - dec_sbrc(r); - else - action(r); - } - static void dec_sbrc(Region *r) - { - while (r->parent != nullptr) + static void dec_lrc(Region* r) { - r = r->parent; - r->sub_region_reference_count--; - if (r->combined_lrc() != 0) - break; + assert(r->local_reference_count != 0); + r->local_reference_count--; + // Edge triggered LRC for parent. + if (r->combined_lrc() == 0) + dec_sbrc(r); + else + action(r); } - action(r); - } - static void inc_lrc(Region *r) { - r->local_reference_count++; - // Edge triggered LRC for parent. - if (r->combined_lrc() == 1) - inc_sbrc(r); - } + static void dec_sbrc(Region* r) + { + while (r->parent != nullptr) + { + r = r->parent; + r->sub_region_reference_count--; + if (r->combined_lrc() != 0) + break; + } + action(r); + } - static void inc_sbrc(Region *r) - { - while (r->parent != nullptr) + static void inc_lrc(Region* r) { - r = r->parent; - r->sub_region_reference_count++; - if (r->combined_lrc() != 1) - break; + r->local_reference_count++; + // Edge triggered LRC for parent. + if (r->combined_lrc() == 1) + inc_sbrc(r); } - } - - static void dec_prc(Region *r) { - std::cout << "Dropping parent reference: " << r << std::endl; - assert(r->parent_reference_count != 0); - r->parent_reference_count--; - if (r->parent_reference_count != 0) - return; - - // This is the last parent reference, so region no longer has a parent. - // If it has internal references, then we need to decrement the parents - // local reference count. - if (r->combined_lrc() != 0) - dec_sbrc(r); - else { - std::cout << "Collecting region: " << r << std::endl; - to_collect.push_back(r); + + static void inc_sbrc(Region* r) + { + while (r->parent != nullptr) + { + r = r->parent; + r->sub_region_reference_count++; + if (r->combined_lrc() != 1) + break; + } } - // Unset parent pointer. - r->parent = nullptr; - } - static void set_parent(Region *r, Region *p) { - assert(r->local_reference_count != 0); + static void dec_prc(Region* r) + { + std::cout << "Dropping parent reference: " << r << std::endl; + assert(r->parent_reference_count != 0); + r->parent_reference_count--; + if (r->parent_reference_count != 0) + return; + + // This is the last parent reference, so region no longer has a parent. + // If it has internal references, then we need to decrement the parents + // local reference count. + if (r->combined_lrc() != 0) + dec_sbrc(r); + else + { + std::cout << "Collecting region: " << r << std::endl; + to_collect.push_back(r); + } + // Unset parent pointer. + r->parent = nullptr; + } - r->parent_reference_count++; + static void set_parent(Region* r, Region* p) + { + assert(r->local_reference_count != 0); + + r->parent_reference_count++; + + // Check if already parented, if so increment the parent reference count. + if (r->parent == p) + { + return; + } + + // Check if already parented to another region. + if (r->parent != nullptr) + ui::error( + "Region already has a parent: Creating region DAG not supported!"); + + // Prevent creating a cycle + auto ancestors = p->parent; + while (ancestors != nullptr) + { + if (ancestors == r) + ui::error("Cycle created in region hierarchy"); + ancestors = ancestors->parent; + } + + // Set the parent and increment the parent reference count. + r->parent = p; + assert(r->parent_reference_count == 1); + + // If the region has local references, then we need the parent to have a + // local reference to. + if (r->local_reference_count == 0) + return; - // Check if already parented, if so increment the parent reference count. - if (r->parent == p) { - return; + inc_sbrc(r); } - // Check if already parented to another region. - if (r->parent != nullptr) - ui::error("Region already has a parent: Creating region DAG not supported!"); - - // Prevent creating a cycle - auto ancestors = p->parent; - while (ancestors != nullptr) { - if (ancestors == r) - ui::error("Cycle created in region hierarchy"); - ancestors = ancestors->parent; + void terminate_region() + { + to_collect.push_back(this); + collect(); } - // Set the parent and increment the parent reference count. - r->parent = p; - assert(r->parent_reference_count == 1); - - // If the region has local references, then we need the parent to have a - // local reference to. - if (r->local_reference_count == 0) - return; - - inc_sbrc(r); - } - - void terminate_region() { - to_collect.push_back(this); - collect(); - } - - std::vector get_objects() { - std::vector result; - for (auto o : objects) - result.push_back(o); - return result; - } - - static void collect() { - // Reentrancy guard. - static thread_local bool collecting = false; - if (collecting) - return; - - collecting = true; - - std::cout << "Starting collection" << std::endl; - while (!to_collect.empty()) { - auto r = to_collect.back(); - to_collect.pop_back(); - // Note destruct could re-enter here, ensure we don't hold onto a pointer - // into to_collect. - for (auto o : r->objects) - destruct(o); - for (auto o : r->objects) - dealloc(o); - r->objects.clear(); - - delete r; + std::vector get_objects() + { + std::vector result; + for (auto o : objects) + result.push_back(o); + return result; } - std::cout << "Finished collection" << std::endl; - collecting = false; - } -}; + static void collect() + { + // Reentrancy guard. + static thread_local bool collecting = false; + if (collecting) + return; + + collecting = true; + + std::cout << "Starting collection" << std::endl; + while (!to_collect.empty()) + { + auto r = to_collect.back(); + to_collect.pop_back(); + // Note destruct could re-enter here, ensure we don't hold onto a + // pointer into to_collect. + for (auto o : r->objects) + destruct(o); + for (auto o : r->objects) + dealloc(o); + r->objects.clear(); + + delete r; + } + std::cout << "Finished collection" << std::endl; + + collecting = false; + } + }; -// Represents the region of specific object. Uses small pointers to -// encode special regions. -using RegionPointer = utils::TaggedPointer; + // Represents the region of specific object. Uses small pointers to + // encode special regions. + using RegionPointer = utils::TaggedPointer; -} // namespace rt::objects \ No newline at end of file +} // namespace rt::objects diff --git a/src/rt/objects/visit.h b/src/rt/objects/visit.h index a04de97..3a851f1 100644 --- a/src/rt/objects/visit.h +++ b/src/rt/objects/visit.h @@ -1,22 +1,25 @@ #pragma once -#include #include "../../utils/nop.h" -namespace rt::objects { -class DynObject; +#include + +namespace rt::objects +{ + class DynObject; -struct Edge { - DynObject *src; - std::string key; - DynObject *target; -}; + struct Edge + { + DynObject* src; + std::string key; + DynObject* target; + }; -using NopDO = utils::Nop; + using NopDO = utils::Nop; -template -inline void visit(Edge e, Pre pre, Post post = {}); + template + inline void visit(Edge e, Pre pre, Post post = {}); -template -inline void visit(DynObject* start, Pre pre, Post post = {}); + template + inline void visit(DynObject* start, Pre pre, Post post = {}); } diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 7d9e50d..476c068 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -1,143 +1,192 @@ +#include "rt.h" + +#include "env.h" +#include "objects/dyn_object.h" + #include #include #include -#include "objects/dyn_object.h" -#include "rt.h" -#include "env.h" +namespace rt +{ + + objects::DynObject* make_func(verona::interpreter::Bytecode* body) + { + return new env::BytecodeFuncObject(body); + } + objects::DynObject* make_iter(objects::DynObject* iter_src) + { + return new env::KeyIterObject(iter_src->fields); + } + objects::DynObject* make_str(std::string value) + { + return new env::StringObject(value); + } + objects::DynObject* make_object() + { + return new objects::DynObject(); + } -namespace rt { - -objects::DynObject *make_func(verona::interpreter::Bytecode *body) { - return new env::BytecodeFuncObject(body); -} -objects::DynObject *make_iter(objects::DynObject *iter_src) { - return new env::KeyIterObject(iter_src->fields); -} -objects::DynObject *make_str(std::string value) { - return new env::StringObject(value); -} -objects::DynObject *make_object() { - return new objects::DynObject(); -} - -objects::DynObject *make_frame(objects::DynObject *parent) { - return new env::FrameObject(parent); -} - -thread_local objects::RegionPointer objects::DynObject::local_region = new Region(); - -void freeze(objects::DynObject *obj) { obj->freeze(); } - -void create_region(objects::DynObject *object) { object->create_region(); } - -objects::DynObject *get(objects::DynObject *obj, std::string key) { - return obj->get(key); -} - -std::string get_key(objects::DynObject* key) { - // TODO Add some checking. This is need to lookup the correct function in the prototype chain. - if (key->get_prototype() != &env::stringPrototypeObject) { - ui::error("Key must be a string."); - } - env::StringObject *str_key = reinterpret_cast(key); - return str_key->as_key(); -} - -objects::DynObject *get(objects::DynObject *obj, objects::DynObject *key) { - return get(obj, get_key(key)); -} - -objects::DynObject *set(objects::DynObject *obj, std::string key, objects::DynObject *value) { - return obj->set(key, value); -} - -objects::DynObject *set(objects::DynObject *obj, objects::DynObject *key, objects::DynObject *value) { - return set(obj, get_key(key), value); -} - -// TODO [[nodiscard]] -objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *proto) { - if (proto->is_primitive() != nullptr) { - ui::error("Cannot set a primitive as a prototype."); - } - if (obj->is_primitive() != nullptr) { - ui::error("Cannot set a prototype on a primitive object."); - } - return obj->set_prototype(proto); -} - -objects::DynObject *get_true() { - return &env::TrueObject; -} -objects::DynObject *get_false() { - return &env::FalseObject; -} - -void add_reference(objects::DynObject *src, objects::DynObject *target) { - objects::DynObject::add_reference(src, target); -} - -void remove_reference(objects::DynObject *src, objects::DynObject *target) { - objects::DynObject::remove_reference(src, target); -} - -void move_reference(objects::DynObject *src, objects::DynObject *dst, objects::DynObject *target) { - objects::DynObject::move_reference(src, dst, target); -} - -size_t pre_run() { - std::cout << "Running test..." << std::endl; - return objects::DynObject::get_count(); -} - -void post_run(size_t initial_count, ui::UI& ui) { - std::cout << "Test complete - checking for cycles in local region..." - << std::endl; - if (objects::DynObject::get_count() != initial_count) { - std::cout << "Cycles detected in local region." << std::endl; - auto objs = objects::DynObject::get_local_region()->get_objects(); - std::vector edges; - for (auto obj : objs) { - edges.push_back({nullptr, "?", obj}); + objects::DynObject* make_frame(objects::DynObject* parent) + { + return new env::FrameObject(parent); + } + + thread_local objects::RegionPointer objects::DynObject::local_region = + new Region(); + + void freeze(objects::DynObject* obj) + { + obj->freeze(); + } + + void create_region(objects::DynObject* object) + { + object->create_region(); + } + + objects::DynObject* get(objects::DynObject* obj, std::string key) + { + return obj->get(key); + } + + std::string get_key(objects::DynObject* key) + { + // TODO Add some checking. This is need to lookup the correct function in + // the prototype chain. + if (key->get_prototype() != &env::stringPrototypeObject) + { + ui::error("Key must be a string."); } - ui.output(edges, "Cycles detected in local region."); + env::StringObject* str_key = reinterpret_cast(key); + return str_key->as_key(); + } + + objects::DynObject* get(objects::DynObject* obj, objects::DynObject* key) + { + return get(obj, get_key(key)); } - objects::DynObject::get_local_region()->terminate_region(); - if (objects::DynObject::get_count() != initial_count) { - std::cout << "Memory leak detected!" << std::endl; - std::cout << "Initial count: " << initial_count << std::endl; - std::cout << "Final count: " << objects::DynObject::get_count() - << std::endl; - std::vector edges; - for (auto obj : objects::DynObject::get_objects()) { - edges.push_back({nullptr, "?", obj}); + objects::DynObject* + set(objects::DynObject* obj, std::string key, objects::DynObject* value) + { + return obj->set(key, value); + } + + objects::DynObject* set( + objects::DynObject* obj, objects::DynObject* key, objects::DynObject* value) + { + return set(obj, get_key(key), value); + } + + // TODO [[nodiscard]] + objects::DynObject* + set_prototype(objects::DynObject* obj, objects::DynObject* proto) + { + if (proto->is_primitive() != nullptr) + { + ui::error("Cannot set a primitive as a prototype."); + } + if (obj->is_primitive() != nullptr) + { + ui::error("Cannot set a prototype on a primitive object."); } - ui.output(edges, "Memory leak detected!"); + return obj->set_prototype(proto); + } + + objects::DynObject* get_true() + { + return &env::TrueObject; + } + objects::DynObject* get_false() + { + return &env::FalseObject; + } + + void add_reference(objects::DynObject* src, objects::DynObject* target) + { + objects::DynObject::add_reference(src, target); + } + + void remove_reference(objects::DynObject* src, objects::DynObject* target) + { + objects::DynObject::remove_reference(src, target); + } + + void move_reference( + objects::DynObject* src, + objects::DynObject* dst, + objects::DynObject* target) + { + objects::DynObject::move_reference(src, dst, target); + } - std::exit(1); - } else { - std::cout << "No memory leaks detected!" << std::endl; + size_t pre_run() + { + std::cout << "Running test..." << std::endl; + return objects::DynObject::get_count(); } -} -objects::DynObject *iter_next(objects::DynObject *iter) { - assert(!iter->is_immutable()); - if (iter->get_prototype() != &env::keyIterPrototypeObject) { - ui::error("Object is not an iterator."); + void post_run(size_t initial_count, ui::UI& ui) + { + std::cout << "Test complete - checking for cycles in local region..." + << std::endl; + if (objects::DynObject::get_count() != initial_count) + { + std::cout << "Cycles detected in local region." << std::endl; + auto objs = objects::DynObject::get_local_region()->get_objects(); + std::vector edges; + for (auto obj : objs) + { + edges.push_back({nullptr, "?", obj}); + } + ui.output(edges, "Cycles detected in local region."); + } + objects::DynObject::get_local_region()->terminate_region(); + if (objects::DynObject::get_count() != initial_count) + { + std::cout << "Memory leak detected!" << std::endl; + std::cout << "Initial count: " << initial_count << std::endl; + std::cout << "Final count: " << objects::DynObject::get_count() + << std::endl; + + std::vector edges; + for (auto obj : objects::DynObject::get_objects()) + { + edges.push_back({nullptr, "?", obj}); + } + ui.output(edges, "Memory leak detected!"); + + std::exit(1); + } + else + { + std::cout << "No memory leaks detected!" << std::endl; + } } - return reinterpret_cast(iter)->iter_next(); -} + objects::DynObject* iter_next(objects::DynObject* iter) + { + assert(!iter->is_immutable()); + if (iter->get_prototype() != &env::keyIterPrototypeObject) + { + ui::error("Object is not an iterator."); + } + + return reinterpret_cast(iter)->iter_next(); + } -verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func) { - if (func->get_prototype() == &env::bytecodeFuncPrototypeObject) { - return reinterpret_cast(func)->get_bytecode(); - } else { - ui::error("Object is not a function."); - return {}; + verona::interpreter::Bytecode* get_bytecode(objects::DynObject* func) + { + if (func->get_prototype() == &env::bytecodeFuncPrototypeObject) + { + return reinterpret_cast(func)->get_bytecode(); + } + else + { + ui::error("Object is not a function."); + return {}; + } } -} } // namespace rt diff --git a/src/rt/rt.h b/src/rt/rt.h index 1f82b03..4fc2046 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -1,41 +1,50 @@ #pragma once -#include -#include - #include "../lang/interpreter.h" #include "objects/visit.h" #include "ui.h" -namespace rt { - -objects::DynObject *make_func(verona::interpreter::Bytecode *body); -objects::DynObject *make_iter(objects::DynObject *iter_src); -objects::DynObject *make_str(std::string str_value); -objects::DynObject *make_object(); -objects::DynObject *make_frame(objects::DynObject *parent); - -void freeze(objects::DynObject *obj); -void create_region(objects::DynObject *objects); - -objects::DynObject *get(objects::DynObject *src, std::string key); -objects::DynObject *get(objects::DynObject *src, objects::DynObject *key); -objects::DynObject *set(objects::DynObject *dst, std::string key, objects::DynObject *value); -objects::DynObject *set(objects::DynObject *dst, objects::DynObject *key, objects::DynObject *value); - -objects::DynObject *set_prototype(objects::DynObject *obj, objects::DynObject *proto); - -objects::DynObject *get_true(); -objects::DynObject *get_false(); - -void add_reference(objects::DynObject *src, objects::DynObject *target); -void remove_reference(objects::DynObject *src, objects::DynObject *target); -void move_reference(objects::DynObject *src, objects::DynObject *dst, objects::DynObject *target); - -size_t pre_run(); -void post_run(size_t count, rt::ui::UI& ui); +#include +#include -objects::DynObject *iter_next(objects::DynObject *iter); -verona::interpreter::Bytecode* get_bytecode(objects::DynObject *func); +namespace rt +{ + + objects::DynObject* make_func(verona::interpreter::Bytecode* body); + objects::DynObject* make_iter(objects::DynObject* iter_src); + objects::DynObject* make_str(std::string str_value); + objects::DynObject* make_object(); + objects::DynObject* make_frame(objects::DynObject* parent); + + void freeze(objects::DynObject* obj); + void create_region(objects::DynObject* objects); + + objects::DynObject* get(objects::DynObject* src, std::string key); + objects::DynObject* get(objects::DynObject* src, objects::DynObject* key); + objects::DynObject* + set(objects::DynObject* dst, std::string key, objects::DynObject* value); + objects::DynObject* set( + objects::DynObject* dst, + objects::DynObject* key, + objects::DynObject* value); + + objects::DynObject* + set_prototype(objects::DynObject* obj, objects::DynObject* proto); + + objects::DynObject* get_true(); + objects::DynObject* get_false(); + + void add_reference(objects::DynObject* src, objects::DynObject* target); + void remove_reference(objects::DynObject* src, objects::DynObject* target); + void move_reference( + objects::DynObject* src, + objects::DynObject* dst, + objects::DynObject* target); + + size_t pre_run(); + void post_run(size_t count, rt::ui::UI& ui); + + objects::DynObject* iter_next(objects::DynObject* iter); + verona::interpreter::Bytecode* get_bytecode(objects::DynObject* func); } // namespace rt diff --git a/src/rt/ui.h b/src/rt/ui.h index 12ccfeb..cb81967 100644 --- a/src/rt/ui.h +++ b/src/rt/ui.h @@ -1,23 +1,25 @@ #pragma once -#include -#include +#include "objects/visit.h" + #include #include +#include +#include -#include "objects/visit.h" - -namespace rt::ui { -class UI +namespace rt::ui { -public: - virtual void output(std::vector &, std::string ) {} -}; + class UI + { + public: + virtual void output(std::vector&, std::string) {} + }; -void mermaid(std::vector &roots, std::ostream &out); + void mermaid(std::vector& roots, std::ostream& out); -[[noreturn]] inline void error(const std::string &msg) { -std::cerr << "Error: " << msg << std::endl; -std::exit(1); -} + [[noreturn]] inline void error(const std::string& msg) + { + std::cerr << "Error: " << msg << std::endl; + std::exit(1); + } } // namespace rt::ui diff --git a/src/rt/ui/mermaid.cc b/src/rt/ui/mermaid.cc index 0a329db..809b20c 100644 --- a/src/rt/ui/mermaid.cc +++ b/src/rt/ui/mermaid.cc @@ -1,132 +1,151 @@ +#include "../objects/dyn_object.h" +#include "../ui.h" + #include #include #include #include -#include "../ui.h" -#include "../objects/dyn_object.h" +namespace rt::ui +{ -namespace rt::ui { - -void replace(std::string& text, std::string from, std::string replace) { - size_t pos = 0; - while ((pos = text.find(from, pos)) != std::string::npos) { + void replace(std::string& text, std::string from, std::string replace) + { + size_t pos = 0; + while ((pos = text.find(from, pos)) != std::string::npos) + { text.replace(pos, from.length(), replace); - pos += replace.length(); // Move past the last replaced position - } -} - -std::string escape(std::string text) { - replace(text, "[", "#91;"); - replace(text, "]", "#93;"); - replace(text, "_", "#95;"); - replace(text, "<", "#60;"); - replace(text, ">", "#62;"); - replace(text, "\"", "#34;"); - return text; -} - -void mermaid(std::vector &roots, std::ostream &out) { - // Give a nice id to each object. - std::map visited; - // Keep track of all the objects in a region. - std::map> region_strings; - // Keep track of the immutable objects. - std::vector immutable_objects; - // // Add frame as local region - // visited[objects::DynObject::frame()] = 0; - // region_strings[objects::DynObject::get_local_region()] = {0}; - // Add nullptr as immutable - visited[nullptr] = 0; - immutable_objects.push_back(0); - // Account for frame and nullptr objects. - size_t id = 1; // was 2 - // Header - out << "```mermaid" << std::endl; - out << "graph TD" << std::endl; - - bool unreachable = false; - - auto explore = [&](objects::Edge e) { - objects::DynObject *dst = e.target; - std::string key = e.key; - objects::DynObject *src = e.src; - if (src != nullptr) { - out << " id" << visited[src] << " -->|" << escape(key) << "| "; + pos += replace.length(); // Move past the last replaced position } - if (visited.find(dst) != visited.end()) { - out << "id" << visited[dst] << std::endl; - return false; - } - auto curr_id = id++; - visited[dst] = curr_id; - out << "id" << curr_id << "[ "; - out << escape(dst->get_name()); - out << "
rc=" << dst->rc; + } - out << " ]" << (unreachable ? ":::unreachable" : "") << std::endl; + std::string escape(std::string text) + { + replace(text, "[", "#91;"); + replace(text, "]", "#93;"); + replace(text, "_", "#95;"); + replace(text, "<", "#60;"); + replace(text, ">", "#62;"); + replace(text, "\"", "#34;"); + return text; + } - auto region = objects::DynObject::get_region(dst); - if (region != nullptr) { - region_strings[region].push_back(curr_id); + void mermaid(std::vector& roots, std::ostream& out) + { + // Give a nice id to each object. + std::map visited; + // Keep track of all the objects in a region. + std::map> region_strings; + // Keep track of the immutable objects. + std::vector immutable_objects; + // // Add frame as local region + // visited[objects::DynObject::frame()] = 0; + // region_strings[objects::DynObject::get_local_region()] = {0}; + // Add nullptr as immutable + visited[nullptr] = 0; + immutable_objects.push_back(0); + // Account for frame and nullptr objects. + size_t id = 1; // was 2 + // Header + out << "```mermaid" << std::endl; + out << "graph TD" << std::endl; + + bool unreachable = false; + + auto explore = [&](objects::Edge e) { + objects::DynObject* dst = e.target; + std::string key = e.key; + objects::DynObject* src = e.src; + if (src != nullptr) + { + out << " id" << visited[src] << " -->|" << escape(key) << "| "; + } + if (visited.find(dst) != visited.end()) + { + out << "id" << visited[dst] << std::endl; + return false; + } + auto curr_id = id++; + visited[dst] = curr_id; + out << "id" << curr_id << "[ "; + out << escape(dst->get_name()); + out << "
rc=" << dst->rc; + + out << " ]" << (unreachable ? ":::unreachable" : "") << std::endl; + + auto region = objects::DynObject::get_region(dst); + if (region != nullptr) + { + region_strings[region].push_back(curr_id); + } + + if (dst->is_immutable()) + { + immutable_objects.push_back(curr_id); + } + return true; + }; + // Output all reachable edges + for (auto& root : roots) + { + objects::visit({root.src, root.key, root.target}, explore); } - if (dst->is_immutable()) { - immutable_objects.push_back(curr_id); + // Output the unreachable parts of the graph + unreachable = true; + for (auto& root : objects::DynObject::all_objects) + { + objects::visit({nullptr, "", root}, explore); } - return true; - }; - // Output all reachable edges - for (auto &root : roots) { - objects::visit({root.src, root.key, root.target}, explore); - } - // Output the unreachable parts of the graph - unreachable = true; - for (auto &root : objects::DynObject::all_objects) { - objects::visit({nullptr, "", root}, explore); - } - - // Output any region parent edges. - for (auto [region, objects] : region_strings) { - if (region->parent == nullptr) - continue; - out << " region" << region->parent << " <-.-o region" << region - << std::endl; - } + // Output any region parent edges. + for (auto [region, objects] : region_strings) + { + if (region->parent == nullptr) + continue; + out << " region" << region->parent << " <-.-o region" << region + << std::endl; + } - // Output all the region membership information - for (auto [region, objects] : region_strings) { - out << "subgraph "; - - if (region == objects::DynObject::get_local_region()) { - out << "local region" << std::endl; - } else { - out << std::endl; - out << " region" << region << "[\\" << region - << "
lrc=" << region->local_reference_count - << "
sbrc=" << region->sub_region_reference_count - << "
prc=" << region->parent_reference_count << "/]" << std::endl; + // Output all the region membership information + for (auto [region, objects] : region_strings) + { + out << "subgraph "; + + if (region == objects::DynObject::get_local_region()) + { + out << "local region" << std::endl; + } + else + { + out << std::endl; + out << " region" << region << "[\\" << region + << "
lrc=" << region->local_reference_count + << "
sbrc=" << region->sub_region_reference_count + << "
prc=" << region->parent_reference_count << "/]" + << std::endl; + } + for (auto obj : objects) + { + out << " id" << obj << std::endl; + } + out << "end" << std::endl; } - for (auto obj : objects) { + + // Output the immutable region. + out << "subgraph Immutable" << std::endl; + out << " id0[nullptr]" << std::endl; + for (auto obj : immutable_objects) + { out << " id" << obj << std::endl; } out << "end" << std::endl; - } - // Output the immutable region. - out << "subgraph Immutable" << std::endl; - out << " id0[nullptr]" << std::endl; - for (auto obj : immutable_objects) { - out << " id" << obj << std::endl; + // Output object count as very useful. + out << "subgraph Count " << objects::DynObject::get_count() << std::endl; + out << "end" << std::endl; + out << "classDef unreachable stroke:red,stroke-width:2px" << std::endl; + // Footer (end of mermaid graph) + out << "```" << std::endl; } - out << "end" << std::endl; - - // Output object count as very useful. - out << "subgraph Count " << objects::DynObject::get_count() << std::endl; - out << "end" << std::endl; - out << "classDef unreachable stroke:red,stroke-width:2px" << std::endl; - // Footer (end of mermaid graph) - out << "```" << std::endl; -} -} // namespace rt::ui \ No newline at end of file +} // namespace rt::ui diff --git a/src/utils/nop.h b/src/utils/nop.h index f4875dd..07580eb 100644 --- a/src/utils/nop.h +++ b/src/utils/nop.h @@ -2,10 +2,10 @@ namespace utils { - template + template class Nop { - public: - void operator()(T) const { } + public: + void operator()(T) const {} }; -} \ No newline at end of file +} diff --git a/src/utils/tagged_pointer.h b/src/utils/tagged_pointer.h index 02276de..24a0db9 100644 --- a/src/utils/tagged_pointer.h +++ b/src/utils/tagged_pointer.h @@ -6,7 +6,7 @@ namespace utils { - template + template class TaggedPointer { uintptr_t ptr; @@ -17,13 +17,25 @@ namespace utils TaggedPointer(T* ptr) : ptr(reinterpret_cast(ptr)) {} constexpr TaggedPointer(std::nullptr_t) : ptr(0) {} - TaggedPointer(T* ptr, uintptr_t tag) : ptr(reinterpret_cast(ptr) | tag) - { assert(tag < 4); } + TaggedPointer(T* ptr, uintptr_t tag) + : ptr(reinterpret_cast(ptr) | tag) + { + assert(tag < 4); + } - constexpr TaggedPointer(std::nullptr_t, std::uintptr_t tag) : ptr(tag) { assert(tag < 4); } + constexpr TaggedPointer(std::nullptr_t, std::uintptr_t tag) : ptr(tag) + { + assert(tag < 4); + } - bool operator==(TaggedPointer other) const { return ptr == other.ptr; } - bool operator!=(TaggedPointer other) const { return ptr != other.ptr; } + bool operator==(TaggedPointer other) const + { + return ptr == other.ptr; + } + bool operator!=(TaggedPointer other) const + { + return ptr != other.ptr; + } void set_tag(uintptr_t tag) { @@ -48,13 +60,19 @@ namespace utils return reinterpret_cast(ptr & ~0x3); } - operator T*() const { return get_ptr(); } + operator T*() const + { + return get_ptr(); + } - T& operator *() const { return *get_ptr(); } + T& operator*() const + { + return *get_ptr(); + } uintptr_t get_tag() const { return ptr & 0x3; } }; -} \ No newline at end of file +} From 1c58f26fa52a4948fa481f858525ea2ee38230d2 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Tue, 8 Oct 2024 10:22:07 +0200 Subject: [PATCH 10/10] Refactoring: Rename `rt::env` to `rt::core` --- src/rt/{env.h => core.h} | 4 ++-- src/rt/rt.cc | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) rename src/rt/{env.h => core.h} (98%) diff --git a/src/rt/env.h b/src/rt/core.h similarity index 98% rename from src/rt/env.h rename to src/rt/core.h index 1a2f01e..d3c86e5 100644 --- a/src/rt/env.h +++ b/src/rt/core.h @@ -1,7 +1,7 @@ #include "objects/dyn_object.h" #include "rt.h" -namespace rt::env +namespace rt::core { class PrototypeObject : public objects::DynObject @@ -147,4 +147,4 @@ namespace rt::env return this; } }; -} // namespace rt::env +} // namespace rt::core diff --git a/src/rt/rt.cc b/src/rt/rt.cc index 476c068..439e87a 100644 --- a/src/rt/rt.cc +++ b/src/rt/rt.cc @@ -1,6 +1,6 @@ #include "rt.h" -#include "env.h" +#include "core.h" #include "objects/dyn_object.h" #include @@ -12,15 +12,15 @@ namespace rt objects::DynObject* make_func(verona::interpreter::Bytecode* body) { - return new env::BytecodeFuncObject(body); + return new core::BytecodeFuncObject(body); } objects::DynObject* make_iter(objects::DynObject* iter_src) { - return new env::KeyIterObject(iter_src->fields); + return new core::KeyIterObject(iter_src->fields); } objects::DynObject* make_str(std::string value) { - return new env::StringObject(value); + return new core::StringObject(value); } objects::DynObject* make_object() { @@ -29,7 +29,7 @@ namespace rt objects::DynObject* make_frame(objects::DynObject* parent) { - return new env::FrameObject(parent); + return new core::FrameObject(parent); } thread_local objects::RegionPointer objects::DynObject::local_region = @@ -54,11 +54,11 @@ namespace rt { // TODO Add some checking. This is need to lookup the correct function in // the prototype chain. - if (key->get_prototype() != &env::stringPrototypeObject) + if (key->get_prototype() != &core::stringPrototypeObject) { ui::error("Key must be a string."); } - env::StringObject* str_key = reinterpret_cast(key); + core::StringObject* str_key = reinterpret_cast(key); return str_key->as_key(); } @@ -96,11 +96,11 @@ namespace rt objects::DynObject* get_true() { - return &env::TrueObject; + return &core::TrueObject; } objects::DynObject* get_false() { - return &env::FalseObject; + return &core::FalseObject; } void add_reference(objects::DynObject* src, objects::DynObject* target) @@ -168,19 +168,19 @@ namespace rt objects::DynObject* iter_next(objects::DynObject* iter) { assert(!iter->is_immutable()); - if (iter->get_prototype() != &env::keyIterPrototypeObject) + if (iter->get_prototype() != &core::keyIterPrototypeObject) { ui::error("Object is not an iterator."); } - return reinterpret_cast(iter)->iter_next(); + return reinterpret_cast(iter)->iter_next(); } verona::interpreter::Bytecode* get_bytecode(objects::DynObject* func) { - if (func->get_prototype() == &env::bytecodeFuncPrototypeObject) + if (func->get_prototype() == &core::bytecodeFuncPrototypeObject) { - return reinterpret_cast(func)->get_bytecode(); + return reinterpret_cast(func)->get_bytecode(); } else {