| How to extend default scope with attributes from superclass? [message #885219] |
Tue, 12 June 2012 12:20  |
Eclipse User |
|
|
|
Consider following grammar definition (... a little part of):
Model: declarations+=(DeclaredConstant | DeclaredFunction | DeclaredEntity)*;
...
EvaluableID : DeclaredAttribute | DeclaredConstant | DeclaredOperation | DeclaredFunction | DeclaredParameter | DeclaredVariable
EvaluableIDRef : ref=[EvaluableID] | builtInC=BuildInConstant | builtInF=BuiltInFunction;
...
PrimaryExpression returns Expression: {Literal} val=INT | {Evaluation} ref=EvaluableIDRef;
...
Statement: ... /* is using of Expressions */ ...;
...
DeclaredFunction: 'FUNCTION' name=ID ... /* is using of Statements */ ...;
DeclaredOperation: 'OPERATION' name=ID ... /* is using of Statements */ ...;
...
DeclaredEntity:
'ENTITY' name=ID ('EXTENDS' super=[DeclaredEntity])?
attrs+=DeclaredAttribute*
opers+=DeclaredOperation*
;
...
What is the easiest way to extend the default scope for "EvaluableIDRef" (which will be given by a standard scope provider) with a list of additional attributes given from all superclasses of the current entity (for example if the current context is Model -> DeclaredEntity -> DeclaredOperation -> "SomeStatement" -> PrimaryExpression -> EvaluableIDRef ...).
I need some code snippet (of expected implementation) to understand how it works.
Once again to clarify -> i don't need to replace the standard scope provider function for this case -> much more i would use the scope returned from this function and extend it with additional attributes from whole superclass hierarchy (attribute names are (can be) also not unique).
Thank you!
[Updated on: Tue, 12 June 2012 12:22] by Moderator
|
|
|
|
|
|
|
|
|
| Re: How to extend default scope with attributes from superclass? [message #885860 is a reply to message #885696] |
Wed, 13 June 2012 14:25   |
Eclipse User |
|
|
|
Hi,
of course you have to do the same for the other side (AssignableIDRef) - this is one reason why i said your grammar is still way to complex to get started with advanced scoping.
and yes if you do scoping this way it will be performance pain in the ass. this is why i suggested you to use the index
(1) introducing dynamic implicit imports
(2) collect all stuff from the index
here an example for (2)
First we have to care the the attributes get a simple name
public class MyDslNameProvider extends DefaultDeclarativeQualifiedNameProvider {
public QualifiedName qualifiedName(DeclaredAttribute attr) {
return QualifiedName.create(attr.getName());
}
}
then we care that the entities add their parent's name to the index
the attributes add their entity's name to the index
public class MyDslResourceDescriptionStrategy extends
DefaultResourceDescriptionStrategy {
public boolean createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) {
if (eObject instanceof DeclaredEntity ) {
Map<String, String> data = new HashMap<String, String>();
List<INode> nodes = NodeModelUtils.findNodesForFeature(eObject, MyDslPackage.Literals.DECLARED_ENTITY__SUPER);
if (nodes.size()>0) {
String parentName = nodes.get(0).getText().trim();
data.put("entity", parentName);
}
return createEOD(eObject, acceptor, data );
} else if (eObject instanceof DeclaredAttribute ) {
Map<String, String> data = new HashMap<String, String>();
DeclaredEntity entity = EcoreUtil2.getContainerOfType(eObject, DeclaredEntity.class);
data.put("entity", entity.getName());
return createEOD(eObject, acceptor, data);
}
return super.createEObjectDescriptions(eObject, acceptor);
}
private boolean createEOD(EObject eObject,
IAcceptor<IEObjectDescription> acceptor, Map<String, String> data) {
if (getQualifiedNameProvider() == null)
return false;
try {
QualifiedName qualifiedName = getQualifiedNameProvider().getFullyQualifiedName(eObject);
if (qualifiedName != null) {
acceptor.accept(EObjectDescription.create(qualifiedName, eObject, data));
}
} catch (Exception exc) {
exc.printStackTrace();
}
return true;
}
}
since scoping for the local file is not done via index we have to fix this too
//fix handling of the local file
public class MyDslImportedNamespaceAwareLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider{
@Inject
private IDefaultResourceDescriptionStrategy rds;
@Override
protected ISelectable internalGetAllDescriptions(final Resource resource) {
Iterable<EObject> allContents = new Iterable<EObject>(){
public Iterator<EObject> iterator() {
return EcoreUtil.getAllContents(resource, false);
}
};
final List<IEObjectDescription> allDescriptions = new ArrayList<IEObjectDescription>();
IAcceptor<IEObjectDescription> acceptor = new IAcceptor<IEObjectDescription>() {
@Override
public void accept(IEObjectDescription t) {
allDescriptions.add(t);
}
};
for (EObject o : allContents) {
rds.createEObjectDescriptions(o, acceptor);
}
return new MultimapBasedSelectable(allDescriptions);
}
}
at last step we fix the scoping and
calculate all parent's names using the index
filter the attributes by the parents names
public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {
IScope scope_EvaluableIDRef_ref(DeclaredEntity context, EReference reference) {
final Set<String> allEntities = getAllEntities(context);
Predicate<IEObjectDescription> filter = new Predicate<IEObjectDescription>() {
@Override
public boolean apply(IEObjectDescription input) {
String entity = input.getUserData("entity");
return entity != null && allEntities.contains(entity);
}
};
return new FilteringScope(delegateGetScope(context, reference), filter );
}
Set<String> getAllEntities(DeclaredEntity context) {
Map<String,String> allEntities = new HashMap<String,String>();
for (IEObjectDescription e : delegateGetScope(context, MyDslPackage.Literals.DECLARED_ENTITY__SUPER).getAllElements()) {
String parent = e.getUserData("entity");
if (parent != null) {
allEntities.put(e.getQualifiedName().toString(), parent);
}
}
Set<String> result = Sets.newHashSet();
String current = context.getName();
while(current != null && result.add(current)) {
current = allEntities.get(current);
}
return result;
}
}
please note: this only handles attributes
the have to be some extra changes to be made to fix
it for other Evaluable types
~Christian
|
|
|
|
|
|
| Re: How to extend default scope with attributes from superclass? [message #889505 is a reply to message #886143] |
Tue, 19 June 2012 05:53  |
Eclipse User |
|
|
|
Hi, here is my solution which i use at the moment. Not so performant as the one from Christian (-> using of indexes, see above), but for the most cases it is OK.
Xtext (snippet):
...
Statement:
{ AssignmentStmt } ref=AssignableIDRef '=' expr=Expression ';'
| { ForStmt } kwd='FOR' var=DeclaredVariable '=' from=Expression 'TO' to=Expression ('STEP' step=Expression)? '{' stmts+=Statement* '}'
| { ReturnStmt } kwd='RETURN' ( expr=Expression )? ';'
;
...
DeclaredEntity:
'ENTITY' name=ID ('EXTENDS' parents+=EntityRef*)? '{'
('ATT' attrs+=DeclaredAttribute+ ';')*
opers+=DeclaredOperation*
'}'
;
EntityRef : ref=[DeclaredEntity];
...
Java:
public class MyDslSP extends AbstractDeclarativeScopeProvider {
private EObject origCtx = null;
public IScope getScope(EObject context, EReference reference) {
origCtx = context;
return super.getScope(context, reference);
}
IScope scope_EvaluableIDRef_ref(DeclaredEntity context, EReference reference) {
return extendInheritanceScope(context, reference);
}
IScope scope_AssignableIDRef_ref(DeclaredEntity context, EReference reference) {
return extendInheritanceScope(context, reference);
}
IScope extendInheritanceScope(DeclaredEntity context, EReference reference) {
// get original context scope
IScope ctxScope = delegateGetScope(origCtx, reference);
// add inheritance scopes
Set<DeclaredEntity> allParents = collectAllParrents(context, new HashSet<DeclaredEntity>());
for (DeclaredEntity ent : allParents)
ctxScope = ((MyDslINALSP)getDelegate()).getLocalScope(ctxScope, ent, reference);
return ctxScope;
}
Set<DeclaredEntity> collectAllParrents(DeclaredEntity context, Set<DeclaredEntity> elements) {
for (EntityRef ref : context.getParents())
{
DeclaredEntity de = ref.getRef();
elements.add(de);
collectAllParrents(de, elements);
}
return elements;
}
}
public class MyDslINALSP extends ImportedNamespaceAwareLocalScopeProvider {
public IScope getLocalScope(IScope parent, final EObject context, final EReference reference) {
return getLocalElementsScope(parent, context, reference);
}
}
public class MyDslQNP extends DefaultDeclarativeQualifiedNameProvider {
int cnt = 0;
// providing of local visibility for "ForStmt" variables
QualifiedName qualifiedName(ForStmt f) {
if ("FOR".equals(f.getKwd()))
f.setKwd("FORSTMT:" + cnt++);
return QualifiedName.create(f.getKwd());
}
}
public class MyDslRuntimeModule extends org.xtext.example.mydsl.AbstractMyDslRuntimeModule {
@Override
public Class<? extends IQualifiedNameProvider> bindIQualifiedNameProvider() {
return MyDslQNP.class;
}
@Override
public Class<? extends IScopeProvider> bindIScopeProvider() {
return MyDslSP.class;
}
@Override
public void configureIScopeProviderDelegate(com.google.inject.Binder binder) {
binder.bind(org.eclipse.xtext.scoping.IScopeProvider.class)
.annotatedWith(com.google.inject.name.Names.named(
org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.NAMED_DELEGATE))
.to(MyDslINALSP.class);
}
}
[Updated on: Tue, 19 June 2012 05:54] by Moderator
|
|
|
Powered by
FUDForum. Page generated in 0.06550 seconds