Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Using both AbstractModelInferrer and IGenerator implementations(Is it possible to have both generators in the same Xtext project?)
Using both AbstractModelInferrer and IGenerator implementations [message #1053825] Tue, 07 May 2013 14:34 Go to next message
Leandro Marques is currently offline Leandro Marques
Messages: 11
Registered: July 2009
Junior Member
I created a gammar for a language I am constructing using Xtext and I would like to add a code generator. At first I need to generate Java code so a AbstractModelInferer is most appropriate and at last I need to generate Xtend code so I guess a IGenerator would be more appopriate. Is it possible to have both generators (ModelInferer and IGenerator) in the same Xtext project?

I tried creating both, but only the IGenerator implementation have been used. To use a IGenerator implementation I added a method to my RuntimeModule class to inject a instance of my IGenerator implementation.

In addition, I would like to learn more details about the AbstractModelInferer but it is hard to find detailed information on how to use it. Is there any tutorial that could help me?

Thanks in advance,
Re: Using both AbstractModelInferrer and IGenerator implementations [message #1053826 is a reply to message #1053825] Tue, 07 May 2013 14:41 Go to previous messageGo to next message
Lorenzo Bettini is currently offline Lorenzo Bettini
Messages: 1260
Registered: July 2009
Senior Member
On 05/07/2013 08:34 PM, Leandro Marques wrote:
> I created a gammar for a language I am constructing using Xtext and I
> would like to add a code generator. At first I need to generate Java
> code so a AbstractModelInferer is most appropriate and at last I need to
> generate Xtend code so I guess a IGenerator would be more appopriate. Is
> it possible to have both generators (ModelInferer and IGenerator) in the
> same Xtext project?
>
> I tried creating both, but only the IGenerator implementation have been
> used. To use a IGenerator implementation I added a method to my
> RuntimeModule class to inject a instance of my IGenerator implementation.
>
> In addition, I would like to learn more details about the
> AbstractModelInferer but it is hard to find detailed information on how
> to use it. Is there any tutorial that could help me?
>
> Thanks in advance,
>

As far as I understand you want to use both JvmModelGenerator (which is
the default generator relying on the JvmModelInferrer which is
automatically bound when using Xbase) and an additional custom generator
to generate other things?

If so you can implement your own generator strategies in, say,
MyCustomGenerator, and then bind another generator (say MyDslGenerator)
which delegates to both JvmModelGenerator and MyCustomGenerator (both
instances must be injected).

For instance

class MyDslGenerator implements IGenerator {
@Inject JvmModelGenerator g1
@Inject MyCustomGenerator g2

generate(...) {
g1.generate(...)
g2.generate(...)
}
}

and in the runtime module you bind MyDslGenerator.

hope this helps
Lorenzo

--
Lorenzo Bettini, PhD in Computer Science, DI, Univ. Torino
HOME: http://www.lorenzobettini.it
Re: Using both AbstractModelInferrer and IGenerator implementations [message #1053829 is a reply to message #1053826] Tue, 07 May 2013 14:54 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 5849
Registered: July 2009
Senior Member
Alternatively you can subclass jvmmodelgenerator and add a dispatch method for the root of your model.

e.g. http://www.eclipse.org/forums/index.php/mv/msg/473491/1038310/#msg_1038310

Re: Using both AbstractModelInferrer and IGenerator implementations [message #1053834 is a reply to message #1053826] Tue, 07 May 2013 15:32 Go to previous messageGo to next message
Leandro Marques is currently offline Leandro Marques
Messages: 11
Registered: July 2009
Junior Member
Ok, got it. However, how would I delegate a call to the infer method:
infer(Entity element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase)

in my JVMModelInferrer?

I only have access to the params of the method doGenerate(Resource input, IFileSystemAccess fsa) ... so how would extract a IJvmDeclaredTypeAcceptor from Resource input given in the doGenerate method?

Thanks for attention,
Re: Using both AbstractModelInferrer and IGenerator implementations [message #1053841 is a reply to message #1053834] Tue, 07 May 2013 15:44 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 5849
Registered: July 2009
Senior Member
I i am not talking about the inferrer.

i mean JvmModelGenerator that is bound as IGenerator by default
Re: Using both AbstractModelInferrer and IGenerator implementations [message #1057834 is a reply to message #1053834] Thu, 09 May 2013 04:03 Go to previous messageGo to next message
Dirk Deyne is currently offline Dirk Deyne
Messages: 8
Registered: May 2013
Junior Member
Leandro:
Here's how I use IGenerator & Inferrer together
... it was not that easy

- create an IOutputConfigurationProvider
public class YourOutputProvider implements IOutputConfigurationProvider {
	
	public static final String DEFAULT = "DEFAULT_OUTPUT";
	public static final String OTHER = "OTHER";
	
	@Override
	public Set<OutputConfiguration> getOutputConfigurations() {
		OutputConfiguration defaultOutput = new OutputConfiguration(DEFAULT);
	    defaultOutput.setDescription("Default Folder");
	    defaultOutput.setOutputDirectory("./src-gen");
	    defaultOutput.setOverrideExistingResources(true);
	    defaultOutput.setCreateOutputDirectory(true);
	    defaultOutput.setCleanUpDerivedResources(true);
	    defaultOutput.setSetDerivedProperty(true);

	    OutputConfiguration otherOutput = new OutputConfiguration(OTHER);
	    otherOutput.setDescription("Other Folder");
	    otherOutput.setOutputDirectory("./src-gen/other");
	    otherOutput.setOverrideExistingResources(true);
	    otherOutput.setCreateOutputDirectory(true);
	    otherOutput.setCleanUpDerivedResources(true);
	    otherOutput.setSetDerivedProperty(true);
	}


notice the properties you can set: overrideExistingResources,...

- create an Adapter
public class OutputConfigurationAdapter implements Adapter {

	private String outputConfigurationName;

	public OutputConfigurationAdapter(String outputConfigurationName) {
		this.outputConfigurationName = outputConfigurationName;
	}

	public String getOutputConfigurationName() {
		return outputConfigurationName;
	}

	@Override
	public void notifyChanged(Notification notification) {
	}

	@Override
	public Notifier getTarget() {
		return null;
	}

	@Override
	public void setTarget(Notifier newTarget) {
	}

	@Override
	public boolean isAdapterForType(Object type) {
		return false;
	}

}


- create an IFileSystemAccess
public class OutputConfigurationFileSystemAccess implements IFileSystemAccess,
		IFileSystemAccessExtension, IFileSystemAccessExtension2 {
	protected IFileSystemAccess fsa;
	protected String outputConfigurationName;

	protected OutputConfigurationFileSystemAccess(IFileSystemAccess fsa,
			String outputConfigurationName) {
		this.fsa = fsa;
		this.outputConfigurationName = outputConfigurationName;
	}

	@Override
	public void generateFile(String fileName, CharSequence contents) {
		fsa.generateFile(fileName, outputConfigurationName, contents);
	}

	@Override
	public void generateFile(String fileName, String outputConfiguration,
			CharSequence contents) {
		fsa.generateFile(fileName, outputConfigurationName, contents);
	}

	@Override
	public void deleteFile(String fileName) {
		deleteFile(fileName, outputConfigurationName);
	}

	@Override
	public void deleteFile(String fileName,
			String ignoredOutputConfigurationName) {
		((IFileSystemAccessExtension) fsa).deleteFile(fileName,
				outputConfigurationName);
	}

	@Override
	public URI getURI(String fileName, String outputConfiguration) {
		return ((IFileSystemAccessExtension2) fsa).getURI(fileName,
				outputConfigurationName);
	}

	@Override
	public URI getURI(String fileName) {
		return ((IFileSystemAccessExtension2) fsa).getURI(fileName,
				outputConfigurationName);
	}
}


- create your IGenerator
class YourIGenerator implements IGenerator {

	
	override doGenerate(Resource input, IFileSystemAccess fsa) {
		...
	}



- create your Inferrer
class YourModelInferrer extends AbstractModelInferrer {

  	def dispatch void infer(Foo foo, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
		var fooClass = foo.toClass(foo.name)
		fooClass.eAdapters.add(new OutputConfigurationAdapter(YourOutputProvider::DEFAULT))
		acceptor.accept(fooClass)
				.initializeLater([ 
					....
				])
				
		var barClass = foo.toClass(foo.name)
		barClass.eAdapters.add(new OutputConfigurationAdapter(YourOutputProvider::OTHER))
		acceptor.accept(fooClass)
				.initializeLater([ 
					// nothing to do here done in YourIGenerator
				])


adding the different eAdapters is important here cfr YourOutputProvider::DEFAULT & YourOutputProvider::OTHER



- create an JvmModelGenerator
public class YourJvmModelGenerator extends JvmModelGenerator {
	
	@Inject private YourGenerator generator;
	
	@Override
	public void doGenerate(Resource input, IFileSystemAccess fsa) {
	    EList<EObject> contents = input.getContents();
	    for (final EObject obj : contents) {
	      String outputConfiguration = null;
	      for (Adapter adapter : obj.eAdapters()) {
	        if (adapter instanceof OutputConfigurationAdapter) {
	          outputConfiguration = ((OutputConfigurationAdapter) adapter).getOutputConfigurationName();
	          break;
	        }
	      }
	      if (outputConfiguration == YourOutputProvider.DEFAULT) {
	        this.internalDoGenerate(obj, fsa); // <= GOTO INFERRER
	      } else if (outputConfiguration == YourOutputProvider.OTHER) {
	        generator.doGenerate(input, fsa); // <= GOTO IGENERATOR
	      }  
	    }
	  }
	
}

here you make the switch to your Inferrer & Igenerator

- configure your RuntimeModule
	@Override
	public void configure(Binder binder) {
		super.configure(binder);
		binder.bind(IOutputConfigurationProvider.class)
        .to(YourOutputProvider.class)
        .in(Singleton.class);
	}

	@Override
	public Class<? extends IGenerator> bindIGenerator() {
		return OutputConfigurationAwaredGenerator.class;
	}

[Updated on: Thu, 09 May 2013 04:19]

Report message to a moderator

Re: Using both AbstractModelInferrer and IGenerator implementations [message #1057859 is a reply to message #1057834] Thu, 09 May 2013 07:31 Go to previous messageGo to next message
Lorenzo Bettini is currently offline Lorenzo Bettini
Messages: 1260
Registered: July 2009
Senior Member
Oh, I think because in your case you needed to generate differently
according to specific inferred elements (I had missed that part)... in
my case I just wanted to generate also xml besides Java code so I did
not need to specify different output configurations right in the inferrer...

On 05/09/2013 10:03 AM, Dirk Deyne wrote:
> Lorenzo: Here's how I use IGenerator & Inferrer together .. it was not
> that easy
>
> - create an IOutputConfigurationProvider
>
> public class YourOutputProvider implements IOutputConfigurationProvider {
>
> public static final String DEFAULT = "DEFAULT_OUTPUT";
> public static final String OTHER = "OTHER";
>
> @Override
> public Set<OutputConfiguration> getOutputConfigurations() {
> OutputConfiguration defaultOutput = new
> OutputConfiguration(DEFAULT);
> defaultOutput.setDescription("Default Folder");
> defaultOutput.setOutputDirectory("./src-gen");
> defaultOutput.setOverrideExistingResources(true);
> defaultOutput.setCreateOutputDirectory(true);
> defaultOutput.setCleanUpDerivedResources(true);
> defaultOutput.setSetDerivedProperty(true);
>
> OutputConfiguration otherOutput = new OutputConfiguration(OTHER);
> otherOutput.setDescription("Other Folder");
> otherOutput.setOutputDirectory("./src-gen/other");
> otherOutput.setOverrideExistingResources(true);
> otherOutput.setCreateOutputDirectory(true);
> otherOutput.setCleanUpDerivedResources(true);
> otherOutput.setSetDerivedProperty(true);
> }
>
>
> notice the properties you can set: overrideExistingResources,...
>
> - create an Adapter
>
> public class OutputConfigurationAdapter implements Adapter {
>
> private String outputConfigurationName;
>
> public OutputConfigurationAdapter(String outputConfigurationName) {
> this.outputConfigurationName = outputConfigurationName;
> }
>
> public String getOutputConfigurationName() {
> return outputConfigurationName;
> }
>
> @Override
> public void notifyChanged(Notification notification) {
> }
>
> @Override
> public Notifier getTarget() {
> return null;
> }
>
> @Override
> public void setTarget(Notifier newTarget) {
> }
>
> @Override
> public boolean isAdapterForType(Object type) {
> return false;
> }
>
> }
>
>
> - create an IFileSystemAccess
>
> public class OutputConfigurationFileSystemAccess implements
> IFileSystemAccess,
> IFileSystemAccessExtension, IFileSystemAccessExtension2 {
> protected IFileSystemAccess fsa;
> protected String outputConfigurationName;
>
> protected OutputConfigurationFileSystemAccess(IFileSystemAccess fsa,
> String outputConfigurationName) {
> this.fsa = fsa;
> this.outputConfigurationName = outputConfigurationName;
> }
>
> @Override
> public void generateFile(String fileName, CharSequence contents) {
> fsa.generateFile(fileName, outputConfigurationName, contents);
> }
>
> @Override
> public void generateFile(String fileName, String outputConfiguration,
> CharSequence contents) {
> fsa.generateFile(fileName, outputConfigurationName, contents);
> }
>
> @Override
> public void deleteFile(String fileName) {
> deleteFile(fileName, outputConfigurationName);
> }
>
> @Override
> public void deleteFile(String fileName,
> String ignoredOutputConfigurationName) {
> ((IFileSystemAccessExtension) fsa).deleteFile(fileName,
> outputConfigurationName);
> }
>
> @Override
> public URI getURI(String fileName, String outputConfiguration) {
> return ((IFileSystemAccessExtension2) fsa).getURI(fileName,
> outputConfigurationName);
> }
>
> @Override
> public URI getURI(String fileName) {
> return ((IFileSystemAccessExtension2) fsa).getURI(fileName,
> outputConfigurationName);
> }
> }
>
>
> - create your IGenerator
>
> class YourIGenerator implements IGenerator {
>
>
> override doGenerate(Resource input, IFileSystemAccess fsa) {
> ...
> }
>
>
>
> - create your Inferrer
>
> class YourModelInferrer extends AbstractModelInferrer {
>
> def dispatch void infer(Foo foo, IJvmDeclaredTypeAcceptor acceptor,
> boolean isPreIndexingPhase) {
> var fooClass = foo.toClass(foo.name)
> fooClass.eAdapters.add(new
> OutputConfigurationAdapter(YourOutputProvider::DEFAULT))
> acceptor.accept(fooClass)
> .initializeLater([ ....
> ])
>
> var barClass = foo.toClass(foo.name)
> barClass.eAdapters.add(new
> OutputConfigurationAdapter(YourOutputProvider::OTHER))
> acceptor.accept(fooClass)
> .initializeLater([ // nothing to do
> here done in YourIGenerator
> ])
>
>
> adding the different eAdapters is important here cfr
> YourOutputProvider::DEFAULT & YourOutputProvider::OTHER
>
>
>
> - create an JvmModelGenerator
>
> public class YourJvmModelGenerator extends JvmModelGenerator {
>
> @Inject private YourGenerator generator;
>
> @Override
> public void doGenerate(Resource input, IFileSystemAccess fsa) {
> EList<EObject> contents = input.getContents();
> for (final EObject obj : contents) {
> String outputConfiguration = null;
> for (Adapter adapter : obj.eAdapters()) {
> if (adapter instanceof OutputConfigurationAdapter) {
> outputConfiguration = ((OutputConfigurationAdapter)
> adapter).getOutputConfigurationName();
> break;
> }
> }
> if (outputConfiguration == YourOutputProvider.DEFAULT) {
> this.internalDoGenerate(obj, fsa); // <= GOTO INFERRER
> } else if (outputConfiguration == YourOutputProvider.OTHER) {
> generator.doGenerate(input, fsa); // <= GOTO IGENERATOR
> } }
> }
>
> }
>
> here you make the switch to your Inferrer & Igenerator
>
> - configure your RuntimeModule
>
> @Override
> public void configure(Binder binder) {
> super.configure(binder);
> binder.bind(IOutputConfigurationProvider.class)
> .to(YourOutputProvider.class)
> .in(Singleton.class);
> }
>
> @Override
> public Class<? extends IGenerator> bindIGenerator() {
> return OutputConfigurationAwaredGenerator.class;
> }
>
>


--
Lorenzo Bettini, PhD in Computer Science, DI, Univ. Torino
HOME: http://www.lorenzobettini.it
icon14.gif  Re: Using both AbstractModelInferrer and IGenerator implementations [message #1057880 is a reply to message #1057834] Thu, 09 May 2013 10:28 Go to previous message
Leandro Marques is currently offline Leandro Marques
Messages: 11
Registered: July 2009
Junior Member
Great answer Dirk. It works like a champ.

Thanks for all other answer. They helped me a lot to understand better the code generation process.

Sincerely,
Previous Topic:Grammar ambiguity only when using external references
Next Topic:Redefining imported name
Goto Forum:
  


Current Time: Sun Apr 20 18:15:42 EDT 2014

Powered by FUDForum. Page generated in 0.01721 seconds