Skip to content

Commit

Permalink
Func: Cleanup and fixing things
Browse files Browse the repository at this point in the history
  • Loading branch information
xFrednet committed Oct 1, 2024
1 parent 54ab889 commit 963d7c1
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 29 deletions.
1 change: 1 addition & 0 deletions src/lang/bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ inline const trieste::TokenDef Label{"label"};
inline const trieste::TokenDef Eq{"=="};
inline const trieste::TokenDef Neq{"!="};
/// Stack: <arg_0>, <arg_1>, <arg_2>, <func_obj>
/// For `function(a, b, c)` the stack would be: `a, b, c, function`
inline const trieste::TokenDef Call{"call"};
/// Unconditional Jump
inline const trieste::TokenDef Jump{"jump", trieste::flag::print};
Expand Down
37 changes: 29 additions & 8 deletions src/lang/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ struct Bytecode {
trieste::Node body;
};

void delete_bytecode(Bytecode* bytecode) {
delete bytecode;
}

std::tuple<bool, std::optional<trieste::Location>> run_stmt(trieste::Node& node, std::vector<objects::DynObject *> &stack, objects::UI* ui) {
if (node == Print) {
std::cout << node->location().view() << std::endl << std::endl;
Expand Down Expand Up @@ -43,7 +47,6 @@ std::tuple<bool, std::optional<trieste::Location>> run_stmt(trieste::Node& node,
objects::set_prototype(obj, v);
} else if (payload == Func) {
assert(payload->size() == 1 && "CreateObject: A bytecode function requires a body node");
// TODO This leaks memory
obj = objects::make_func(new Bytecode { payload->at(0) });
} else {
assert(false && "CreateObject has to specify a value");
Expand Down Expand Up @@ -230,11 +233,13 @@ std::tuple<bool, std::optional<trieste::Location>> run_stmt(trieste::Node& node,
}

if (node == Call) {
// Get the operator
std::cout << "function call" << std::endl;
auto func = stack.back();
stack.pop_back();
std::cout << "pop " << func << "(function)" << std::endl;

// Copy the arguments into a new stack
std::vector<objects::DynObject *> call_stack;
auto arg_ctn = std::stoul(std::string(node->location().view()));
assert(stack.size() >= arg_ctn && "The stack doesn't have enough values for this call");
Expand All @@ -243,12 +248,17 @@ std::tuple<bool, std::optional<trieste::Location>> run_stmt(trieste::Node& node,
stack.pop_back();
}

// TODO Return value
objects::value::call(func, call_stack, ui);
// Call function and process return
auto return_value = objects::value::call(func, call_stack, ui);
remove_reference(objects::get_frame(), func);
if (return_value) {
auto value = return_value.value();
stack.push_back(value);
std::cout << "push " << value << " (return value)" << std::endl;
} else {
std::cout << "function didn't return anything" << std::endl;
}

// stack.push_back(obj);
std::cout << "push " << "TODO obj" << " (return value)" << std::endl;
return {false, {}};
}

Expand All @@ -260,7 +270,12 @@ std::tuple<bool, std::optional<trieste::Location>> run_stmt(trieste::Node& node,

if (node == PopFrame) {
std::cout << "pop frame" << std::endl;
objects::pop_frame();
assert(stack.empty() && "the local stack has to be empty, after the frame was popped");
auto return_value = objects::pop_frame();
if (return_value) {
stack.push_back(return_value.value());
}

return {false, {}};
}

Expand Down Expand Up @@ -325,7 +340,13 @@ std::optional<objects::DynObject *> run_body(trieste::Node body, std::vector<obj
ui->output(edges, std::string((*it)->location().view()));
it++;
}
assert(stack.empty() && "the stack must be empty when the body ends");

assert(stack.size() <= 1 && "the stack can't have more than a single return value, at the end of the body");
if (stack.size() == 1) {
auto return_value = stack.back();
stack.pop_back();
return return_value;
}

return {};
}
Expand All @@ -336,7 +357,7 @@ std::optional<objects::DynObject *> run_body(Bytecode *body, std::vector<objects
void start(trieste::Node main_body, bool interactive) {
size_t initial = objects::pre_run();

// Our main has no arguments, menaing an empty starting stack.
// Our main has no arguments, meaning it has an empty starting stack.
std::vector<objects::DynObject *> stack;
UI ui(interactive);
run_body(main_body, stack, &ui);
Expand Down
8 changes: 5 additions & 3 deletions src/lang/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ namespace objects {

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 will be pushed and poped by the function callee. It's recommendable
/// 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 order of their definition. They have to
/// be popped of in reverse order.
/// The stack holds the arguments in reverse order of their definition. They have to
/// be popped of in order.
std::optional<objects::DynObject *> run_body(Bytecode *body, std::vector<objects::DynObject *> &stack, objects::UI* ui);
} // namespace verona::interpreter
12 changes: 7 additions & 5 deletions src/lang/lang.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ inline const auto parser =
;

inline const auto lv = Ident | Lookup;
inline const auto rv = lv | Empty | Null | String | Create;
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;

Expand Down Expand Up @@ -155,7 +155,9 @@ trieste::Parse parser() {
m.push(Parens);
},
"\\)" >> [](auto &m) {
m.term({List, Parens});
m.term({List});
m.extend_before(Parens);
m.term({Parens});
},
"return" >> [](auto &m) {
m.seq(Return);
Expand Down Expand Up @@ -238,7 +240,7 @@ trieste::Parse parser() {
}

auto LV = T(Ident, Lookup);
auto RV = T(Empty, Ident, Lookup, Null, String, Create);
auto RV = T(Empty, Ident, Lookup, Null, String, Create, Call);
auto CMP_V = T(Ident, Lookup, Null);
auto KEY = T(Ident, Lookup, String);

Expand Down Expand Up @@ -315,7 +317,7 @@ PassDef grouping() {
},

T(Assign) << ((T(Group) << LV[Lhs] * End) *
(T(Group) << RV[Rhs] * End) * 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) >>
Expand Down Expand Up @@ -350,7 +352,7 @@ PassDef grouping() {
(T(Group) << (T(Block)[Block] * End)) *
End) >>
[](auto &_) {
// This function for now only has a block, as a lowering pass still needs to
// 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)
Expand Down
26 changes: 15 additions & 11 deletions src/rt/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ inline void visit(Edge e, Pre pre, Post post = {});
template <typename Pre, typename Post = NopDO>
inline void visit(DynObject* start, Pre pre, Post post = {});


// Representation of objects
class DynObject {
friend class Reference;
Expand Down Expand Up @@ -215,11 +214,6 @@ class DynObject {
return nullptr;
}

virtual std::optional<DynObject*> function_apply(std::vector<objects::DynObject *> &stack, objects::UI* ui) {
assert(false && "Not available as function");
return nullptr;
}

inline static void push_frame(DynObject* frame) {
frame_stack.push_back(frame);
}
Expand All @@ -239,9 +233,10 @@ class DynObject {
// and return `nullprt` if it wasn't found.
auto result = frame->fields.find("return");
if (result != frame->fields.end()) {
result->second->change_rc(1);
return_value = result->second;
}

frame_stack.pop_back();
remove_reference(frame_stack.back(), frame);

Expand Down Expand Up @@ -442,13 +437,22 @@ DynObject funcPrototypeObject{nullptr, true};
// TODO put some stuff in here?
DynObject bytecodeFuncPrototypeObject{&funcPrototypeObject, true};

class BytecodeFuncObject : public DynObject {
// TODO: This memory is currently leaked.
class FuncObject : public DynObject {
public:
FuncObject(DynObject* prototype_, bool global = false) : DynObject(prototype_, global) {}
virtual std::optional<DynObject*> function_apply(std::vector<objects::DynObject *> &stack, objects::UI* ui) = 0;
};

class BytecodeFuncObject : public FuncObject {
verona::interpreter::Bytecode *body;
public:
BytecodeFuncObject(verona::interpreter::Bytecode *body_) : DynObject(&bytecodeFuncPrototypeObject), body(body_) {}
BytecodeFuncObject(verona::interpreter::Bytecode *body_) : FuncObject(&bytecodeFuncPrototypeObject), body(body_) {}
~BytecodeFuncObject() {
verona::interpreter::delete_bytecode(this->body);
this->body = nullptr;
}

std::optional<DynObject*> function_apply(std::vector<objects::DynObject *> &stack, objects::UI* ui) {
std::optional<DynObject*> function_apply(std::vector<objects::DynObject *> &stack, objects::UI* ui) override {
return verona::interpreter::run_body(this->body, stack, ui);
}
};
Expand Down
1 change: 0 additions & 1 deletion src/rt/rt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ DynObject *make_object(std::string value) {
}
DynObject *make_object() { return new DynObject(); }

// thread_local std::vector<DynObject *> DynObject::frame_stack = { new DynObject{nullptr, true} };
thread_local std::vector<DynObject *> DynObject::frame_stack = { FrameObject::create_first_stack() };

void push_frame() {
Expand Down
4 changes: 3 additions & 1 deletion tests/funcs.vpy
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ def no_args():
return a


no_args()
_ = no_args()

three_args("A", "B", "C")

a = {}

0 comments on commit 963d7c1

Please sign in to comment.