Skip to content

Commit

Permalink
Merge pull request #29 from mjp41/16-build-out-buildin-funcs
Browse files Browse the repository at this point in the history
Implement buildin functions and refactor mermaid generation
  • Loading branch information
xFrednet authored Oct 24, 2024
2 parents 3b85885 + abeafc7 commit 27d6b32
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 147 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ set (TRIESTE_ENABLE_TESTING OFF)
FetchContent_MakeAvailable_ExcludeFromAll(trieste)
set(CMAKE_CXX_STANDARD 20)

add_library(rt OBJECT src/rt/rt.cc src/rt/ui/mermaid.cc)
add_library(
rt OBJECT
src/rt/rt.cc
src/rt/ui/mermaid.cc
src/rt/core/builtin.cc
)

add_library(
lang OBJECT
Expand Down
79 changes: 39 additions & 40 deletions src/lang/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -221,17 +221,22 @@ namespace verona::interpreter
{
std::string field{node->location().view()};

// Local frame
auto v = rt::get(frame(), field);
if (v)

// User globals
if (!v)
{
rt::add_reference(frame(), v);
v = rt::get(global_frame(), field);
}
else

// Builtin globals
if (!v)
{
v = rt::get(global_frame(), field);
rt::add_reference(global_frame(), v);
v = rt::get_builtin(field);
}

rt::add_reference(frame(), v);
stack().push_back(v);
std::cout << "push " << v << std::endl;
return ExecNext{};
Expand Down Expand Up @@ -379,9 +384,32 @@ namespace verona::interpreter
{
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 (auto bytecode = rt::try_get_bytecode(func))
{
rt::remove_reference(frame(), func);
return ExecFunc{bytecode.value()->body, arg_ctn};
}
else if (auto builtin = rt::try_get_builtin_func(func))
{
// This calls the built-in function with the current frame and current
// stack. This makes the implementation on the interpreter side a lot
// easier and makes builtins more powerful. The tradeoff is that the
// arguments are still in reverse order on the stack, and the function
// can potentially modify the "calling" frame.
auto result = (builtin.value())(frame(), &stack(), arg_ctn);
if (result)
{
stack().push_back(result.value());
rt::add_reference(frame(), result.value());
}
rt::remove_reference(frame(), func);
return ExecNext{};
}
else
{
rt::ui::error("Object is not a function");
}
}

if (node == Dup)
Expand Down Expand Up @@ -491,41 +519,12 @@ namespace verona::interpreter
}
};

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);
}

void
output(std::vector<rt::objects::DynObject*>& roots, std::string message)
{
out << "```" << std::endl;
out << message << std::endl;
out << "```" << std::endl;
rt::ui::mermaid(roots, 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();
rt::ui::MermaidUI ui(interactive);

size_t initial = rt::pre_run(&ui);

UI ui(interactive);
Interpreter inter(&ui);
inter.run(main_body);

Expand Down
6 changes: 3 additions & 3 deletions src/lang/passes/grouping.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PassDef grouping()
// function(arg, arg)
--In(Func) *
(T(Group)[Group] << (T(Ident)[Ident]) *
(T(Parens)[Parens] << (~T(List)[List])) * Any++[Rest]) >>
(T(Parens)[Parens] << (~T(List)[List] * End)) * Any++[Rest]) >>
[](auto& _) {
auto list = _(List);
if (!list)
Expand Down Expand Up @@ -122,8 +122,8 @@ PassDef grouping()
<< _(Ident) << (create_from(Params, _(Parens)) << _[List])
<< (Body << _(Block));
},
// Normalize functions with a single ident to also have a list token
T(Parens)[Parens] << (T(Group) << (T(Ident)[Ident] * End)) >>
// Normalize parenthesis with a single node to also have a list token
T(Parens)[Parens] << (T(Group) << (Any[Ident] * End)) >>
[](auto& _) {
return create_from(Parens, _(Parens))
<< (create_from(List, _(Parens)) << _(Ident));
Expand Down
40 changes: 40 additions & 0 deletions src/rt/core.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "objects/dyn_object.h"
#include "rt.h"

#include <map>

namespace rt::core
{
class PrototypeObject : public objects::DynObject
Expand Down Expand Up @@ -59,6 +61,12 @@ namespace rt::core
new PrototypeObject("BytecodeFunction", funcPrototypeObject());
return proto;
}
inline PrototypeObject* builtinFuncPrototypeObject()
{
static PrototypeObject* proto =
new PrototypeObject("BuiltinFunction", funcPrototypeObject());
return proto;
}

class FuncObject : public objects::DynObject
{
Expand Down Expand Up @@ -88,6 +96,21 @@ namespace rt::core
}
};

class BuiltinFuncObject : public FuncObject
{
BuiltinFuncPtr func;

public:
BuiltinFuncObject(BuiltinFuncPtr func_)
: FuncObject(builtinFuncPrototypeObject()), func(func_)
{}

BuiltinFuncPtr get_func()
{
return func;
}
};

inline PrototypeObject* stringPrototypeObject()
{
static PrototypeObject* proto = new PrototypeObject("String");
Expand Down Expand Up @@ -181,11 +204,28 @@ namespace rt::core
framePrototypeObject(),
funcPrototypeObject(),
bytecodeFuncPrototypeObject(),
builtinFuncPrototypeObject(),
stringPrototypeObject(),
keyIterPrototypeObject(),
trueObject(),
falseObject(),
};
return globals;
}

