Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Escape Hatch
Escape Hatch [message #1028999] Fri, 29 March 2013 02:24 Go to next message
First Last is currently offline First Last
Messages: 15
Registered: March 2013
Junior Member
After an intense effort to migrate from a somewhat clumsy, template-based code-generation system to an Xtext system, which would have many technical advantages and permit a much clearer syntax, it seems necessary to abandon this effort.

At this point a number of issues have rapidly cropped up -- any one of which makes the migration impossible, but collectively they indicate that no simple, quickly forthcoming fix is likely to occur. These include:
Bug 403151
Bug 402578
No support for static initializers (apparently)

But most critically, there is no "escape hatch" mechanism to address this class of problems. No technique by which one could tell Xtext to generate arbitrary text at some point. If this existed, then one might write:
members += ArbitraryText("transient String foo;")

or
members += ArbitraryText("static { ... }")

and thus generate any required construct, regardless of weak Xtext support for that construct at a point in time.

I do not know when the next update to Xtext is planned, but I would encourage you to facilitate and empower your users by allowing them to generate any piece of text they may find necessary.

Xtext is a very clever and mostly elegant framework which has many fine uses, but it is fundamentally a rather complicated tool. Its most powerful use will be to make the difficult Java programming tasks easier -- but it can only achieve that if it makes generating those difficult programming tasks possible.
Re: Escape Hatch [message #1029128 is a reply to message #1028999] Fri, 29 March 2013 07:18 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6388
Registered: July 2009
Senior Member
Hi,

if you say Xtext you mean Xbase/JvmModelInferrer right?
you can always subclass JvmModelGenerator and do whatever you want.

and btw you dont have to use Xbase/JvmModelInferrer at all and can use xtend to write a complete custom generator.

~Christian
Re: Escape Hatch [message #1029133 is a reply to message #1029128] Fri, 29 March 2013 07:29 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6388
Registered: July 2009
Senior Member
Here some example with the greetings example

package org.xtext.example.mydsl4.jvmmodel

import com.google.inject.Inject
import org.eclipse.xtext.common.types.JvmGenericType
import org.eclipse.xtext.common.types.util.TypeReferences
import org.eclipse.xtext.documentation.IEObjectDocumentationProvider
import org.eclipse.xtext.documentation.IFileHeaderProvider
import org.eclipse.xtext.documentation.IJavaDocTypeReferenceProvider
import org.eclipse.xtext.generator.trace.ITraceURIConverter
import org.eclipse.xtext.naming.IQualifiedNameConverter
import org.eclipse.xtext.resource.ILocationInFileProvider
import org.eclipse.xtext.scoping.IScopeProvider
import org.eclipse.xtext.xbase.compiler.ErrorSafeExtensions
import org.eclipse.xtext.xbase.compiler.GeneratorConfig
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider
import org.eclipse.xtext.xbase.compiler.JavaKeywords
import org.eclipse.xtext.xbase.compiler.JvmModelGenerator
import org.eclipse.xtext.xbase.compiler.LoopExtensions
import org.eclipse.xtext.xbase.compiler.TreeAppendableUtil
import org.eclipse.xtext.xbase.compiler.XbaseCompiler
import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider
import org.eclipse.xtext.xbase.jvmmodel.JvmTypeExtensions
import org.xtext.example.mydsl4.myDsl.Model

class MyJvmModelGenerator extends JvmModelGenerator {
	
	@Inject extension ILogicalContainerProvider
	@Inject extension TypeReferences 
	@Inject extension TreeAppendableUtil
	@Inject extension JvmTypeExtensions
	@Inject extension LoopExtensions
	@Inject extension ErrorSafeExtensions
	
	@Inject XbaseCompiler compiler
	@Inject ILocationInFileProvider locationProvider
	@Inject IEObjectDocumentationProvider documentationProvider
	@Inject IFileHeaderProvider fileHeaderProvider
	@Inject IJvmModelAssociations jvmModelAssociations
	@Inject JavaKeywords keywords
	@Inject IGeneratorConfigProvider generatorConfigProvider
	@Inject ITraceURIConverter converter
	@Inject IJavaDocTypeReferenceProvider javaDocTypeReferenceProvider
	@Inject IScopeProvider scopeProvider
	@Inject IQualifiedNameConverter qualifiedNameConverter
	
	override dispatch ITreeAppendable generateBody(JvmGenericType it, ITreeAppendable appendable, GeneratorConfig config) {
		generateJavaDoc(appendable, config)
		val childAppendable = appendable.trace(it)
		if(config.generateSyntheticSuppressWarnings)
			generateAnnotationsWithSyntheticSuppressWarnings(childAppendable, config)
		else
			annotations.generateAnnotations(childAppendable, true, config)
		generateModifier(childAppendable, config)
		if (isInterface) {
			childAppendable.append("interface ")
		} else {
			childAppendable.append("class ")
		}
		childAppendable.traceSignificant(it).append(simpleName)
		generateTypeParameterDeclaration(childAppendable, config)
		if (typeParameters.empty)
			childAppendable.append(" ")
		generateExtendsClause(childAppendable, config)
		childAppendable.append('{').increaseIndentation
		
		childAppendable.append('static {').increaseIndentation
		val model = jvmModelAssociations.getPrimarySourceElement(it) as Model
		for (g : model.greetings) {
			childAppendable.newLine.append('//'+g.name)
		}
		childAppendable.decreaseIndentation.newLine.append('}')
		
		childAppendable.forEach(membersToBeCompiled, [
				separator = [ITreeAppendable it | newLine]
			], [
				val memberAppendable = childAppendable.traceWithComments(it)
				memberAppendable.openScope
				generateMember(memberAppendable, config)
				memberAppendable.closeScope
			])
		childAppendable.decreaseIndentation.newLine.append('}')
		appendable.newLine
	}
	
}


public class MyDslRuntimeModule extends org.xtext.example.mydsl4.AbstractMyDslRuntimeModule {

	public Class<? extends JvmModelGenerator> bindJvmModelGenerator() {
		return MyJvmModelGenerator.class;
	}
	
}
Re: Escape Hatch [message #1029425 is a reply to message #1029133] Fri, 29 March 2013 17:16 Go to previous messageGo to next message
First Last is currently offline First Last
Messages: 15
Registered: March 2013
Junior Member
Thank you. This is the kind of functionality I was trying to find; though it is unclear if this is using an "officially valid" technique, or if it's just taking advantage of quirks in the current implementation. To what degree can I rely on extending JvmModelGenerator as an API?

I had looked at the code at www.rcp-vision.com/?p=1640, which simply implements IGenerator directly, and that seems more like proper use of an API -- but also a lot of redundant work (in this case).

I am now curious what approach you would recommend to address interleaving text injection with iterating membersToBeCompiled -- would be appropriate to put custom subclasses of JvmMember into "members" in the inferrer, and then detect & handle them in the generator? Something like:

members += model.toField(...)
members += model.staticInitalizer('do this;') // returns JvmStaticInitializerImplMyModel
members += model.toField(...)
members += model.staticInitalizer('do that;')


Re: Escape Hatch [message #1029440 is a reply to message #1029425] Fri, 29 March 2013 17:49 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6388
Registered: July 2009
Senior Member
Hi,

yes adding a own member and handle it in the generator sounds like a proper option too.
since everything arround xbase is still "provisional api" you have to be ready for changes
anyway. since xtend offers a nice dispatch option
it should not be to difficult to do it,
but depending on how you do it you might get trouble
if the initializer is actually a block in your dsl.
Re: Escape Hatch [message #1029611 is a reply to message #1029440] Fri, 29 March 2013 23:19 Go to previous message
First Last is currently offline First Last
Messages: 15
Registered: March 2013
Junior Member
For the moment, I am using something like this:
class MyJvmTextImpl extends JvmFieldImpl {
  @Property String value
}

And, (in MyJvmModelGenerator extends JvmModelGenerator):
def dispatch ITreeAppendable generateMember(MyJvmTextImpl it, ITreeAppendable appendable, GeneratorConfig config) {
  appendable.newLine.append(value)
}

This works, but because I am using JvmFieldImpl, I have to give it a name/visibility/type, which ultimately isn't used. I tried to use a different base class, but ultimately it seems like anything put into members will be poked for that kind of data.

At the moment, this definitely feels like a hack. I am wondering if it would make sense for Xtext to check to see if members are instanceof JvmField (or such) before they perform those name&type-using operations, so that a non-field/non-method (non-named) member can be used without having a name or type.

This inter-ordering in members is obviously somewhat important for static initializers -- since the order in which they (and field initializers) appear in the resulting class determines runtime execution order. And it's critical when dropping text like 'transient' before a field definition.

(I have considered that one could suggest that static initializers should be thought of as a "feature" of (static) JvmFields -- since the initializer ultimately would generally be storing something in a static field; however that's not always true, and one can use a static initializer purely for logging or other purposes that don't interact with a static field. So while that argument would be a convenient justification for the current behavior, I don't think it should be seen as one.)
Previous Topic:Update to Xtext 2.4 and Xtend 2.4
Next Topic:How to import and parse a file with xtext and generate an EMF model out of it?
Goto Forum:
  


Current Time: Sat Oct 25 11:22:21 GMT 2014

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

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