Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Reify cowns and add taint for visual story telling #27

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ clangformat_targets()


message(STATUS "Adding tests")
FILE(GLOB ALL_FILES
FILE(GLOB_RECURSE ALL_FILES
CONFIGURE_DEPENDS
tests/*
)
Expand All @@ -62,3 +62,5 @@ endforeach()

set_property(TEST three_regions.vpy PROPERTY WILL_FAIL true)
set_property(TEST leak_with_global.vpy PROPERTY WILL_FAIL true)
set_property(TEST modify_cown.vpy PROPERTY WILL_FAIL true)
set_property(TEST read_region.vpy PROPERTY WILL_FAIL true)
2 changes: 2 additions & 0 deletions src/lang/bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ inline const trieste::TokenDef StoreField{"store_field"};
inline const trieste::TokenDef CreateObject{"create_object"};
inline const trieste::TokenDef Proto{"prototype"};
inline const trieste::TokenDef Dictionary{"dictionary"};
inline const trieste::TokenDef Cown{"cown"};
inline const trieste::TokenDef String{"string", trieste::flag::print};
inline const trieste::TokenDef KeyIter{"key_iter"};
inline const trieste::TokenDef Func{"func"};
Expand Down Expand Up @@ -43,4 +44,5 @@ inline const trieste::TokenDef Jump{"jump", trieste::flag::print};
/// Jump if the current stack frame is `False`
inline const trieste::TokenDef JumpFalse{"jump_false", trieste::flag::print};
inline const trieste::TokenDef Print("print", trieste::flag::print);
inline const trieste::TokenDef Taint{"display_taint"};
inline const trieste::TokenDef IterNext("iter_next");
29 changes: 24 additions & 5 deletions src/lang/interpreter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,25 @@ namespace verona::interpreter
// ==========================================
// Operators that shouldn't be printed
// ==========================================
if (node == Print)
if (node == Print || node == Taint)
{
// Console output
std::cout << node->location().view() << std::endl << std::endl;

std::vector<rt::objects::DynObject*> taint = {};
if (node == Taint)
{
auto v = pop("taint source");
taint.push_back(v);
// Removing the reference here is a bit early, but should be safe
// since it comes from an ident. Removing it later would require an
// additional if clause
rt::remove_reference(frame(), v);
}

// Mermaid output
std::vector<rt::objects::DynObject*> roots{frame()};
ui->output(roots, std::string(node->location().view()));
ui->output(roots, std::string(node->location().view()), &taint);

// Continue
return ExecNext{};
Expand Down Expand Up @@ -174,6 +185,12 @@ namespace verona::interpreter
"CreateObject: A bytecode function requires a body node");
obj = rt::make_func(new Bytecode{payload->at(0)});
}
else if (payload == Cown)
{
auto v = pop("cown reagion");
obj = rt::make_cown(v);
rt::move_reference(frame(), obj, v);
}
else
{
assert(false && "CreateObject has to specify a value");
Expand Down Expand Up @@ -464,13 +481,15 @@ namespace verona::interpreter
out.open(path);
}

void
output(std::vector<rt::objects::DynObject*>& roots, std::string message)
void output(
std::vector<rt::objects::DynObject*>& roots,
std::string message,
std::vector<rt::objects::DynObject*>* taint = nullptr)
{
out << "```" << std::endl;
out << message << std::endl;
out << "```" << std::endl;
rt::ui::mermaid(roots, out);
rt::ui::mermaid(roots, out, taint);
if (interactive)
{
out.close();
Expand Down
20 changes: 11 additions & 9 deletions src/lang/lang.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,21 @@ inline const TokenDef Compile{"compile"};
namespace verona::wf
{
inline const auto lv = Ident | Lookup;
inline const auto rv = lv | Empty | Null | String | Create | Call | Method;
inline const auto rv =
lv | Empty | Null | String | Create | Call | Method | Cown;
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 grouping = (Top <<= File) | (File <<= Body) |
(Body <<= Block) |
(Block <<=
(Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call |
Method)++) |
(Freeze | Taint | Region | Assign | If | For | Func | Return |
ReturnValue | Call | Method)++) |
(Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) |
(Lookup <<= (Op >>= operand) * (Rhs >>= key)) | (Region <<= Ident) |
(Freeze <<= Ident) | (Create <<= Ident) | (If <<= Eq * Block * Block) |
(Freeze <<= Ident) | (Taint <<= Ident) | (Cown <<= 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 <<= Ident * List) |
Expand All @@ -54,16 +56,16 @@ namespace verona::wf
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)++) |
(CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) |
CreateObject | CreateRegion | FreezeObject | Taint | IterNext | Print |
Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue |
ClearStack | Dup)++) |
(CreateObject <<= (Dictionary | String | KeyIter | Proto | Func | Cown)) |
(Func <<= Body) | (Label <<= Ident)[Ident];
}

inline const auto LV = T(Ident, Lookup);
inline const auto RV =
T(Empty, Ident, Lookup, Null, String, Create, Call, Method);
T(Empty, Ident, Lookup, Null, String, Create, Call, Method, Cown);
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);
Expand Down
20 changes: 20 additions & 0 deletions src/lang/passes/bytecode.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "../lang.h"

inline const trieste::TokenDef DestructiveRead{"destructive_read"};

PassDef bytecode()
{
PassDef p{
Expand Down Expand Up @@ -74,6 +76,24 @@ PassDef bytecode()
<< create_print(_(Op));
},

T(Compile) << (T(Taint)[Op] << T(Ident)[Ident]) >>
[](auto& _) {
auto print_str = std::string(create_print(_(Op))->location().view());
return Seq << (Compile << _[Ident]) << (Taint ^ print_str);
},

T(Compile) << (T(DestructiveRead) << T(Ident)[Ident]) >>
[](auto& _) {
// Read the value from the frame and set the frame value to null
return Seq << (Compile << _(Ident)) << Null
<< create_from(StoreFrame, _(Ident));
},
T(Compile) << (T(Cown)[Op] << T(Ident)[Ident]) >>
[](auto& _) {
return Seq << (Compile << (DestructiveRead << _(Ident)))
<< (CreateObject << Cown);
},

T(Compile) << (T(Create)[Op] << T(Ident)[Ident]) >>
[](auto& _) {
return Seq << (Compile << _[Ident]) << (CreateObject << Proto);
Expand Down
4 changes: 2 additions & 2 deletions src/lang/passes/call_stmts.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace verona::wf

inline const auto call_stmts = grouping |
(Block <<=
(Freeze | Region | Assign | If | For | Func | Return | ReturnValue | Call |
Method | ClearStack | Print)++);
(Freeze | Taint | Region | Assign | If | For | Func | Return |
ReturnValue | Call | Method | ClearStack | Print)++);
}

PassDef call_stmts()
Expand Down
13 changes: 7 additions & 6 deletions src/lang/passes/flatten.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ namespace verona::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 | Method | Return | ReturnValue |
ClearStack)++) |
(Freeze | Taint | Region | Assign | Eq | Neq | Label | Jump | JumpFalse |
Print | StoreFrame | LoadFrame | CreateObject | Ident | IterNext |
Create | StoreField | Lookup | String | Call | Method | Return |
ReturnValue | ClearStack)++) |
(CreateObject <<= (KeyIter | String | Dictionary | Func)) |
(Func <<= Compile) | (Compile <<= Body) | (Create <<= Ident) |
(Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) |
(Lookup <<= (Op >>= operand) * (Rhs >>= key)) | (Region <<= Ident) |
(Freeze <<= Ident) | (Call <<= Ident * List) | (Method <<= Lookup * List) |
(List <<= rv++) | (Params <<= Ident++) |
(Freeze <<= Ident) | (Taint <<= Ident) | (Cown <<= Ident) |
(Call <<= Ident * List) | (Method <<= Lookup * List) | (List <<= rv++) |
(Params <<= Ident++) |
(Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) |
(Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) |
(Label <<= Ident)[Ident];
Expand Down
14 changes: 5 additions & 9 deletions src/lang/passes/grouping.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ PassDef grouping()
In(Group) * OPERAND[Op] * (T(Lookup)[Lookup] << (T(Group) << KEY[Rhs])) >>
[](auto& _) { return Lookup << _(Op) << _(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) >>
T(Group)
<< ((T(Freeze, Taint, Cown, Region)[Op] << End) * T(Ident)[Ident] *
End) >>
[](auto& _) {
_(Freeze)->extend(_(Ident)->location());
return _(Freeze) << _(Ident);
_(Op)->extend(_(Ident)->location());
return _(Op) << _(Ident);
},

T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >>
Expand Down
4 changes: 3 additions & 1 deletion src/lang/passes/parse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace verona::wf
using namespace trieste::wf;

inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze |
Drop | Null | String | Create | Parens;
Taint | Cown | Drop | Null | String | Create | Parens;
inline const auto parse_groups =
Group | Assign | If | Else | Block | For | Func | List | Return;

Expand Down Expand Up @@ -154,6 +154,8 @@ trieste::Parse parser()
"drop" >> [](auto& m) { m.add(Drop); },
"create" >> [](auto& m) { m.add(Create); },
"freeze" >> [](auto& m) { m.add(Freeze); },
"taint" >> [](auto& m) { m.add(Taint); },
"cown" >> [](auto& m) { m.add(Cown); },
"region" >> [](auto& m) { m.add(Region); },
"None" >> [](auto& m) { m.add(Null); },
"[0-9A-Za-z_]+" >> [](auto& m) { m.add(Ident); },
Expand Down
50 changes: 50 additions & 0 deletions src/rt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,55 @@ namespace rt::core
}
};

// The prototype object for cown
inline PrototypeObject* cownPrototypeObject()
{
static PrototypeObject* proto = new PrototypeObject("Cown");
return proto;
}

class CownObject : public objects::DynObject
{
// For now always false, but might be needed later if we want to simulate
// concurrency.
bool acquired = false;

public:
CownObject(objects::DynObject* region)
: objects::DynObject(cownPrototypeObject())
{
// FIXME: Add once regions are reified
// assert(
// region->get_prototype() == regionPrototype() &&
// "Cowns can only store regions");
//
// FIXME: Also check that the region has a LRC == 1, with 1
// being the reference passed into this constructor
auto old = this->set("region", region);
assert(old == nullptr);
}

std::string get_name()
{
return "<cown>";
}

objects::DynObject* is_primitive()
{
return this;
}

bool is_cown() override
{
return true;
}

bool is_cown_acquired() override
{
return acquired;
}
};

inline std::set<objects::DynObject*>* globals()
{
static std::set<objects::DynObject*>* globals =
Expand All @@ -185,6 +234,7 @@ namespace rt::core
keyIterPrototypeObject(),
trueObject(),
falseObject(),
cownPrototypeObject(),
};
return globals;
}
Expand Down
Loading