DevBoost / EMFText

EMFText is an Eclipse plug-in that allows you to define text syntax for languages described by an Ecore metamodel. EMFText enables developers to define textual Domain Specific Languages quickly and without the need to learn new technologies and concepts.
14 stars 12 forks source link

How to determine Resource of current model in a TokenResolver? #39

Closed jreimone closed 11 years ago

jreimone commented 11 years ago

I have a metamodel where one of its EClasses has an attribute of type 'EJavaClass'. This type comes from Ecore itself and is mapped to java.lang.Class. Thus, I have defined a token like this:

DEFINE CLASSNAME IDENTIFIER + $('.'$ + IDENTIFIER + $)*$;

And the rule for the EClass is:

PreProcessor ::= !0 "prepare with" class[CLASSNAME];

Therefore a CLASSNAMETokenResolver is generated in which I want to resolve the String to the according class in the classpath of the project in which the textual model is contained. Thus, I need to know at least the resource in which the model is contained for determining the project and to get the classloader for it. But, unfortunately, the resolve method of a token resolver only has this signature:

public void resolve(String lexem, EStructuralFeature feature, IGueryTokenResolveResult result)

But, if you search for all uses of resolve(..), one can see that the needed information is present. In the scope of the invocation of resolve(..) the actual model element is known and could be passed to the resolve(..) method.

Is there a chance that TokenResolvers could get such a method or do you see any other possibility?

best regards, Jan

mirkoseifert commented 11 years ago

Hi Jan,

most probably no one required the resource or the EObject while resolving tokens before, because token resolvers usually only convert strings to primitive values.

You can extend the generator for the token resolver class, but this has some severe consequences. If you add a parameter to the method resolve() method in IXYZTokenResolver, all existing resolvers will break. You could add a generator for a second interface (e.g., IXYZTokenResolver2) and modify the client code to check which kind of token resolver is present and let newly generated resolvers implement the new interface.

I'm not completely sure what is the better alternative. I tend to break the existing clients, because adding a single parameter is easy to fix and DSL designers can decide when to update. Any opinions?

jreimone commented 11 years ago

I tend to modify the generator so that the resolve method will get an additional parameter. Existing DSLs only get affected in case the whole project is re-generated.

just right before committing this comment I had another idea: dependency injection modify the generator so that the parser injects the current EObject. The generated IXYZTokenResolver then needs a field of type EObject with the @Inject annotation and the @Named annotation to determine, e.g., the current parsed element. Have a look at http://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection#.40Named_.28javax.inject.29 for named injection. I don't know how much effort is needed to realize this, but this alternative wouldn't break any existing clients and DSLs. What do you think?

mirkoseifert commented 11 years ago

I see the advantage of the dependency injection, but we do not use this anywhere else. If we decide to introduce DI, we must do so everywhere. Otherwise we end up with yet another way to customize code.

Feel free to add the new parameter. The languages that are actively used are built on out server and I'll fix the token resolvers.

jreimone commented 11 years ago

Ok, I modified the generators. I didn't pushed it yet, because now I have the problem that the eObject.eResource() method always returns null, rather eObject is contained in a containment hierarchy. Seems that the passed eObject is separated. Is there a possibility to retrieve the resource from a XYZParser?

jreimone commented 11 years ago

I modified my metamodel and my syntax so that the attribute isn't of type EJavaClass anymore but of EString. I added an operation which maps the string to the appropriate class in demand. So the additional parameter isn't needed anymore. I will revert the changes in my local repository. Everything stays as it was :)

mirkoseifert commented 11 years ago

Ok, I didn't think of this solution, but I like it very much as it requires no change in EMFText :)