Search code examples
xtextscoping

Getting an index of a current multi-valued feature while scoping


Lets say I want to be able to declare a bunch of nodes, possibly with links to previous ones. And then declare paths trough those nodes, following the links. I'd like the DSL to look like this:

node A
node B1 -> A
node B2 -> A
node C1 -> B1
node C2 -> B1
path C2 -> B1 -> A
path B2 -> A

Here is an XText grammar that I'd like to use. Note that I'm placing nodes links in the multi-valued feature nodes of the path.

Model:(
      nodes += Node
    | paths += Path
    )*
;

Node: 
    'node' name=ID ('->' from=[Node])? ;

Path:
    'path' nodes+=[Node] ('->' nodes+=[Node])* ;

Now, I need to constraint those [Node] links in the path so that they only follow the declared ones. I guess, I have to do it via scoping -- with something like that:

override getScope(EObject ctx, EReference ref){
    if(ref == MyDslPackage.Literals.PATH__NODES ){
        if(ctx instanceof Path) 
        return Scopes::scopeFor(/* Node link, previous to the current one */);
    }
    return super.getScope(ctx,ref)
}

In order to get to the previous link, I'll need an index of the current one, but I cannot find a way to obtain it. Is there a way to get such an index? Should I do it somehow via accessing ctx.nodes directly? (It seems to lead to a linking-resolution-cycle-error, but, maybe, I'm doing it properly.)


Edit. Changing the grammar adding {Path.parent=current} and adding this to scoping does the trick:

 return Scopes::scopeFor(#[ctx.parent.node.from])

Solution

  • Instead of parsing it into a list of references you should parse it into distinct Path objects with parent pathes like so:

    Path:
       'path' node=[Node] ({Path.parent=current} '->' node=[Node])* ;
    

    It makes it easier to work with the individual path elements.