Hello everyone!
I have a Scoping issue and I hope you could help me ...
I'm trying to achieve the following:
1. Restrict the default GlobalScope only to explicitly imported resources (and some default imports)
2. Access it without use of fully qualified name
So, I can address to elements by their fully qualified name, but I would want to automatically import the namespace, to address to ID directly (like if it was under the same namespace).
How can I add all importURI resources to the current scope?
For example:
<ModelName>.<ElementName> to <ElementName>
in some cases: <ModelName>.<OuterElement>.<InnerElement> to just <InnerElement> ?
Because my actual grammar is too big and irrelevant for this question, let's say that I have the following (very simplified):
Grammar:
Model:
name=ID ':'
include+=Include*
ownedNamedElements+=NamedElement*
greeting+=Greeting*;
Include:
'import' importURI=STRING
;
NamedElement:
'def' name=ID
;
Greeting:
'Hi' name=[NamedElement|QualifiedName] '!'
;
QualifiedName:
ID ('.'ID)*
;
ResourceDescriptionStrategy:
class CGResourceDescriptionStrategy extends DefaultResourceDescriptionStrategy{
public static final String INCLUDES = "includes"
@Inject
ImportUriResolver uriResolver
override createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) {
if(eObject instanceof Model) {
this.createEObjectDescriptionForModel(eObject, acceptor)
return true
}
else {
super.createEObjectDescriptions(eObject, acceptor)
}
}
def void createEObjectDescriptionForModel(Model model, IAcceptor<IEObjectDescription> acceptor) {
val uris = newArrayList()
model.include.forEach[uris.add(uriResolver.apply(it))]
val userData = new HashMap<String,String>
userData.put(INCLUDES, uris.join(","))
acceptor.accept(EObjectDescription.create(QualifiedName.create(model.eResource.URI.toString), model, userData))
}
}
RuntimeModule:
class CGRuntimeModule extends AbstractCGRuntimeModule {
def Class<? extends IDefaultResourceDescriptionStrategy> bindIDefaultResourceDescriptionStrategy() {
CGResourceDescriptionStrategy
}
override Class<? extends IGlobalScopeProvider> bindIGlobalScopeProvider() {
CGGlobalScopeProvider;
}
}
CGGlobalScopeProvider:
class CGGlobalScopeProvider extends ImportUriGlobalScopeProvider{
static final Splitter SPLITTER = Splitter.on(',');
@Inject
IResourceDescription.Manager descriptionManager;
@Inject
IResourceScopeCache cache;
override protected getImportedUris(Resource resource) {
return cache.get(CGGlobalScopeProvider.getSimpleName(), resource, new Provider<LinkedHashSet<URI>>() {
override get() {
val uniqueImportURIs = collectImportUris(resource, new LinkedHashSet<URI>())
val uriIter = uniqueImportURIs.iterator()
while(uriIter.hasNext()) {
if (!EcoreUtil2.isValidUri(resource, uriIter.next()))
uriIter.remove()
}
return uniqueImportURIs
}
def LinkedHashSet<URI> collectImportUris(Resource resource, LinkedHashSet<URI> uniqueImportURIs) {
val resourceDescription = descriptionManager.getResourceDescription(resource)
val models = resourceDescription.getExportedObjectsByType(ModelPackage.Literals.MODEL)
models.forEach[
val userData = getUserData(CGResourceDescriptionStrategy.INCLUDES)
if(userData !== null) {
SPLITTER.split(userData).forEach[uri |
var includedUri = URI.createURI(uri)
includedUri = includedUri.resolve(resource.URI)
if(uniqueImportURIs.add(includedUri)) {
collectImportUris(resource.getResourceSet().getResource(includedUri, true), uniqueImportURIs)
}
]
}
]
return uniqueImportURIs
}
});
}
}