From b69a27feab9cdadd045b41ec081887d5dfcd3078 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Fri, 18 Oct 2024 16:59:36 +0200 Subject: [PATCH] Passes: Support cown creation --- src/lang/bytecode.h | 1 + src/lang/interpreter.cc | 6 ++++++ src/lang/lang.h | 11 ++++++----- src/lang/passes/bytecode.cc | 14 ++++++++++++++ src/lang/passes/flatten.cc | 5 +++-- src/lang/passes/grouping.cc | 20 +++++--------------- src/lang/passes/parse.cc | 5 +++-- src/rt/core.h | 4 ++-- src/rt/objects/dyn_object.h | 12 ++++++++---- tests/valid_cowns.vpy | 21 +++++++++++++++++++++ 10 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 tests/valid_cowns.vpy diff --git a/src/lang/bytecode.h b/src/lang/bytecode.h index 4fab1e3..67eacfe 100644 --- a/src/lang/bytecode.h +++ b/src/lang/bytecode.h @@ -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"}; diff --git a/src/lang/interpreter.cc b/src/lang/interpreter.cc index 9195c08..ed02d0d 100644 --- a/src/lang/interpreter.cc +++ b/src/lang/interpreter.cc @@ -185,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"); diff --git a/src/lang/lang.h b/src/lang/lang.h index d8eea35..20711f4 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -32,7 +32,8 @@ 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; @@ -44,8 +45,8 @@ namespace verona::wf ReturnValue | Call | Method)++) | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | (Lookup <<= (Op >>= operand) * (Rhs >>= key)) | (Region <<= Ident) | - (Freeze <<= Ident) | (Taint <<= 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) | @@ -58,13 +59,13 @@ namespace verona::wf CreateObject | CreateRegion | FreezeObject | Taint | IterNext | Print | Eq | Neq | Jump | JumpFalse | Label | Call | Return | ReturnValue | ClearStack | Dup)++) | - (CreateObject <<= (Dictionary | String | KeyIter | Proto | Func)) | + (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); diff --git a/src/lang/passes/bytecode.cc b/src/lang/passes/bytecode.cc index 4b06a31..94c452c 100644 --- a/src/lang/passes/bytecode.cc +++ b/src/lang/passes/bytecode.cc @@ -1,5 +1,7 @@ #include "../lang.h" +inline const trieste::TokenDef DestructiveRead{"destructive_read"}; + PassDef bytecode() { PassDef p{ @@ -79,6 +81,18 @@ PassDef bytecode() return Seq << (Compile << _[Ident]) << create_from(Taint, _(Op)); }, + 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); diff --git a/src/lang/passes/flatten.cc b/src/lang/passes/flatten.cc index 9809b80..2d89994 100644 --- a/src/lang/passes/flatten.cc +++ b/src/lang/passes/flatten.cc @@ -14,8 +14,9 @@ namespace verona::wf (Func <<= Compile) | (Compile <<= Body) | (Create <<= Ident) | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | (Lookup <<= (Op >>= operand) * (Rhs >>= key)) | (Region <<= Ident) | - (Freeze <<= Ident) | (Taint <<= 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]; diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index 738779d..3301af8 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -16,22 +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) >> - [](auto& _) { - _(Freeze)->extend(_(Ident)->location()); - return _(Freeze) << _(Ident); - }, - - T(Group) << ((T(Taint)[Taint] << End) * T(Ident)[Ident] * End) >> + T(Group) + << ((T(Freeze, Taint, Cown, Region)[Op] << End) * T(Ident)[Ident] * + End) >> [](auto& _) { - _(Taint)->extend(_(Ident)->location()); - return _(Taint) << _(Ident); + _(Op)->extend(_(Ident)->location()); + return _(Op) << _(Ident); }, T(Group) << ((T(Drop)[Drop] << End) * LV[Lhs] * End) >> diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index dfabfff..8e21dab 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -5,7 +5,7 @@ namespace verona::wf using namespace trieste::wf; inline const auto parse_tokens = Region | Ident | Lookup | Empty | Freeze | - Drop | Taint | 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; @@ -154,8 +154,9 @@ trieste::Parse parser() "drop" >> [](auto& m) { m.add(Drop); }, "create" >> [](auto& m) { m.add(Create); }, "freeze" >> [](auto& m) { m.add(Freeze); }, - "region" >> [](auto& m) { m.add(Region); }, "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); }, "\\[" >> [](auto& m) { m.push(Lookup); }, diff --git a/src/rt/core.h b/src/rt/core.h index c4f1e52..0ede3cb 100644 --- a/src/rt/core.h +++ b/src/rt/core.h @@ -189,7 +189,7 @@ namespace rt::core public: CownObject(objects::DynObject* region) - : objects::DynObject(cownPrototypeObject()), + : objects::DynObject(cownPrototypeObject()) { // FIXME: Add once regions are reified // assert( @@ -218,7 +218,7 @@ namespace rt::core bool is_cown() override { - return false; + return true; } }; diff --git a/src/rt/objects/dyn_object.h b/src/rt/objects/dyn_object.h index a5285e9..973e312 100644 --- a/src/rt/objects/dyn_object.h +++ b/src/rt/objects/dyn_object.h @@ -79,8 +79,11 @@ namespace rt::objects return; } - assert(target->parent == src); - Region::dec_prc(target); + if (src) + { + assert(target->parent == src); + Region::dec_prc(target); + } return; } @@ -234,7 +237,7 @@ namespace rt::objects // TODO SCC algorithm visit(this, [](Edge e) { auto obj = e.target; - if (obj->is_immutable()) + if (!obj || obj->is_immutable()) return false; auto r = get_region(obj); @@ -244,7 +247,8 @@ namespace rt::objects } obj->region.set_tag(ImmutableTag); - return !obj->is_cown(); + auto cown = obj->is_cown(); + return !cown; }); } diff --git a/tests/valid_cowns.vpy b/tests/valid_cowns.vpy new file mode 100644 index 0000000..56093a7 --- /dev/null +++ b/tests/valid_cowns.vpy @@ -0,0 +1,21 @@ +global = {} + +# A simple cown +a = {} +a.b = {} +region a +c01 = cown a + +# Store the cown in a global +global.cown = c01 +taint global + +# Freeze global with a cown +freeze global + +# FIXME: traint with cowns is wrong +# FIXME: Show local region address +# FIXME: Cowns should have special rendering and out edges + +drop c01 +drop global