Home » Modeling » TMF (Xtext) » Problem with scopes
Problem with scopes [message #893350] |
Tue, 03 July 2012 12:14  |
Eclipse User |
|
|
|
Hi
I've succesfully written scopes definitions using xtend if the referenced objects can be accesible via EMF
def IScope scope_Origin_atr(Origin or, EReference ref) {
Scopes::scopeFor(or.navigateEMF.allReferencesINeed)
}
Now i have another case where from all default referenced objects, i want to remove some of them using a condition. I've tried several combinations, but i haven't been able:
def IScope scope_OtherOrigin_atr(OtherOrigin or, EReference ref) {
val baseScope = super.delegateGetScope(or, ref)
//Remove some of the elements in baseScope
val filteredScope = baseScope
filteredScope
}
Any idea?
Thanks
Sergio
|
|
| |
Re: Problem with scopes [message #893377 is a reply to message #893350] |
Tue, 03 July 2012 14:39   |
Eclipse User |
|
|
|
Hi
I'll try to define the problem using a variation of the Martin Fowler example (and writing without Eclipse, so maybe there are some errors)
Imagine that when selecting the State in a Transition, you don't want all available States, but only States without Actions (i know it doesn't make sense here, it's only a example).
Transition: event=[Event] '=>' state=[State]
You can accomplish that doing:
def IScope scope_Transition_state(Transition t, EReference ref) {
Scopes::scopeFor(t.stateMachine.states.filter[s | s.actions.size == 0])
}
def Statemachine stateMachine(Transition t) {
// navigate from transition to it's parent Statemachine
}
Suppose you change the grammar to support the definition of events, commands and states in separated files
From:
Statemachine :
'events'
(events+=Event)+
'end'
('resetEvents'
(resetEvents+=[Event])+
'end')?
'commands'
(commands+=Command)+
'end'
(states+=State)+;
To
Statemachine: Event | Command | State
Only with this change, you can define in separate files Events, Commands and States and references like "Transition: event=[Event] '=>' state=[State];" continue to work perfectly.
The problem is that now i cannot do the "trick" of browsing the EMF model to do the scoping.
Instead of that, i would need to get the default proposal and filter those that have 0 actions (this is only an alternative without the grammar change):
def IScope scope_Transition_state(Transition t, EReference ref) {
val baseScope = super.delegateGetScope(t, ref)
// I don't know how to filter here the object IScope
baseScope
}
I've tried to use FilteringScope with a closure like you suggested in other thread (http://www.eclipse.org/forums/index.php/m/802897/). More or less like that:
val filtscope = new FilteringScope(baseScope, [iod| EObjectOrProxy instanceof State])
It's not testing if the State has 0 actions, but even that returns false because the object is a proxy, not the State.
Maybe digging more inside IEObjectDescription i could get it to work, but something tells me this is not the best way
If you need more clarifications, please tell me.
Thanks
Sergio
|
|
|
Re: Problem with scopes [message #893391 is a reply to message #893377] |
Tue, 03 July 2012 15:52   |
Eclipse User |
|
|
|
Hi,
Using this example you a facing a lot of problems/restrictions at the same time.
never the less lets give it a try, (using the fowler sample of xtext 2.2.1)
(0) change grammar to allow only one thing in one file and states having zero actions
(1) we want to store the information of a State having actions in the index. since indexing is done at a state where no cross refs exists/are linked we could do something like ....
sadly the hooks for such things are still far away from being perfect,
public class StatenachineResourceDescriptionStrategy extends
DefaultResourceDescriptionStrategy {
public static final String HAS_ACTIONS = "HAS_ACTIONS";
@Override
public boolean createEObjectDescriptions(EObject eObject,
IAcceptor<IEObjectDescription> acceptor) {
if (eObject instanceof State) {
return createStateDescriptions((State) eObject, acceptor);
}
return super.createEObjectDescriptions(eObject, acceptor);
}
public boolean createStateDescriptions(State state, IAcceptor<IEObjectDescription> acceptor) {
if (getQualifiedNameProvider() == null)
return false;
try {
QualifiedName qualifiedName = getQualifiedNameProvider().getFullyQualifiedName(state);
if (qualifiedName != null) {
Map<String, String> data = new HashMap<String, String>();
data.put(HAS_ACTIONS, Boolean.toString(NodeModelUtils.findNodesForFeature(state, StatemachinePackage.Literals.STATE__ACTIONS).size() > 0));
acceptor.accept(EObjectDescription.create(qualifiedName, state, data ));
}
} catch (Exception exc) {
exc.printStackTrace();
}
return true;
}
}
and bind it in the runtime module
public Class<? extends IDefaultResourceDescriptionStrategy> bindIDefaultResourceDescriptionStrategy() {
return StatenachineResourceDescriptionStrategy.class;
}
finally we use the data in the scope provider
public class StatemachineScopeProvider extends AbstractDeclarativeScopeProvider {
public IScope scope_Transition_state(Transition t, EReference ref) {
return new FilteringScope(delegateGetScope(t, ref), new Predicate<IEObjectDescription>() {
@Override
public boolean apply(IEObjectDescription input) {
String hasActions = input.getUserData(StatenachineResourceDescriptionStrategy.HAS_ACTIONS);
return hasActions != null && !Boolean.valueOf(hasActions);
}
});
}
}
please note: (if states and transitions are defined in the same file) you have to do a second adoptions for the local resource
public class StatemchineImportedNamespaceAwareLocalScopeProvider extends
ImportedNamespaceAwareLocalScopeProvider {
@Inject
private IQualifiedNameProvider qualifiedNameProvider;
@Override
protected ISelectable internalGetAllDescriptions(final Resource resource) {
Iterable<EObject> allContents = new Iterable<EObject>(){
public Iterator<EObject> iterator() {
return EcoreUtil.getAllContents(resource, false);
}
};
Iterable<IEObjectDescription> allDescriptions = scopedElementsFor2(allContents, qualifiedNameProvider);
return new MultimapBasedSelectable(allDescriptions);
}
public <T extends EObject> Iterable<IEObjectDescription> scopedElementsFor2(Iterable<? extends T> elements,
final Function<T, QualifiedName> nameComputation) {
Iterable<IEObjectDescription> transformed = Iterables.transform(elements,
new Function<T, IEObjectDescription>() {
public IEObjectDescription apply(T from) {
final QualifiedName qualifiedName = nameComputation.apply(from);
Map<String, String> data = new HashMap<String, String>();
if (from instanceof State) {
data.put(StatenachineResourceDescriptionStrategy.HAS_ACTIONS,Boolean.toString(((State)from).getActions().size() > 0));
if (qualifiedName != null)
return new EObjectDescription(qualifiedName, from, data );
} else {
if (qualifiedName != null)
return new EObjectDescription(qualifiedName, from, null );
}
return null;
}
});
return Iterables.filter(transformed, Predicates.notNull());
}
}
and again do the binding
public void configureIScopeProviderDelegate(com.google.inject.Binder binder) {
binder.bind(IScopeProvider.class).annotatedWith(Names.named(AbstractDeclarativeScopeProvider.NAMED_DELEGATE)).to(StatemchineImportedNamespaceAwareLocalScopeProvider.class);
}
~Christian
--
Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
|
|
|
Re: Problem with scopes [message #893394 is a reply to message #893391] |
Tue, 03 July 2012 16:18  |
Eclipse User |
|
|
|
In my case, changing the grammar doesn't solve it because it's a semantic problem (i think so), so i'll adapt the solution to my problem and i think it'll work.
Anyway, for a more complex condition involving not only the referenced node but also properties of it's childs, maybe it'll be more scalable to do a validation that trying to compute all the posible choices.
Thanks
Sergio
|
|
|
Goto Forum:
Current Time: Mon Jul 07 12:38:19 EDT 2025
Powered by FUDForum. Page generated in 0.04092 seconds
|