[generator] Tested and improved new generator

Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
Miro Spönemann 2015-07-07 18:47:38 +02:00
parent 2971ce7151
commit 5e5d636d22
18 changed files with 489 additions and 106 deletions

View file

@ -11,7 +11,6 @@ import com.google.inject.Binder
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.emf.mwe.core.issues.Issues
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.parser.EclipseProjectPropertiesEncodingProvider
import org.eclipse.xtext.parser.IEncodingProvider
import org.eclipse.xtext.resource.XtextResourceSet
import org.eclipse.xtext.service.AbstractGenericModule
@ -22,36 +21,44 @@ import org.eclipse.xtext.xtext.generator.model.XtextProjectConfig
class DefaultGeneratorModule extends AbstractGenericModule {
@Accessors
@Accessors(PUBLIC_SETTER)
XtextProjectConfig project
@Accessors
@Accessors(PUBLIC_SETTER)
CodeConfig code
protected def checkConfiguration(XtextGenerator generator, Issues issues) {
if (project !== null) {
project.checkConfiguration(generator, issues)
}
}
def configureXtextProjectConfig(Binder binder) {
def XtextProjectConfig getProject() {
if (project === null)
project = new WizardConfig
binder.bind(IXtextProjectConfig).toInstance(project)
return project
}
def configureCodeConfig(Binder binder) {
def CodeConfig getCode() {
if (code === null)
code = new CodeConfig
binder.bind(CodeConfig).toInstance(code)
return code
}
def configureResourceSet(Binder binder) {
binder.bind(ResourceSet).toInstance(new XtextResourceSet)
protected def void checkConfiguration(XtextGenerator generator, Issues issues) {
getProject.checkConfiguration(generator, issues)
}
def Class<? extends IEncodingProvider> bindIEncodingProvider() {
EclipseProjectPropertiesEncodingProvider
def void configureXtextProjectConfig(Binder binder) {
binder.bind(IXtextProjectConfig).toInstance(getProject)
}
def void configureCodeConfig(Binder binder) {
binder.bind(CodeConfig).toInstance(getCode)
}
def void configureResourceSet(Binder binder) {
binder.bind(ResourceSet).to(XtextResourceSet)
}
def void configureIEncodingProvider(Binder binder) {
binder.bind(IEncodingProvider).toInstance(new IEncodingProvider.Runtime => [
defaultEncoding = getCode.encoding
])
}
}

View file

@ -24,6 +24,7 @@ import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.emf.ecore.util.EcoreUtil
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend2.lib.StringConcatenationClient
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.GrammarUtil
import org.eclipse.xtext.ReferencedMetamodel
@ -32,16 +33,19 @@ import org.eclipse.xtext.ecore.EcoreSupportStandaloneSetup
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.resource.XtextResource
import org.eclipse.xtext.resource.containers.IAllContainersState
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
import org.eclipse.xtext.util.internal.Log
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
import org.eclipse.xtext.xtext.generator.model.IXtextProjectConfig
import org.eclipse.xtext.xtext.generator.model.StandaloneSetupAccess
import org.eclipse.xtext.xtext.generator.model.TypeReference
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
@Log
class LanguageConfig2 extends CompositeGeneratorFragment2 {
@Inject Provider<ResourceSet> resourceSetProvider
@Accessors
String uri
@ -62,6 +66,10 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 {
@Accessors
val GuiceModuleAccess eclipsePluginGenModule = new GuiceModuleAccess
@Inject Provider<ResourceSet> resourceSetProvider
@Inject IXtextProjectConfig projectConfig
def void setFileExtensions(String fileExtensions) {
this.fileExtensions = fileExtensions.trim.split("\\s*,\\s*").toList
}
@ -226,4 +234,27 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 {
throw new IllegalStateException(msg)
}
override generate(LanguageConfig2 language) {
addImplicitContributions()
super.generate(language)
}
protected def void addImplicitContributions() {
if (projectConfig.runtimeManifest !== null) {
projectConfig.runtimeManifest.requiredBundles.addAll(#[
'org.eclipse.xtext', 'org.eclipse.xtext.util'
])
projectConfig.runtimeManifest.importedPackages.add('org.apache.log4j')
}
if (projectConfig.eclipsePluginManifest !== null) {
projectConfig.eclipsePluginManifest.requiredBundles.addAll(#[
'org.eclipse.xtext.ui', 'org.eclipse.xtext.ui.shared', 'org.eclipse.ui.editors', 'org.eclipse.ui'
])
}
val StringConcatenationClient expression = '''«'org.eclipse.xtext.ui.shared.Access'.typeRef».getJavaProjectsState()'''
new GuiceModuleAccess.BindingFactory()
.addTypeToProviderInstance(new TypeReference(IAllContainersState), expression)
.contributeTo(eclipsePluginGenModule)
}
}

View file

@ -16,12 +16,16 @@ import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.HashMap
import java.util.List
import org.eclipse.emf.mwe.core.WorkflowContext
import org.eclipse.emf.mwe.core.issues.Issues
import org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.EcoreUtil2
import org.eclipse.xtext.GeneratedMetamodel
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.XtextStandaloneSetup
import org.eclipse.xtext.util.MergeableManifest
import org.eclipse.xtext.xtext.generator.model.CodeConfig
@ -43,6 +47,7 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
@Accessors
String activator
@Accessors
val List<LanguageConfig2> languageConfigs = newArrayList
Injector injector
@ -65,11 +70,22 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
}
override protected checkConfigurationInternal(Issues issues) {
createInjector()
if (configuration !== null) {
configuration.checkConfiguration(this, issues)
}
val uris = new HashMap<String, Grammar>
for (language : languageConfigs) {
language.checkConfiguration(this, issues)
for (generatedMetamodel : EcoreUtil2.typeSelect(language.grammar.metamodelDeclarations, GeneratedMetamodel)) {
val nsURI = generatedMetamodel.EPackage.nsURI
if (uris.containsKey(nsURI)) {
issues.addError(this, "Duplicate generated grammar with nsURI '" + nsURI + "' in "
+ uris.get(nsURI).name + " and " + language.grammar.name)
} else {
uris.put(nsURI, language.grammar)
}
}
}
}
@ -86,6 +102,9 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
override initialize(Injector injector) {
injector.injectMembers(this)
projectConfig.initialize(injector)
for (language : languageConfigs) {
language.initialize(injector)
}
injector.getInstance(CodeConfig) => [ codeConfig |
codeConfig.initialize(injector)
]
@ -95,9 +114,8 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
}
protected override invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
val injector = createInjector()
createInjector()
for (language : languageConfigs) {
language.initialize(injector)
language.generate(language)
language.generateRuntimeSetup()
language.generateModules()

View file

@ -16,7 +16,13 @@ import com.google.inject.Module
import com.google.inject.Provider
import com.google.inject.Singleton
import com.google.inject.name.Names
import java.util.Arrays
import java.util.Collections
import java.util.List
import java.util.Map
import java.util.Properties
import org.apache.log4j.Logger
import org.eclipse.xtend2.lib.StringConcatenationClient
import org.eclipse.xtext.Constants
import org.eclipse.xtext.ISetup
import org.eclipse.xtext.ISetupExtension
@ -30,9 +36,12 @@ import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
import org.eclipse.xtext.xtext.generator.model.JavaFileAccess
import org.eclipse.xtext.xtext.generator.model.ManifestAccess
import org.eclipse.xtext.xtext.generator.model.PluginXmlAccess
import org.eclipse.xtext.xtext.generator.model.SuppressWarningsAnnotation
import org.eclipse.xtext.xtext.generator.model.TextFileAccess
import org.eclipse.xtext.xtext.generator.model.TypeReference
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
@Singleton
class XtextGeneratorTemplates {
@ -85,13 +94,17 @@ class XtextGeneratorTemplates {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.runtimeGenSetup, codeConfig)
javaFile.encodingProvider = encodingProvider
for (type : langConfig.runtimeGenSetup.imports) {
javaFile.importType(type)
}
javaFile.annotations += new SuppressWarningsAnnotation
javaFile.javaContent = '''
public class «g.runtimeGenSetup.simpleName» implements «ISetup», «ISetupExtension» {
@Override
public «'java.util.List'»<String> getFileExtensions() {
return «'java.util.Arrays'».asList(«FOR fileExtension : langConfig.fileExtensions SEPARATOR ','»"«fileExtension»"«ENDFOR»);
public «List»<String> getFileExtensions() {
return «Arrays».asList(«FOR fileExtension : langConfig.fileExtensions SEPARATOR ','»"«fileExtension»"«ENDFOR»);
}
@Override
@ -99,20 +112,20 @@ class XtextGeneratorTemplates {
«FOR usedGrammar : g.usedGrammars»
«usedGrammar.runtimeSetup».doSetup();
«ENDFOR»
«IF g.usedGrammars.isEmpty»
// register default ePackages
if (!«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("ecore"))
«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ecore", new «'org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl'»());
if (!«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xmi"))
«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xmi", new «'org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl'»());
if (!«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xtextbin"))
«'org.eclipse.emf.ecore.resource.Resource'».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
if (!«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("ecore"))
«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ecore", new «'org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl'.typeRef»());
if (!«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xmi"))
«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xmi", new «'org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl'.typeRef»());
if (!«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xtextbin"))
«'org.eclipse.emf.ecore.resource.Resource'.typeRef».Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xtextbin", new «BinaryGrammarResourceFactoryImpl»());
if (!«'org.eclipse.emf.ecore.EPackage'».Registry.INSTANCE.containsKey(«XtextPackage».eNS_URI))
«'org.eclipse.emf.ecore.EPackage'».Registry.INSTANCE.put(«XtextPackage».eNS_URI, «XtextPackage».eINSTANCE);
if (!«'org.eclipse.emf.ecore.EPackage'.typeRef».Registry.INSTANCE.containsKey(«XtextPackage».eNS_URI))
«'org.eclipse.emf.ecore.EPackage'.typeRef».Registry.INSTANCE.put(«XtextPackage».eNS_URI, «XtextPackage».eINSTANCE);
«ENDIF»
«Injector» injector = createInjector();
@ -120,7 +133,7 @@ class XtextGeneratorTemplates {
return injector;
}
public «Injector» createInjector() {
public «Injector» createInjector() {
return «Guice».createInjector(new «g.runtimeModule»());
}
@ -141,37 +154,37 @@ class XtextGeneratorTemplates {
else if (value.statements.isEmpty)
'provide'
else 'configure')
+ getSimpleMethodName(key.type)
+ key.type.simpleMethodName
+ if (value.expression !== null && !value.provider) 'ToInstance' else ''
}
private def getSimpleMethodName(String qn) {
qn.replaceAll('<', '\\.').replaceAll('>', '\\.').split('\\.').filter[matches('[A-Z].*')].join('$')
private def getSimpleMethodName(TypeReference type) {
type.name.replaceAll('<', '\\.').replaceAll('>', '\\.').split('\\.').filter[matches('[A-Z].*')].join('$')
}
private def endsWith(CharSequence sequence, char c) {
sequence.length > 0 && sequence.charAt(sequence.length - 1) == c
}
private def createBindingMethod(GuiceModuleAccess.Binding it) '''
private def StringConcatenationClient createBindingMethod(GuiceModuleAccess.Binding it) '''
«IF !value.provider && value.statements.isEmpty»
// contributed by «contributedBy»
«IF key.singleton»@«SingletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression === null»Class<? extends «key.type»>«ELSE»«key.type»«ENDIF» «bindMethodName»() {
return «IF value.expression !== null»«value.expression»«ELSE»«value.typeName».class«ENDIF»;
return «IF value.expression !== null»«value.expression»«ELSE»«value.type».class«ENDIF»;
}
«ELSEIF value.statements.isEmpty»
// contributed by «contributedBy»
«IF key.singleton»@«SingletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression==null»Class<? extends «Provider»<«key.type»>>«ELSE»«Provider»<«key.type»>«ENDIF» «bindMethodName»() {
return «IF value.expression!=null»«value.expression»«ELSE»«value.typeName».class«ENDIF»;
return «IF value.expression!=null»«value.expression»«ELSE»«value.type».class«ENDIF»;
}
«ELSE»
// contributed by «contributedBy»
public void «bindMethodName»(«Binder» binder) {
«FOR statement : value.statements»
«statement»«IF !statement.endsWith(';')»;«ENDIF»
«ENDFOR»
«FOR statement : value.statements»
«statement»«IF !statement.endsWith(';')»;«ENDIF»
«ENDFOR»
}
«ENDIF»
'''
@ -195,6 +208,10 @@ class XtextGeneratorTemplates {
def JavaFileAccess createRuntimeGenModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val superClass =
if (langConfig.runtimeGenModule.superClassName !== null)
new TypeReference(langConfig.runtimeGenModule.superClassName)
else g.runtimeDefaultModule
val javaFile = new JavaFileAccess(g.runtimeGenModule, codeConfig)
javaFile.encodingProvider = encodingProvider
@ -203,10 +220,11 @@ class XtextGeneratorTemplates {
* Manual modifications go to {@link «g.runtimeModule.simpleName»}.
*/
'''
javaFile.annotations += new SuppressWarningsAnnotation
javaFile.javaContent = '''
public abstract class «g.runtimeGenModule.simpleName» extends «g.runtimeDefaultModule» {
public abstract class «g.runtimeGenModule.simpleName» extends «superClass» {
protected «'java.util.Properties'» properties = null;
protected «Properties» properties = null;
@Override
public void configure(«Binder» binder) {
@ -225,6 +243,7 @@ class XtextGeneratorTemplates {
«FOR binding : langConfig.runtimeGenModule.bindings»
«binding.createBindingMethod»
«ENDFOR»
}
'''
@ -243,7 +262,7 @@ class XtextGeneratorTemplates {
'''
javaFile.javaContent = '''
public class «g.eclipsePluginModule.simpleName» extends «g.eclipsePluginGenModule» {
public «g.eclipsePluginModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'» plugin) {
public «g.eclipsePluginModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'.typeRef» plugin) {
super(plugin);
}
}
@ -253,6 +272,10 @@ class XtextGeneratorTemplates {
def JavaFileAccess createEclipsePluginGenModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val superClass =
if (langConfig.eclipsePluginGenModule.superClassName !== null)
new TypeReference(langConfig.eclipsePluginGenModule.superClassName)
else g.eclipsePluginDefaultModule
val javaFile = new JavaFileAccess(g.eclipsePluginGenModule, codeConfig)
javaFile.encodingProvider = encodingProvider
@ -261,15 +284,17 @@ class XtextGeneratorTemplates {
* Manual modifications go to {@link «g.eclipsePluginModule.simpleName»}.
*/
'''
javaFile.annotations += new SuppressWarningsAnnotation
javaFile.javaContent = '''
public abstract class «g.eclipsePluginGenModule.simpleName» extends «g.eclipsePluginDefaultModule» {
public abstract class «g.eclipsePluginGenModule.simpleName» extends «superClass» {
public «g.eclipsePluginGenModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'» plugin) {
public «g.eclipsePluginGenModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'.typeRef» plugin) {
super(plugin);
}
«FOR binding : langConfig.eclipsePluginGenModule.bindings»
«binding.createBindingMethod»
«ENDFOR»
}
'''
@ -319,10 +344,10 @@ class XtextGeneratorTemplates {
*/
'''
javaFile.javaContent = '''
public class «g.eclipsePluginExecutableExtensionFactory.simpleName» extends «'org.eclipse.xtext.ui.guice.AbstractGuiceAwareExecutableExtensionFactory'» {
public class «g.eclipsePluginExecutableExtensionFactory.simpleName» extends «'org.eclipse.xtext.ui.guice.AbstractGuiceAwareExecutableExtensionFactory'.typeRef» {
@Override
protected «'org.osgi.framework.Bundle'» getBundle() {
protected «'org.osgi.framework.Bundle'.typeRef» getBundle() {
return «g.eclipsePluginActivator».getInstance().getBundle();
}
@ -356,20 +381,20 @@ class XtextGeneratorTemplates {
public static final String «grammar.name.toUpperCase.replaceAll('\\.', '_')» = "«grammar.name»";
«ENDFOR»
private static final Logger logger = Logger.getLogger(«activator.simpleName».class);
private static final «Logger» logger = «Logger».getLogger(«activator.simpleName».class);
private static «activator.simpleName» INSTANCE;
private «'java.util.Map'»<String, «Injector»> injectors = «'java.util.Collections'».synchronizedMap(«Maps».<String, «Injector»> newHashMapWithExpectedSize(1));
private «Map»<String, «Injector»> injectors = «Collections».synchronizedMap(«Maps».<String, «Injector»> newHashMapWithExpectedSize(1));
@Override
public void start(«'org.osgi.framework.BundleContext'» context) throws Exception {
public void start(«'org.osgi.framework.BundleContext'.typeRef» context) throws Exception {
super.start(context);
INSTANCE = this;
}
@Override
public void stop(«'org.osgi.framework.BundleContext'» context) throws Exception {
public void stop(«'org.osgi.framework.BundleContext'.typeRef» context) throws Exception {
injectors.clear();
INSTANCE = null;
super.stop(context);
@ -422,7 +447,7 @@ class XtextGeneratorTemplates {
}
protected «Module» getSharedStateModule() {
return new «'org.eclipse.xtext.ui.shared.SharedStateModule'»();
return new «'org.eclipse.xtext.ui.shared.SharedStateModule'.typeRef»();
}
}

View file

@ -112,6 +112,12 @@ class ProjectConfigGenerator {
private FileSystemAccess aceJsGen;
public void checkConfiguration(XtextGenerator generator, Issues issues) {
if («PROJECTS.head»Src == null) {
issues.addError(generator, "The property '«PROJECTS.head»Src' must be set.", this);
}
if («PROJECTS.head»SrcGen == null) {
issues.addError(generator, "The property '«PROJECTS.head»SrcGen' must be set.", this);
}
«FOR p : PROJECTS»
if («p»Manifest != null && Strings.isEmpty(«p»Manifest.getPath())) {
issues.addError(generator, "The property 'path' must be set.", «p»Manifest);

View file

@ -31,6 +31,9 @@ class CodeConfig implements IGuiceAwareGeneratorComponent {
static val FILE_HEADER_VAR_USER = '${user}'
static val FILE_HEADER_VAR_VERSION = '${version}'
@Accessors
String encoding
@Accessors
String lineDelimiter

View file

@ -83,7 +83,11 @@ class FileSystemAccess implements IFileSystemAccess2, IGuiceAwareGeneratorCompon
override generateFile(String fileName, String outputConfiguration, CharSequence contents) {
if (outputConfiguration == DEFAULT_OUTPUT) {
val uri = fileName.URI
Files.write(contents, new File(uri.toFileString), uri.charset)
val file = new File(uri.toFileString)
val parent = file.parentFile
if (parent !== null)
parent.mkdirs
Files.write(contents, file, uri.charset)
} else {
throw new IllegalArgumentException('Unsupported configuration: ' + outputConfiguration)
}
@ -96,7 +100,11 @@ class FileSystemAccess implements IFileSystemAccess2, IGuiceAwareGeneratorCompon
override generateFile(String fileName, String outputConfiguration, InputStream content) throws RuntimeIOException {
if (outputConfiguration == DEFAULT_OUTPUT) {
val uri = fileName.URI
val fileWriter = Files.newWriter(new File(uri.toFileString), uri.charset)
val file = new File(uri.toFileString)
val parent = file.parentFile
if (parent !== null)
parent.mkdirs
val fileWriter = Files.newWriter(file, uri.charset)
try {
var c = content.read()
while (c >= 0) {

View file

@ -16,12 +16,11 @@ import org.eclipse.xtext.xtext.generator.XtextGenerator
/**
* A class annotation configuration for the <code>@Generated</code> annotation.
*/
@Accessors
class GeneratedClassAnnotation implements IClassAnnotation {
@Accessors
boolean includeDate = false
@Accessors
String comment
override generate() {

View file

@ -7,36 +7,242 @@
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.model
import java.util.Collections
import java.util.List
import java.util.Set
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend.lib.annotations.Data
import org.eclipse.xtext.util.internal.Log
@Accessors
@Log
class GuiceModuleAccess {
@Data
static class BindKey {
String type
TypeReference type
boolean singleton
boolean eagerSingleton
override equals(Object other) {
if (other instanceof BindKey)
this.type == other.type
else
false
}
override hashCode() {
type.hashCode
}
}
@Data
static class BindValue {
private String expression
private String typeName
private boolean provider
private List<CharSequence> statements
Object expression
TypeReference type
boolean provider
List<CharSequence> statements
}
@Data
static class Binding {
BindKey key
BindValue value
String contributedBy
boolean isFinal
String contributedBy
override equals(Object other) {
if (other instanceof Binding)
this.key == other.key
else
false
}
override hashCode() {
key.hashCode
}
}
val List<Binding> bindings = newArrayList
val Set<Binding> bindings = newLinkedHashSet
@Accessors
String superClassName
def void add(Binding newBinding) {
if (bindings.contains(newBinding)) {
val iterator = bindings.iterator()
var found = false
while (iterator.hasNext && !found) {
val oldBinding = iterator.next
if (oldBinding == newBinding) {
if (oldBinding.isFinal) {
if (newBinding.isFinal) {
throw new IllegalStateException("Conflicting final bindings for '" + oldBinding.key.type + "' from fragments "
+ oldBinding.contributedBy + " and " + newBinding.contributedBy)
} else {
LOG.warn("Cannot override final binding '" + oldBinding + "'. "
+ "Ignoring binding from fragment '" + newBinding.contributedBy + "'")
}
} else {
LOG.debug("replacing binding : " + oldBinding)
LOG.debug(" with new binding : " + newBinding)
iterator.remove()
}
found = true
}
}
}
bindings.add(newBinding)
}
def void addAll(Iterable<Binding> bindings) {
for (binding : bindings) {
add(binding)
}
}
def Set<Binding> getBindings() {
Collections.unmodifiableSet(bindings)
}
static class BindingFactory {
@Accessors
val String contributedBy
val Set<Binding> bindings = newLinkedHashSet
new() {
this.contributedBy = new Exception().stackTrace.get(1).className
}
new(String contributedBy) {
this.contributedBy = contributedBy
}
private def add(BindKey type, BindValue expr) {
add(type, expr, false);
}
private def add(BindKey type, BindValue expr, boolean isFinal) {
add(new Binding(type, expr, isFinal, contributedBy))
}
private def add(Binding binding) {
if (!bindings.add(binding))
throw new IllegalArgumentException("Duplicate binding for " + binding.key + " in " + contributedBy)
}
private def key(TypeReference type) {
return new BindKey(type, false, false)
}
private def eagerSingleton(TypeReference type) {
return new BindKey(type, true, true)
}
private def singleton(TypeReference type) {
return new BindKey(type, true, false)
}
private def value(TypeReference type) {
return new BindValue(null, type, false, Collections.emptyList)
}
private def expr(Object expr) {
return new BindValue(expr, null, false, Collections.emptyList)
}
private def provider(TypeReference type) {
return new BindValue(null, type, true, Collections.emptyList)
}
private def providerExpr(Object expr) {
return new BindValue(expr, null, true, Collections.emptyList)
}
private def statements(String[] statements) {
return new BindValue(null, null, false, statements)
}
def BindingFactory addTypeToInstance(TypeReference s1, Object s2) {
add(key(s1), expr(s2))
return this
}
def BindingFactory addTypeToProviderInstance(TypeReference s1, Object s2) {
add(key(s1), providerExpr(s2))
return this
}
def BindingFactory addConfiguredBinding(TypeReference key, String... statements) {
add(key(key), statements(statements))
return this
}
def BindingFactory addTypeToType(TypeReference s1, TypeReference s2){
add(key(s1), value(s2))
return this
}
def BindingFactory addTypeToTypeSingleton(TypeReference s1, TypeReference s2){
add(singleton(s1), value(s2))
return this
}
def BindingFactory addTypeToTypeEagerSingleton(TypeReference s1, TypeReference s2){
add(eagerSingleton(s1), value(s2))
return this
}
def BindingFactory addTypeToProvider(TypeReference s1, TypeReference s2){
add(key(s1), provider(s2))
return this
}
def BindingFactory addTypeToProviderSingleton(TypeReference s1, TypeReference s2){
add(singleton(s1), provider(s2))
return this
}
def BindingFactory addTypeToProviderEagerSingleton(TypeReference s1, TypeReference s2){
add(eagerSingleton(s1), provider(s2))
return this
}
def BindingFactory addfinalTypeToType(TypeReference s1, TypeReference s2){
add(key(s1), value(s2), true)
return this
}
def BindingFactory addfinalTypeToTypeSingleton(TypeReference s1, TypeReference s2){
add(singleton(s1), value(s2), true)
return this
}
def BindingFactory addfinalTypeToTypeEagerSingleton(TypeReference s1, TypeReference s2){
add(eagerSingleton(s1), value(s2), true)
return this
}
def BindingFactory addfinalTypeToProvider(TypeReference s1, TypeReference s2){
add(key(s1), provider(s2), true)
return this
}
def BindingFactory addfinalTypeToProviderSingleton(TypeReference s1, TypeReference s2){
add(singleton(s1), provider(s2), true)
return this
}
def BindingFactory addfinalTypeToProviderEagerSingleton(TypeReference s1, TypeReference s2){
add(eagerSingleton(s1), provider(s2), true)
return this
}
def void contributeTo(GuiceModuleAccess module) {
module.addAll(this.bindings)
}
}
}

View file

@ -9,8 +9,8 @@ package org.eclipse.xtext.xtext.generator.model
import com.google.common.collect.Lists
import java.util.Collections
import java.util.List
import java.util.Map
import java.util.regex.Pattern
import org.eclipse.emf.codegen.util.CodeGenUtil
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend2.lib.StringConcatenation
@ -30,6 +30,9 @@ class JavaFileAccess extends TextFileAccess {
@Accessors
boolean markedAsGenerated
@Accessors
val List<IClassAnnotation> annotations = newArrayList
new(String qualifiedName, CodeConfig codeConfig) {
this(new TypeReference(qualifiedName), codeConfig)
}
@ -43,28 +46,25 @@ class JavaFileAccess extends TextFileAccess {
}
def String importType(TypeReference typeRef) {
val simpleName = typeRef.simpleName
if (CodeGenUtil.isJavaDefaultType(simpleName) || this.packageName == typeRef.package)
return simpleName
val imported = imports.get(simpleName)
if (imported != null) {
if (imported == typeRef)
return simpleName
else
return typeRef.name
var name = typeRef.simpleName
if (!CodeGenUtil.isJavaDefaultType(name) && this.packageName != typeRef.package) {
val imported = imports.get(name)
if (imported === null)
imports.put(name, typeRef)
else if (imported.name != typeRef.name)
name = typeRef.name
}
imports.put(simpleName, typeRef)
return simpleName
return name + typeRef.arguments.join('<', ', ', '>', [importType])
}
def void setJavaContent(StringConcatenationClient javaContent) {
val javaStringConcat = new JavaStringConcatenation(this)
javaStringConcat.append(javaContent)
content = javaStringConcat
setContent(javaStringConcat)
}
override generate() {
val classAnnotations = codeConfig.classAnnotations.filter[appliesTo(this)]
val classAnnotations = annotations + codeConfig.classAnnotations.filter[appliesTo(this)]
classAnnotations.forEach[importType(annotationImport)]
val sortedImports = Lists.newArrayList(imports.values.map[name])
Collections.sort(sortedImports)
@ -88,8 +88,6 @@ class JavaFileAccess extends TextFileAccess {
val JavaFileAccess access
val typeNamePattern = Pattern.compile('[a-z]+(\\.[a-z]+)*(\\.[A-Z][a-zA-Z]*)+')
new(JavaFileAccess access) {
super(access.codeConfig.lineDelimiter)
this.access = access
@ -99,9 +97,7 @@ class JavaFileAccess extends TextFileAccess {
if (object instanceof TypeReference)
access.importType(object)
else if (object instanceof Class<?>)
access.importType(new TypeReference(object as Class<?>))
else if (object instanceof String && typeNamePattern.matcher(object as String).matches)
access.importType(new TypeReference(object as String))
access.importType(new TypeReference(object))
else
object.toString
}

View file

@ -19,7 +19,7 @@ class ManifestAccess {
String symbolicName
String version = '0.0.1'
String version = '0.0.1.qualifier'
boolean merge = true

View file

@ -8,6 +8,7 @@
package org.eclipse.xtext.xtext.generator.model
import java.util.List
import java.util.Set
import org.eclipse.xtend.lib.annotations.Accessors
@Accessors
@ -15,4 +16,6 @@ class StandaloneSetupAccess {
val List<CharSequence> registrations = newArrayList
val Set<TypeReference> imports = newHashSet
}

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.model
import org.eclipse.xtend.lib.annotations.Accessors
/**
* A class annotation configuration for the <code>@SuppressWarnings</code> annotation.
*/
@Accessors
class SuppressWarningsAnnotation implements IClassAnnotation {
String suppress = 'all'
override generate() {
val stringBuilder = new StringBuilder('@SuppressWarnings(')
val suppressedWarnings = suppress.split("\\s*,\\s*")
if (suppressedWarnings.length != 1)
stringBuilder.append('{')
stringBuilder.append(suppressedWarnings.join('"', '", "', '"', [it]))
if (suppressedWarnings.length != 1)
stringBuilder.append('}')
stringBuilder.append(')')
return stringBuilder
}
override appliesTo(JavaFileAccess javaFile) {
return true
}
override getAnnotationImport() {
return new TypeReference('java.lang.SuppressWarnings')
}
}

View file

@ -43,7 +43,11 @@ class TextFileAccess {
} else {
charset = Charset.defaultCharset
}
Files.write(generate(), new File(path), charset)
val file = new File(path)
val parent = file.parentFile
if (parent !== null)
parent.mkdirs
Files.write(generate(), file, charset)
}
}

View file

@ -7,39 +7,62 @@
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.model
import java.util.Collections
import java.util.List
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend.lib.annotations.EqualsHashCode
@Accessors
@EqualsHashCode
class TypeReference {
static def TypeReference typeRef(String name, String... arguments) {
new TypeReference(name, arguments.map[new TypeReference(it)])
}
static def TypeReference typeRef(Class<?> clazz, Class<?>... arguments) {
new TypeReference(clazz, arguments.map[new TypeReference(it)])
}
val String name
val List<TypeReference> arguments
new(String name) {
this.name = name
this.arguments = Collections.emptyList
}
new(String name, List<TypeReference> arguments) {
this.name = name
this.arguments = Collections.unmodifiableList(arguments)
}
new(String packageName, String className) {
this.name = packageName + '.' + className
this.arguments = Collections.emptyList
}
new(Class<?> clazz) {
this.name = clazz.name.replace('$', '.')
this.arguments = Collections.emptyList
}
new(Class<?> clazz, List<TypeReference> arguments) {
this.name = clazz.name.replace('$', '.')
this.arguments = Collections.unmodifiableList(arguments)
}
override toString() {
name
name + arguments.join('<', ', ', '>', [toString])
}
def getName() {
name
}
def getSimpleName() {
def String getSimpleName() {
val simpleNameIndex = name.lastIndexOf('.')
return name.substring(simpleNameIndex + 1)
}
def getPackage() {
def String getPackage() {
var packageEnd = name.length
for (var i = name.length - 1; i >= 0; i--) {
if (name.charAt(i).matches('.')) {

View file

@ -27,7 +27,7 @@ class WizardConfig extends XtextProjectConfig {
boolean testingSupport = false
boolean mavenLayout = true
boolean mavenLayout = false
override checkConfiguration(XtextGenerator generator, Issues issues) {
super.checkConfiguration(generator, issues)
@ -96,11 +96,17 @@ class WizardConfig extends XtextProjectConfig {
if (testingSupport) {
if (runtimeTestSrc === null)
runtimeTestSrc = runtimeBase + '.test/' + src
runtimeTestSrc = runtimeBase + '.tests/' + src
if (runtimeTestSrcGen === null)
runtimeTestSrcGen = runtimeBase + '.test/' + srcGen
runtimeTestSrcGen = runtimeBase + '.tests/' + srcGen
if (runtimeTestManifest === null)
runtimeTestManifest = new ManifestAccess => [path = runtimeBase + '.test/META-INF/MANIFEST.MF']
runtimeTestManifest = new ManifestAccess => [path = runtimeBase + '.tests/META-INF/MANIFEST.MF']
if (eclipsePluginTestSrc === null)
eclipsePluginTestSrc = runtimeBase + '.tests/' + src
if (eclipsePluginTestSrcGen === null)
eclipsePluginTestSrcGen = runtimeBase + '.tests/' + srcGen
if (eclipsePluginTestManifest === null)
eclipsePluginTestManifest = new ManifestAccess => [path = runtimeBase + '.tests/META-INF/MANIFEST.MF']
}
super.initialize(injector)

View file

@ -66,6 +66,12 @@ public class XtextProjectConfig implements IXtextProjectConfig {
private FileSystemAccess aceJsGen;
public void checkConfiguration(XtextGenerator generator, Issues issues) {
if (runtimeSrc == null) {
issues.addError(generator, "The property 'runtimeSrc' must be set.", this);
}
if (runtimeSrcGen == null) {
issues.addError(generator, "The property 'runtimeSrcGen' must be set.", this);
}
if (runtimeManifest != null && Strings.isEmpty(runtimeManifest.getPath())) {
issues.addError(generator, "The property 'path' must be set.", runtimeManifest);
}

View file

@ -43,11 +43,13 @@ public class EclipseProjectPropertiesEncodingProvider extends IEncodingProvider.
return result;
// Read the project properties
try {
result = getFromProperties(uri);
if (result != null)
return result;
} catch (IOException e) {
if (uri != null) {
try {
result = getFromProperties(uri);
if (result != null)
return result;
} catch (IOException e) {
}
}
// Fall back to the standard encoding