Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Implicit imports based on type
Implicit imports based on type [message #734541] Sat, 08 October 2011 14:10 Go to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
In the language I am modeling there exists a type called Enum. If an Enum is imported, it's constructors should also be imported.

I can not find a good way to solve this using xText. I tried using my custom scope provider with a loop through all available Enum objects. This slows down building to a crawl.

I am now trying to use an extended version of the ImportedNamespaceAwareLocalScopeProvider. I will have to override the 'getImplicitImports' and the 'internalGetImportedNamespaceResolvers' methods in order to add ImportNormalizers. The overridden code will look something like this:

IEObjectDescription singleElement = globalScope.getSingleElement(qualifiedName);
		
if (singleElement != null && singleElement.getEClass().equals(eClass))
{
	Enum resolve = (Enum) EcoreUtil2.resolve(singleElement.getEObjectOrProxy(), res);
	EList<EnumConstructor> constructors = resolve.getConstructors();
			
	for (EnumConstructor constructor : constructors)
	{
		implicitImports.add(new ImportNormalizer(qualifiedName.append(constructor.getName()), false, ignoreCase));
	}
}


Is there a better way to do this, or am I on the right track?

How would I deal with wild card imports? If "my.package.*" is imported, how do I loop though all Enums within that package?
Re: Implicit imports based on type [message #734543 is a reply to message #734541] Sat, 08 October 2011 14:17 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

how do you do the import? with std means? if yes:
what about exporting the Enums Constructor unter the same name as the enum. (or at least in the same namespace)

~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Sat, 08 October 2011 14:29]

Report message to a moderator

Re: Implicit imports based on type [message #734544 is a reply to message #734543] Sat, 08 October 2011 14:32 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
Imports are done in two ways. Using the grammar with 'importedNamespace':

Import:
	'import' importedNamespace=QualifiedNameWithWildcard ';';


And with implicit imports:

protected List<ImportNormalizer> getImplicitImports(boolean ignoreCase, IScope globalScope, Resource res) {
	List<ImportNormalizer> implicitImports = super.getImplicitImports(ignoreCase);
	implicitImports = Lists.newArrayList(implicitImports);
	implicitImports.add(
			new ImportNormalizer(
					QualifiedName.create("package.Type"), 
					false, 
					ignoreCase
			)
	);
}



I do not understand your suggestion. If I would export the Enum constructors under the same name as the Enum itself how would that help?

I have (for example) the following enum:

enum Bool {
	true;
	false;
}


This enum is imported using an implicit import:

implicitImports.add(new ImportNormalizer(QualifiedName.create("Bool"), false, ignoreCase));


In the code I want to use it like this:

class X
{
	function y() : Bool {
        	return true;
	}
}


true would point to the 'true' constructor of the Bool enum.
Re: Implicit imports based on type [message #734546 is a reply to message #734544] Sat, 08 October 2011 14:42 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

maybe your term constructor is totally wrong chosen: it is a LITERAL.

so the question in your case:

consider you have another enum

enum Bool2 {
	true;
	false;
        null;
}


so if you write

return true;


and you use Bool and Bool2 should this be Bool.true or Bool2.true?

thus i would solve this either by

(1) using local scoping for the true
(2) try to adopt org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider.internalGetImportedNamespaceResolvers(EObject, boolean) (based on a reference to the enum Bool + maybe nodemodel to find out that bool is used and not bool2 - but i dont know if this will work)

~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Sat, 08 October 2011 14:53]

Report message to a moderator

Re: Implicit imports based on type [message #734548 is a reply to message #734546] Sat, 08 October 2011 15:02 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
I think Bool was the wrong example (the language I am creating a grammar for has defined Bool as an enum). This is an enum as well:

enum Color2 {
        red;
        green;
        blue;
        grey( v : Int );
        rgb( r : Int, g : Int, b : Int );
}


As for your proposed problem, if Bool.true is imported, that one will be used if a reference to true is made. If both Bool.true and Bool2.true are imported the editor of course will report an error as it can not distinguish between the two.


The question I have is essentially a bit more general: How can I import features of a specific type automatically?

If I would import the Color2 type, it should automatically import Color2.red, Color2.green, etc. In the first post of this thread I posted a solution, I am not sure if this is the correct way to answer this problem.

I am also unsure how to deal with wildcard imports.


You did give me two options. Are those the two options I described in the first post?
Re: Implicit imports based on type [message #734549 is a reply to message #734548] Sat, 08 October 2011 15:09 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

yes and no, i mean something like

public class MyDslImportedNamespaceAwareLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider {
	
	@Override
	protected List<ImportNormalizer> internalGetImportedNamespaceResolvers(
			EObject context, boolean ignoreCase) {
		List<ImportNormalizer> result = super.internalGetImportedNamespaceResolvers(context, ignoreCase);
		if (context instanceof Function) {
			Function function = (Function) context;
			String value = NodeModelUtils.findNodesForFeature(function, MyDslPackage.Literals.FUNCTION__RETURN_TYPE).get(0).getText();
			ImportNormalizer resolver = createImportedNamespaceResolver(value+".*", ignoreCase);
			if (resolver != null)
				result.add(resolver);
		}
		return result;
	}

}


cause you do not the resolving stuff you might be way more performant.

here is my test grammar

Model:
	elements+=Element*;
	
Element:
	Enum | Class
;

Enum:
	"enum" name=ID "{"
		literals+=Literal*
	"}"
;

Literal:
	name=ID ";"
;

Class:
	"class" name=ID "{"
		functions+=Function*
	"}"
;

Function:
	"function" name=ID "()" ":" returnType=[Enum] "{"
        	statements+=Statement*
	"}"
;

Statement:
	"return" ref=[Literal] ";"
;


~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Sat, 08 October 2011 15:09]

Report message to a moderator

Re: Implicit imports based on type [message #734550 is a reply to message #734549] Sat, 08 October 2011 15:15 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
And here the local scoping solution:

public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {

	IScope scope_Statement_ref(Function f, EReference ref) {
		return Scopes.scopeFor(f.getReturnType().getLiterals());
	}
	
}


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Implicit imports based on type [message #734552 is a reply to message #734549] Sat, 08 October 2011 15:24 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
Thank you very much! The support in this forum is simply awesome.

I never thought about using the wildcard to my advantage. That makes stuff a bit more easy.

So basically what I have to do is the following:

1. get the imports the implicit ones and the ones from the file
2. use the global scope to determine if the import points to a description of an Enum
3. if the description is of type Enum, I add a normalizer for 'EnumName.*'

I then still have a small problem with the wild card imports. How can I obtain all EObjectDescriptions that start with the wild card import?
Re: Implicit imports based on type [message #734554 is a reply to message #734552] Sat, 08 October 2011 15:29 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

i guess you have to do this manually. you might let inspire you from the code in
org.eclipse.xtext.scoping.impl.ImportScope.getAliasedElements(Iterable<IEObjectDescription>)

but why do you want to do this proactive if a Literal/Constuctor can never occur without it Enum?

~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Sat, 08 October 2011 15:30]

Report message to a moderator

Re: Implicit imports based on type [message #734559 is a reply to message #734554] Sat, 08 October 2011 15:40 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
Thank you for the suggestions, very helpful.

Christian Dietrich wrote on Sat, 08 October 2011 11:29
but why do you want to do this proactive if a Literal/Constuctor can never occur without it Enum?


I do not completely understand what you mean by this. In your example you use the returntype of the method to determine the candidates. In a real example I could have something like this:

import my.package.Color;

class X
{
   function y(a)
   {
      //red, blue and green are the literals defined in the Color enum 
      switch (a)
      {
         case red: return 1;
         case blue: return 2;
         case green: return 3;
      }
   }
}


How would I solve this in a 'non-proactive' fashion?
Re: Implicit imports based on type [message #734560 is a reply to message #734559] Sat, 08 October 2011 15:44 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

a has a type and this is a enum isnt it?

you could of course cheat somehow.
what about giving the constructors a name

Boolean_Constructor.true
and add an additional xxxx_Constructor.* for every import you can find?

~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Implicit imports based on type [message #734562 is a reply to message #734560] Sat, 08 October 2011 15:53 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
Ahh I see what you mean. Yes, at runtime a has a type. I might be a bit complicated to find the type though in the editor.

The constructors indeed have a name (a snippet from the grammar):

Enum:
	metadata=Metadata?
	extern='extern'? visibility=Visibility? 'enum' name=ValidID typeParameters=TypeParameters?
	'{'
		(constructors+=EnumConstructor)*
	'}';

EnumConstructor:
	metadata=Metadata?
	name=ValidID ('(' parameters+=OptionalParameter (',' parameters+=OptionalParameter)* ')')? ';'?;


I will think about the cheat suggestion. Might be a good one (although indeed a bit dirty), haha


Thanks again for the suggestions. I will dive into the code when I have a bit more time.
Re: Implicit imports based on type [message #735845 is a reply to message #734554] Wed, 12 October 2011 21:01 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
Christian Dietrich wrote on Sat, 08 October 2011 11:29

but why do you want to do this proactive if a Literal/Constuctor can never occur without it Enum?


The language I am creating a grammar for uses type inference. So I might use a constructor without have the type defined anywhere in a function. That is the reason (if I am correct) to do it proactive.
Re: Implicit imports based on type [message #735855 is a reply to message #735845] Wed, 12 October 2011 21:51 Go to previous messageGo to next message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
For now I solved it by overriding the createImportScope method of the ImportedNamespaceAwareLocalScopeProvider class.

	protected ImportScope createImportScope(IScope parent, List<ImportNormalizer> namespaceResolvers, ISelectable importFrom, EClass type, boolean ignoreCase) {
		
		List<ImportNormalizer> newNamespaceResolvers = namespaceResolvers;
		
		if (isFeature(type)) {
			newNamespaceResolvers = Lists.newArrayList(namespaceResolvers);
			
			try {
				importedNamespacePrefixField.setAccessible(true);
				
				for (ImportNormalizer namespaceResolver : namespaceResolvers) {
					QualifiedName qn = (QualifiedName) importedNamespacePrefixField.get(namespaceResolver);
					
					IEObjectDescription singleElement = parent.getSingleElement(qn);
					
					if (singleElement != null && isEnum(singleElement)) {
						newNamespaceResolvers.add(new ImportNormalizer(qn, true, ignoreCase));
					}
				}
				
				importedNamespacePrefixField.setAccessible(false);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		
		return super.createImportScope(parent, newNamespaceResolvers, importFrom, type, ignoreCase);
	}


As you can see this requires some reflection. I will file a feature request that asks for a getImportedNamespace() or getImportedNamespacePrefix() method on ImportNormalizer
Re: Implicit imports based on type [message #735856 is a reply to message #735855] Wed, 12 October 2011 22:02 Go to previous message
eecolor is currently offline eecolorFriend
Messages: 36
Registered: September 2011
Member
BugZilla: https://bugs.eclipse.org/bugs/show_bug.cgi?id=360739
Previous Topic:Problem with initialization of preferences
Next Topic:Build clean - no effect in dirty editor
Goto Forum:
  


Current Time: Thu Apr 25 13:17:44 GMT 2024

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

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

Back to the top