Skip to content

Commit

Permalink
Merge pull request #28 from mjp41/0-linked-lists
Browse files Browse the repository at this point in the history
Recursive linked list and smaller fixes
  • Loading branch information
xFrednet authored Oct 23, 2024
2 parents e4d90be + 0f2fba1 commit 3b85885
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 37 deletions.
8 changes: 8 additions & 0 deletions src/lang/bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

#include "trieste/ast.h"

/// Loads a value with a given name from the current frame.
///
/// The value name is stored in the location of the node
inline const trieste::TokenDef LoadFrame{"load_frame", trieste::flag::print};
inline const trieste::TokenDef StoreFrame{"store_frame", trieste::flag::print};
/// Loads a value with a given name from the current scope or the global
/// namespace. This should be used for function resolution.
///
/// The value name is stored in the location of the node
inline const trieste::TokenDef LoadGlobal{"load_global", trieste::flag::print};
inline const trieste::TokenDef LoadField{"load_field"};
inline const trieste::TokenDef StoreField{"store_field"};
inline const trieste::TokenDef CreateObject{"create_object"};
Expand Down
42 changes: 41 additions & 1 deletion src/lang/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ namespace verona::interpreter
{
return frame_stack.back()->frame;
}
rt::objects::DynObject* global_frame()
{
return frame_stack.front()->frame;
}

rt::objects::DynObject* pop(char const* data_info)
{
Expand Down Expand Up @@ -195,12 +199,44 @@ namespace verona::interpreter
{
std::string field{node->location().view()};
auto v = rt::get(frame(), field);
if (!v)
{
if (field == "True")
{
v = rt::get_true();
}
else if (field == "False")
{
rt::get_false();
}
}

rt::add_reference(frame(), v);
stack().push_back(v);
std::cout << "push " << v << std::endl;
return ExecNext{};
}

if (node == LoadGlobal)
{
std::string field{node->location().view()};

auto v = rt::get(frame(), field);
if (v)
{
rt::add_reference(frame(), v);
}
else
{
v = rt::get(global_frame(), field);
rt::add_reference(global_frame(), v);
}

stack().push_back(v);
std::cout << "push " << v << std::endl;
return ExecNext{};
}

if (node == StoreFrame)
{
auto v = pop("value to store");
Expand Down Expand Up @@ -284,6 +320,7 @@ namespace verona::interpreter
result = rt::get_false();
result_str = "false";
}
rt::add_reference(frame(), result);
stack().push_back(result);
std::cout << "push " << result << " (" << result_str << ")"
<< std::endl;
Expand All @@ -302,6 +339,7 @@ namespace verona::interpreter
{
auto v = pop("jump condition");
auto jump = (v == rt::get_false());
rt::remove_reference(frame(), v);
if (jump)
{
return ExecJump{node->location()};
Expand Down Expand Up @@ -418,7 +456,9 @@ namespace verona::interpreter
// Setup the new frame
for (size_t i = 0; i < func.arg_ctn; i++)
{
frame->stack.push_back(parent_frame->stack.back());
auto value = parent_frame->stack.back();
frame->stack.push_back(value);
rt::move_reference(parent_frame->frame, frame->frame, value);
parent_frame->stack.pop_back();
}
}
Expand Down
14 changes: 9 additions & 5 deletions src/lang/lang.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace verona::wf
inline const auto cmp_values = Ident | Lookup | Null;
inline const auto key = Ident | Lookup | String;
inline const auto operand = Lookup | Call | Method | Ident;
inline const auto Cond = Eq | Neq;

inline const auto grouping = (Top <<= File) | (File <<= Body) |
(Body <<= Block) |
Expand All @@ -44,19 +45,21 @@ namespace verona::wf
Method)++) |
(Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) |
(Lookup <<= (Op >>= operand) * (Rhs >>= key)) | (Region <<= Ident) |
(Freeze <<= Ident) | (Create <<= Ident) | (If <<= Eq * Block * Block) |
(Freeze <<= Ident) | (Create <<= Ident) |
(If <<= (Op >>= Cond) * Block * Block) |
(For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) |
(Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) |
(Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) |
(Func <<= Ident * Params * Body) | (Call <<= Ident * List) |
(Method <<= Lookup * 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 |
Dup)++) |
(LoadFrame | LoadGlobal | StoreFrame | LoadField | StoreField | Drop |
Null | CreateObject | CreateRegion | FreezeObject | IterNext | Print |
Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue |
ClearStack | Dup)++) |
(CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) |
(Func <<= Body) | (Label <<= Ident)[Ident];
}
Expand All @@ -67,6 +70,7 @@ inline const auto RV =
inline const auto CMP_V = T(Ident, Lookup, Null);
inline const auto KEY = T(Ident, Lookup, String);
inline const auto OPERAND = T(Lookup, Call, Method, Ident);
inline const auto COND = T(Eq, Neq);

