1
votes

I started developing an XText DSL, which has now two sub-languages, which reference each other (to be more precise, A refers to B). They each have their own plugins, and generator workflow.

The relevant part of looks something like this:

Language A:

ARoot:
    'rootOfB:' (foos+=Foo)*;

Foo:
    'foo' name=ID;

Language B:

import 'url-of-a' as A

BRoot:
    'rootOfA:' (bars+=Bar)*;

Bar:
    'bar' name=ID 'for' foo=[A::Foo] ;

Now I try to provide a scope provider, so that in language B foo elements are recognized, but i did not find a way yet to get access to the parsed elements of A. I did some debugging, and it looks like neither the parameter foo, nor the eReference has any kind of connection to the elements of language A:

class MyScopeProvider extends AbstractDeclarativeScopeProvider {
    def IScope scope_Bar_foo(Bar bar, EReference eReference){
        // How should i reference and return all the Foo objects here?
    }
}

Foo elements also have a full-qualified name provider, so that shouldn't be a problem, i tested it from another scope, while still working on plugin A:

class MyQualifiedNameProvider extends DefaultDeclarativeQualifiedNameProvider {
    override qualifiedName(Object o) {
        if (o instanceof Foo) {
            val f = o as Foo
            return QualifiedName.create(f.name)
        }
        super.qualifiedName(o);
    }
}

So my question is: How would i get the parsed EObjects in the a different plugin?

Example usage:

Contents of a file, that uses grammar A:

rootOfA
    foo firstFoo
    foo secondFoo

Contents of a file, that uses grammar B:

rootOfB
    bar firstBar for [i would like reference firstFoo or secondFoo here]
1
I tried your sample grammars and linking works when resources from languageA and languageB are in the same project, is that your case? Also, if you press Ctrl + Shift + F3, can you see Foo item? how are they named? - Fabien Fleureau
No, the problem is they are in different projects (plugins). And from project B i try to access some model elements which are in project A. It should be possible, but i couldn't find a way to do it yet. When they were in the same project (and grammar) it worked. - Balázs Édes

1 Answers

1
votes

You have to add a dependency to plugin A in the Manifest of the plugin B. You also have to add dependency into workflow mwe2.

See http://www.eclipse.org/Xtext/documentation.html#grammarMixins for more details.

Edit 1

You are trying to make a reference to another resource. This article explains differences between local and global scope: http://blogs.itemis.de/leipzig/archives/809

ScopeProvider does not apply here. You should implement your own ResourceDescriptionStrategy for plugin A in order to describe what EObject you want to be exported from a resource A. In your ScopeProvider (plugin B) you have to call delegateGetScope() to have global scope (A + B).

Edit 2

If you want to make linking work between two different project you can use the following Eclipse standard mechanism:

Right-click on project B and open Properties, and go to "Project Reference". You will see Project A, you just have to select it.

When it's done, clean your two projects and your linking will be ok.

Edit 3

Here an example of custom implementation for ResourceDescriptionStrategy:

public class MyResourceDescriptionStrategy extends DefaultResourceDescriptionStrategy {
    @Override
    public boolean createEObjectDescriptions(EObject eObject,
            IAcceptor<IEObjectDescription> acceptor) {
        if (eObject instanceof Foo) {
            QualifiedName fullyQualifiedName = getQualifiedNameProvider().getFullyQualifiedName(eObject);
            IEObjectDescription ieObjectDescription = EObjectDescription.create(fullyQualifiedName, eObject);
            acceptor.accept(ieObjectDescription);
            return true;
        }
        return super.createEObjectDescriptions(eObject, acceptor);
    }
}

You have to bind this class in plugin A RuntimeModule:

public Class<? extends IDefaultResourceDescriptionStrategy> bindIDefaultResourceDescriptionStrategy() {
    return MyResourceDescriptionStrategy.class;
}

Here an example of ScopeProvider implementation using "global scope":

def IScope scope_Bar_foo(Bar bar, EReference eReference){
    return delegateGetScope(bar, eReference);
}

In this example, it will only search into global scope. If want to add something else to the scope you should use SimpleScope which can manage "parent scope".