Conditional definitions?
Hi,
I’ve got the following problem. In my language the assignment operation is sometimes an iteration over a collection for which the RHS is assigned. Example:
Proc a(G:Graph, dist:N_P<Int>, root: Node) { G.dist = (_ == root) ? 0 : +INF; }
In the example above
G.dist
refers to the propertydist
of all of nodes inG
. The type of the LHS of the assignment dictates that the assignment is a batch-assignment. When this happens, a variable _ of typeN_P<Int>
should be defined in the RHS of the assignment. If the assignment is not a batch assignment then _ is not defined. Any clue how I could achieve this? I’m pretty sure that batch-assignments are not distinguishable purely on syntax.I was thinking of a few options, but i’m not sure which is best or how to achieve them:
- Have a conditional definition in NaBL. The definition could be enabled/disabled by the success of a property-task.
- During create-type-task on the
LHS = RHS
statement, add the definition for _ programmatically.Thanks.
Submitted by Vlad Vergu on 20 December 2013 at 12:53
Issue Log
I think you can express the check in a
nabl-constraint
rule. You match on the assignment, create a task to calculate the LHS type, generate an error for each_
if the LHS type is not a node/edge property.Assigning a type to
_
is a bit more hacky. You annotate each_
manually with the LHS type, and in thecreate-type-task
for_
calculate the type (or be untyped) based on that annotation.
Edit: this would be a custom annotation that doesn’t interfere with the type/property annotations from NaBL.Do you think that works?
Hi Gabriël, thanks for the answer.
I’ve only looked at assigning a type to
_
so far. This could work, but i do not know how to create the annotation on the tree. I only know the type of_
duringcreate-type-task
, butcreate-type-task
is expected to result a task number and cannot return a tree. Here’s what i’ve tried:signature constructors WldType: Term rules /* assignments */ /* special handling for property batch assignment */ create-type-task(|ctx): |[ exp0.name = exp1; ]|-> <fail> with exp0-ty := <type-task(|ctx)> exp0; name-ty := <type-lookup(|ctx)> name; name-prop-ty := <type-task-is-property(|ctx)> name-ty with exp0-coll-ty := <type-task-collection-is(|ctx)> exp0-ty; exp0-coll-elem-ty := <type-task-collection-get-elem-type(|ctx)> exp0-coll-ty; coll-prop-same-member := <type-task-has-eq-members(|ctx)> (name-prop-ty, exp0-coll-elem-ty) with wld-type := <type-is(|ctx, [coll-prop-same-member])> exp0-coll-elem-ty with // push annotation down. How to make it stick because this rule <fails> fail create-type-task(|ctx): w@Wld() -> <get-prop-anno(|WldType())> w
Where, when i see an assignment with a
exp.name
on the LHS, i try to see if thename
is a property of the things stored in the collectionexp
(the graph case is not handled yet). If this is true then the type of_
is the type of the elements stored in the collection. At this stage i need to remember this, but i’m not allowed to rewrite the tree during create-type-task.Assuming i have annotated the tree with the calculated type, then (2nd rule) when i see a
_
i return the task that was previously created.I like the solution. I think it is reasonably neat. If we figure out how to remember what the type of
_
is until thecreate-type-task
is called on_
, then we’re good i think.
You’re right, you cannot change the AST during
create-type-task
, forgot about that.After some discussion with Guido we found a better solution. You can implicitly define
_
with some type in an assignment:Assign(a, e): implicitly defines Variable "_" of type t in e where a has type t
Then you need to wrap
_
within another constructor and calculate the type, for example:create-type-task(|ctx): Wrapped(v) -> t where v-ty := <type-task(|ctx)> v ; t := <calc_real_type|ctx)> v-ty ; <create_error_when_not_batch_assign> t
and you create an error when the type cannot be batch assigned, instead of having a conditional definition.
Thanks. I think it will be fine with a slightly different variant i think. The type of
a
is not sufficient to figure out if it’s a batch assign. A batch assign happens if the LHS isexp.name
andexp
is a collection of things of whichname
is a property of. But i think i can remember a bit more:Assign(a, e): implicitly defines Variable "_" of type t of typegenerator a in e where a has type t
And then:
create-type-task(|ctx): Wrapped(v) -> t where v-ty := <type-task(|ctx)> v ; v-ty-gen := <typegenerator-task(|ctx)> v ; t := <calc_real_type|ctx)> v-ty-gen ; <create_error_when_not_batch_assign> t
What do you think?
This has worked. Thank you.
Log in to post comments