// Parsing && AST construction
Parse parser();
Expand Down
8 changes: 5 additions & 3 deletions src/lang/passes/bytecode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ PassDef bytecode()
ClearStack)[Op] >>
[](auto& _) -> Node { return _(Op); },

T(Compile) << (T(Eq, Neq)[Op] << (Any[Lhs] * Any[Rhs])) >>
T(Compile) << (COND[Op] << (Any[Lhs] * Any[Rhs])) >>
[](auto& _) {
return Seq << (Compile << _(Lhs)) << (Compile << _(Rhs))
<< _(Op)->type();
Expand Down Expand Up @@ -104,10 +104,12 @@ PassDef bytecode()
<< (Call ^ std::to_string(arg_ctn + 1));
},
T(Compile)
<< (T(Call)[Call] << (KEY[Op] * (T(List) << Any++[List]) * End)) >>
<< (T(Call)[Call]
<< (T(Ident)[Ident] * (T(List) << Any++[List]) * End)) >>
[](auto& _) {
// The print is done by the called function
return Seq << (Compile << _[List]) << (Compile << _(Op))
return Seq << (Compile << _[List])
<< create_from(LoadGlobal, _(Ident))
<< (Call ^ std::to_string(_[List].size()));
},

Expand Down
3 changes: 1 addition & 2 deletions src/lang/passes/flatten.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ PassDef flatten()
In(Body) * (T(Block) << Any++[Block]) >>
[](auto& _) { return Seq << _[Block]; },
T(If)[If]
<< (T(Eq)[Op] * (T(Block) << Any++[Lhs]) *
(T(Block) << Any++[Rhs])) >>
<< (COND[Op] * (T(Block) << Any++[Lhs]) * (T(Block) << Any++[Rhs])) >>
[](auto& _) {
auto else_label = new_jump_label();
auto join_label = new_jump_label();
Expand Down
16 changes: 10 additions & 6 deletions src/lang/passes/grouping.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,20 @@ PassDef grouping()
<< ((T(Group) << LV[Lhs] * End) *
((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >>
[](auto& _) { return Assign << _[Lhs] << _[Rhs]; },
T(Eq)
COND[Op]
<< ((T(Group) << CMP_V[Lhs] * End) * (T(Group) << CMP_V[Rhs] * End) *
End) >>
[](auto& _) { return Eq << _[Lhs] << _[Rhs]; },
[](auto& _) {
return create_from(_(Op)->type(), _(Op)) << _[Lhs] << _[Rhs];
},

(T(If) << (T(Group) * T(Eq)[Eq] * (T(Group) << T(Block)[Block]))) >>
[](auto& _) { return If << _(Eq) << _(Block); },
(T(If) << (T(Group) * COND[Op] * (T(Group) << T(Block)[Block]))) >>
[](auto& _) { return If << _(Op) << _(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]) >>
(T(If)[If] << (COND * T(Block) * End)) * (T(Else) << T(Block)[Block]) >>
[](auto& _) { return _(If) << _(Block); },
(T(If)[If] << (T(Eq) * T(Block) * End)) * (--T(Else)) >>
(T(If)[If] << (COND * T(Block) * End)) * (--T(Else)) >>
[](auto& _) {
// This adds an empty else block, if no else was written
return _(If) << Block;
Expand Down Expand Up @@ -132,6 +134,8 @@ PassDef grouping()
T(Return)[Return]
<< ((T(Group) << End) * (T(Group) << (RV[Rhs] * End)) * End) >>
[](auto& _) { return create_from(ReturnValue, _(Return)) << _(Rhs); },
T(Return)[Return] << ((T(Group) << End) * (RV[Rhs] * End)) >>
[](auto& _) { return create_from(ReturnValue, _(Return)) << _(Rhs); },

}};

Expand Down
38 changes: 22 additions & 16 deletions src/lang/passes/parse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ namespace verona::wf
Group | Assign | If | Else | Block | For | Func | List | Return;

inline const auto parser = (Top <<= File) | (File <<= parse_groups++) |
(Assign <<= Group++) | (If <<= Group * Eq * Group) |
(Assign <<= Group++) | (If <<= Group * (Op >>= Cond) * 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++);
(Neq <<= Group * Group) | (Lookup <<= Group) |
(For <<= Group * List * Group * Group) | (List <<= Group++) |
(Parens <<= (Group | List)++) | (Func <<= Group * Group * Group) |
(Return <<= Group++);
}

struct Indent
Expand Down Expand Up @@ -92,29 +93,33 @@ trieste::Parse parser()
// Line comment
"(?:#[^\\n\\r]*)" >> [](auto&) {},

"def" >> [](auto& m) { m.seq(Func); },
"def\\b" >> [](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\\b" >> [](auto& m) { m.seq(Return); },

"for" >> [](auto& m) { m.seq(For); },
"in" >>
"for\\b" >> [](auto& m) { m.seq(For); },
"in\\b" >>
[](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); },
"if\\b" >>
[](auto& m) {
m.term();
m.seq(If);
},
"else\\b" >> [](auto& m) { m.seq(Else); },
":" >>
[indent](auto& m) {
// Exit conditionals expressions.
m.term({Eq});
m.term({Eq, Neq});

Token toc = Empty;
if (m.in(If))
Expand Down Expand Up @@ -151,11 +156,11 @@ trieste::Parse parser()

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); },
"drop\\b" >> [](auto& m) { m.add(Drop); },
"create\\b" >> [](auto& m) { m.add(Create); },
"freeze\\b" >> [](auto& m) { m.add(Freeze); },
"region\\b" >> [](auto& m) { m.add(Region); },
"None\\b" >> [](auto& m) { m.add(Null); },
"[0-9A-Za-z_]+" >> [](auto& m) { m.add(Ident); },
"\\[" >> [](auto& m) { m.push(Lookup); },
"\\]" >> [](auto& m) { m.term({Lookup}); },
Expand All @@ -167,6 +172,7 @@ trieste::Parse parser()
},
"\"([^\\n\"]+)\"" >> [](auto& m) { m.add(String, 1); },
"==" >> [](auto& m) { m.seq(Eq); },
"!=" >> [](auto& m) { m.seq(Neq); },
"=" >> [](auto& m) { m.seq(Assign); },
"{}" >> [](auto& m) { m.add(Empty); },
});
Expand Down
5 changes: 4 additions & 1 deletion src/rt/objects/dyn_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ namespace rt::objects
}

