Constrain operations on DotExpression

I have a concept "PartyDeclaration" with child "Party" and a name. The "Party" concept has a child "input" of type InputDeclaration. The InputDeclaration can be accessed via the concept "InputRef", and the PartyDeclaration via the concept "PartyRef". I want to be able to access this input from a PartyRef with a DotExpression, and thus my InputRef concept extends IOperation. This works, I now can access all inputs via a dot after the parties name. See the following picture:

But as you can see, the auto-complete menu includes the input from all the parties, not just the one from which it is accessed (here Y). I tried to add "can be child" constraints to InputReference, so that the operand and operation of the DotExpression have to point to the same Party. My attempt is as follows:

Now, I do get no suggestions when trying to do a dot expression. I realised that this was because "node" is null at the moment when this constraint is called and thus the comparison does not work. Does anyone have a solution for this problem? I cannot think of a solution that does not have to access "node" itself.

Thanks in advance for any answers!

 

6 comments
Comment actions Permalink

Within your concept constraint, there is a section where you can provide a "scope" for a reference (the "ref" in your PartyRef concept). You want to build a scope based on the left side of the Dot operation. There are (at least) two ways how you can define your scope, see https://www.jetbrains.com/help/mps/scopes.html

If you opt for "using reference scope", you use the contextNode that is passed in to naviagte in your AST to the Party, collect all its inputs in a sequence. Then, you could return a "ListScope", which expects a collection of things it should contain. Hope this helps.

1
Comment actions Permalink

Thank you so much for answering!

I am not sure I understand completely though. You suggest that I should build a scope based on the left side of the Dot Expression, which is a PartyRef. So I tried adding a reference scope on "ref" in PartyRef, the way you suggested, as follows:

But doesn't this just restrict what "ref" in PartyRef can point to? It results in the following situation, where I cannot use PartyRef's anywhere in my program, because "The reference Y (ref) is out of search scope".

Did I specify the reference scope in the wrong file or did I do something wrong with the definition of the scope itself?

Thanks again for any answers!

0
Comment actions Permalink

Yeah, I misspoke, you need to create a scope for the reference inside your InputRef concept. 

You need to do

contextNode.ancestor<DotExpression, +>.partyRef.ref.party.input;

to get the inputs, assuming that your InputRef is a child of DotExpression, which also holds the PartyRef child called "partyRef".

I'm not sure why, in your screenshot, there is "ref.party", since I would assume "ref" already points to a node of concept "Party", but you get the idea, right?

Don't forget the "+" in the "ancestor<...>" operation to include the contextNode itself in the lookup (based on your structure, the contextNode might already be the DotExpression you are looking for.

1
Comment actions Permalink

Thanks you for the quick reply! 

Now I got the idea! With your code snippet and your explanation I was able to make it work perfectly.

"ref" actually points to a "PartyDeclaration", which in turn contains the "Party" itself, that's why I have to call "ref.party".

My final working constraint now looks like this: 

I am really grateful for your help :)

0
Comment actions Permalink

Very good.

I would probably factor out the cast to PartyRef, since the ":" operator might give you a NullReferenceException at runtime.

node<DotExpression> dotExpr = contextNode.ancestor<concept = DotExpression, +>;
ifInstanceOf(dotExp.operand as PartyRef partyRef) {
return ListScope.forNamedElements(partyRef.ref.party.input);
}

return new EmptyScope();

Did you know that, when you select the "ancestor" operation in your code and you press "CTRL+ALT+V" (or "CMD+ALT+V" on a Mac I assume) MPS will automatically create a local variable for you?

1
Comment actions Permalink

Thanks for the tips!

0

Please sign in to leave a comment.