Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Limiting scoped elements, but allowing simple names to be used
Limiting scoped elements, but allowing simple names to be used [message #1002595] Fri, 18 January 2013 17:53 Go to next message
Joost van Pinxten is currently offline Joost van Pinxten
Messages: 50
Registered: November 2012
Member
First off, Xtext has some very awesome defaults. I like them very much! Good work.

Now then, I want to achieve the same behaviour as the default scoping provider, but for a subset of all available elements. I use FQN to achieve hiding/accessing of duplicated names.

The grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Model:	applications+=Application*;
Application:	"Application" name=ID "{" tasks+=Task* "}";
Task:	"Task" name=ID "{" ports += Port* edges += Edge* "}";
Port:	"Port" name=ID ";";
Edge:	"Edge" "to" from=[Port | FQN] ";";
FQN:	ID ("."ID )* ;


Allowing me to define models like:
Application app1 { 
	Task task1 {
		Port p1;
		Edge a to p1;
	}
	
	Task task2 {
		Port p1;
		Edge a to task1.p1;
	}
}

Application app2 {
	Task task1 {
		Port p1;
		Edge a to app1.task1.p1; // Should not be allowed, as app1 !== app2
	}
}


I want the default scoping/proposal behavior, but then limited to Application, as the following code intends to do:
 public IScope scope_Port(Edge context, EReference reference) {
	Application app = (Application) context.eContainer().eContainer();
	
	List<Port> elements = new ArrayList<Port>(); 
	for (Task t : app.getTasks()) {
		elements.addAll(t.getPorts());
	}
	
	return Scopes.scopeFor(elements);
}

But, then the simple name is forced (i.e. just p1 is allowed); injecting the DefaultDeclarativeQualifiedNameProvider and using this in combination with a NULLSCOPE or a scope containing the Tasks/Application as outer scope also does not give me the correct behavior, as then the full FQN always needs to be specified.

Might have a look into exporting the IEObjectDescriptions, but it seems this will only work when exporting from a file to another. Can you give me pointers on what the way to go is? If anything is unclear, let me know, I'll rephrase or add the details.
Re: Limiting scoped elements, but allowing simple names to be used [message #1002725 is a reply to message #1002595] Sat, 19 January 2013 03:10 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander Nittka
Messages: 1151
Registered: July 2009
Senior Member
Hi,

this sounds like an application of FilteringScope where you define the predicate such that it applies only to IEObjectDescriptions where the first segment of the qualified name matches the the application of the given edge.

Alex


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: Limiting scoped elements, but allowing simple names to be used [message #1002922 is a reply to message #1002725] Sat, 19 January 2013 16:35 Go to previous message
Joost van Pinxten is currently offline Joost van Pinxten
Messages: 50
Registered: November 2012
Member
Thanks so much for the pointer, Alexander. So basically, I needed two elements: delegateGetScope, to get the original behavior; and then to use the FilteringScope to weed out the ones that are explicitly not accessible. Instead of checking by FQN, I am checking by containment, as I think that is more resilient to changes in the model/grammar.

public IScope scope_Port(Edge context, EReference reference) {
	EObject parent = context;
	
	// Check for containment in an Application object
	while (parent != null && !(parent instanceof Application)) {
		parent = parent.eContainer();
	}
	if(parent == null) {
		return IScope.NULLSCOPE;
	}
	
	final Application app = (Application) parent;
	// Add all port objects that are in this Application
	List<Port> elements = new ArrayList<Port>(); 
	for (Task t : app.getTasks()) {
		elements.addAll(t.getPorts());
	}
	
	// get the default/original scope, which uses shorthand FQNs
	IScope originalScope = delegateGetScope(context, reference);
	
	Predicate<IEObjectDescription> predicate = new Predicate<IEObjectDescription>(){
		public boolean apply(IEObjectDescription input) {
			if (input == null) {
				return false;
			}
			
			EObject parent = input.getEObjectOrProxy();
			// Search for the containing Application again
			while (parent != null && !(parent instanceof Application)) {
				parent = parent.eContainer();
			}
			// Only return true if the app is the same object as the application that contains this element
			return app.equals(parent);
		};
	};
	// Apply the predicate to the original scope
	return new FilteringScope(originalScope, predicate);
}


There is some stuff out there, for example in the Xtext documentation, and on the itemis blog, but none of them give an actual overview of methods, classes, what they do and how they should be applied. As I have stated before, Xtext works brilliantly out of the box, but it is a pain to search through all of the classes to find what you need. The FilteringScope class is only documented with a few comments, but I did not find any pointers to it anywhere in the documentation. And I've been missing those pointers quite a lot... But perhaps I'm just spoiled with the quality of the documentation of the Qt library Smile
Previous Topic:Null pointer after extends AbstractProcessorBasedRenameParticipant
Next Topic:xtext-utils - integration test failing, whitespace mismatch?
Goto Forum:
  


Current Time: Thu Aug 21 10:21:58 EDT 2014

Powered by FUDForum. Page generated in 0.01530 seconds