if (prototype != nullptr)
prototype->change_rc(1);
{
// prototype->change_rc(1);
add_reference(this, prototype);
}
std::cout << "Allocate: " << this << std::endl;
}

Expand Down
10 changes: 7 additions & 3 deletions src/rt/rt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,14 @@ namespace rt
objects::DynObject*
set_prototype(objects::DynObject* obj, objects::DynObject* proto)
{
if (proto->is_primitive() != nullptr)
if (proto && proto->is_primitive() != nullptr)
{
ui::error("Cannot set a primitive as a prototype.");
}
if (obj == nullptr)
{
ui::error("Cannot set a prototype on null.");
}
if (obj->is_primitive() != nullptr)
{
ui::error("Cannot set a prototype on a primitive object.");
Expand Down Expand Up @@ -183,7 +187,7 @@ namespace rt
objects::DynObject* iter_next(objects::DynObject* iter)
{
assert(!iter->is_immutable());
if (iter->get_prototype() != core::keyIterPrototypeObject())
if (iter && iter->get_prototype() != core::keyIterPrototypeObject())
{
ui::error("Object is not an iterator.");
}
Expand All @@ -193,7 +197,7 @@ namespace rt

verona::interpreter::Bytecode* get_bytecode(objects::DynObject* func)
{
if (func->get_prototype() == core::bytecodeFuncPrototypeObject())
if (func && func->get_prototype() == core::bytecodeFuncPrototypeObject())
{
return reinterpret_cast<core::BytecodeFuncObject*>(func)->get_bytecode();
}
Expand Down
51 changes: 51 additions & 0 deletions tests/recursive_list.vpy
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# For now separate
def insert(node, item):
if node.next == None:
node.next = {}
node.next.data = item
node.next.prev = node
else:
insert(node.next, item)

def contains(node, item):
if node.data == item:
return True
if node.next == None:
return False
return find(node.next, item)

def remove(node, item):
if node.data == item:
node.prev.next = node.next
if node.next != None:
node.next.prev = node.prev
return True
if node.next == None:
return False
return remove(node.next, item)

def new_list():
list = {}
list.head = {}
return list

list = new_list()

# Required to not leak memory
region list

value = "x"

# Dyrona doesn't freeze shared objects automatically (yet)
proto = value["__proto__"]
freeze proto
drop proto

insert(list.head, {})
insert(list.head, {})
insert(list.head, value)
insert(list.head, {})
remove(list.head, value)

drop value
drop list

0 comments on commit 3b85885

Please sign in to comment.