Scoping with Xtext / TMF

The new Xtext version in Galileo changed a few things. To do scoping, a little bit of Java development is necessary. Documentation is very brief, but with a little research it is quite easy. Consider the following grammar, that allows us to define components, instances of those components and – the interesting part here – connect ports of instances:

Component :
    "component" name = ID "{"
    (ports+=Port)*
    "}";

Port :
    "port" dir=Direction name=ID ":"  ref=[Interface|ID] ";"
    ;

enum Direction :
    IN="in" | OUT="out";

Instance:
    "instance" name=ID ":" type=[Component|ID] ";"
    ;

Connection:
    "connect" in=[Instance|ID]"."p=[Port|ID] "->" in2=[Instance|ID]"."p2=[Port|ID] ";"
    ;

The default code completion will traverse all defined Ports for the references p and p2 in the Connection rule. A better behaviour would be:

  • Show only the ports in the instances (in, in2)
  • For p, show only “OUT”-Ports, for p2, show only “IN”-ports.

To do this, we need to define methods in a class derived from AbstractDeclarativeScopeProvider. The method names follow the signature scope_<rule>_<element>, so the code fragment for p2 is:

IScope scope_Connection_p2(Connection ctx, EReference ref)
    {
        if(ctx.getIn2() == null )
            return IScope.NULLSCOPE;
        else
            return new SimpleScope(IScope.NULLSCOPE, getRPorts(ctx.getIn2().getType()));

    }

With some additional code the full Provider for p and p2 looks like this:

public class AutomotiveDSLScopeProvider extends AbstractDeclarativeScopeProvider {
    IScope scope_Connection_p2(Connection ctx, EReference ref)
    {
        if(ctx.getIn2() == null )
            return IScope.NULLSCOPE;
        else
            return new SimpleScope(IScope.NULLSCOPE, getRPorts(ctx.getIn2().getType()));
    }

    IScope scope_Connection_p(Connection ctx, EReference ref)
    {
        if(ctx.getIn() == null )
            return IScope.NULLSCOPE;
        else
            return new SimpleScope(IScope.NULLSCOPE, getPPorts(ctx.getIn().getType()));
    }
    private Iterable<IScopedElement> getPPorts(Component clazz) {
        List<IScopedElement> result = new ArrayList<IScopedElement>();

        for (Port f : clazz.getPorts())
            if (f instanceof Port && f.getDir() == Direction.OUT)
                result.add(ScopedElement.create(f.getName(), f,"("));

        return result;
    }

    private Iterable<IScopedElement> getRPorts(Component clazz) {
        List<IScopedElement> result = new ArrayList<IScopedElement>();

        for (Port f : clazz.getPorts())
            if (f instanceof Port && f.getDir() == Direction.IN)
                result.add(ScopedElement.create(f.getName(), f));

        return result;
    }

}

4 thoughts on “Scoping with Xtext / TMF

  1. Hello,

    Please, can you post the whole Xtext-grammar?
    It is not possible to write a “Instance” or “Connection”-rule in the created editor. And what do you mean with the rule “Interface”?

    Thanks!

    Thomas V.

  2. The grammar is only an excerpt to show the scoping. I might publish more of it when I have time.

  3. Scoping is not very well documented. Could you please provide an example for the new Xtext 1.0

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">