Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » ?how to mix strategies of global scoping?(?how to adapt two strategies of global scopting for one language?)
?how to mix strategies of global scoping? [message #699001] Wed, 20 July 2011 16:10 Go to next message
alex.ren2006 is currently offline alex.ren2006Friend
Messages: 46
Registered: June 2011
Member
Trying to combine "Global Scopes Based On Explicit Imports (ImportURI Mechanism)"
and
"Global Scopes Based On External Configuration (e.g. Classpath-Based)".

I am currently building an IDE for ATS (www.ats-lang.org). I am wondering whether Xtext can support the following strategies of scoping for one language at the same time.

For clarity, the example grammar goes as follows.
====================================================
grammar org.eclipse.xtext.example.fowlerdsl.Statemachine with org.eclipse.xtext.common.Terminals

generate statemachine "http://www.eclipse.org/xtext/example/fowlerdsl/Statemachine"

Statemachine :
     {Statemachine}
     (imp+=Import)*
	('events' 
		events+=Event+ 
	'end')?
	('resetEvents' 
		resetEvents+=[Event]+ 
	'end')?
	('commands' 
		commands+=Command+ 
	'end')?
	states+=State*
;

Event:
	name=ID code=ID
;

Command:
	name=ID code=ID
;

State:
	'state' name=ID
		('actions' '{' actions+=[Command]+ '}')?
		transitions+=Transition*
	'end'
;

Transition:
	event=[Event] '=>' state=[State]
;

Import: 'import' importURI=STRING;
====================================================

One source of cross-reference is "import". File "a.statemachine" imports file "b.statemachine" to refer to the elements in "b.statemachine". A file "c.statemachine" may reside in the same folder as "a.statemachine". But "a.statemachine" cannot refer to any elements of "c.statemachine" even if "c.statemachine" has the same elements as "b.statemachine" as long as "a.statemachine" doesn't import "c.statemachine" at all.

Another source of cross-reference is default library. There exists certain library folders, any source code can refer to elements in the files inside these library folders without explicitly importing them. These libraries folders can be set in eclipse as java class path.

If two sources of cross-reference have element of the same name, then the previous source has the higher priority over the library. (Or let user chooses from multiple options.)

By juggling the following part of mwe2 file
=================================
            // scoping and exporting API
            // fragment = scoping.ImportURIScopingFragment {}
            // fragment = exporting.SimpleNamesFragment {}

            // scoping and exporting API
            fragment = scoping.ImportNamespacesScopingFragment {}
            fragment = exporting.QualifiedNamesFragment {}
            fragment = builder.BuilderIntegrationFragment {}


            // provides the necessary bindings for java types integration
            fragment = types.TypesGeneratorFragment {}
====================================
I can manage to have either of these two strategies of scoping. But I just cannot have both of them at the same time. Any suggestion is highly appreciated. Thanks a lot.




[Updated on: Thu, 21 July 2011 07:40]

Report message to a moderator

Re: ?how to mix strategies of global scoping? [message #702288 is a reply to message #699001] Tue, 26 July 2011 07:29 Go to previous messageGo to next message
alex.ren2006 is currently offline alex.ren2006Friend
Messages: 46
Registered: June 2011
Member
I am now thinking about creating my own global scope provider which combines DefaultGlobalScopeProvider and ImportUriGlobalScopeProvider. Is it feasible?
Re: ?how to mix strategies of global scoping? [message #702343 is a reply to message #702288] Tue, 26 July 2011 08:45 Go to previous messageGo to next message
alex.ren2006 is currently offline alex.ren2006Friend
Messages: 46
Registered: June 2011
Member
I simply merged DefaultGlobalScopeProvider and ImportUriGlobalScopeProvider and it works. The "CustomGlobalScopeProvider.java" goes as follows
========================
package org.eclipse.xtext.example.fowlerdsl.scoping;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.IContainer;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescription.Event.Source;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.resource.containers.FilterUriContainer;
import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.AbstractGlobalScopeProvider;
import org.eclipse.xtext.scoping.impl.DelegatingEventSource;
import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider;
import org.eclipse.xtext.scoping.impl.ImportUriResolver;
import org.eclipse.xtext.scoping.impl.LoadOnDemandResourceDescriptions;
import org.eclipse.xtext.scoping.impl.SelectableBasedScope;
import org.eclipse.xtext.util.IResourceScopeCache;
import org.eclipse.xtext.util.OnChangeEvictingCache;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;


/**
 * @author Sven Efftinge - Initial contribution and API
 */
public class CustomGlobalScopeProvider extends AbstractGlobalScopeProvider {

	@Inject
	private IContainer.Manager containerManager;

	@Inject
	private IResourceDescription.Manager descriptionManager;
	
	// for classpath
	protected IScope getScope(IScope parent, final Resource context, boolean ignoreCase, EClass type, Predicate<IEObjectDescription> filter) {
		System.out.println("getScope0001");
		IScope result = parent;
		if (context == null || context.getResourceSet() == null)
			return result;
		List<IContainer> containers = Lists.newArrayList(getVisibleContainers(context));
		Collections.reverse(containers);
		Iterator<IContainer> iter = containers.iterator();
		while (iter.hasNext()) {
			IContainer container = iter.next();
			result = createContainerScopeWithContext(context, result, container, filter, type, ignoreCase);
		}
		return getScope1(result, context, ignoreCase, type, filter);
	}
	
	protected IScope getScope(final Resource context, boolean ignoreCase, EClass type, Predicate<IEObjectDescription> filter) {
		System.out.println("getScope0002");
		return getScope(IScope.NULLSCOPE, context, ignoreCase, type, filter);
	}
	
	// @Override  
	// for import
	protected IScope getScope1(IScope parent, Resource resource, boolean ignoreCase, EClass type, Predicate<IEObjectDescription> filter) {
		final LinkedHashSet<URI> uniqueImportURIs = getImportedUris(resource);
		IResourceDescriptions descriptions = getResourceDescriptions(resource, uniqueImportURIs);
		List<URI> urisAsList = Lists.newArrayList(uniqueImportURIs);
		Collections.reverse(urisAsList);
		// IScope scope = IScope.NULLSCOPE;
		for (URI uri : urisAsList) {
			parent = createLazyResourceScope(parent, uri, descriptions, type, filter, ignoreCase);
		}
		return parent;
	}

	protected List<IContainer> getVisibleContainers(Resource resource) {
		System.out.println("getVisibleContainers");
		IResourceDescription description = descriptionManager.getResourceDescription(resource);
		IResourceDescriptions resourceDescriptions = getResourceDescriptions(resource);
		String cacheKey = getCacheKey("VisibleContainers", resource.getResourceSet());
		OnChangeEvictingCache.CacheAdapter cache = new OnChangeEvictingCache().getOrCreate(resource);
		List<IContainer> result = null;
		result = cache.get(cacheKey);
		if (result == null) {
			result = containerManager.getVisibleContainers(description,	resourceDescriptions);
			// SZ: I'ld like this dependency to be moved to the implementation of the
			// container manager, but it is not aware of a CacheAdapter
			if (resourceDescriptions instanceof IResourceDescription.Event.Source) {
				IResourceDescription.Event.Source eventSource = (Source) resourceDescriptions;
				DelegatingEventSource delegatingEventSource = new DelegatingEventSource(eventSource);
				delegatingEventSource.addListeners(Lists.newArrayList(Iterables.filter(result, IResourceDescription.Event.Listener.class)));
				delegatingEventSource.initialize();
				cache.addCacheListener(delegatingEventSource);
			}
			cache.set(cacheKey, result);
		}
		return result;
	}
	
	protected String getCacheKey(String base, ResourceSet context) {
		System.out.println("getCacheKey");
		Map<Object, Object> loadOptions = context.getLoadOptions();
		if (loadOptions.containsKey(ResourceDescriptionsProvider.NAMED_BUILDER_SCOPE)) {
			return base + "@" + ResourceDescriptionsProvider.NAMED_BUILDER_SCOPE;
		} 
		return base + "@DEFAULT_SCOPE"; 
	}

	protected IScope createContainerScopeWithContext(Resource eResource, IScope parent, IContainer container,
			Predicate<IEObjectDescription> filter, EClass type, boolean ignoreCase) {
		System.out.println("createContainerScopeWithContext");
		if (eResource != null) {
			URI uriToFilter = eResource.getURI();
			if (container.hasResourceDescription(uriToFilter))
				container = new FilterUriContainer(uriToFilter, container);
		}
		return createContainerScope(parent, container, filter, type, ignoreCase);
	}

	protected IScope createContainerScope(IScope parent, IContainer container, Predicate<IEObjectDescription> filter, EClass type, boolean ignoreCase) {
		System.out.println("createContainerScope");
		return SelectableBasedScope.createScope(parent, container, filter, type, ignoreCase);
	}
//======================================

	@Inject
	private ImportUriResolver importResolver;
	
	@Inject
	private Provider<LoadOnDemandResourceDescriptions> loadOnDemandDescriptions;
	
	@Inject
	private IResourceScopeCache cache;
	
	public ImportUriResolver getImportUriResolver() {
		return importResolver;
	}
	
	public void setImportResolver(ImportUriResolver importResolver) {
		this.importResolver = importResolver;
	}
	public void setCache(IResourceScopeCache cache) {
		this.cache = cache;
	}
	
	public IResourceDescriptions getResourceDescriptions(Resource resource, Collection<URI> importUris) {
		IResourceDescriptions result = getResourceDescriptions(resource);
		LoadOnDemandResourceDescriptions demandResourceDescriptions = loadOnDemandDescriptions.get();
		demandResourceDescriptions.initialize(result, importUris, resource);
		return demandResourceDescriptions;
	}
	

	protected LinkedHashSet<URI> getImportedUris(final Resource resource) {
		return cache.get(ImportUriGlobalScopeProvider.class.getName(), resource, new Provider<LinkedHashSet<URI>>(){
			public LinkedHashSet<URI> get() {
				TreeIterator<EObject> iterator = resource.getAllContents();
				final LinkedHashSet<URI> uniqueImportURIs = new LinkedHashSet<URI>(10);
				while (iterator.hasNext()) {
					EObject object = iterator.next();
					String uri = importResolver.apply(object);
					if (uri != null) {
						URI importUri = URI.createURI(uri);
						uniqueImportURIs.add(importUri);
					}
				}
				Iterator<URI> uriIter = uniqueImportURIs.iterator();
				while(uriIter.hasNext()) {
					if (!EcoreUtil2.isValidUri(resource, uriIter.next()))
						uriIter.remove();
				}
				return uniqueImportURIs;
			}
		});
	}

	protected IScope createLazyResourceScope(IScope parent, final URI uri, final IResourceDescriptions descriptions,
			EClass type, final Predicate<IEObjectDescription> filter, boolean ignoreCase) {
		IResourceDescription description = descriptions.getResourceDescription(uri);
		return SelectableBasedScope.createScope(parent, description, filter, type, ignoreCase);
	}

	public void setLoadOnDemandDescriptions(Provider<LoadOnDemandResourceDescriptions> loadOnDemandDescriptions) {
		this.loadOnDemandDescriptions = loadOnDemandDescriptions;
	}

	public Provider<LoadOnDemandResourceDescriptions> getLoadOnDemandDescriptions() {
		return loadOnDemandDescriptions;
	}
}
=============================
I did nothing but merged two "getScope" methods. (The order is important.) I am lucky it works because I still don't understand the machanism behind very well. It would be great if the documentation can have a little bit clearer explanation for beginners about this topic.

So far I modify "AbstractStatemachineRuntimeModule.java" to make "CustomGlobalScopeProvider" to be effective.
=====================
	// contributed by org.eclipse.xtext.generator.scoping.AbstractScopingFragment
	public Class<? extends org.eclipse.xtext.scoping.IGlobalScopeProvider> bindIGlobalScopeProvider() {
		// return org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider.class;
		// DefaultGlobalScopeProvider.class
		return org.eclipse.xtext.example.fowlerdsl.scoping.CustomGlobalScopeProvider.class;
	}
===========================
Once I rerun the mwe2 file, it's gone. Should I modify the mwe2 file to add my own fragment or there is simpler way to do this? Thanks a lot.
Re: ?how to mix strategies of global scoping? [message #702784 is a reply to message #702343] Tue, 26 July 2011 19:47 Go to previous messageGo to next message
Laurent Kempeneers is currently offline Laurent KempeneersFriend
Messages: 2
Registered: June 2011
Junior Member
Look at a post on Meinte's DSL on septembre 2 last year (Configuring local and global scope providers at the same time). I think it may help you. Sorry I can't give you the URL because I'm a new on this forum and not authorized to use this stuff.
Re: ?how to mix strategies of global scoping? [message #703410 is a reply to message #702784] Wed, 27 July 2011 14:43 Go to previous message
alex.ren2006 is currently offline alex.ren2006Friend
Messages: 46
Registered: June 2011
Member
I found it. It's very useful. Now I have my own xpt file. Thank you for the guide.
Previous Topic:[xtext 2.0] Create Scopes
Next Topic:How to implicitly import an XMI resource ?
Goto Forum:
  


Current Time: Sun Apr 11 05:36:17 GMT 2021

Powered by FUDForum. Page generated in 0.01442 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top