inline std::map<std::string, objects::DynObject*>* global_names()
{
static std::map<std::string, objects::DynObject*>* global_names =
new std::map<std::string, objects::DynObject*>{
{"True", trueObject()},
{"False", falseObject()},
};
return global_names;
}

/// @brief Initilizes builtin functions and adds them to the global namespace.
///
/// @param ui The UI to allow builtin functions to create output, when they're
/// called.
void init_builtins(ui::UI* ui);
} // namespace rt::core
57 changes: 57 additions & 0 deletions src/rt/core/builtin.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "../core.h"
#include "../rt.h"

namespace rt::core
{
void mermaid_builtins(ui::UI* ui)
{
if (!ui->is_mermaid())
{
return;
}
auto mermaid = reinterpret_cast<ui::MermaidUI*>(ui);

add_builtin("mermaid_hide", [mermaid](auto frame, auto stack, auto args) {
assert(args >= 1);

for (int i = 0; i < args; i++)
{
auto value = stack->back();
mermaid->add_always_hide(value);
remove_reference(frame, value);
stack->pop_back();
}

return std::nullopt;
});

add_builtin("mermaid_show", [mermaid](auto frame, auto stack, auto args) {
assert(args >= 1);

for (int i = 0; i < args; i++)
{
auto value = stack->back();
mermaid->remove_unreachable_hide(value);
mermaid->remove_always_hide(value);
remove_reference(frame, value);
stack->pop_back();
}

return std::nullopt;
});

add_builtin("mermaid_show_all", [mermaid](auto, auto, auto args) {
assert(args == 0);

mermaid->unreachable_hide.clear();
mermaid->always_hide.clear();

return std::nullopt;
});
}

void init_builtins(ui::UI* ui)
{
mermaid_builtins(ui);
}
}
4 changes: 2 additions & 2 deletions src/rt/objects/dyn_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ namespace rt::objects
{
friend class Reference;
friend objects::DynObject* rt::make_iter(objects::DynObject* obj);
friend void
rt::ui::mermaid(std::vector<objects::DynObject*>& roots, std::ostream& out);
friend class ui::MermaidUI;
friend class ui::MermaidDiagram;
friend void destruct(DynObject* obj);
friend void dealloc(DynObject* obj);
template<typename Pre, typename Post>
Expand Down
43 changes: 38 additions & 5 deletions src/rt/rt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@

namespace rt
{
void add_builtin(std::string name, BuiltinFuncPtr func)
{
auto builtin = new core::BuiltinFuncObject(func);
core::globals()->insert(builtin);
core::global_names()->insert({name, builtin});
}
objects::DynObject* get_builtin(std::string name)
{
auto globals = core::global_names();

auto search = globals->find(name);
if (search != globals->end())
{
return search->second;
}
return nullptr;
}

objects::DynObject* make_func(verona::interpreter::Bytecode* body)
{
Expand Down Expand Up @@ -127,10 +144,20 @@ namespace rt
objects::DynObject::move_reference(src, dst, target);
}

size_t pre_run()
size_t pre_run(ui::UI* ui)
{
std::cout << "Initilizing global objects" << std::endl;
core::globals();
core::init_builtins(ui);

if (ui->is_mermaid())
{
auto mermaid = reinterpret_cast<ui::MermaidUI*>(ui);
for (auto global : *core::globals())
{
mermaid->add_unreachable_hide(global);
}
}

std::cout << "Running test..." << std::endl;
return objects::DynObject::get_count();
Expand Down Expand Up @@ -195,17 +222,23 @@ namespace rt
return reinterpret_cast<core::KeyIterObject*>(iter)->iter_next();
}

verona::interpreter::Bytecode* get_bytecode(objects::DynObject* func)
std::optional<verona::interpreter::Bytecode*>
try_get_bytecode(objects::DynObject* func)
{
if (func && func->get_prototype() == core::bytecodeFuncPrototypeObject())
{
return reinterpret_cast<core::BytecodeFuncObject*>(func)->get_bytecode();
}
else
return std::nullopt;
}

std::optional<BuiltinFuncPtr> try_get_builtin_func(objects::DynObject* func)
{
if (func && func->get_prototype() == core::builtinFuncPrototypeObject())
{
ui::error("Object is not a function.");
return {};
return reinterpret_cast<core::BuiltinFuncObject*>(func)->get_func();
}
return std::nullopt;
}

} // namespace rt
13 changes: 11 additions & 2 deletions src/rt/rt.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@
#include "objects/visit.h"
#include "ui.h"

#include <functional>
#include <optional>
#include <string>
#include <vector>

namespace rt
{

using BuiltinFuncPtr = std::function<std::optional<objects::DynObject*>(
objects::DynObject*, std::vector<objects::DynObject*>*, size_t)>;
void add_builtin(std::string name, BuiltinFuncPtr func);
objects::DynObject* get_builtin(std::string name);

objects::DynObject* make_func(verona::interpreter::Bytecode* body);
objects::DynObject* make_iter(objects::DynObject* iter_src);
objects::DynObject* make_str(std::string str_value);
Expand Down Expand Up @@ -41,10 +48,12 @@ namespace rt
objects::DynObject* dst,
objects::DynObject* target);

size_t pre_run();
size_t pre_run(rt::ui::UI* ui);
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);
std::optional<verona::interpreter::Bytecode*>
try_get_bytecode(objects::DynObject* func);
std::optional<BuiltinFuncPtr> try_get_builtin_func(objects::DynObject* func);

} // namespace rt
Loading

0 comments on commit 27d6b32

Please sign in to comment.