summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorahaase2008-03-01 11:42:47 (EST)
committerahaase2008-03-01 11:42:47 (EST)
commit62c122976fed7e6d9fb2b590112043008150ed69 (patch)
tree7071c34f289c1022a3895f58cf49ad6da10058f9
parentbdf4ee9881c68a94bb1158fe1e38b11735198c3a (diff)
downloadorg.eclipse.xpand-62c122976fed7e6d9fb2b590112043008150ed69.zip
org.eclipse.xpand-62c122976fed7e6d9fb2b590112043008150ed69.tar.gz
org.eclipse.xpand-62c122976fed7e6d9fb2b590112043008150ed69.tar.bz2
*** empty log message ***
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/.classpath7
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/.project28
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/build.properties5
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/plugin.xml11
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/OldXpandRegistry.java179
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandBackendFacade.java294
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandComponent.java227
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldDefinitionConverter.java405
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldXpandRegistryFactory.java35
-rw-r--r--plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/plugin/XpandDefinitionName.java116
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/.classpath7
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/.project28
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/META-INF/MANIFEST.MF17
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/build.properties5
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/plugin.xml11
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckBackendFacade.java33
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckComponent.java126
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/OldXtendRegistry.java231
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendBackendFacade.java176
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendComponent.java124
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldExpressionConverter.java475
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldHelper.java89
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldTypeAnalyzer.java319
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/TypeToBackendType.java183
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/CheckConverter.java110
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/JavaExtensionFunction.java62
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/OldExtensionConverter.java130
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XpandIsDeleteLine.java114
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendCollectionOperations.java91
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendGlobalVarOperations.java27
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendIterator.java51
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibContributor.java42
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibNames.java27
-rw-r--r--plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/plugin/OldXtendRegistryFactory.java35
35 files changed, 3834 insertions, 0 deletions
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/.classpath b/plugins/org.eclipse.xtend.middleend.xpand/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/.project b/plugins/org.eclipse.xtend.middleend.xpand/.project
new file mode 100644
index 0000000..ab87d74
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.middleend.xpand</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtend.middleend.xpand/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6650b49
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Xpand Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.middleend.xpand;singleton:=true
+Bundle-Version: 1.0.0
+Export-Package: org.eclipse.xtend.middleend.xpand,
+ org.eclipse.xtend.middleend.xpand.internal;x-internal:=true,
+ org.eclipse.xtend.middleend.xpand.plugin
+Require-Bundle: org.eclipse.xpand,
+ org.eclipse.xtend,
+ org.eclipse.xtend.backend,
+ org.eclipse.xtend.middleend.xtend,
+ org.eclipse.emf.mwe.core,
+ org.apache.commons.logging
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/build.properties b/plugins/org.eclipse.xtend.middleend.xpand/build.properties
new file mode 100644
index 0000000..e9863e2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/plugin.xml b/plugins/org.eclipse.xtend.middleend.xpand/plugin.xml
new file mode 100644
index 0000000..c89b990
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension
+ point="org.eclipse.xtend.backend.MiddleEnd">
+ <element_1
+ class="org.eclipse.xtend.middleend.xpand.internal.OldXpandRegistryFactory">
+ </element_1>
+ </extension>
+
+</plugin>
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/OldXpandRegistry.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/OldXpandRegistry.java
new file mode 100644
index 0000000..54b735f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/OldXpandRegistry.java
@@ -0,0 +1,179 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xpand;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipose.xtend.middleend.MiddleEnd;
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd;
+import org.eclipse.internal.xpand2.ast.Advice;
+import org.eclipse.internal.xpand2.ast.Template;
+import org.eclipse.internal.xpand2.model.XpandAdvice;
+import org.eclipse.internal.xpand2.model.XpandDefinition;
+import org.eclipse.xpand2.XpandExecutionContext;
+import org.eclipse.xpand2.XpandUtil;
+import org.eclipse.xtend.backend.aop.AroundAdvice;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.FunctionDefContextFactory;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.backend.util.Cache;
+import org.eclipse.xtend.middleend.xpand.internal.OldDefinitionConverter;
+import org.eclipse.xtend.middleend.xpand.plugin.XpandDefinitionName;
+import org.eclipse.xtend.middleend.xtend.internal.OldHelper;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendLibContributor;
+
+
+/**
+ * This class manages the interdependent graph of parsed and converted Xpand files, allowing access to them by "compilation unit".
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldXpandRegistry implements LanguageSpecificMiddleEnd {
+ private final XpandExecutionContext _ctx;
+ private BackendTypesystem _ts;
+ private MiddleEnd _middleEnd;
+
+ private final Cache<String, FunctionDefContextInternal> _functionDefContexts = new Cache<String, FunctionDefContextInternal> () {
+ @Override
+ protected FunctionDefContextInternal create (String compilationUnit) {
+ return new FunctionDefContextFactory (_ts).create();
+ }
+ };
+
+ /**
+ * all functions actually defined in a given compilation unit
+ */
+ private final Map<String, List<NamedFunction>> _functionsByResource = new HashMap <String, List<NamedFunction>>();
+
+ private final Map<String, List<AroundAdvice>> _adviceByResource = new HashMap <String, List<AroundAdvice>> ();
+
+ private FunctionDefContextInternal getFunctionDefContext (String xtendName) {
+ return _functionDefContexts.get (OldHelper.normalizeXtendResourceName (xtendName));
+ }
+
+
+ public OldXpandRegistry (Object specificData) {
+ if (specificData == null)
+ throw new IllegalArgumentException (getName() + " middle end is not initialized - will not contribute");
+
+ _ctx = (XpandExecutionContext) specificData;
+ }
+
+ public void setMiddleEnd (MiddleEnd middleEnd) {
+ _middleEnd = middleEnd;
+ _ts = middleEnd.getTypesystem();
+ }
+
+
+ /**
+ * parses and converts an Xpand file and all other files it depends on.
+ */
+ public void registerXpandFile (String xpandFile) {
+ xpandFile = OldHelper.normalizeXpandResourceName (xpandFile);
+
+ if (_functionsByResource.containsKey (xpandFile))
+ return;
+
+ final String xpandResourceName = OldHelper.xpandFileAsOldResourceName (xpandFile);
+ final Template file = (Template) _ctx.getResourceManager().loadResource (xpandResourceName, XpandUtil.TEMPLATE_EXTENSION);
+ if (file == null)
+ throw new IllegalArgumentException ("could not find Xpand file '" + xpandResourceName + "'");
+
+ final XpandExecutionContext ctx = (XpandExecutionContext) _ctx.cloneWithResource (file);
+
+ final TypeToBackendType typeConverter = new TypeToBackendType (_ts, ctx);
+ final OldDefinitionConverter definitionFactory = new OldDefinitionConverter (ctx, typeConverter);
+
+ final List<NamedFunction> defined = new ArrayList<NamedFunction>();
+ final FunctionDefContextInternal fdc = getFunctionDefContext (xpandFile);
+
+ // register the XtendLib. Do this first so the extension can override functions
+ for (NamedFunction f: new XtendLibContributor (_ts).getContributedFunctions())
+ fdc.register (f, false);
+
+ final Set<XpandDefinitionName> referenced = new HashSet<XpandDefinitionName> ();
+
+ for (XpandDefinition ext: file.getDefinitions ())
+ defined.add (definitionFactory.create (ext, fdc, referenced));
+
+ _functionsByResource.put (xpandFile, defined);
+
+ final List<AroundAdvice> newAdvice = new ArrayList<AroundAdvice>();
+ for (XpandAdvice a: file.getAdvices())
+ newAdvice.add (definitionFactory.create ((Advice) a, referenced, fdc));
+ _adviceByResource.put(xpandResourceName, newAdvice);
+
+ // make sure all imported resources are registered as well
+ for (String imported: file.getImportedExtensions())
+ for (NamedFunction f: _middleEnd.getFunctions (imported).getPublicFunctions())
+ fdc.register (f, false);
+
+ // collect all referenced template files...
+ final Set<String> xpandFileNames = new HashSet<String> ();
+ for (XpandDefinitionName n: referenced)
+ xpandFileNames.add (n.getCanonicalTemplateFileName());
+
+ // ... and register all template definitions from these files. It is necessary to have them all registered to enable
+ // polymorphism - static type analysis does not find all potential matches.
+ for (String xpandFileName: xpandFileNames)
+ for (NamedFunction f: _middleEnd.getFunctions (xpandFileName).getPublicFunctions())
+ fdc.register (f, false);
+
+ }
+
+
+ public FunctionDefContext getContributedFunctions (String xpandFile) {
+ registerXpandFile (xpandFile);
+ return getFunctionDefContext (xpandFile);
+ }
+
+
+ public boolean canHandle (String xpandFile) {
+ xpandFile = OldHelper.normalizeXpandResourceName (xpandFile);
+
+ if (_functionsByResource.containsKey (xpandFile))
+ return true;
+
+ final String xpandResourceName = OldHelper.xpandFileAsOldResourceName (xpandFile);
+ try {
+ final Template file = (Template) _ctx.getResourceManager().loadResource (xpandResourceName, XpandUtil.TEMPLATE_EXTENSION);
+ return file != null;
+ }
+ catch (Exception exc) {
+ return false;
+ }
+ }
+
+
+ public List<AroundAdvice> getContributedAdvice (String resourceName) {
+ registerXpandFile (resourceName);
+ return _adviceByResource.get (OldHelper.normalizeXpandResourceName (resourceName));
+ }
+
+ public String getName () {
+ return "Xpand";
+ }
+}
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandBackendFacade.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandBackendFacade.java
new file mode 100644
index 0000000..c937875
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandBackendFacade.java
@@ -0,0 +1,294 @@
+package org.eclipse.xtend.middleend.xpand;
+
+
+import java.io.File;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipose.xtend.middleend.MiddleEnd;
+import org.eclipose.xtend.middleend.MiddleEndFactory;
+import org.eclipse.internal.xpand2.ast.Definition;
+import org.eclipse.internal.xpand2.ast.Statement;
+import org.eclipse.internal.xpand2.ast.Template;
+import org.eclipse.internal.xpand2.codeassist.XpandTokens;
+import org.eclipse.internal.xpand2.parser.XpandParseFacade;
+import org.eclipse.xpand2.XpandExecutionContext;
+import org.eclipse.xpand2.XpandExecutionContextImpl;
+import org.eclipse.xpand2.output.FileHandle;
+import org.eclipse.xpand2.output.Outlet;
+import org.eclipse.xpand2.output.Output;
+import org.eclipse.xpand2.output.OutputImpl;
+import org.eclipse.xpand2.output.PostProcessor;
+import org.eclipse.xtend.backend.BackendFacade;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.FunctionDefContextFactory;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.backend.syslib.FileIoOperations;
+import org.eclipse.xtend.backend.syslib.FileOutlet;
+import org.eclipse.xtend.backend.syslib.InMemoryPostprocessor;
+import org.eclipse.xtend.backend.syslib.SysLibNames;
+import org.eclipse.xtend.backend.syslib.UriBasedPostprocessor;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.middleend.xpand.internal.OldDefinitionConverter;
+import org.eclipse.xtend.middleend.xpand.internal.OldXpandRegistryFactory;
+import org.eclipse.xtend.middleend.xpand.plugin.XpandDefinitionName;
+import org.eclipse.xtend.middleend.xtend.internal.OldHelper;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.middleend.xtend.plugin.OldXtendRegistryFactory;
+import org.eclipse.xtend.typesystem.MetaModel;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XpandBackendFacade {
+ private final String _xpandFile;
+ private final MiddleEnd _middleEnd;
+
+ private final String _fileEncoding;
+ private final Collection<MetaModel> _mms;
+ private final Collection<Outlet> _outlets;
+
+ /**
+ * This method executes Xpand code that is passed in as a string, script language style.<br>
+ *
+ * There are two restrictions. Firstly, no DEFINEs are allowed - the string that is passed in must be a valid body for a DEFINE. Never
+ * mind the "parameters" - the "variables" parameter defines all variables that will be defined during execution. Use "this" as a
+ * variable name to specify the variable that is implicitly bound as the "special" parameter passed to a definition.<br>
+ *
+ * Secondly, no IMPORT or EXTENSION statements are possible. So types must be referenced by their fully qualified names, and no calls
+ * to extensions are possible. Calls to other templates that are available as files are possible, just as you would expect.<br>
+ *
+ * Both the "variables" and "outlets" parameter may be null.
+ */
+ public static Object executeStatement (String code, Collection<MetaModel> mms, Map<String, Object> variables, Collection <Outlet> outlets) {
+ return executeStatement (code, null, mms, variables, outlets);
+ }
+
+ /**
+ * This method executes Xpand code that is passed in as a string, script language style.<br>
+ *
+ * There are two restrictions. Firstly, no DEFINEs are allowed - the string that is passed in must be a valid body for a DEFINE. Never
+ * mind the "parameters" - the "variables" parameter defines all variables that will be defined during execution. Use "this" as a
+ * variable name to specify the variable that is implicitly bound as the "special" parameter passed to a definition.<br>
+ *
+ * Secondly, no IMPORT or EXTENSION statements are possible. So types must be referenced by their fully qualified names, and no calls
+ * to extensions are possible. Calls to other templates that are available as files are possible, just as you would expect.<br>
+ *
+ * Both the "variables" and "outlets" parameter may be null.
+ */
+ public static Object executeStatement (String code, String fileEncoding, Collection<MetaModel> mms, Map<String, Object> variables, Collection <Outlet> outlets) {
+ return executeStatement (code, fileEncoding, mms, variables, outlets, null);
+ }
+
+ /**
+ * This method executes Xpand code that is passed in as a string, script language style.<br>
+ *
+ * There are two restrictions. Firstly, no DEFINEs are allowed - the string that is passed in must be a valid body for a DEFINE. Never
+ * mind the "parameters" - the "variables" parameter defines all variables that will be defined during execution. Use "this" as a
+ * variable name to specify the variable that is implicitly bound as the "special" parameter passed to a definition.<br>
+ *
+ * Secondly, no IMPORT or EXTENSION statements are possible. So types must be referenced by their fully qualified names, and no calls
+ * to extensions are possible. Calls to other templates that are available as files are possible, just as you would expect.<br>
+ *
+ * The "variables", "outlets" and "advice" parameter may be null.
+ */
+ public static Object executeStatement (String code, String fileEncoding, Collection<MetaModel> mms, Map<String, Object> variables, Collection <Outlet> outlets, List<String> advice) {
+ return createForFile (null, fileEncoding, mms, outlets).executeStatement (code, variables, advice);
+ }
+
+
+ public Object executeStatement (String code, Map<String, Object> variables, List<String> advice) {
+ if (variables == null)
+ variables = new HashMap<String, Object> ();
+ if (advice == null)
+ advice = new ArrayList<String> ();
+
+ for (String adv: advice)
+ _middleEnd.applyAdvice (adv);
+
+ final Template tpl = XpandParseFacade.file (new StringReader (XpandTokens.LT + "DEFINE dUmMy FOR dUmMy" + XpandTokens.RT + code + XpandTokens.RT + XpandTokens.LT + "ENDDEFINE" + XpandTokens.RT), null);
+ final Statement[] statements = ((Definition) tpl.getDefinitions()[0]).getBody();
+
+ XpandExecutionContext ctx = createXpandExecutionContext (_fileEncoding, _mms, _outlets);
+ for (String varName: variables.keySet())
+ ctx = (XpandExecutionContext) ctx.cloneWithVariable (new Variable (varName, ctx.getType (variables.get (varName))));
+
+ final Set<XpandDefinitionName> referenced = new HashSet<XpandDefinitionName>();
+ final OldDefinitionConverter defConverter = new OldDefinitionConverter (ctx, new TypeToBackendType (_middleEnd.getTypesystem(), ctx));
+ final ExpressionBase converted = defConverter.convertStatementSequence (statements, tpl, referenced);
+
+ final FunctionDefContextInternal fdc = new FunctionDefContextFactory (_middleEnd.getTypesystem()).create();
+
+ for (XpandDefinitionName xdn: referenced)
+ for (NamedFunction f: _middleEnd.getFunctions (xdn.getCanonicalTemplateFileName ()).getPublicFunctions())
+ fdc.register (f, false);
+
+ final ExecutionContext backendCtx = BackendFacade.createExecutionContext (fdc, _middleEnd.getTypesystem(), true); //TODO configure isLogStacktrace
+ backendCtx.getLocalVarContext().getLocalVars().putAll (variables);
+ registerOutlets (backendCtx, _outlets);
+
+ return converted.evaluate (backendCtx);
+ }
+
+ public static void registerOutlets (ExecutionContext ctx, Collection<Outlet> outlets) {
+ for (Outlet oldOutlet: outlets) {
+ final FileOutlet newOutlet = new FileOutlet ();
+ newOutlet.setAppend (oldOutlet.isAppend());
+ newOutlet.setBaseDir (new File (oldOutlet.getPath()));
+ if (oldOutlet.getFileEncoding() != null)
+ newOutlet.setFileEncoding (oldOutlet.getFileEncoding());
+ newOutlet.setOverwrite (oldOutlet.isOverwrite());
+
+ for (PostProcessor pp: oldOutlet.postprocessors) {
+ newOutlet.register (new InMemoryPpAdapter (pp, oldOutlet));
+ newOutlet.register (new UriBasedPpAdapter (pp, oldOutlet));
+ }
+
+ final String outletName = (oldOutlet.getName() != null) ? oldOutlet.getName() : FileIoOperations.DEFAULT_OUTLET_NAME;
+ ctx.getFunctionDefContext ().invoke (ctx, SysLibNames.REGISTER_OUTLET, Arrays.asList (outletName, newOutlet));
+ }
+ }
+
+ private static class InMemoryPpAdapter implements InMemoryPostprocessor {
+ private final PostProcessor _oldPp;
+ private final Outlet _outlet;
+
+ public InMemoryPpAdapter (PostProcessor oldPp, Outlet outlet) {
+ _oldPp = oldPp;
+ _outlet = outlet;
+ }
+
+ public CharSequence process (CharSequence unprocessed, String uri) {
+ final FileHandle fh = new FileHandleImpl (unprocessed, _outlet, new File (uri));
+ _oldPp.beforeWriteAndClose (fh);
+ return fh.getBuffer();
+ }
+ }
+
+ private static class FileHandleImpl implements FileHandle {
+ private CharSequence _buffer;
+ private final Outlet _outlet;
+ private final File _file;
+
+ public FileHandleImpl (CharSequence buffer, Outlet outlet, File file) {
+ _buffer = buffer;
+ _outlet = outlet;
+ _file = file;
+ }
+
+ public CharSequence getBuffer () {
+ return _buffer;
+ }
+
+ public String getFileEncoding () {
+ return _outlet.getFileEncoding();
+ }
+
+ public Outlet getOutlet () {
+ return _outlet;
+ }
+
+ public File getTargetFile () {
+ return _file;
+ }
+
+ public boolean isAppend () {
+ return _outlet.isAppend();
+ }
+
+ public boolean isOverwrite () {
+ return _outlet.isOverwrite();
+ }
+
+ public void setBuffer (CharSequence buffer) {
+ _buffer = buffer;
+ }
+
+ public void writeAndClose () {
+ throw new UnsupportedOperationException ();
+ }
+ }
+
+ private static class UriBasedPpAdapter implements UriBasedPostprocessor {
+ private final PostProcessor _oldPp;
+ private final Outlet _outlet;
+
+ public UriBasedPpAdapter (PostProcessor oldPp, Outlet outlet) {
+ _oldPp = oldPp;
+ _outlet = outlet;
+ }
+
+ public void process (String uri) {
+ final FileHandle fh = new FileHandleImpl ("", _outlet, new File (uri));
+ _oldPp.afterClose (fh);
+ }
+ }
+
+ public static XpandBackendFacade createForFile (String xpandFilename, String fileEncoding, Collection<MetaModel> mms, Collection <Outlet> outlets) {
+ return new XpandBackendFacade (xpandFilename, fileEncoding, mms, outlets);
+ }
+
+
+ private XpandExecutionContext createXpandExecutionContext (String fileEncoding, Collection<MetaModel> mms, Collection<Outlet> outlets) {
+ fileEncoding = OldHelper.normalizedFileEncoding (fileEncoding);
+
+ final Output output = new OutputImpl ();
+ for (Outlet outlet: outlets)
+ output.addOutlet (outlet);
+ //TODO ProtectedRegionResolver
+
+ final XpandExecutionContextImpl ctx = new XpandExecutionContextImpl (output, null);
+ for (MetaModel mm: mms)
+ ctx.registerMetaModel (mm);
+ ctx.setFileEncoding (fileEncoding);
+
+ return ctx;
+ }
+
+ private Map<Class<?>, Object> createSpecificParameters (String fileEncoding, Collection<MetaModel> mms, Collection<Outlet> outlets) {
+ final XpandExecutionContext ctx = createXpandExecutionContext (fileEncoding, mms, outlets);
+
+ final Map<Class<?>, Object> result = new HashMap<Class<?>, Object> ();
+ result.put (OldXtendRegistryFactory.class, ctx);
+ result.put (OldXpandRegistryFactory.class, ctx);
+ return result;
+ }
+
+
+ private XpandBackendFacade (String xpandFilename, String fileEncoding, Collection<MetaModel> mms, Collection <Outlet> outlets) {
+ if (outlets == null)
+ outlets = new ArrayList<Outlet> ();
+
+ _xpandFile = OldHelper.normalizeXpandResourceName (xpandFilename);
+ _middleEnd = MiddleEndFactory.create (OldHelper.guessTypesystem (mms), createSpecificParameters (fileEncoding, mms, outlets));
+
+ _fileEncoding = fileEncoding;
+ _mms = mms;
+ _outlets = outlets;
+ }
+
+ public Collection<NamedFunction> getContributedFunctions () {
+ return _middleEnd.getFunctions(_xpandFile).getPublicFunctions();
+ }
+
+ public FunctionDefContext getFunctionDefContext () {
+ if (_xpandFile == null)
+ return new FunctionDefContextFactory (_middleEnd.getTypesystem()).create();
+
+ return _middleEnd.getFunctions (_xpandFile);
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandComponent.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandComponent.java
new file mode 100644
index 0000000..25b02b9
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/XpandComponent.java
@@ -0,0 +1,227 @@
+package org.eclipse.xtend.middleend.xpand;
+
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.mwe.core.WorkflowContext;
+import org.eclipse.emf.mwe.core.issues.Issues;
+import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
+import org.eclipse.internal.xpand2.ast.Definition;
+import org.eclipse.internal.xpand2.ast.ExpandStatement;
+import org.eclipse.internal.xpand2.ast.Template;
+import org.eclipse.internal.xpand2.codeassist.XpandTokens;
+import org.eclipse.internal.xpand2.parser.XpandParseFacade;
+import org.eclipse.internal.xtend.xtend.parser.ParseException;
+import org.eclipse.xpand2.XpandExecutionContextImpl;
+import org.eclipse.xpand2.output.Outlet;
+import org.eclipse.xpand2.output.Output;
+import org.eclipse.xpand2.output.OutputImpl;
+import org.eclipse.xpand2.output.PostProcessor;
+import org.eclipse.xtend.expression.AbstractExpressionsUsingWorkflowComponent;
+
+
+/**
+ * This workflow component executes an Xpand template based on the new backend implementation. It
+ * combines the steps of parsing and transforming the source files, and of invoking the script.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class XpandComponent extends AbstractExpressionsUsingWorkflowComponent {
+ //TODO profiler
+
+ private String _genPath = null;
+ private String _srcPath = null;
+
+ private String _expand = null;
+ private String _fileEncoding = null;
+ private boolean _automaticHyphens = false;
+ private Output _output = null;
+
+ private final List<Outlet> _outlets = new ArrayList<Outlet>();
+
+ private List<PostProcessor> _postprocessors = new ArrayList <PostProcessor>();
+ private List<Outlet> _initializedOutlets = new ArrayList<Outlet> ();
+
+
+ public List<PostProcessor> getBeautifier() {
+ return _postprocessors;
+ }
+
+ public void addBeautifier (PostProcessor beautifier) {
+ _postprocessors.add (beautifier);
+ }
+
+ public List<PostProcessor> getPostprocessors() {
+ return _postprocessors;
+ }
+
+ public void addPostprocessor (PostProcessor postprocessor) {
+ _postprocessors.add (postprocessor);
+ }
+
+ public void setAutomaticHyphens(boolean automaticHyphens) {
+ this._automaticHyphens = automaticHyphens;
+ }
+
+ @Override
+ public String getLogMessage() {
+ return "generating '" + _expand + "' => directory '" + _genPath + "'";
+ }
+
+ public void setFileEncoding(final String fileEncoding) {
+ _fileEncoding = fileEncoding;
+ }
+
+ public String getFileEncoding() {
+ return _fileEncoding;
+ }
+
+ public void setExpand (String invoke) {
+ _expand = invoke;
+ }
+
+ /**
+ * @deprecated use outlets instead
+ */
+ @Deprecated
+ public void setGenPath(final String genPath) {
+ _genPath = fixPath(genPath);
+ }
+
+ /**
+ *
+ * @deprecated use outlets instead
+ */
+ @Deprecated
+ public void setSrcPath(final String srcPath) {
+ _srcPath = fixPath(srcPath);
+ }
+
+
+ private String fixPath(final String p) {
+ if (p.endsWith("\\"))
+ return p.replace('\\', '/');
+ if (p.endsWith("/"))
+ return p;
+ return p + "/";
+ }
+
+
+ @Override
+ protected void invokeInternal2 (WorkflowContext wfContext, ProgressMonitor monitor, Issues issues) {
+
+ // set up the execution context
+ XpandExecutionContextImpl executionContext = new XpandExecutionContextImpl (getOutput(), null, getGlobalVars (wfContext), null, getNullEvaluationHandler());
+
+ if (_fileEncoding != null)
+ executionContext.setFileEncoding (_fileEncoding);
+
+ final String code = XpandTokens.LT + "EXPAND " + _expand + XpandTokens.RT;
+
+ final Map<String, Object> variables = new HashMap<String, Object> ();
+ for (String name: wfContext.getSlotNames())
+ variables.put (name, wfContext.get (name));
+
+ XpandBackendFacade.executeStatement (code, _fileEncoding, metaModels, variables, _outlets, _advice);
+ }
+
+ public void addOutlet (Outlet outlet) {
+ _outlets.add(outlet);
+ }
+
+ public void setOutput (Output output) {
+ _output = output;
+ }
+
+ private Output getOutput () {
+ if (_output == null) {
+ // lazy initialization
+ OutputImpl out = new OutputImpl();
+ out.setAutomaticHyphens (_automaticHyphens);
+ _output = out;
+ }
+
+ return _output;
+ }
+
+
+ private List<Outlet> getInitializedOutlets() {
+ if (_initializedOutlets.isEmpty()) {
+ final List<Outlet> result = new ArrayList<Outlet> (_outlets);
+ if (result.isEmpty()) {
+ if (_genPath != null) { // backward compatibility
+ result.add (new Outlet (false, _fileEncoding, null, true, _genPath));
+ result.add (new Outlet (true, _fileEncoding, "APPEND", true, _genPath));
+ }
+
+ if (_srcPath != null)
+ result.add (new Outlet (false, _fileEncoding, "ONCE", false, _srcPath));
+ }
+
+ for (Outlet o: result) {
+ if (o.postprocessors.isEmpty())
+ for (PostProcessor pp: _postprocessors)
+ o.addPostprocessor (pp);
+
+ if (o.hasDefaultEncoding() && _fileEncoding!=null)
+ o.setFileEncoding(_fileEncoding);
+ }
+ }
+
+ return _initializedOutlets;
+ }
+
+
+ private ExpandStatement getStatement() {
+ Template tpl = XpandParseFacade.file (new StringReader(XpandTokens.LT + "DEFINE test FOR test" + XpandTokens.RT + XpandTokens.LT + "EXPAND " + _expand + XpandTokens.RT + XpandTokens.LT + "ENDDEFINE" + XpandTokens.RT), null);
+ ExpandStatement es = null;
+ try {
+ es = (ExpandStatement) ((Definition) tpl.getDefinitions()[0]).getBody()[1];
+ } catch (final Exception e) {
+ log.error(e);
+ }
+ return es;
+ }
+
+ @Override
+ public void checkConfiguration(final Issues issues) {
+ super.checkConfiguration(issues);
+ if (_genPath == null && getInitializedOutlets().isEmpty())
+ issues.addError(this, "You need to configure at least one outlet!");
+
+ if ((_genPath != null || _srcPath != null) && !_outlets.isEmpty())
+ issues.addWarning(this, "'genPath' is ignored since you have specified outlets!");
+
+ int defaultOutlets = 0;
+ for (final Iterator<Outlet> iter = getInitializedOutlets().iterator(); iter.hasNext();) {
+ final Outlet o = iter.next();
+ if (o.getName() == null)
+ defaultOutlets++;
+ }
+
+ if (defaultOutlets > 1)
+ issues.addError(this, "Only one outlet can be the default outlet. Please specifiy a name for the other outlets!");
+ else if (defaultOutlets == 0)
+ issues.addWarning(this, "No default outlet configured!");
+
+ if (_expand == null)
+ issues.addError(this, "property 'expand' not configured!");
+ else {
+ try {
+ final ExpandStatement es = getStatement();
+ if (es == null) {
+ issues.addError(this, "property 'expand' has wrong syntax!");
+ }
+ } catch (ParseException e) {
+ issues.addError(this, "property 'expand' has wrong syntax : "+e.getMessage());
+ }
+ }
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldDefinitionConverter.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldDefinitionConverter.java
new file mode 100644
index 0000000..1710e40
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldDefinitionConverter.java
@@ -0,0 +1,405 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xpand.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.internal.xpand2.ast.Advice;
+import org.eclipse.internal.xpand2.ast.Definition;
+import org.eclipse.internal.xpand2.ast.ErrorStatement;
+import org.eclipse.internal.xpand2.ast.ExpandStatement;
+import org.eclipse.internal.xpand2.ast.ExpressionStatement;
+import org.eclipse.internal.xpand2.ast.FileStatement;
+import org.eclipse.internal.xpand2.ast.ForEachStatement;
+import org.eclipse.internal.xpand2.ast.IfStatement;
+import org.eclipse.internal.xpand2.ast.LetStatement;
+import org.eclipse.internal.xpand2.ast.ProtectStatement;
+import org.eclipse.internal.xpand2.ast.Statement;
+import org.eclipse.internal.xpand2.ast.TextStatement;
+import org.eclipse.internal.xpand2.model.XpandDefinition;
+import org.eclipse.internal.xpand2.type.IteratorType;
+import org.eclipse.internal.xtend.expression.ast.DeclaredParameter;
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.expression.ast.SyntaxElement;
+import org.eclipse.xpand2.XpandExecutionContext;
+import org.eclipse.xpand2.output.Outlet;
+import org.eclipse.xtend.backend.aop.AroundAdvice;
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.common.SourcePos;
+import org.eclipse.xtend.backend.common.SyntaxConstants;
+import org.eclipse.xtend.backend.expr.ConcatExpression;
+import org.eclipse.xtend.backend.expr.HidingLocalVarDefExpression;
+import org.eclipse.xtend.backend.expr.IfExpression;
+import org.eclipse.xtend.backend.expr.InitClosureExpression;
+import org.eclipse.xtend.backend.expr.InvocationOnObjectExpression;
+import org.eclipse.xtend.backend.expr.LiteralExpression;
+import org.eclipse.xtend.backend.expr.LocalVarEvalExpression;
+import org.eclipse.xtend.backend.expr.NewLocalVarDefExpression;
+import org.eclipse.xtend.backend.expr.SequenceExpression;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.backend.functions.SourceDefinedFunction;
+import org.eclipse.xtend.backend.syslib.FileIoOperations;
+import org.eclipse.xtend.backend.syslib.SysLibNames;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+import org.eclipse.xtend.expression.AnalysationIssue;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.middleend.xpand.plugin.XpandDefinitionName;
+import org.eclipse.xtend.middleend.xtend.internal.OldExpressionConverter;
+import org.eclipse.xtend.middleend.xtend.internal.OldTypeAnalyzer;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XpandIsDeleteLine;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendIterator;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendLibNames;
+import org.eclipse.xtend.typesystem.ParameterizedType;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single template
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldDefinitionConverter {
+ private XpandExecutionContext _ctx;
+ private final TypeToBackendType _typeConverter;
+
+ private String _definitionName;
+
+ private int _localVarCounter = 0;
+
+
+ public OldDefinitionConverter (XpandExecutionContext ctx, TypeToBackendType typeConverter) {
+ _ctx = ctx;
+ _typeConverter = typeConverter;
+ }
+
+
+ public AroundAdvice create (Advice a, Set<XpandDefinitionName> referencedDefinitions, FunctionDefContext fdc) {
+ final XpandExecutionContext oldCtx = _ctx;
+
+ try {
+ final OldExpressionConverter exprConv = new OldExpressionConverter (_ctx, _typeConverter, "<around>");
+
+ _ctx = (XpandExecutionContext) _ctx.cloneWithoutVariables();
+
+ final List<String> localVarNames = exprConv.getAdviceLocalVarNames();
+ final List<Type> localVarTypes = exprConv.getAdviceLocalVarTypes (oldCtx);
+ for (int i=0; i<localVarNames.size(); i++)
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (localVarNames.get(i), localVarTypes.get(i)));
+
+ final ExpressionBase body = convertStatementSequence (a.getBody(), a, referencedDefinitions);
+ return exprConv.convertAdvice (body, a.getName(), Arrays.asList (a.getParams()), a.isWildcardParams(), fdc);
+ }
+ finally {
+ _ctx = oldCtx;
+ }
+ }
+
+ /**
+ * converts an extension to a function, taking care of mutual registration with its fdc
+ */
+ public NamedFunction create (XpandDefinition def, FunctionDefContextInternal fdc, Set<XpandDefinitionName> referencedDefinitions) {
+ final NamedFunction result = createUnregistered (def, fdc, referencedDefinitions);
+ fdc.register (result, true);
+ return result;
+ }
+
+ private NamedFunction createUnregistered (XpandDefinition def, FunctionDefContextInternal fdc, Set<XpandDefinitionName> referencedDefinitions) {
+ if (def instanceof Definition) {
+ final String canonicalName = new XpandDefinitionName (def).getCanonicalDefinitionName();
+ return new NamedFunction (canonicalName, createNormalDefinition ((Definition) def, fdc, referencedDefinitions));
+ }
+
+ throw new IllegalArgumentException ("unsupported definition type " + def.getClass().getName());
+ }
+
+
+ private Function createNormalDefinition (Definition def, FunctionDefContext fdc, Set<XpandDefinitionName> referencedDefinitions) {
+ final XpandExecutionContext oldCtx = _ctx;
+
+ try {
+ final List<String> paramNames = new ArrayList<String>();
+ final List<BackendType> paramTypes = new ArrayList<BackendType>();
+
+ final Type ft = _ctx.getTypeForName (def.getTargetType());
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (ExecutionContext.IMPLICIT_VARIABLE, ft));
+ paramNames.add (SyntaxConstants.THIS);
+ paramTypes.add (_typeConverter.convertToBackendType(ft));
+
+ for (DeclaredParameter dp: def.getParams()) {
+ final Type pt = _ctx.getTypeForName (dp.getType().getValue());
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (dp.getName().getValue(), pt));
+ paramNames.add (dp.getName().getValue());
+ paramTypes.add (_typeConverter.convertToBackendType (pt));
+ }
+
+ return new SourceDefinedFunction (def.getName(), paramNames, paramTypes, fdc, convertStatementSequence (def.getBody(), def, referencedDefinitions), false, null);
+ }
+ finally {
+ _ctx = oldCtx;
+ }
+ }
+
+ public ExpressionBase convertStatementSequence (Statement[] statements, SyntaxElement oldPos, Set<XpandDefinitionName> referencedDefinitions) {
+ final List<ExpressionBase> parts = new ArrayList<ExpressionBase> ();
+
+ for (Statement stmt: statements)
+ parts.add (convertStatement (stmt, referencedDefinitions));
+
+ if (parts.size() == 1)
+ return parts.get (0);
+ else
+ return new ConcatExpression (parts, getSourcePos(oldPos));
+ }
+
+
+ public ExpressionBase convertStatement (Statement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ if (stmt instanceof ErrorStatement)
+ return convertErrorStatement((ErrorStatement) stmt);
+ if (stmt instanceof ExpandStatement)
+ return convertExpandStatement ((ExpandStatement) stmt, referencedDefinitions);
+ if (stmt instanceof ExpressionStatement)
+ return convertExpressionStatement ((ExpressionStatement) stmt);
+ if (stmt instanceof FileStatement)
+ return convertFileStatement ((FileStatement) stmt, referencedDefinitions);
+ if (stmt instanceof ForEachStatement)
+ return convertForEachStatement ((ForEachStatement) stmt, referencedDefinitions);
+ if (stmt instanceof IfStatement)
+ return convertIfStatement ((IfStatement) stmt, referencedDefinitions);
+ if (stmt instanceof LetStatement)
+ return convertLetStatement ((LetStatement) stmt, referencedDefinitions);
+ if (stmt instanceof ProtectStatement)
+ return convertProtectStatement ((ProtectStatement) stmt, referencedDefinitions);
+ if (stmt instanceof TextStatement)
+ return convertTextStatement ((TextStatement) stmt);
+
+ throw new IllegalArgumentException ("unknown statement type " + stmt.getClass().getName());
+ }
+
+ private ExpressionBase convertErrorStatement (ErrorStatement stmt) {
+ final ExpressionBase msg = convertExpression (stmt.getMessage());
+
+ return new ExpressionBase (OldExpressionConverter.getSourcePos (stmt, stmt.getFileName())) {
+ @Override
+ protected Object evaluateInternal (org.eclipse.xtend.backend.common.ExecutionContext ctx) {
+ System.err.println (msg.evaluate (ctx)); // TODO throw an exception instead?
+ return null;
+ }
+ };
+ }
+
+ private ExpressionBase convertExpandStatement (ExpandStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ if (stmt.isForeach()) {
+ final ExpressionBase separator = (stmt.getSeparator() != null) ? convertExpression (stmt.getSeparator()) : null;
+ final ExpressionBase target = convertExpression (stmt.getTarget());
+
+ final String closureParamName = createUniqueLocalVarName();
+ final List<ExpressionBase> params = new ArrayList<ExpressionBase> ();
+ params.add (new LocalVarEvalExpression (closureParamName, getSourcePos(stmt)));
+ for (Expression e: stmt.getParameters())
+ params.add (convertExpression (e));
+
+ final Type rawTargetType = new OldTypeAnalyzer().analyze(_ctx, stmt.getTarget());
+ final Type targetType = (rawTargetType instanceof ParameterizedType) ? ((ParameterizedType) rawTargetType).getInnerType() : _ctx.getObjectType();
+
+ final Type[] argTypes = new Type[stmt.getParametersAsList().size()];
+ for (int i=0; i<stmt.getParametersAsList().size(); i++)
+ argTypes[i] = stmt.getParametersAsList().get(i).analyze (_ctx, new HashSet<AnalysationIssue> ());
+
+ final XpandDefinitionName called = new XpandDefinitionName (stmt.getDefinition().getValue(), targetType, argTypes, _ctx);
+ referencedDefinitions.add (called);
+
+
+ final ExpressionBase invocationExpression = new InvocationOnObjectExpression (called.getCanonicalDefinitionName(), params, false, getSourcePos(stmt));
+ final ExpressionBase loopBody = new InitClosureExpression (Arrays.asList(closureParamName), Arrays.asList(ObjectType.INSTANCE), invocationExpression, getSourcePos(stmt));
+
+ if (separator == null)
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, loopBody), true, getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, loopBody, separator), true, getSourcePos (stmt));
+ }
+ else {
+ final List<ExpressionBase> params = new ArrayList<ExpressionBase>();
+ if (stmt.getTarget() != null)
+ params.add (convertExpression(stmt.getTarget()));
+ else
+ params.add (new LocalVarEvalExpression (SyntaxConstants.THIS, getSourcePos(stmt)));
+
+ for (Expression e: stmt.getParameters())
+ params.add (convertExpression (e));
+
+ final XpandDefinitionName called = new XpandDefinitionName (stmt.getDefinition().getValue(), stmt.getTarget(), stmt.getParametersAsList(), _ctx);
+ referencedDefinitions.add (called);
+ return new InvocationOnObjectExpression (called.getCanonicalDefinitionName(), params, true, getSourcePos(stmt));
+ }
+ }
+
+ private String createUniqueLocalVarName () {
+ return "$localVar_" + _localVarCounter++;
+ }
+
+
+ private ExpressionBase convertExpressionStatement (ExpressionStatement stmt) {
+ return convertExpression (stmt.getExpression());
+ }
+
+ private ExpressionBase convertForEachStatement (ForEachStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ final XpandExecutionContext oldContext = _ctx;
+
+ final ExpressionBase separator = (stmt.getSeparator() != null) ? convertExpression (stmt.getSeparator()) : null;
+ final ExpressionBase target = convertExpression (stmt.getTarget());
+
+ final Type collType = new OldTypeAnalyzer().analyze (oldContext, stmt.getTarget());
+ final Type eleType = (collType instanceof ParameterizedType) ? ((ParameterizedType) collType).getInnerType() : _ctx.getObjectType();
+
+ final String varName = stmt.getVariable().getValue();
+
+ ExpressionBase body;
+
+ if (stmt.getIteratorName() == null) {
+ // forEach without an iterator
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (varName, eleType));
+ try {
+ body = convertStatementSequence (stmt.getBody(), stmt, referencedDefinitions);
+ }
+ finally {
+ _ctx = oldContext;
+ }
+ final ExpressionBase closureCreation = new InitClosureExpression (Arrays.asList (varName), Arrays.asList (_typeConverter.convertToBackendType(eleType)), body, getSourcePos (stmt));
+
+ if (separator == null)
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, closureCreation), true, getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, closureCreation, separator), true, getSourcePos (stmt));
+ }
+ else {
+ // forEach with an iterator
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (varName, eleType));
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (stmt.getIteratorName().getValue(), _ctx.getTypeForName (IteratorType.TYPE_NAME)));
+ try {
+ body = convertStatementSequence (stmt.getBody(), stmt, referencedDefinitions);
+ }
+ finally {
+ _ctx = oldContext;
+ }
+
+ final List<String> paramNames = Arrays.asList (varName, stmt.getIteratorName().getValue());
+ final List<BackendType> paramTypes = Arrays.asList (_typeConverter.convertToBackendType (eleType), _typeConverter.convertToBackendType (XtendIterator.class));
+
+ final ExpressionBase closureCreation = new InitClosureExpression (paramNames, paramTypes, body, getSourcePos (stmt));
+
+ if (separator == null)
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITH_ITERATOR, Arrays.asList(target, closureCreation), true, getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (XtendLibNames.FOREACH_WITH_ITERATOR, Arrays.asList(target, closureCreation, separator), true, getSourcePos (stmt));
+ }
+ }
+
+ private ExpressionBase convertIfStatement (IfStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ if (stmt.getCondition() != null) {
+ final ExpressionBase condExpr = convertExpression (stmt.getCondition());
+ final ExpressionBase ifExpr = convertStatement (stmt.getUpperIf(), referencedDefinitions);
+ final ExpressionBase elseExpr = stmt.getElseIf() != null ? convertStatement (stmt.getElseIf(), referencedDefinitions) : new LiteralExpression (null, getSourcePos (stmt));
+
+ return new IfExpression (condExpr, ifExpr, elseExpr, getSourcePos (stmt));
+ }
+ else {
+ // the else part is an IfStatement with null condition
+ return convertStatementSequence (stmt.getBody(), stmt, referencedDefinitions);
+ }
+ }
+
+
+ private ExpressionBase convertLetStatement (LetStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ final String varName = stmt.getVarName().getValue();
+ final Type type = new OldTypeAnalyzer().analyze (_ctx, stmt.getVarValue());
+
+ final XpandExecutionContext oldContext = _ctx;
+ _ctx = (XpandExecutionContext) _ctx.cloneWithVariable (new Variable (varName, type));
+
+ try {
+ final ExpressionBase def = convertExpression (stmt.getVarValue());
+ final ExpressionBase body = convertStatementSequence (stmt.getBody(), stmt, referencedDefinitions);
+
+ if (oldContext.getVisibleVariables().containsKey (varName))
+ return new HidingLocalVarDefExpression (varName, def, body, getSourcePos (stmt));
+ else
+ return new NewLocalVarDefExpression (varName, def, body, getSourcePos (stmt));
+ }
+ finally {
+ _ctx = oldContext;
+ }
+ }
+
+ private ExpressionBase convertFileStatement (FileStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ final ExpressionBase body = convertStatementSequence (stmt.getBody(), stmt, referencedDefinitions);
+ final ExpressionBase filename = convertExpression (stmt.getTargetFileName());
+
+ final Outlet outlet = _ctx.getOutput().getOutlet (stmt.getOutletName());
+ if (outlet == null) {
+ if (stmt.getOutletName() == null)
+ throw new IllegalStateException ("no default outlet was registered");
+ else
+ throw new IllegalStateException ("no outlet for name '" + stmt.getOutletName() + "' was registered");
+ }
+
+ final ExpressionBase outletName = new LiteralExpression ((stmt.getOutletName() != null) ? stmt.getOutletName() : FileIoOperations.DEFAULT_OUTLET_NAME, getSourcePos(stmt));
+ final ExpressionBase append = new LiteralExpression (outlet.isAppend(), getSourcePos(stmt));
+
+ final List<ExpressionBase> emptyParamList = Collections.emptyList();
+ final ExpressionBase initIsDeleteLineExpression = new InvocationOnObjectExpression (XtendLibNames.DELETE_LINE_INIT, emptyParamList, false, getSourcePos (stmt));
+
+ final ExpressionBase postprocessIsDeleteLineExpression = new InvocationOnObjectExpression (XtendLibNames.DELETE_LINE_POSTPROCESS, Arrays.asList(body), false, getSourcePos (stmt));
+ final ExpressionBase writeToFileExpression = new InvocationOnObjectExpression (SysLibNames.WRITE_TO_FILE, Arrays.asList(outletName, filename, append, postprocessIsDeleteLineExpression), false, getSourcePos (stmt));
+
+ return new SequenceExpression (Arrays.asList (initIsDeleteLineExpression, writeToFileExpression), getSourcePos (stmt));
+ }
+
+ private ExpressionBase convertProtectStatement (ProtectStatement stmt, Set<XpandDefinitionName> referencedDefinitions) {
+ throw new UnsupportedOperationException(); //TODO implement ProtectStatement
+ }
+
+ private ExpressionBase convertTextStatement (TextStatement stmt) {
+ if (stmt.isDeleteLine()) {
+ final List<ExpressionBase> emptyParamList = Collections.emptyList();
+ final ExpressionBase registerExpression = new InvocationOnObjectExpression (XtendLibNames.DELETE_LINE_REGISTER, emptyParamList, false, getSourcePos(stmt));
+
+ final ExpressionBase markerExpression = new LiteralExpression (XpandIsDeleteLine.MARKER_FOR_IS_DELETE_LINE, getSourcePos(stmt));
+ final ExpressionBase contentExpression = new LiteralExpression (stmt.getValue(), getSourcePos (stmt));
+ final ExpressionBase concatExpression = new ConcatExpression (Arrays.asList(markerExpression, contentExpression), getSourcePos (stmt));
+
+ return new SequenceExpression (Arrays.asList(registerExpression, concatExpression), getSourcePos (stmt));
+ }
+ else
+ return new LiteralExpression (stmt.getValue(), getSourcePos(stmt));
+ }
+
+
+ private SourcePos getSourcePos (SyntaxElement stmt) {
+ return OldExpressionConverter.getSourcePos(stmt, _definitionName);
+ }
+
+ private ExpressionBase convertExpression (Expression expr) {
+ final OldExpressionConverter exprConverter = new OldExpressionConverter (_ctx, _typeConverter, _definitionName);
+ return exprConverter.convert (expr);
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldXpandRegistryFactory.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldXpandRegistryFactory.java
new file mode 100644
index 0000000..d3fe236
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/internal/OldXpandRegistryFactory.java
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xpand.internal;
+
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd;
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEndFactory;
+import org.eclipse.xtend.middleend.xpand.OldXpandRegistry;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldXpandRegistryFactory implements LanguageSpecificMiddleEndFactory {
+
+ public LanguageSpecificMiddleEnd create (Object specificData) {
+ return new OldXpandRegistry (specificData);
+ }
+
+ public String getName () {
+ return "Xpand";
+ }
+
+ public int getPriority () {
+ return 0;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/plugin/XpandDefinitionName.java b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/plugin/XpandDefinitionName.java
new file mode 100644
index 0000000..c449bd8
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xpand/src/org/eclipse/xtend/middleend/xpand/plugin/XpandDefinitionName.java
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+*/
+package org.eclipse.xtend.middleend.xpand.plugin;
+
+import java.util.List;
+
+import org.eclipse.internal.xpand2.model.XpandDefinition;
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.expression.ast.FeatureCall;
+import org.eclipse.internal.xtend.expression.ast.Identifier;
+import org.eclipse.xpand2.XpandExecutionContext;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.middleend.xtend.internal.OldTypeAnalyzer;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * This class serves as a representation of an Xpand definition name. It takes
+ * care of the intricacies and ambiguities of Xpand template referencing
+ * (fully qualified, relative, ...) by providing a normalized, canonical
+ * name.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XpandDefinitionName {
+ private final String _canonicalDefinitionName;
+ private final String _canonicalTemplateFileName;
+
+
+ public XpandDefinitionName (XpandDefinition def) {
+ _canonicalTemplateFileName = def.getFileName();
+ _canonicalDefinitionName = _canonicalTemplateFileName.substring (0, _canonicalTemplateFileName.length() - 4) + "/" + def.getName();
+ }
+
+ /**
+ * @param rawDefName the name as it appears in Xpand code
+ * @param targetType may not be null
+ * @param argTypes
+ * @param ctx the XpandExecutionContext that is valid at the place from which the definition is called. This
+ * is necessary to resolve relative references.
+ */
+ public XpandDefinitionName (String rawDefName, Type targetType, Type[] argTypes, XpandExecutionContext ctx) {
+ this (ctx.findDefinition(rawDefName, targetType, argTypes));
+ }
+
+ public XpandDefinitionName (String rawDefName, Expression target, List<Expression> args, XpandExecutionContext ctx) {
+ this (rawDefName, typeForTargetExpression (target, ctx), typesForArgExpressions(args, ctx), ctx);
+ }
+
+ private static Type typeForTargetExpression (Expression target, XpandExecutionContext ctx) {
+ if (target == null)
+ target = new FeatureCall (new Identifier (ExecutionContext.IMPLICIT_VARIABLE), null); // no target is treated as a 'this' reference
+
+ return new OldTypeAnalyzer().analyze (ctx, target);
+ }
+
+ private static Type[] typesForArgExpressions (List<Expression> args, XpandExecutionContext ctx) {
+ final Type[] result = new Type[args.size()];
+ for (int i=0; i<args.size(); i++)
+ result[i] = new OldTypeAnalyzer().analyze (ctx, args.get(i));
+ return result;
+ }
+
+
+ public String getCanonicalDefinitionName () {
+ return _canonicalDefinitionName;
+ }
+
+ public String getCanonicalTemplateFileName () {
+ return _canonicalTemplateFileName;
+ }
+
+ @Override
+ public String toString () {
+ return _canonicalDefinitionName;
+ }
+
+ @Override
+ public int hashCode () {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_canonicalDefinitionName == null) ? 0 : _canonicalDefinitionName.hashCode());
+ result = prime * result + ((_canonicalTemplateFileName == null) ? 0 : _canonicalTemplateFileName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals (Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final XpandDefinitionName other = (XpandDefinitionName) obj;
+ if (_canonicalDefinitionName == null) {
+ if (other._canonicalDefinitionName != null)
+ return false;
+ } else if (!_canonicalDefinitionName.equals(other._canonicalDefinitionName))
+ return false;
+ if (_canonicalTemplateFileName == null) {
+ if (other._canonicalTemplateFileName != null)
+ return false;
+ } else if (!_canonicalTemplateFileName.equals(other._canonicalTemplateFileName))
+ return false;
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/.classpath b/plugins/org.eclipse.xtend.middleend.xtend/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/.project b/plugins/org.eclipse.xtend.middleend.xtend/.project
new file mode 100644
index 0000000..7c856d5
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.middleend.xtend</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtend.middleend.xtend/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..874a39e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Xtend Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.middleend.xtend;singleton:=true
+Bundle-Version: 1.0.0
+Export-Package: org.eclipse.xtend.middleend.xtend,
+ org.eclipse.xtend.middleend.xtend.internal;x-friends:="org.eclipse.xtend.middleend.xpand",
+ org.eclipse.xtend.middleend.xtend.internal.xtend;x-internal:=true,
+ org.eclipse.xtend.middleend.xtend.internal.xtendlib;x-friends:="org.eclipse.xtend.middleend.xpand",
+ org.eclipse.xtend.middleend.xtend.plugin
+Require-Bundle: org.eclipse.xtend.backend,
+ org.eclipse.xtend,
+ org.apache.commons.logging,
+ org.eclipse.emf.mwe.core,
+ org.eclipse.emf.ecore,
+ org.eclipse.xtend.typesystem.emf,
+ org.eclipse.xpand
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/build.properties b/plugins/org.eclipse.xtend.middleend.xtend/build.properties
new file mode 100644
index 0000000..e9863e2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/plugin.xml b/plugins/org.eclipse.xtend.middleend.xtend/plugin.xml
new file mode 100644
index 0000000..e3aaec5
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension
+ point="org.eclipse.xtend.backend.MiddleEnd">
+ <element_1
+ class="org.eclipse.xtend.middleend.xtend.plugin.OldXtendRegistryFactory">
+ </element_1>
+ </extension>
+
+</plugin>
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckBackendFacade.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckBackendFacade.java
new file mode 100644
index 0000000..bb6bc9d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckBackendFacade.java
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend;
+
+import java.util.Collection;
+
+import org.eclipse.emf.mwe.core.issues.Issues;
+import org.eclipse.xtend.middleend.xtend.internal.xtend.CheckConverter;
+import org.eclipse.xtend.typesystem.MetaModel;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class CheckBackendFacade {
+
+ public static void checkAll (String xtendFileName, Collection<MetaModel> mms, Issues issues, Collection<?> allObjects) {
+ checkAll (xtendFileName, null, mms, issues, allObjects);
+ }
+
+ public static void checkAll (String xtendFileName, String fileEncoding, Collection<MetaModel> mms, Issues issues, Collection<?> allObjects) {
+ XtendBackendFacade.invokeXtendFunction (xtendFileName, fileEncoding, mms, CheckConverter.ALL_CHECKS_FUNCTION_NAME, issues, allObjects);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckComponent.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckComponent.java
new file mode 100644
index 0000000..ea8f68d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/CheckComponent.java
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.mwe.core.WorkflowContext;
+import org.eclipse.emf.mwe.core.WorkflowInterruptedException;
+import org.eclipse.emf.mwe.core.issues.Issues;
+import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
+import org.eclipse.xtend.expression.AbstractExpressionsUsingWorkflowComponent;
+
+
+//TODO test this
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class CheckComponent extends AbstractExpressionsUsingWorkflowComponent {
+
+ private String _expression = null;
+ private List<String> _checkFiles = new ArrayList<String>();
+ private boolean _abortOnError = true;
+ private boolean _warnIfNothingChecked = false;
+ private String _emfAllChildrenSlot;
+ private String _fileEncoding = null;
+
+ public void setAbortOnError (boolean abortOnError) {
+ _abortOnError = abortOnError;
+ }
+
+ public void addCheckFile (String checkFile) {
+ _checkFiles.add(checkFile);
+ }
+
+ public void setExpression (String expression) {
+ _expression = expression;
+ }
+
+ public void setWarnIfNothingChecked (boolean b) {
+ _warnIfNothingChecked = b;
+ }
+
+ public void setEmfAllChildrenSlot (String childExpression) {
+ _emfAllChildrenSlot = childExpression;
+ }
+
+ public void setFileEncoding (String fileEncoding) {
+ _fileEncoding = fileEncoding;
+ }
+
+ @Override
+ public String getLogMessage() {
+ final StringBuilder result = new StringBuilder ();
+ if ( _emfAllChildrenSlot != null )
+ result.append ("slot " + _emfAllChildrenSlot + " ");
+ else
+ result.append ("expression " + _expression + " ");
+
+ result.append ("check file(s): ");
+ for (String f: _checkFiles)
+ result.append (f + " ");
+
+ return result.toString();
+ }
+
+
+ @Override
+ protected void invokeInternal2 (WorkflowContext wfCtx, ProgressMonitor monitor, Issues issues) {
+ final Collection<?> allObjects = getExpressionResult (wfCtx, _expression);
+
+ for (String checkFile : _checkFiles)
+ CheckBackendFacade.checkAll (checkFile, _fileEncoding, metaModels, issues, allObjects);
+
+ if (_abortOnError && issues.hasErrors())
+ throw new WorkflowInterruptedException ("Errors during validation.");
+ }
+
+
+ @Override
+ public void checkConfiguration (Issues issues) {
+ super.checkConfiguration (issues);
+
+ if (_expression == null && _emfAllChildrenSlot != null)
+ _expression = _emfAllChildrenSlot + ".eAllContents.union ( {" + _emfAllChildrenSlot + "} )";
+ else if (_expression != null && _emfAllChildrenSlot == null) {
+ // ok - do nothing, expression already has a reasonable value
+ }
+ else
+ issues.addError(this, "You have to set one of the properties 'expression' and 'emfAllChildrenSlot'!");
+
+ if (_checkFiles.isEmpty())
+ issues.addError (this, "Property 'checkFile' not set!");
+ }
+
+ private Collection<?> getExpressionResult (WorkflowContext wfCtx, String expression2) {
+ final Map<String, Object> localVars = new HashMap<String, Object>();
+ final String[] names = wfCtx.getSlotNames ();
+ for (int i = 0; i < names.length; i++)
+ localVars.put (names[i], wfCtx.get (names[i]));
+
+ final Object result = XtendBackendFacade.evaluateExpression (expression2, metaModels, localVars);
+
+ if (result instanceof Collection)
+ return (Collection<?>) result;
+
+ if (result == null)
+ return Collections.EMPTY_SET;
+
+ return Collections.singleton (result);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/OldXtendRegistry.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/OldXtendRegistry.java
new file mode 100644
index 0000000..89d8d98
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/OldXtendRegistry.java
@@ -0,0 +1,231 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipose.xtend.middleend.MiddleEnd;
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd;
+import org.eclipse.internal.xtend.xtend.XtendFile;
+import org.eclipse.internal.xtend.xtend.ast.Around;
+import org.eclipse.internal.xtend.xtend.ast.Extension;
+import org.eclipse.internal.xtend.xtend.ast.ExtensionFile;
+import org.eclipse.internal.xtend.xtend.ast.ImportStatement;
+import org.eclipse.xtend.backend.aop.AroundAdvice;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.FunctionDefContextFactory;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.backend.util.Cache;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.middleend.xtend.internal.OldHelper;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.middleend.xtend.internal.xtend.CheckConverter;
+import org.eclipse.xtend.middleend.xtend.internal.xtend.OldExtensionConverter;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendLibContributor;
+
+
+/**
+ * This class manages the interdependent graph of parsed and converted files, allowing access to them by "compilation unit".
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldXtendRegistry implements LanguageSpecificMiddleEnd {
+ private final ExecutionContext _ctx;
+
+ @SuppressWarnings("unused")
+ private MiddleEnd _middleEnd;
+
+ private BackendTypesystem _ts;
+
+ private final Cache<String, FunctionDefContextInternal> _functionDefContexts = new Cache<String, FunctionDefContextInternal> () {
+ @Override
+ protected FunctionDefContextInternal create (String compilationUnit) {
+ return new FunctionDefContextFactory (_ts).create();
+ }
+ };
+
+
+ /**
+ * all functions actually defined in a given compilation unit
+ */
+ private final Map<String, List<NamedFunction>> _definedFunctionsByResource = new HashMap <String, List<NamedFunction>>();
+
+ /**
+ * all functions exported by a compilation unit, i.e. those functions visible to others that import it
+ */
+ private final Map<String, List<NamedFunction>> _exportedFunctionsByResource = new HashMap <String, List<NamedFunction>>();
+
+ /**
+ * all locally defined functions that are exported by a compilation unit. This is an artifact to cleanly handle
+ * reexports.
+ */
+ private final Map<String, List<NamedFunction>> _locallyExportedFunctionsByResource = new HashMap <String, List<NamedFunction>>();
+
+ private final Map<String, List<AroundAdvice>> _advice = new HashMap<String, List<AroundAdvice>> ();
+
+
+ /**
+ * the specificData field contains an ExecutionContext initialized with the MetaModels and the file encoding
+ */
+ public OldXtendRegistry (Object specificData) {
+ if (specificData == null)
+ throw new IllegalArgumentException (getName() + " middle end is not initialized - will not contribute");
+
+ _ctx = (ExecutionContext) specificData;
+ }
+
+ public void setMiddleEnd (MiddleEnd middleEnd) {
+ _middleEnd = middleEnd;
+ _ts = middleEnd.getTypesystem();
+ }
+
+
+ private FunctionDefContextInternal getFunctionDefContext (String xtendName) {
+ return _functionDefContexts.get (OldHelper.normalizeXtendResourceName (xtendName));
+ }
+
+
+ /**
+ * parses and converts an Xtend file and all other files it depends on.
+ */
+ public void registerExtensionFile (String xtendFile) {
+ xtendFile = OldHelper.normalizeXtendResourceName (xtendFile);
+
+ if (_definedFunctionsByResource.containsKey (xtendFile))
+ return;
+
+ final ExtensionFile extensionFile = (ExtensionFile) _ctx.getResourceManager().loadResource (xtendFile, XtendFile.FILE_EXTENSION);
+ if (extensionFile == null)
+ throw new IllegalArgumentException ("could not find extension '" + xtendFile + "'");
+
+ final ExecutionContext ctx = _ctx.cloneWithResource (extensionFile);
+
+ final TypeToBackendType typeConverter = new TypeToBackendType (_ts, ctx);
+ final OldExtensionConverter extensionFactory = new OldExtensionConverter (ctx, typeConverter);
+
+ for (Extension ext: extensionFile.getExtensions())
+ ext.init (ctx);
+
+ final List<NamedFunction> defined = new ArrayList<NamedFunction>();
+ final List<NamedFunction> exported = new ArrayList<NamedFunction>();
+
+ final FunctionDefContextInternal fdc = getFunctionDefContext (xtendFile);
+
+ // register the XtendLib. Do this first so the extension can override functions
+ for (NamedFunction f: new XtendLibContributor (_ts).getContributedFunctions())
+ fdc.register (f, false);
+
+ fdc.register (new CheckConverter (ctx, typeConverter).createCheckFunction(_ts, fdc, extensionFile), false);
+
+ for (Extension ext: extensionFile.getExtensions()) {
+ final NamedFunction f = extensionFactory.create (ext, fdc);
+
+ defined.add(f);
+
+ if (!ext.isPrivate())
+ exported.add (f);
+ }
+
+ _definedFunctionsByResource.put (xtendFile, defined);
+ _exportedFunctionsByResource.put (xtendFile, exported);
+ _locallyExportedFunctionsByResource.put (xtendFile, new ArrayList<NamedFunction> (exported));
+
+ // make sure all imported resources are registered as well
+ for (String imported: extensionFile.getImportedExtensions())
+ registerExtensionFile (imported);
+
+ // make all imported extensions visible for the scope of this compilation unit
+ for (String importedResource: extensionFile.getImportedExtensions()) {
+ for (NamedFunction f: _locallyExportedFunctionsByResource.get (OldHelper.normalizeXtendResourceName (importedResource)))
+ fdc.register (f, false);
+ }
+
+ final Set<String> visitedForReexport = new HashSet<String>();
+ visitedForReexport.add (xtendFile);
+ final List<NamedFunction> reexported = new ArrayList<NamedFunction>();
+ getReexported (xtendFile, reexported, visitedForReexport, new HashSet<String>());
+
+ for (NamedFunction f: reexported) {
+ exported.add (f);
+ fdc.register (f, true);
+ }
+
+ final List<AroundAdvice> advice = new ArrayList<AroundAdvice> ();
+ _advice.put (xtendFile, advice);
+ for (Around a: extensionFile.getArounds())
+ advice.add (extensionFactory.create (a, fdc));
+ }
+
+ private void getReexported (String xtendFile, Collection<NamedFunction> result, Set<String> harvestedCompilationUnits, Set<String> processedCompilationUnits) {
+ xtendFile = OldHelper.normalizeXtendResourceName (xtendFile);
+
+ if (processedCompilationUnits.contains (xtendFile))
+ return;
+ processedCompilationUnits.add (xtendFile);
+
+ if (! harvestedCompilationUnits.contains (xtendFile)) {
+ for (NamedFunction f: _locallyExportedFunctionsByResource.get(xtendFile))
+ result.add (f);
+
+ harvestedCompilationUnits.add (xtendFile);
+ }
+
+ final ExtensionFile file = (ExtensionFile) _ctx.getResourceManager().loadResource (xtendFile, XtendFile.FILE_EXTENSION);
+ for (ImportStatement imp: file.getExtImports()) {
+ if (imp.isExported())
+ getReexported (imp.getImportedId().getValue(), result, harvestedCompilationUnits, processedCompilationUnits);
+ }
+ }
+
+ public boolean canHandle (String resourceName) {
+ resourceName = OldHelper.normalizeXtendResourceName (resourceName);
+
+ if (_definedFunctionsByResource.containsKey (resourceName))
+ return true;
+
+ try {
+ final ExtensionFile extensionFile = (ExtensionFile) _ctx.getResourceManager().loadResource (resourceName, XtendFile.FILE_EXTENSION);
+ return extensionFile != null;
+ }
+ catch (Exception exc) {
+ return false;
+ }
+ }
+
+ public FunctionDefContext getContributedFunctions (String xtendFile) {
+ registerExtensionFile (xtendFile);
+ return getFunctionDefContext(xtendFile);
+ }
+
+ public List<AroundAdvice> getContributedAdvice (String resourceName) {
+ registerExtensionFile (resourceName);
+ return _advice.get (OldHelper.normalizeXtendResourceName (resourceName));
+ }
+
+ public String getName () {
+ return "Xtend";
+ }
+}
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendBackendFacade.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendBackendFacade.java
new file mode 100644
index 0000000..0ab0e7a
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendBackendFacade.java
@@ -0,0 +1,176 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipose.xtend.middleend.MiddleEnd;
+import org.eclipose.xtend.middleend.MiddleEndFactory;
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.xtend.parser.ParseFacade;
+import org.eclipse.xtend.backend.BackendFacade;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.FunctionDefContextFactory;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.expression.ExecutionContextImpl;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.middleend.xtend.internal.OldExpressionConverter;
+import org.eclipse.xtend.middleend.xtend.internal.OldHelper;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendGlobalVarOperations;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendLibContributor;
+import org.eclipse.xtend.middleend.xtend.plugin.OldXtendRegistryFactory;
+import org.eclipse.xtend.typesystem.MetaModel;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XtendBackendFacade {
+ private final String _xtendFile;
+ private final MiddleEnd _middleEnd;
+ private final Collection<MetaModel> _mms;
+
+ /**
+ * This method invokes a "stand alone" expression that knows nothing about any functions defined in files. It is useful for
+ * *very* simple use cases, and for testing purposes. <br>
+ *
+ * Both mms and localVars may be null.
+ */
+ public static Object evaluateExpression (String expression, Collection<MetaModel> mms, Map<String, Object> localVars) {
+ return evaluateExpression (expression, mms, localVars, null);
+ }
+
+ public static Object evaluateExpression (String expression, Collection<MetaModel> mms, Map<String, Object> localVars, Map<String, Object> globalVars) {
+ return evaluateExpression (expression, null, null, mms, localVars, globalVars, null);
+ }
+
+ /**
+ * This method invokes an expression that may call functions from an Xtend file.<br>
+ *
+ * The fileEncoding may be null, in which case the platform's default encoding is used. Both mms and localVars may be null.
+ */
+ public static Object evaluateExpression (String expression, String initialXtendFileName, String fileEncoding, Collection<MetaModel> mms, Map<String, Object> localVars) {
+ return evaluateExpression (expression, initialXtendFileName, fileEncoding, mms, localVars, null, null);
+ }
+
+ public static Object evaluateExpression (String expression, String initialXtendFileName, String fileEncoding, Collection<MetaModel> mms, Map<String, Object> localVars, Map<String, Object> globalVars, List<String> adviceResources) {
+ return createForFile (initialXtendFileName, fileEncoding, mms).evaluateExpression (expression, localVars, globalVars, adviceResources);
+ }
+
+ public Object evaluateExpression (String expression, Map<String, Object> localVars) {
+ return evaluateExpression (expression, localVars, null, null);
+ }
+
+ public Object evaluateExpression (String expression, Map<String, Object> localVars, Map<String, Object> globalVars, List<String> adviceResources) {
+ if (localVars == null)
+ localVars = new HashMap<String, Object> ();
+ if (globalVars == null)
+ globalVars = new HashMap<String, Object> ();
+ if (adviceResources == null)
+ adviceResources = new ArrayList<String> ();
+
+ for (String a: adviceResources)
+ _middleEnd.applyAdvice (a);
+
+ final Expression oldAst = ParseFacade.expression (expression);
+
+ ExecutionContextImpl ctx = new ExecutionContextImpl ();
+ for (MetaModel mm: _mms)
+ ctx.registerMetaModel (mm);
+ for (String varName: localVars.keySet())
+ ctx = (ExecutionContextImpl) ctx.cloneWithVariable (new Variable (varName, ctx.getType (localVars.get (varName))));
+
+ final TypeToBackendType typeConverter = new TypeToBackendType (_middleEnd.getTypesystem(), ctx);
+ final ExpressionBase newAst = new OldExpressionConverter (ctx, typeConverter, "<no file>").convert (oldAst);
+
+ final FunctionDefContext fdc = createFdc ();
+ _middleEnd.getExecutionContext().setFunctionDefContext (fdc);
+ //TODO configure isLogStacktrace
+ _middleEnd.getExecutionContext().getLocalVarContext().getLocalVars().putAll (localVars);
+ _middleEnd.getExecutionContext().getContributionStateContext().storeState (XtendGlobalVarOperations.GLOBAL_VAR_VALUES_KEY, globalVars);
+
+ return newAst.evaluate (_middleEnd.getExecutionContext());
+ }
+
+
+ private FunctionDefContext createFdc () {
+ if (_xtendFile != null)
+ return getFunctionDefContext();
+
+ final FunctionDefContextInternal result = new FunctionDefContextFactory (_middleEnd.getTypesystem()).create();
+
+ for (NamedFunction f: new XtendLibContributor (_middleEnd.getTypesystem()).getContributedFunctions())
+ result.register (f, false);
+ return result;
+ }
+
+
+ /**
+ * This function invokes a single Xtend function, returning the result. The fileEncoding may be null, in which case the platform's default file
+ * encoding is used.
+ */
+ public static Object invokeXtendFunction (String xtendFileName, String fileEncoding, Collection<MetaModel> mms, String functionName, Object... parameters) {
+ return createForFile (xtendFileName, fileEncoding, mms).invokeXtendFunction (functionName, parameters);
+ }
+
+ public Object invokeXtendFunction (String functionName, Object... parameters) {
+ final FunctionDefContext fdc = getFunctionDefContext();
+ final ExecutionContext ctx = BackendFacade.createExecutionContext (fdc, _middleEnd.getTypesystem(), true); //TODO configure isLogStacktrace
+ return fdc.invoke (ctx, functionName, Arrays.asList (parameters));
+ }
+
+
+ public static XtendBackendFacade createForFile (String xtendFileName, String fileEncoding, Collection<MetaModel> mms) {
+ return new XtendBackendFacade (xtendFileName, fileEncoding, mms);
+ }
+
+ private Map<Class<?>, Object> getSpecificParameters (String fileEncoding, Collection<MetaModel> mms) {
+ fileEncoding = OldHelper.normalizedFileEncoding (fileEncoding);
+
+ final ExecutionContextImpl ctx = new ExecutionContextImpl ();
+ ctx.setFileEncoding (fileEncoding);
+ for (MetaModel mm: mms)
+ ctx.registerMetaModel (mm);
+
+ final Map<Class<?>, Object> result = new HashMap<Class<?>, Object> ();
+ result.put (OldXtendRegistryFactory.class, ctx);
+ return result;
+ }
+
+
+ private XtendBackendFacade (String xtendFileName, String fileEncoding, Collection<MetaModel> mms) {
+ if (mms == null)
+ mms = new ArrayList<MetaModel> ();
+
+ _xtendFile = OldHelper.normalizeXtendResourceName (xtendFileName);
+ _mms = mms;
+ _middleEnd = MiddleEndFactory.create (OldHelper.guessTypesystem (mms), getSpecificParameters (fileEncoding, mms));
+ }
+
+ public FunctionDefContext getFunctionDefContext () {
+ if (_xtendFile == null)
+ return new FunctionDefContextFactory (_middleEnd.getTypesystem()).create();
+
+ return _middleEnd.getFunctions (_xtendFile);
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendComponent.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendComponent.java
new file mode 100644
index 0000000..a53de4d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/XtendComponent.java
@@ -0,0 +1,124 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.mwe.core.WorkflowContext;
+import org.eclipse.emf.mwe.core.issues.Issues;
+import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
+import org.eclipse.emf.mwe.core.resources.ResourceLoaderFactory;
+import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
+import org.eclipse.internal.xtend.xtend.XtendFile;
+import org.eclipse.xtend.expression.AbstractExpressionsUsingWorkflowComponent;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class XtendComponent extends AbstractExpressionsUsingWorkflowComponent {
+
+ /** Stores the value of the 'invoke' property. Needed for error analysis. */
+ private String _invokeExpression;
+ String _extensionFile = null;
+ private String _expression = null;
+ private String _outputSlot = WorkflowContext.DEFAULT_SLOT;
+
+ private String _fileEncoding = null;
+
+ public void setFileEncoding (String fileEncoding) {
+ _fileEncoding = fileEncoding;
+ }
+
+ @Override
+ public String getLogMessage() {
+ return "executing '" + _invokeExpression + "'";
+ }
+
+ public void setInvoke (String invoke) {
+ _invokeExpression = invoke;
+ final int i = invoke.lastIndexOf (SyntaxConstants.NS_DELIM);
+ if (i != -1) {
+ _extensionFile = invoke.substring(0, i);
+ _expression = invoke.substring (i + SyntaxConstants.NS_DELIM.length());
+ }
+ else
+ _expression = invoke;
+ }
+
+ public void setOutputSlot (String outputSlot) {
+ _outputSlot = outputSlot;
+ }
+
+ @Override
+ public void invokeInternal2(final WorkflowContext ctx, final ProgressMonitor monitor, final Issues issues) {
+ if (! extensionFileExists ()) {
+ issues.addError ("Cannot find extension file: " + _extensionFile);
+ return;
+ }
+
+ final Map<String, Object> localVars = new HashMap<String, Object> ();
+ for (String slotName: ctx.getSlotNames())
+ localVars.put (slotName, ctx.get (slotName));
+
+ final Map<String, Object> globalVars = new HashMap<String, Object> ();
+ for (GlobalVarDef gvd: globalVarDefs)
+ globalVars.put (gvd.getName(), gvd.getValue());
+
+ final Object result = XtendBackendFacade.evaluateExpression (_expression, _extensionFile, _fileEncoding, metaModels, localVars, globalVars, _advice);
+ ctx.set (_outputSlot, result);
+ }
+
+ private boolean extensionFileExists() {
+ InputStream is = null;
+ try {
+ is = ResourceLoaderFactory.createResourceLoader().getResourceAsStream (_extensionFile.replace (SyntaxConstants.NS_DELIM, "/") + XtendFile.FILE_EXTENSION);
+ }
+ catch (Exception exc) {
+ // do nothing - an exception just means that the extension file does not exist
+ }
+ if (is != null) {
+ try {
+ is.close ();
+ }
+ catch (Exception e) {}
+ }
+ return is != null;
+ }
+
+ @Override
+ public void checkConfiguration (Issues issues) {
+ super.checkConfiguration (issues);
+
+ // Try to create detailed error message (see Bug#172567)
+ String compPrefix = getId()!=null ? getId()+": " : "";
+
+ if (_invokeExpression == null || _invokeExpression.trim().length()==0) {
+ issues.addError(compPrefix + "Property 'invoke' not specified.");
+ return;
+ }
+ if (_extensionFile == null) {
+ issues.addError (compPrefix + "Error parsing property 'invoke': Could not extract name of the extension file.");
+ return;
+ }
+ if (! extensionFileExists () || _expression == null) {
+ issues.addError (compPrefix + "Property 'invoke' not specified properly. Extension file '" + _extensionFile + "' not found.");
+ return;
+ }
+ if (_expression == null) {
+ issues.addError (compPrefix + "Error parsing property 'invoke': Could not extract the expression to invoke in extension file '" + _extensionFile + "'.");
+ return;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldExpressionConverter.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldExpressionConverter.java
new file mode 100644
index 0000000..c05ec79
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldExpressionConverter.java
@@ -0,0 +1,475 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.internal.xtend.expression.ast.BooleanLiteral;
+import org.eclipse.internal.xtend.expression.ast.BooleanOperation;
+import org.eclipse.internal.xtend.expression.ast.Case;
+import org.eclipse.internal.xtend.expression.ast.ChainExpression;
+import org.eclipse.internal.xtend.expression.ast.CollectionExpression;
+import org.eclipse.internal.xtend.expression.ast.ConstructorCallExpression;
+import org.eclipse.internal.xtend.expression.ast.DeclaredParameter;
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.expression.ast.FeatureCall;
+import org.eclipse.internal.xtend.expression.ast.GlobalVarExpression;
+import org.eclipse.internal.xtend.expression.ast.IfExpression;
+import org.eclipse.internal.xtend.expression.ast.IntegerLiteral;
+import org.eclipse.internal.xtend.expression.ast.LetExpression;
+import org.eclipse.internal.xtend.expression.ast.ListLiteral;
+import org.eclipse.internal.xtend.expression.ast.Literal;
+import org.eclipse.internal.xtend.expression.ast.NullLiteral;
+import org.eclipse.internal.xtend.expression.ast.OperationCall;
+import org.eclipse.internal.xtend.expression.ast.RealLiteral;
+import org.eclipse.internal.xtend.expression.ast.StringLiteral;
+import org.eclipse.internal.xtend.expression.ast.SwitchExpression;
+import org.eclipse.internal.xtend.expression.ast.SyntaxElement;
+import org.eclipse.internal.xtend.expression.ast.TypeSelectExpression;
+import org.eclipse.internal.xtend.type.baseimpl.types.CollectionTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.ListTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.ObjectTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.SetTypeImpl;
+import org.eclipse.xtend.backend.aop.AdviceParamType;
+import org.eclipse.xtend.backend.aop.AroundAdvice;
+import org.eclipse.xtend.backend.aop.ExecutionPointcut;
+import org.eclipse.xtend.backend.aop.Pointcut;
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.SourcePos;
+import org.eclipse.xtend.backend.common.SyntaxConstants;
+import org.eclipse.xtend.backend.expr.AndExpression;
+import org.eclipse.xtend.backend.expr.CreateUncachedExpression;
+import org.eclipse.xtend.backend.expr.HidingLocalVarDefExpression;
+import org.eclipse.xtend.backend.expr.InitClosureExpression;
+import org.eclipse.xtend.backend.expr.InvocationOnCollectionExpression;
+import org.eclipse.xtend.backend.expr.InvocationOnObjectExpression;
+import org.eclipse.xtend.backend.expr.InvocationOnWhateverExpression;
+import org.eclipse.xtend.backend.expr.ListLiteralExpression;
+import org.eclipse.xtend.backend.expr.LiteralExpression;
+import org.eclipse.xtend.backend.expr.LocalVarEvalExpression;
+import org.eclipse.xtend.backend.expr.NewLocalVarDefExpression;
+import org.eclipse.xtend.backend.expr.OrExpression;
+import org.eclipse.xtend.backend.expr.PropertyOnCollectionExpression;
+import org.eclipse.xtend.backend.expr.PropertyOnObjectExpression;
+import org.eclipse.xtend.backend.expr.PropertyOnWhateverExpression;
+import org.eclipse.xtend.backend.expr.SequenceExpression;
+import org.eclipse.xtend.backend.syslib.SysLibNames;
+import org.eclipse.xtend.backend.types.builtin.CollectionType;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+import org.eclipse.xtend.backend.util.CollectionHelper;
+import org.eclipse.xtend.backend.util.Pair;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.TypeSystem;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.middleend.xtend.internal.xtendlib.XtendLibNames;
+import org.eclipse.xtend.typesystem.StaticProperty;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single expression or advice
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldExpressionConverter {
+ private final TypeToBackendType _typeConverter;
+ private ExecutionContext _ctx;
+ private final String _extensionName;
+
+ public OldExpressionConverter (ExecutionContext ctx, TypeToBackendType typeConverter, String extensionName) {
+ _typeConverter = typeConverter;
+ _ctx = ctx;
+ _extensionName = extensionName;
+ }
+
+ private static final List<String> _adviceLocalVarNames = Arrays.asList (SyntaxConstants.THIS_JOINPOINT, SyntaxConstants.THIS_JOINPOINT_STATICPART);
+
+ public List<String> getAdviceLocalVarNames () {
+ return _adviceLocalVarNames;
+ }
+
+ public List<Type> getAdviceLocalVarTypes (TypeSystem ts) {
+ return Arrays.asList (ts.getStringType(), ts.getStringType()); // any type other than Object will do - as a hint for the right optimizations
+ }
+
+ private static final AdviceParamType _wildCardParamType = new AdviceParamType (ObjectType.INSTANCE, true);
+
+ public AroundAdvice convertAdvice (ExpressionBase body, String namePattern, List<DeclaredParameter> params, boolean hasVarArgs, FunctionDefContext fdc) {
+ final List <Pair <String, AdviceParamType>> paramTypes = new ArrayList <Pair <String, AdviceParamType>> ();
+ for (DeclaredParameter dp: params)
+ paramTypes.add (new Pair <String, AdviceParamType> (dp.getName().getValue(), new AdviceParamType (_typeConverter.convertToBackendType (dp.getType()), true)));
+
+ final Pointcut pointcut = new ExecutionPointcut (namePattern, paramTypes, hasVarArgs, _wildCardParamType);
+
+ return new AroundAdvice (body, pointcut, false, fdc);
+ }
+
+ public ExpressionBase convert (Expression expr) {
+ if (expr instanceof BooleanLiteral)
+ return new LiteralExpression ("true".equals (((Literal) expr).getLiteralValue().getValue()), getSourcePos (expr));
+ if (expr instanceof IntegerLiteral)
+ return new LiteralExpression (new Long (((Literal) expr).getLiteralValue().getValue()), getSourcePos(expr));
+ if (expr instanceof NullLiteral)
+ return new LiteralExpression (null, getSourcePos (expr));
+ if (expr instanceof RealLiteral)
+ return new LiteralExpression (new Double (((Literal) expr).getLiteralValue().getValue()), getSourcePos(expr));
+ if (expr instanceof StringLiteral)
+ return new LiteralExpression (((StringLiteral) expr).getValue(), getSourcePos(expr));
+ if (expr instanceof ListLiteral)
+ return convertListLiteral ((ListLiteral) expr);
+
+ if (expr instanceof OperationCall)
+ return convertOperationCall ((OperationCall) expr);
+ if (expr instanceof CollectionExpression)
+ return convertCollectionExpression ((CollectionExpression) expr);
+ if (expr instanceof TypeSelectExpression)
+ return convertTypeSelectExpression ((TypeSelectExpression) expr);
+
+ // This case must come *after* OperationCall etc. because of implementation inheritance in the Xtend AST!
+ if (expr instanceof FeatureCall)
+ return convertFeatureCallExpression ((FeatureCall) expr);
+
+ if (expr instanceof BooleanOperation)
+ return convertBooleanOperation ((BooleanOperation) expr);
+
+ if (expr instanceof GlobalVarExpression)
+ return convertGlobalVarExpression ((GlobalVarExpression) expr);
+ if (expr instanceof LetExpression)
+ return convertLetExpression((LetExpression) expr);
+ if (expr instanceof ChainExpression)
+ return convertChainExpression ((ChainExpression) expr);
+
+ if (expr instanceof ConstructorCallExpression)
+ return convertConstructorCallExpression ((ConstructorCallExpression) expr);
+
+ if (expr instanceof IfExpression)
+ return convertIfExpression((IfExpression) expr);
+ if (expr instanceof SwitchExpression)
+ return convertSwitchExpression ((SwitchExpression) expr);
+
+ throw new IllegalArgumentException ("unsupported expression type: " + expr.getClass().getName());
+ }
+
+ private ExpressionBase convertOperationCall (OperationCall expr) {
+ final SourcePos sourcePos = getSourcePos (expr);
+ final String functionName = transformFunctionName (expr.getName().getValue());
+
+ final List<ExpressionBase> params = new ArrayList<ExpressionBase> ();
+ for (Expression e: expr.getParams ())
+ params.add (convert (e));
+
+ final List<Type> paramTypes = new ArrayList<Type>();
+ for (Expression e: expr.getParams())
+ paramTypes.add (new OldTypeAnalyzer ().analyze (_ctx, e));
+
+ if (expr.getTarget() == null) {
+ if (hasThis()) {
+ // if a function matches directly (i.e. without implicitly passing 'this' as a first parameter), that
+ // has precedence in matching
+ if (hasMatchingOperationCall (functionName, paramTypes.toArray (new Type[0])))
+ return new InvocationOnObjectExpression (functionName, params, false, sourcePos);
+ else {
+ final ExpressionBase thisExpression = new LocalVarEvalExpression (org.eclipse.xtend.backend.common.SyntaxConstants.THIS, sourcePos);
+ final Type thisType = (Type) _ctx.getVariable (ExecutionContext.IMPLICIT_VARIABLE).getValue();
+ return createInvocationOnTargetExpression (functionName, thisExpression, thisType, params, paramTypes, true, sourcePos);
+ }
+ }
+ else
+ return new InvocationOnObjectExpression (functionName, params, false, sourcePos);
+ }
+ else
+ return createInvocationOnTargetExpression(functionName, convert (expr.getTarget()), new OldTypeAnalyzer ().analyze (_ctx, expr.getTarget ()), params, paramTypes, true, sourcePos);
+ }
+
+ private boolean hasMatchingOperationCall (String functionName, Type[] paramTypes) {
+ if (_ctx.getExtensionForTypes (functionName, paramTypes) != null)
+ return true;
+
+ if (paramTypes.length == 0)
+ return false;
+
+ final Type target = paramTypes[0];
+ return target.getOperation (functionName, CollectionHelper.withoutFirst (paramTypes)) != null;
+ }
+
+
+ /**
+ * transform built-in operator names from the old to the new special names
+ */
+ private String transformFunctionName (String functionName) {
+ if ("+".equals (functionName))
+ return SysLibNames.OPERATOR_PLUS;
+ if ("-".equals (functionName))
+ return SysLibNames.OPERATOR_MINUS;
+ if ("*".equals (functionName))
+ return SysLibNames.OPERATOR_MULT;
+ if ("/".equals (functionName))
+ return SysLibNames.OPERATOR_DIV;
+ if ("%".equals (functionName))
+ return SysLibNames.OPERATOR_MOD;
+
+ if ("==".equals (functionName))
+ return SysLibNames.OPERATOR_EQUALS;
+ if ("!=".equals (functionName))
+ return SysLibNames.OPERATOR_NOT_EQUALS;
+ if ("<".equals (functionName))
+ return SysLibNames.OPERATOR_LESS;
+ if ("<=".equals (functionName))
+ return SysLibNames.OPERATOR_LESS_OR_EQUALS;
+ if (">=".equals (functionName))
+ return SysLibNames.OPERATOR_GREATER_OR_EQUALS;
+ if (">".equals (functionName))
+ return SysLibNames.OPERATOR_GREATER;
+
+ if ("!".equals (functionName))
+ return SysLibNames.OPERATOR_NOT;
+
+ if ("subString".equals (functionName))
+ return SysLibNames.SUBSTRING;
+ if ("replaceAll".equals (functionName))
+ return SysLibNames.REPLACE_ALL_REGEX;
+
+ return functionName;
+ }
+
+ private ExpressionBase createInvocationOnTargetExpression (String functionName, ExpressionBase targetExpression, Type targetType, List<ExpressionBase> params, List<Type> paramTypes, boolean isMethodStyle, SourcePos sourcePos) {
+ final List<ExpressionBase> paramsWithoutFirst = params;
+ final List<ExpressionBase> allParams = new ArrayList<ExpressionBase> ();
+ allParams.add (targetExpression);
+ allParams.addAll (params);
+
+ if (isCollectionType (targetType)) {
+ paramTypes.add (0, targetType);
+ final Type[] paramTypeArray = paramTypes.toArray(new Type[0]);
+
+ if (hasMatchingOperationCall (functionName, paramTypeArray))
+ // check if there is a function that directly matches the collection
+ return new InvocationOnObjectExpression (functionName, allParams, true, sourcePos);
+ else
+ // otherwise, do a 'collect' and call the function on all elements of the collection
+ return new InvocationOnCollectionExpression (targetExpression, functionName, paramsWithoutFirst, sourcePos);
+ }
+
+ if (isObjectType (targetType))
+ // if the static type is "Object", we do not know if it is a collection, so we do the logic at runtime
+ return new InvocationOnWhateverExpression (functionName, allParams, isMethodStyle, sourcePos);
+
+ // otherwise we know that it is not a collection and can avoid repeating this logic at runtime
+ return new InvocationOnObjectExpression (functionName, allParams, true, sourcePos);
+ }
+
+ private ExpressionBase convertTypeSelectExpression (TypeSelectExpression expr) {
+ final SourcePos sourcePos = getSourcePos (expr);
+
+ final Type t = _ctx.getTypeForName (expr.getTypeName());
+ final ExpressionBase typeExpr = new LiteralExpression (_typeConverter.convertToBackendType(t), sourcePos);
+
+ if (expr.getTarget() == null) {
+ if (! hasThis())
+ throw new IllegalStateException ("typeSelect with neither a target nor an implicit 'this'");
+
+ final ExpressionBase thisExpr = new LocalVarEvalExpression (org.eclipse.xtend.backend.common.SyntaxConstants.THIS, sourcePos);
+ return new InvocationOnObjectExpression (SysLibNames.TYPE_SELECT, Arrays.asList (thisExpr, typeExpr), true, sourcePos);
+ }
+ else
+ return new InvocationOnObjectExpression (SysLibNames.TYPE_SELECT, Arrays.asList(convert (expr.getTarget()), typeExpr), false, sourcePos);
+ }
+
+ private ExpressionBase convertSwitchExpression (SwitchExpression expr) {
+ final List<Pair<ExpressionBase, ExpressionBase>> cases = new ArrayList<Pair<ExpressionBase,ExpressionBase>>();
+ for (Case c: expr.getCases())
+ cases.add (new Pair<ExpressionBase, ExpressionBase> (convert (c.getCondition()), convert (c.getThenPart())));
+
+ return new org.eclipse.xtend.backend.expr.SwitchExpression (convert (expr.getSwitchExpr()), cases, convert (expr.getDefaultExpr()), getSourcePos(expr));
+ }
+
+ private ExpressionBase convertListLiteral (ListLiteral expr) {
+ final List<ExpressionBase> inner = new ArrayList<ExpressionBase>();
+
+ for (Expression e: expr.getElements ())
+ inner.add (convert (e));
+
+ return new ListLiteralExpression (inner, getSourcePos(expr));
+ }
+
+ private ExpressionBase convertLetExpression (LetExpression expr) {
+ final ExpressionBase varExpr = convert (expr.getVarExpression());
+ final Type varType = new OldTypeAnalyzer ().analyze (_ctx, expr.getVarExpression());
+
+ final ExecutionContext oldCtx = _ctx;
+ _ctx = _ctx.cloneWithVariable (new Variable (expr.getName(), varType));
+
+ try {
+ if (oldCtx.getVisibleVariables().containsKey(expr.getName()))
+ return new HidingLocalVarDefExpression (expr.getName(), varExpr, convert (expr.getTargetExpression()), getSourcePos(expr));
+ else
+ return new NewLocalVarDefExpression (expr.getName(), varExpr, convert (expr.getTargetExpression()), getSourcePos(expr));
+ }
+ finally {
+ _ctx = oldCtx;
+ }
+ }
+
+ private ExpressionBase convertIfExpression (IfExpression expr) {
+ final ExpressionBase elseExpr = (expr.getElsePart() != null) ? convert (expr.getElsePart()) : new LiteralExpression (null, getSourcePos (expr));
+
+ return new org.eclipse.xtend.backend.expr.IfExpression (
+ convert (expr.getCondition()),
+ convert (expr.getThenPart()),
+ elseExpr,
+ getSourcePos(expr));
+ }
+
+ private ExpressionBase convertFeatureCallExpression (FeatureCall expr) {
+ final SourcePos sourcePos = getSourcePos(expr);
+
+ if (expr.getTarget() == null) {
+ // 1. check for a static property
+ final StaticProperty staticProp = expr.getEnumLiteral (_ctx);
+ if (staticProp != null)
+ return new LiteralExpression (staticProp.get(), sourcePos);
+
+ // 2. check for a local variable
+ if (_ctx.getVisibleVariables().containsKey (expr.getName().getValue()))
+ return new LocalVarEvalExpression (expr.getName().getValue(), sourcePos);
+
+ // 3. check for a type literal
+ try {
+ return new LiteralExpression (_typeConverter.convertToBackendType (expr.getName()), sourcePos);
+ }
+ catch (IllegalArgumentException exc) {} // do nothing - this means it is not a type literal
+
+ // 4. check for "this"
+ if (hasThis()) {
+ final ExpressionBase thisExpr = new LocalVarEvalExpression (org.eclipse.xtend.backend.common.SyntaxConstants.THIS, sourcePos);
+ return createPropertyExpression (thisExpr, (Type) _ctx.getVisibleVariables().get (ExecutionContext.IMPLICIT_VARIABLE).getValue(), expr.getName().getValue(), sourcePos);
+ }
+
+ throw new IllegalArgumentException ("feature call " + expr.toString() + " does not match any feature: " + sourcePos);
+ }
+ else {
+ // evaluate the target and evaluate the property on the result
+ final Type t = new OldTypeAnalyzer ().analyze (_ctx,expr.getTarget());
+ return createPropertyExpression(convert (expr.getTarget()), t, expr.getName().getValue(), sourcePos);
+ }
+ }
+
+ private ExpressionBase createPropertyExpression (ExpressionBase target, Type type, String varName, SourcePos sourcePos) {
+ if (isCollectionType (type)) {
+ if (CollectionType.INSTANCE.getProperties().keySet().contains (varName))
+ return new PropertyOnObjectExpression (target, varName, sourcePos);
+ else
+ return new PropertyOnCollectionExpression (target, varName, sourcePos);
+ }
+
+ if (isObjectType (type))
+ return new PropertyOnWhateverExpression (target, varName, sourcePos);
+
+ return new PropertyOnObjectExpression (target, varName, sourcePos);
+ }
+
+ private ExpressionBase convertConstructorCallExpression (ConstructorCallExpression expr) {
+ final BackendType t = _typeConverter.convertToBackendType (expr.getType ());
+ return new CreateUncachedExpression (t, getSourcePos(expr));
+ }
+
+ private ExpressionBase convertCollectionExpression (CollectionExpression expr) {
+ final SourcePos sourcePos = getSourcePos (expr);
+
+ final String functionName = expr.getName().getValue();
+
+ final ExecutionContext oldCtx = _ctx;
+ _ctx = _ctx.cloneWithVariable (new Variable (expr.getElementName(), new ObjectTypeImpl (_ctx, "Object")));
+ final ExpressionBase bodyExpr = convert (expr.getClosure());
+ _ctx = oldCtx;
+
+ final InitClosureExpression closureExpr = new InitClosureExpression (Arrays.asList(expr.getElementName()), Arrays.asList(ObjectType.INSTANCE), bodyExpr, sourcePos);
+
+ if (expr.getTarget() == null) {
+ if (! hasThis())
+ throw new IllegalStateException (functionName + " with neither a target nor an implicit 'this'");
+
+ final ExpressionBase thisExpr = new LocalVarEvalExpression (org.eclipse.xtend.backend.common.SyntaxConstants.THIS, sourcePos);
+ return new InvocationOnObjectExpression (functionName, Arrays.asList (thisExpr, closureExpr), true, sourcePos);
+ }
+ else
+ return new InvocationOnObjectExpression (functionName, Arrays.asList(convert (expr.getTarget()), closureExpr), true, sourcePos);
+ }
+
+ private ExpressionBase convertChainExpression (ChainExpression expr) {
+ return new SequenceExpression (getInner(expr), getSourcePos(expr));
+ }
+
+ /**
+ * extract the inner expressions as a "flat" list - they are stored as a
+ * binary tree in the ChainExpression...
+ */
+ private List<ExpressionBase> getInner (ChainExpression expr) {
+ final List<ExpressionBase> result = new ArrayList<ExpressionBase>();
+
+ if (expr.getFirst() instanceof ChainExpression)
+ result.addAll (getInner ((ChainExpression) expr.getFirst()));
+ else
+ result.add (convert (expr.getFirst()));
+
+ if (expr.getNext() instanceof ChainExpression)
+ result.addAll (getInner ((ChainExpression) expr.getNext()));
+ else
+ result.add (convert (expr.getNext()));
+
+ return result;
+ }
+
+ private ExpressionBase convertGlobalVarExpression (GlobalVarExpression expr) {
+ return new InvocationOnObjectExpression (XtendLibNames.GLOBAL_VAR_VALUE, Arrays.asList (new LiteralExpression (expr.getVarName(), getSourcePos(expr))), true, getSourcePos (expr));
+ }
+
+ private ExpressionBase convertBooleanOperation (BooleanOperation expr) {
+ final ExpressionBase left = convert (expr.getLeft());
+ final ExpressionBase right = convert (expr.getRight());
+
+ if ("&&".equals (expr.getOperator().getValue()))
+ return new AndExpression (left, right, getSourcePos(expr));
+ if ("||".equals (expr.getOperator().getValue()))
+ return new OrExpression (left, right, getSourcePos(expr));
+ if ("implies".equals (expr.getOperator().getValue()))
+ return new InvocationOnObjectExpression (SysLibNames.IMPLIES, Arrays.asList(left, right), true, getSourcePos(expr));
+
+ throw new IllegalArgumentException ("unknown boolean operator " + expr.getOperator().getValue());
+ }
+
+ public SourcePos getSourcePos (SyntaxElement se) {
+ return getSourcePos (se, _extensionName);
+ }
+
+ public static SourcePos getSourcePos (SyntaxElement se, String extensionName) {
+ return new SourcePos (se.getFileName(), extensionName, se.getLine());
+ }
+
+ private boolean isObjectType (Type t) {
+ return t instanceof ObjectTypeImpl;
+ }
+
+ private boolean isCollectionType (Type t) {
+ return t instanceof CollectionTypeImpl ||
+ t instanceof ListTypeImpl ||
+ t instanceof SetTypeImpl;
+ }
+
+ private boolean hasThis () {
+ return _ctx.getVisibleVariables().containsKey (ExecutionContext.IMPLICIT_VARIABLE);
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldHelper.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldHelper.java
new file mode 100644
index 0000000..4cf0ded
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldHelper.java
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal;
+
+import java.util.Collection;
+
+import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
+import org.eclipse.internal.xtend.xtend.XtendFile;
+import org.eclipse.xpand2.XpandUtil;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.types.CompositeTypesystem;
+import org.eclipse.xtend.backend.types.emf.EmfTypesystem;
+import org.eclipse.xtend.typesystem.MetaModel;
+import org.eclipse.xtend.typesystem.emf.EmfRegistryMetaModel;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldHelper {
+ public static BackendTypesystem guessTypesystem (Collection<MetaModel> mms) {
+ boolean hasEmf = false;
+
+ for (MetaModel mm: mms) {
+ if (mm instanceof EmfRegistryMetaModel)
+ hasEmf = true;
+ }
+
+ final CompositeTypesystem result = new CompositeTypesystem ();
+ if (hasEmf)
+ result.register (new EmfTypesystem ());
+ //TODO register uml mm
+ //TODO replace this by adding "asBackendType" to the frontend types
+
+ return result;
+ }
+
+
+ public static String normalizedFileEncoding (String fileEncoding) {
+ if (fileEncoding == null)
+ return System.getProperty ("file.encoding");
+
+ return fileEncoding;
+ }
+
+ public static String normalizeXtendResourceName (String xtendName) {
+ if (xtendName == null)
+ return null;
+
+ xtendName = xtendName.replace (SyntaxConstants.NS_DELIM, "/");
+ if (xtendName.endsWith ("." + XtendFile.FILE_EXTENSION))
+ xtendName = xtendName.substring (0, xtendName.length() - (XtendFile.FILE_EXTENSION.length() + 1));
+
+ return xtendName;
+ }
+
+ public static String normalizeXpandResourceName (String xpandName) {
+ if (xpandName == null)
+ return null;
+
+ if (! xpandName.endsWith("." + XpandUtil.TEMPLATE_EXTENSION))
+ xpandName += "." + XpandUtil.TEMPLATE_EXTENSION;
+
+ xpandName = xpandName.replace (SyntaxConstants.NS_DELIM, "/");
+
+ return xpandName;
+ }
+
+ public static String xpandFileAsOldResourceName (String xpandName) {
+ if (xpandName == null)
+ return null;
+
+ if (xpandName.toLowerCase().endsWith (XpandUtil.TEMPLATE_EXTENSION))
+ xpandName = xpandName.substring (0, xpandName.length() - XpandUtil.TEMPLATE_EXTENSION.length() - 1);
+
+ xpandName = xpandName.replace ("/", SyntaxConstants.NS_DELIM);
+
+ return xpandName;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldTypeAnalyzer.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldTypeAnalyzer.java
new file mode 100644
index 0000000..e3cbffc
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/OldTypeAnalyzer.java
@@ -0,0 +1,319 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.internal.xtend.expression.ast.BooleanLiteral;
+import org.eclipse.internal.xtend.expression.ast.BooleanOperation;
+import org.eclipse.internal.xtend.expression.ast.Case;
+import org.eclipse.internal.xtend.expression.ast.ChainExpression;
+import org.eclipse.internal.xtend.expression.ast.CollectionExpression;
+import org.eclipse.internal.xtend.expression.ast.ConstructorCallExpression;
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.expression.ast.FeatureCall;
+import org.eclipse.internal.xtend.expression.ast.GlobalVarExpression;
+import org.eclipse.internal.xtend.expression.ast.IfExpression;
+import org.eclipse.internal.xtend.expression.ast.IntegerLiteral;
+import org.eclipse.internal.xtend.expression.ast.LetExpression;
+import org.eclipse.internal.xtend.expression.ast.ListLiteral;
+import org.eclipse.internal.xtend.expression.ast.NullLiteral;
+import org.eclipse.internal.xtend.expression.ast.OperationCall;
+import org.eclipse.internal.xtend.expression.ast.RealLiteral;
+import org.eclipse.internal.xtend.expression.ast.StringLiteral;
+import org.eclipse.internal.xtend.expression.ast.SwitchExpression;
+import org.eclipse.internal.xtend.expression.ast.TypeSelectExpression;
+import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
+import org.eclipse.internal.xtend.xtend.ast.CreateExtensionStatement;
+import org.eclipse.internal.xtend.xtend.ast.ExpressionExtensionStatement;
+import org.eclipse.internal.xtend.xtend.ast.Extension;
+import org.eclipse.internal.xtend.xtend.ast.JavaExtensionStatement;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.typesystem.ParameterizedType;
+import org.eclipse.xtend.typesystem.Property;
+import org.eclipse.xtend.typesystem.StaticProperty;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * This class is a visitor that serves as a replacement for the "analyze"
+ * methods of the Expression classes. While the "analyze" methods perform
+ * strict static checking, this class does a "best effort": It finds
+ * the best statically predictable type, based on the assumption that
+ * the code is dynamically correct.<br>
+ *
+ * An example can illustrate this. Let "x" be a collection with statically
+ * unknown inner type. Then the two approaches yield different results for
+ * "x.myProperty". The analyze methods in the expressions return "null"
+ * because they can not statically ensure the type correctness of the
+ * expression. This class on the other hand returns the type "Collection[Object]".
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldTypeAnalyzer {
+ public Type analyze (ExecutionContext ctx, Extension ext, Type[] paramTypes) {
+ if (ext instanceof JavaExtensionStatement)
+ return analyzeJavaExtension (ctx, (JavaExtensionStatement) ext);
+ if (ext instanceof ExpressionExtensionStatement)
+ return analyzeExpressionExtension (ctx, (ExpressionExtensionStatement) ext, paramTypes);
+ if (ext instanceof CreateExtensionStatement)
+ return ctx.getTypeForName (((CreateExtensionStatement) ext).getReturnTypeIdentifier().getValue());;
+
+ throw new IllegalArgumentException ("unknown extension type " + ext.getClass().getName());
+ }
+
+ private Type analyzeExpressionExtension (ExecutionContext ctx, ExpressionExtensionStatement ext, Type[] paramTypes) {
+ ctx = ctx.cloneWithoutVariables();
+
+ for (int i=0; i<ext.getParameterNames().size(); i++) {
+ final String name = ext.getParameterNames().get(i);
+ final Type value = paramTypes[i];
+
+ ctx = ctx.cloneWithVariable (new Variable (name, value));
+ }
+
+ return analyze (ctx, ext.getExpression());
+ }
+
+ private Type analyzeJavaExtension (ExecutionContext ctx, JavaExtensionStatement ext) {
+ if (ext.getReturnTypeIdentifier() != null)
+ return ctx.getTypeForName (ext.getReturnTypeIdentifier().getValue());
+
+ return ctx.getObjectType(); // Typesystem provides no support for evaluating the return type of the Method...
+ }
+
+
+ public Type analyze (ExecutionContext ctx, Expression expr) {
+ if (expr instanceof BooleanLiteral)
+ return ctx.getBooleanType();
+ if (expr instanceof IntegerLiteral)
+ return ctx.getIntegerType();
+ if (expr instanceof NullLiteral)
+ return ctx.getVoidType();
+ if (expr instanceof RealLiteral)
+ return ctx.getRealType();
+ if (expr instanceof StringLiteral)
+ return ctx.getStringType();
+ if (expr instanceof ListLiteral)
+ return analyzeListLiteral (ctx, (ListLiteral) expr);
+
+ if (expr instanceof OperationCall)
+ return analyzeOperationCall (ctx, (OperationCall) expr);
+ if (expr instanceof CollectionExpression)
+ return analyzeCollectionExpression (ctx, (CollectionExpression) expr);
+ if (expr instanceof TypeSelectExpression)
+ return analyzeTypeSelect (ctx, (TypeSelectExpression) expr);
+
+ // This case must come *after* OperationCall etc. because of implementation inheritance in the Xtend AST!
+ if (expr instanceof FeatureCall)
+ return analyzeFeatureCall (ctx, (FeatureCall) expr);
+
+ if (expr instanceof BooleanOperation)
+ return ctx.getBooleanType();
+
+ if (expr instanceof GlobalVarExpression)
+ return analyzeGlobalVar (ctx, (GlobalVarExpression) expr);
+ if (expr instanceof LetExpression)
+ return analyzeLet (ctx, (LetExpression) expr);
+ if (expr instanceof ChainExpression)
+ return analyzeChain (ctx, (ChainExpression) expr);
+
+ if (expr instanceof ConstructorCallExpression)
+ return analyzeConstructorCall (ctx, (ConstructorCallExpression) expr);
+
+ if (expr instanceof IfExpression)
+ return analyzeIf (ctx, (IfExpression) expr);
+ if (expr instanceof SwitchExpression)
+ return analyzeSwitch (ctx, (SwitchExpression) expr);
+
+ throw new IllegalArgumentException ("unknown expression kind " + expr.getClass().getName());
+ }
+
+ private Type analyzeListLiteral (ExecutionContext ctx, ListLiteral expr) {
+ Type innerType = null;
+
+ for (Expression ele: expr.getElements()) {
+ if (innerType == null)
+ innerType = analyze (ctx, ele);
+ else
+ innerType = getCommonSupertype (innerType, analyze (ctx, ele));
+ }
+
+ if (innerType == null)
+ innerType = ctx.getObjectType();
+
+ return ctx.getListType (innerType);
+ }
+
+ private Type analyzeOperationCall (ExecutionContext ctx, @SuppressWarnings("unused") OperationCall expr) {
+ return ctx.getObjectType();
+
+ // it would require extreme effort to find matching extensions etc. because we do not know
+ // the parameter types but their *super*types, so ObjectType is a safe assumption here.
+ }
+
+
+ private Type analyzeCollectionExpression (ExecutionContext ctx, CollectionExpression expr) {
+ if (Arrays.asList (SyntaxConstants.COLLECT, SyntaxConstants.SELECT, SyntaxConstants.REJECT, SyntaxConstants.SORT_BY).contains (expr.getName().getValue()))
+ return analyze (ctx, expr.getTarget());
+
+ if (expr.getName().getValue().equals(SyntaxConstants.SELECTFIRST))
+ return ((ParameterizedType) analyze (ctx, expr.getTarget())).getInnerType();
+
+ if (Arrays.asList (SyntaxConstants.EXISTS, SyntaxConstants.NOT_EXISTS, SyntaxConstants.FOR_ALL).contains (expr.getName().getValue()))
+ return ctx.getBooleanType();
+
+ throw new IllegalArgumentException ("unknown collection operation " + expr.getName().getValue());
+ }
+
+ private Type analyzeTypeSelect (ExecutionContext ctx, TypeSelectExpression expr) {
+ final Type innerType = ctx.getTypeForName (expr.getTypeName ());
+ return ctx.getCollectionType(innerType);
+ }
+
+ private Type analyzeFeatureCall (ExecutionContext ctx, FeatureCall expr) {
+ Type targetType = null;
+ if (expr.getTarget() == null) {
+ // enum literal
+ final StaticProperty staticProp = expr.getEnumLiteral(ctx);
+ if (staticProp != null)
+ return staticProp.getReturnType();
+
+ // variable
+ Variable var = ctx.getVariable (expr.getName().getValue());
+ if (var != null)
+ return (Type) var.getValue();
+
+ // implicit variable 'this'
+ var = ctx.getVariable (ExecutionContext.IMPLICIT_VARIABLE);
+ if (var != null)
+ targetType = (Type) var.getValue();
+
+ }
+ else
+ targetType = analyze (ctx, expr.getTarget());
+
+ // simple property
+ if (targetType != null) {
+ Property p = targetType.getProperty (expr.getName().getValue());
+ if (p != null)
+ return p.getReturnType();
+
+ if (targetType instanceof ParameterizedType) {
+ final Type innerType = ((ParameterizedType) targetType).getInnerType ();
+ p = innerType.getProperty (expr.getName().getValue());
+ if (p != null) {
+ Type rt = p.getReturnType();
+
+ if (rt instanceof ParameterizedType)
+ rt = ((ParameterizedType) rt).getInnerType();
+
+ return ctx.getListType(rt);
+ }
+ }
+
+ return ctx.getObjectType();
+ }
+
+ // type literal
+ if (expr.getTarget() == null) {
+ final Type type = ctx.getTypeForName (expr.getName().getValue());
+ if (type != null)
+ return ctx.getTypeType();
+ }
+
+ return ctx.getObjectType();
+ }
+
+ private Type analyzeGlobalVar (ExecutionContext ctx, @SuppressWarnings("unused") GlobalVarExpression expr) {
+ return ctx.getObjectType();
+ }
+
+ private Type analyzeLet (ExecutionContext ctx, LetExpression expr) {
+ final Type t = analyze (ctx, expr.getVarExpression());
+ ctx = ctx.cloneWithVariable (new Variable (expr.getName(), t));
+ return analyze (ctx, expr.getTargetExpression());
+ }
+
+ private Type analyzeChain (ExecutionContext ctx, ChainExpression expr) {
+ return analyze (ctx, expr.getNext());
+ }
+
+ private Type analyzeConstructorCall (ExecutionContext ctx, ConstructorCallExpression expr) {
+ return ctx.getTypeForName (expr.getTypeName());
+ }
+
+ private Type analyzeIf (ExecutionContext ctx, IfExpression expr) {
+ if (expr.getElsePart() == null)
+ return analyze (ctx, expr.getThenPart());
+ else
+ return getCommonSupertype (analyze (ctx, expr.getThenPart()), analyze (ctx, expr.getElsePart()));
+ }
+
+ private Type analyzeSwitch (ExecutionContext ctx, SwitchExpression expr) {
+ Type result = analyze (ctx, expr.getDefaultExpr());
+ for (Case curCase: expr.getCases())
+ result = getCommonSupertype (result, analyze (ctx, curCase.getThenPart()));
+
+ return result;
+ }
+
+ private Type getCommonSupertype (Type t1, Type t2) {
+ if (t1.isAssignableFrom (t2))
+ return t1;
+ if (t2.isAssignableFrom (t1))
+ return t2;
+
+ final Set<Type> commonSupertypes = new HashSet<Type>();
+ for (Type parent1: t1.getSuperTypes())
+ for (Type parent2: t2.getSuperTypes())
+ commonSupertypes.add (getCommonSupertype (parent1, parent2));
+
+ // this is an arbitrary way to disambiguate in the case of several matches / multiple inheritance
+ final Iterator<Type> iter = commonSupertypes.iterator();
+ Type result = iter.next();
+ while (iter.hasNext()) {
+ final Type candidate = iter.next();
+ if (candidate.isAssignableFrom (result))
+ result = candidate;
+ }
+
+ return result;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/TypeToBackendType.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/TypeToBackendType.java
new file mode 100644
index 0000000..17cb1d6
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/TypeToBackendType.java
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.internal.xtend.expression.ast.Identifier;
+import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
+import org.eclipse.internal.xtend.type.baseimpl.types.BooleanTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.CollectionTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.IntegerTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.ListTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.ObjectTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.OperationTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.PropertyTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.RealTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.SetTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.StaticPropertyTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.StringTypeImpl;
+import org.eclipse.internal.xtend.type.baseimpl.types.TypeTypeImpl;
+import org.eclipse.internal.xtend.type.impl.java.JavaTypeImpl;
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.types.CompositeTypesystem;
+import org.eclipse.xtend.backend.types.builtin.BooleanType;
+import org.eclipse.xtend.backend.types.builtin.CollectionType;
+import org.eclipse.xtend.backend.types.builtin.DoubleType;
+import org.eclipse.xtend.backend.types.builtin.FunctionType;
+import org.eclipse.xtend.backend.types.builtin.ListType;
+import org.eclipse.xtend.backend.types.builtin.LongType;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+import org.eclipse.xtend.backend.types.builtin.PropertyType;
+import org.eclipse.xtend.backend.types.builtin.SetType;
+import org.eclipse.xtend.backend.types.builtin.StaticPropertyType;
+import org.eclipse.xtend.backend.types.builtin.StringType;
+import org.eclipse.xtend.backend.types.builtin.TypeType;
+import org.eclipse.xtend.backend.types.builtin.VoidType;
+import org.eclipse.xtend.backend.types.emf.EmfTypesystem;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.typesystem.Type;
+import org.eclipse.xtend.typesystem.emf.EClassType;
+import org.eclipse.xtend.typesystem.emf.EDataTypeType;
+import org.eclipse.xtend.typesystem.emf.EEnumType;
+import org.eclipse.xtend.typesystem.emf.EObjectType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class TypeToBackendType {
+ private final BackendTypesystem _backendTypes;
+ private final EmfTypesystem _emfTypes;
+ private final ExecutionContext _ctx;
+
+ public TypeToBackendType (BackendTypesystem backendTypes, ExecutionContext ctx) {
+ _backendTypes = backendTypes;
+ _ctx = ctx;
+
+ EmfTypesystem ets = null;
+ for (BackendTypesystem bts: ((CompositeTypesystem) _backendTypes).getInner()) {
+ if (bts instanceof EmfTypesystem)
+ ets = (EmfTypesystem) bts;
+ }
+
+ _emfTypes = ets;
+ }
+
+ public BackendType convertToBackendType (Identifier typeName) {
+ return convertToBackendType (Arrays.asList (typeName.getValue().split (SyntaxConstants.NS_DELIM)));
+ }
+
+ private BackendType convertToBackendType (List<String> segments) {
+ final StringBuilder sb = new StringBuilder();
+ boolean first = true;
+
+ for (String s: segments) {
+ if (!first) {
+ sb.append (SyntaxConstants.NS_DELIM);
+ }
+ first = false;
+
+ sb.append (s);
+ }
+
+ final Type t = _ctx.getTypeForName (sb.toString());
+ return convertToBackendType(t);
+ }
+
+ public BackendType convertToBackendType (Class<?> cls) {
+ return _backendTypes.findType (cls);
+ }
+
+ public BackendType convertToBackendType (Type t) {
+ if (t instanceof EClassType)
+ return convertEClassType (t);
+ if (t instanceof EDataTypeType)
+ return convertEDataTypeType (t);
+ if (t instanceof EEnumType)
+ return convertEEnumType (t);
+ if (t instanceof EObjectType)
+ return org.eclipse.xtend.backend.types.emf.internal.EObjectType.INSTANCE;
+
+ if (t instanceof JavaTypeImpl)
+ return convertJavaType (t);
+
+ if (t instanceof BooleanTypeImpl)
+ return BooleanType.INSTANCE;
+ if (t instanceof ListTypeImpl)
+ return ListType.INSTANCE;
+ if (t instanceof SetTypeImpl)
+ return SetType.INSTANCE;
+ if (t instanceof CollectionTypeImpl)
+ return CollectionType.INSTANCE;
+ if (t instanceof IntegerTypeImpl)
+ return LongType.INSTANCE;
+ if (t instanceof ObjectTypeImpl)
+ return ObjectType.INSTANCE;
+ if (t instanceof OperationTypeImpl)
+ return FunctionType.INSTANCE;
+ if (t instanceof PropertyTypeImpl)
+ return PropertyType.INSTANCE;
+ if (t instanceof RealTypeImpl)
+ return DoubleType.INSTANCE;
+ if (t instanceof StaticPropertyTypeImpl)
+ return StaticPropertyType.INSTANCE;
+ if (t instanceof StringTypeImpl)
+ return StringType.INSTANCE;
+ if (t instanceof TypeTypeImpl)
+ return TypeType.INSTANCE;
+ if (t instanceof org.eclipse.internal.xtend.type.baseimpl.types.VoidType)
+ return VoidType.INSTANCE;
+
+ if (t != null)
+ throw new IllegalArgumentException ("unable to convert type " + t.getClass().getName());
+ else
+ throw new IllegalArgumentException ("unable to convert type 'null'");
+ }
+
+ private BackendType convertJavaType (Type t) {
+ final Class<?> cls = (Class<?>) getField (t, "clazz");
+ return _backendTypes.findType(cls);
+ }
+
+ private BackendType convertEClassType (Type t) {
+ final EClass eClass = (EClass) getField(t, "eClass");
+ return _emfTypes.getTypeForEClassifier(eClass);
+ }
+
+ private BackendType convertEDataTypeType (Type t) {
+ final EDataType eClass = (EDataType) getField(t, "dataType");
+ return _emfTypes.getTypeForEClassifier(eClass);
+ }
+
+ private BackendType convertEEnumType (Type t) {
+ final EEnum eClass = (EEnum) getField(t, "eEnum");
+ return _emfTypes.getTypeForEClassifier(eClass);
+ }
+
+ private Object getField (Object o, String fieldName) {
+ try {
+ final Class<?> cls = o.getClass();
+ final Field f = cls.getDeclaredField(fieldName);
+ f.setAccessible(true);
+ return f.get(o);
+ } catch (Exception e) {
+ throw new RuntimeException (e);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/CheckConverter.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/CheckConverter.java
new file mode 100644
index 0000000..ef36b5d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/CheckConverter.java
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtend;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.emf.mwe.core.issues.Issues;
+import org.eclipse.internal.xtend.xtend.ast.Check;
+import org.eclipse.internal.xtend.xtend.ast.ExtensionFile;
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.common.SourcePos;
+import org.eclipse.xtend.backend.common.SyntaxConstants;
+import org.eclipse.xtend.backend.expr.AndExpression;
+import org.eclipse.xtend.backend.expr.IfExpression;
+import org.eclipse.xtend.backend.expr.InitClosureExpression;
+import org.eclipse.xtend.backend.expr.InvocationOnObjectExpression;
+import org.eclipse.xtend.backend.expr.LiteralExpression;
+import org.eclipse.xtend.backend.expr.LocalVarEvalExpression;
+import org.eclipse.xtend.backend.expr.SequenceExpression;
+import org.eclipse.xtend.backend.functions.SourceDefinedFunction;
+import org.eclipse.xtend.backend.syslib.SysLibNames;
+import org.eclipse.xtend.backend.types.builtin.CollectionType;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.middleend.xtend.internal.OldExpressionConverter;
+import org.eclipse.xtend.middleend.xtend.internal.OldHelper;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CheckConverter {
+ public static final String ALL_CHECKS_FUNCTION_NAME = "CheckAllChecks";
+
+ /**
+ * name of the parameter in which the Issues are passed to the check function. This is not intended to
+ * be edited in a source file, so it is chosen not to be a valid identifier to avoid name clashes.
+ */
+ public static final String ISSUES_PARAM_NAME = "$issues";
+ public static final String ALL_OBJECTS_PARAM_NAME = "$allObjects";
+
+ private final TypeToBackendType _typeConverter;
+ private final ExecutionContext _emptyExecutionContext;
+
+ public CheckConverter (ExecutionContext ctx, TypeToBackendType typeConverter) {
+ _emptyExecutionContext = ctx;
+ _typeConverter = typeConverter;
+ }
+
+
+ public NamedFunction createCheckFunction (BackendTypesystem ts, FunctionDefContext fdc, ExtensionFile extensionFile) {
+ final OldExpressionConverter exprConv = new OldExpressionConverter (_emptyExecutionContext.cloneWithResource (extensionFile), _typeConverter, OldHelper.normalizeXtendResourceName (extensionFile.getFullyQualifiedName()));
+ final List<String> paramNames = Arrays.asList (ISSUES_PARAM_NAME, ALL_OBJECTS_PARAM_NAME);
+ final List<BackendType> paramTypes = Arrays.asList (ts.findType (Issues.class), CollectionType.INSTANCE);
+
+ final List<ExpressionBase> allChecks = new ArrayList<ExpressionBase> ();
+ for (Check chk: extensionFile.getChecks())
+ allChecks.add (convertCheck (chk, exprConv));
+
+ final ExpressionBase body = new SequenceExpression (allChecks, exprConv.getSourcePos (extensionFile));
+
+ return new NamedFunction (ALL_CHECKS_FUNCTION_NAME, new SourceDefinedFunction (ALL_CHECKS_FUNCTION_NAME, paramNames, paramTypes, fdc, body, false, null));
+ }
+
+
+ private ExpressionBase convertCheck (Check chk, OldExpressionConverter exprConv) {
+ final SourcePos sourcePos = exprConv.getSourcePos (chk);
+
+ final ExpressionBase preCondExpression = (chk.getGuard() == null) ?
+ exprConv.convert (chk.getConstraint()) :
+ new AndExpression (exprConv.convert (chk.getGuard()), exprConv.convert (chk.getConstraint()), sourcePos);
+
+ final String addIssueMethodName = chk.isErrorCheck() ? "addError" : "addWarning";
+
+ final List<ExpressionBase> failureParams = new ArrayList<ExpressionBase> ();
+ failureParams.add (new LocalVarEvalExpression (ISSUES_PARAM_NAME, sourcePos));
+ failureParams.add (exprConv.convert(chk.getMsg()));
+ failureParams.add (new LocalVarEvalExpression (SyntaxConstants.THIS, sourcePos));
+
+ final ExpressionBase failureExpression = new InvocationOnObjectExpression (addIssueMethodName, failureParams, true, sourcePos);
+
+ final ExpressionBase onEachExpression = new IfExpression (preCondExpression, failureExpression, new LiteralExpression (null, sourcePos), sourcePos);
+
+ final List<ExpressionBase> typeSelectParams = new ArrayList<ExpressionBase> ();
+ typeSelectParams.add (new LocalVarEvalExpression (ALL_OBJECTS_PARAM_NAME, sourcePos));
+ typeSelectParams.add (new LiteralExpression (_typeConverter.convertToBackendType (chk.getType()), sourcePos));
+ final ExpressionBase typeSelectExpression = new InvocationOnObjectExpression (SysLibNames.TYPE_SELECT, typeSelectParams, true, sourcePos);
+
+ final List<ExpressionBase> collectParams = new ArrayList<ExpressionBase> ();
+ collectParams.add (typeSelectExpression);
+ collectParams.add (new InitClosureExpression (Arrays.asList(SyntaxConstants.THIS), Arrays.asList(ObjectType.INSTANCE), onEachExpression, sourcePos));
+ return new InvocationOnObjectExpression (SysLibNames.COLLECT, collectParams, true, sourcePos);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/JavaExtensionFunction.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/JavaExtensionFunction.java
new file mode 100644
index 0000000..c87980b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/JavaExtensionFunction.java
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtend;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.util.ErrorHandler;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class JavaExtensionFunction implements Function {
+ private final Method _mtd;
+ private final boolean _cached;
+ private final List<? extends BackendType> _paramTypes;
+
+ public JavaExtensionFunction (Method mtd, boolean cached, List<? extends BackendType> paramTypes) {
+ _mtd = mtd;
+ _cached = cached;
+ _paramTypes = paramTypes;
+ }
+
+ public ExpressionBase getGuard () {
+ return null;
+ }
+
+ public String getName () {
+ return _mtd.getName();
+ }
+
+ public List<? extends BackendType> getParameterTypes () {
+ return _paramTypes;
+ }
+
+ public Object invoke (ExecutionContext ctx, Object[] params) {
+ try {
+ return _mtd.invoke (null, params);
+ } catch (Exception e) {
+ ErrorHandler.handle(e);
+ return null; // to make the compiler happy - this is never executed
+ }
+ }
+
+ public boolean isCached () {
+ return _cached;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/OldExtensionConverter.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/OldExtensionConverter.java
new file mode 100644
index 0000000..e48cc97
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtend/OldExtensionConverter.java
@@ -0,0 +1,130 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtend;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.internal.xtend.expression.ast.Expression;
+import org.eclipse.internal.xtend.xtend.ast.Around;
+import org.eclipse.internal.xtend.xtend.ast.CreateExtensionStatement;
+import org.eclipse.internal.xtend.xtend.ast.ExpressionExtensionStatement;
+import org.eclipse.internal.xtend.xtend.ast.Extension;
+import org.eclipse.internal.xtend.xtend.ast.JavaExtensionStatement;
+import org.eclipse.xtend.backend.aop.AroundAdvice;
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.common.SyntaxConstants;
+import org.eclipse.xtend.backend.expr.CreateCachedExpression;
+import org.eclipse.xtend.backend.expr.LocalVarEvalExpression;
+import org.eclipse.xtend.backend.expr.NewLocalVarDefExpression;
+import org.eclipse.xtend.backend.functions.FunctionDefContextInternal;
+import org.eclipse.xtend.backend.functions.SourceDefinedFunction;
+import org.eclipse.xtend.expression.AnalysationIssue;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.middleend.xtend.internal.OldExpressionConverter;
+import org.eclipse.xtend.middleend.xtend.internal.TypeToBackendType;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single extension function
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OldExtensionConverter {
+ private final ExecutionContext _ctx;
+ private final TypeToBackendType _typeConverter;
+
+
+ public OldExtensionConverter (ExecutionContext ctx, TypeToBackendType typeConverter) {
+ _ctx = ctx;
+ _typeConverter = typeConverter;
+ }
+
+ public AroundAdvice create (Around around, FunctionDefContext fdc) {
+ final OldExpressionConverter exprConv = new OldExpressionConverter (_ctx, _typeConverter, "<around>");
+ final ExpressionBase body = convertExpression (around.getExpression(), exprConv.getAdviceLocalVarNames(), exprConv.getAdviceLocalVarTypes(_ctx), "<around>");
+ return exprConv.convertAdvice (body, around.getPointCut().getValue(), around.getParams(), around.isWildparams(), fdc);
+ }
+
+ /**
+ * converts an extension to a function, taking care of mutual registration with its fdc
+ */
+ public NamedFunction create (Extension extension, FunctionDefContextInternal fdc) {
+ final NamedFunction result = new NamedFunction (extension.getName(), createUnregistered (extension, fdc));
+ fdc.register (result, !extension.isPrivate());
+ return result;
+ }
+
+ private Function createUnregistered (Extension extension, FunctionDefContextInternal fdc) {
+ if (extension instanceof JavaExtensionStatement)
+ return createJavaExtension ((JavaExtensionStatement) extension);
+
+ if (extension instanceof ExpressionExtensionStatement)
+ return createExpressionExtension ((ExpressionExtensionStatement) extension, fdc);
+
+ if (extension instanceof CreateExtensionStatement)
+ return createCreateExtension ((CreateExtensionStatement) extension, fdc);
+
+ throw new IllegalArgumentException ("unsupported extension type " + extension.getClass().getName());
+ }
+
+ private List<BackendType> getParameterTypes (Extension extension) {
+ final List<Type> unconvertedParamTypes = extension.getParameterTypes();
+
+ final List<BackendType> result = new ArrayList<BackendType>();
+ for (Type t: unconvertedParamTypes)
+ result.add (_typeConverter.convertToBackendType(t));
+
+ return result;
+ }
+
+ private ExpressionBase convertExpression (Expression expr, List<String> localVarNames, List<Type> localVarTypes, String extensionName) {
+ ExecutionContext ctx = _ctx.cloneWithoutVariables();
+
+ for (int i=0; i<localVarNames.size(); i++)
+ ctx = ctx.cloneWithVariable(new Variable (localVarNames.get(i), localVarTypes.get (i)));
+
+ final OldExpressionConverter exprConverter = new OldExpressionConverter (ctx, _typeConverter, extensionName);
+ return exprConverter.convert (expr);
+ }
+
+ private Function createExpressionExtension (ExpressionExtensionStatement extension, FunctionDefContext fdc) {
+ return new SourceDefinedFunction (extension.getName(), extension.getParameterNames(), getParameterTypes (extension), //
+ fdc, convertExpression (extension.getExpression(), extension.getParameterNames(), extension.getParameterTypes(), extension.getName ()), extension.isCached(), null);
+ }
+
+ private Function createCreateExtension (CreateExtensionStatement extension, FunctionDefContext fdc) {
+ final Type createdType = _ctx.getTypeForName (extension.getReturnTypeIdentifier().getValue());
+ final List<ExpressionBase> paramExprs = new ArrayList<ExpressionBase> ();
+ for (String varName: extension.getParameterNames())
+ paramExprs.add (new LocalVarEvalExpression (varName, OldExpressionConverter.getSourcePos (extension, extension.getName())));
+
+ final ExpressionBase body = convertExpression (extension.getExpression(), extension.getParameterNames(), extension.getParameterTypes(), extension.getName ());
+ final ExpressionBase createExpr = new CreateCachedExpression (_typeConverter.convertToBackendType(createdType), paramExprs, OldExpressionConverter.getSourcePos (extension, extension.getName()));
+ final ExpressionBase createWrapper = new NewLocalVarDefExpression (SyntaxConstants.THIS, createExpr, body, OldExpressionConverter.getSourcePos (extension, extension.getName ()));
+
+ return new SourceDefinedFunction (extension.getName(), extension.getParameterNames(), getParameterTypes(extension), fdc, createWrapper, true, null);
+ }
+
+ private Function createJavaExtension (JavaExtensionStatement extension) {
+ final Method mtd = extension.getJavaMethod (_ctx, new HashSet<AnalysationIssue>());
+ return new JavaExtensionFunction (mtd, extension.isCached(), getParameterTypes(extension));
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XpandIsDeleteLine.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XpandIsDeleteLine.java
new file mode 100644
index 0000000..b221acc
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XpandIsDeleteLine.java
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+
+/**
+ * This class supports the "isDeleteLine" feature of Xpand, i.e. the "-" at the end of a statement that deletes
+ * whitespace both backward and forward.<br>
+ *
+ * Since it is non-local functionality, it requires global postprocessing. For this purpose, a marker string is inserted wherever
+ * this deletion of whitespace should be performed.<br>
+ *
+ * Since this postprocessing requires transformation of the entire contents of a file into a flat string, this feature precludes
+ * streaming. Therefore a flag is introduced to indicate if the feature was actually used. This requires resetting at the beginning
+ * of each FILE statement.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class XpandIsDeleteLine {
+ public static final String MARKER_FOR_IS_DELETE_LINE = "MARKER_FOR_XPAND_ISDELETELINE_\ufa92\u9988\u7123\u9881\u5499\u9284\u9934\ufa92\u9988\u7123\u9882\u5499\u9284\u9934_ENDMARKER";
+
+ private boolean _isInScope = false;
+ private boolean _hasDeleteLine = false;
+
+
+ public void XpandInitNewScope () {
+ if (_isInScope)
+ throw new IllegalStateException ("nested FILE statements are not permitted");
+ _isInScope = true;
+ _hasDeleteLine = false;
+ }
+
+ public void XpandRegisterDeleteLine() {
+ _hasDeleteLine = true;
+ }
+
+ public CharSequence XpandPostprocess (CharSequence s) {
+ try {
+ if (! _hasDeleteLine)
+ return s;
+
+ String result = s.toString();
+ int indMarker = result.indexOf (MARKER_FOR_IS_DELETE_LINE);
+
+ while (indMarker >= 0) {
+ // if and only if there is nothing but whitespace between the marker and the previous newline, delete this whitespace (leaving the newline alone)
+ final int startOfDelete = indBeginDelete (result, indMarker);
+
+ // delete all whitespace after the marker up to, and including, the subsequent newline - or nothing, if there is anything but whitespace between the marker and the subsequent newline
+ final int endOfDelete = indEndDelete (result, indMarker);
+
+ result = result.substring(0, startOfDelete) + result.substring (endOfDelete);
+ indMarker = result.indexOf (MARKER_FOR_IS_DELETE_LINE);
+ }
+
+ return result;
+ }
+ finally {
+ _isInScope = false;
+ _hasDeleteLine = false;
+ }
+ }
+
+ private boolean isNewLine(char c) {
+ return c == '\n' || c == '\r';
+ }
+
+ private int indEndDelete (String buffer, int indMarker) {
+ boolean wsOnly = true;
+ int result = indMarker + MARKER_FOR_IS_DELETE_LINE.length();
+
+ while (result < buffer.length() && wsOnly) {
+ final char c = buffer.charAt (result);
+ wsOnly = Character.isWhitespace(c);
+ if (wsOnly && isNewLine(c)) {
+ if (c == '\r' && result + 1 < buffer.length() && buffer.charAt (result + 1) == '\n')
+ result++;
+ return result + 1;
+ }
+
+ result++;
+ }
+
+ return indMarker + MARKER_FOR_IS_DELETE_LINE.length();
+ }
+
+ private int indBeginDelete (String buffer, int indMarker) {
+ boolean wsOnly = true;
+ int result = indMarker;
+
+ while (result > 0 && wsOnly) {
+ final char c = buffer.charAt (result - 1);
+ wsOnly = Character.isWhitespace(c);
+ if (wsOnly && isNewLine (c))
+ return result;
+
+ result--;
+ }
+
+ if (wsOnly)
+ return 0;
+ else
+ return indMarker;
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendCollectionOperations.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendCollectionOperations.java
new file mode 100644
index 0000000..366580d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendCollectionOperations.java
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+import java.util.Collection;
+
+import org.eclipse.xtend.backend.common.EfficientLazyString;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.functions.java.AbstractExecutionContextAware;
+import org.eclipse.xtend.backend.syslib.StringOperations;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XtendCollectionOperations extends AbstractExecutionContextAware {
+
+ /**
+ * invokes the function for each element of the collection, concatenating the results.
+ */
+ public CharSequence XpandForEach (Collection<?> c, Function f) {
+ return XpandForEach (c, f, null);
+ }
+
+ /**
+ * invokes the function for each element of the collection, concatenating the results and
+ * adding the separator between them.
+ */
+ public CharSequence XpandForEach (Collection<?> c, Function f, CharSequence separator) {
+ EfficientLazyString result = new EfficientLazyString ();
+
+ boolean first = true;
+
+ for (Object o: c) {
+ if (first)
+ first = false;
+ else
+ result = EfficientLazyString.createAppendedString (result, separator);
+
+ final Object part = f.invoke (_ctx, new Object[] {o});
+ if (part != null)
+ result = EfficientLazyString.createAppendedString (result, StringOperations.overridableToString (_ctx, o));
+ }
+
+ return result;
+ }
+
+ /**
+ * invokes the function for each element of the collection, concatenating the results. The function
+ * is passed an "XtendIterator" instance as a second parameter.
+ */
+ public CharSequence XpandForEachWithIterator (Collection<?> c, Function f) {
+ return XpandForEachWithIterator (c, f, null);
+ }
+
+ /**
+ * invokes the function for each element of the collection, concatenating the results and
+ * adding the separator between themn. The function is passed an "XtendIterator" instance
+ * as a second parameter.
+ */
+ public CharSequence XpandForEachWithIterator (Collection<?> c, Function f, CharSequence separator) {
+ EfficientLazyString result = new EfficientLazyString ();
+
+ boolean first = true;
+
+ final XtendIterator iter = new XtendIterator (c.size());
+ for (Object o: c) {
+ if (first)
+ first = false;
+ else
+ result = EfficientLazyString.createAppendedString (result, separator);
+
+ final Object part = f.invoke (_ctx, new Object[] {o, iter});
+ if (part != null)
+ result = EfficientLazyString.createAppendedString (result, StringOperations.overridableToString (_ctx, o));
+
+ iter.increment();
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendGlobalVarOperations.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendGlobalVarOperations.java
new file mode 100644
index 0000000..eeef0c0
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendGlobalVarOperations.java
@@ -0,0 +1,27 @@
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.xtend.backend.functions.java.AbstractExecutionContextAware;
+
+
+public class XtendGlobalVarOperations extends AbstractExecutionContextAware {
+ public static final Class<?> GLOBAL_VAR_VALUES_KEY = new Object(){}.getClass ();
+ final Log _log = LogFactory.getLog(getClass());
+
+ public Object XtendGlobalVar (String varName) {
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> globalParams = (Map<String, Object>) _ctx.getContributionStateContext().retrieveState (GLOBAL_VAR_VALUES_KEY);
+ if (globalParams == null)
+ return null;
+
+ final Object result = globalParams.get (varName);
+
+ if (_log.isDebugEnabled())
+ _log.debug ("retrieving global var " + varName + ": " + result);
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendIterator.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendIterator.java
new file mode 100644
index 0000000..b90db71
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendIterator.java
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XtendIterator {
+ private long _counter = 0L;
+ private final long _elementCount;
+
+
+ public XtendIterator (long elementCount) {
+ _elementCount = elementCount;
+ }
+
+ public void increment() {
+ _counter++;
+ }
+
+ public boolean isLastIteration() {
+ return _counter + 1 == _elementCount;
+ }
+
+ public boolean isFirstIteration() {
+ return _counter == 0;
+ }
+
+ public long getCounter0() {
+ return _counter;
+ }
+
+ public long getCounter1() {
+ return _counter+1;
+ }
+
+ public long getElementCount() {
+ return _elementCount;
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibContributor.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibContributor.java
new file mode 100644
index 0000000..82e7775
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibContributor.java
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+import java.util.Collection;
+
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.DuplicateAwareNamedFunctionCollection;
+import org.eclipse.xtend.backend.functions.java.JavaFunctionClassContributor;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class XtendLibContributor {
+ private final DuplicateAwareNamedFunctionCollection _functions = new DuplicateAwareNamedFunctionCollection ();
+
+ public XtendLibContributor (BackendTypesystem ts) {
+ registerExtensionClass (ts, XtendCollectionOperations.class);
+ registerExtensionClass (ts, XpandIsDeleteLine.class);
+ registerExtensionClass (ts, XtendGlobalVarOperations.class);
+ }
+
+ private void registerExtensionClass (BackendTypesystem ts, Class<?> cls) {
+ for (NamedFunction f: new JavaFunctionClassContributor (cls, ts).getContributedFunctions())
+ _functions.register (f);
+ }
+
+ public Collection<NamedFunction> getContributedFunctions () {
+ return _functions.getFunctions();
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibNames.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibNames.java
new file mode 100644
index 0000000..e4e1a21
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/internal/xtendlib/XtendLibNames.java
@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.internal.xtendlib;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface XtendLibNames {
+ String FOREACH_WITHOUT_ITERATOR = "XpandForEach";
+ String FOREACH_WITH_ITERATOR = "XpandForEachWithIterator";
+
+ String DELETE_LINE_INIT = "XpandInitNewScope";
+ String DELETE_LINE_REGISTER = "XpandRegisterDeleteLine";
+ String DELETE_LINE_POSTPROCESS = "XpandPostprocess";
+
+ String GLOBAL_VAR_VALUE = "XtendGlobalVar";
+}
diff --git a/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/plugin/OldXtendRegistryFactory.java b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/plugin/OldXtendRegistryFactory.java
new file mode 100644
index 0000000..99387ef
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.xtend/src/org/eclipse/xtend/middleend/xtend/plugin/OldXtendRegistryFactory.java
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2008 Arno Haase.
+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
+
+Contributors:
+ Arno Haase - initial API and implementation
+ */
+package org.eclipse.xtend.middleend.xtend.plugin;
+
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEnd;
+import org.eclipose.xtend.middleend.plugins.LanguageSpecificMiddleEndFactory;
+import org.eclipse.xtend.middleend.xtend.OldXtendRegistry;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class OldXtendRegistryFactory implements LanguageSpecificMiddleEndFactory {
+
+ public LanguageSpecificMiddleEnd create (Object specificData) {
+ return new OldXtendRegistry (specificData);
+ }
+
+ public String getName () {
+ return "Xtend";
+ }
+
+ public int getPriority () {
+ return 0;
+ }
+}