summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbkolb2008-01-11 06:18:55 (EST)
committer bkolb2008-01-11 06:18:55 (EST)
commitcc2b24f2d9c6fa5ae561dd2b9467e271eafe418c (patch)
tree57c4b7f105ce7b759b27068f98d23df956c26ee5
parent22dc63abab81d5372bf551f854e9f0a6e0ad3c82 (diff)
downloadorg.eclipse.xpand-cc2b24f2d9c6fa5ae561dd2b9467e271eafe418c.zip
org.eclipse.xpand-cc2b24f2d9c6fa5ae561dd2b9467e271eafe418c.tar.gz
org.eclipse.xpand-cc2b24f2d9c6fa5ae561dd2b9467e271eafe418c.tar.bz2
initial
-rw-r--r--plugins/org.eclipse.xtend.backend/.classpath7
-rw-r--r--plugins/org.eclipse.xtend.backend/.cvsignore1
-rw-r--r--plugins/org.eclipse.xtend.backend/.project28
-rw-r--r--plugins/org.eclipse.xtend.backend/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.xtend.backend/build.properties4
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/BackendFacade.java22
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/CreationCacheImpl.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/ExecutionContextImpl.java74
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/FunctionInvokerImpl.java34
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/GlobalVarContextImpl.java19
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendType.java26
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendTypesystem.java22
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Constants.java14
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ContributionStateContext.java26
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/CreationCache.java12
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/EfficientLazyString.java100
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionContext.java24
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionException.java42
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionListener.java20
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExpressionBase.java54
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Function.java21
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionDefContext.java35
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionInvoker.java14
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/GlobalVarContext.java12
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/LocalVarContext.java32
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/NamedFunction.java62
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Property.java16
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/SourcePos.java35
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/StaticProperty.java15
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/AndExpression.java41
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateCachedExpression.java36
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateUncachedExpression.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurriedFunction.java64
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurryingExpression.java35
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/GlobalVarExpression.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/HidingLocalVarDefExpression.java37
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/IfExpression.java37
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InitClosureExpression.java36
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnCollectionExpression.java53
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnObjectExpression.java34
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnWhateverExpression.java54
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/ListLiteralExpression.java32
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LiteralExpression.java24
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LocalVarEvalExpression.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/NewLocalVarDefExpression.java36
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/OrExpression.java41
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnCollectionExpression.java43
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnObjectExpression.java33
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnWhateverExpression.java60
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SequenceExpression.java31
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SetPropertyExpression.java41
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SwitchExpression.java55
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/Closure.java84
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareFunctionCollection.java68
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareNamedFunctionCollection.java79
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/FunctionDefContextImpl.java148
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/PolymorphicResolver.java111
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/SourceDefinedFunction.java88
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/TypesComparator.java43
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/iface/BackendContributor.java26
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/AbstractType.java107
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/CompositeTypesystem.java124
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BooleanType.java19
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltInOperation.java39
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltinProperty.java64
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/CollectionType.java28
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/DoubleType.java19
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/FunctionType.java45
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ListType.java26
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/LongType.java24
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ObjectType.java19
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/PropertyType.java27
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/SetType.java28
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StaticPropertyType.java30
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StringType.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/TypeType.java45
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/VoidType.java21
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Cache.java28
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/CollectionHelper.java14
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/DoubleKeyCache.java30
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ErrorHandler.java27
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/FatalException.java31
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/NullWriter.java25
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Pair.java60
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ReflectionHelper.java22
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ResourceToList.java62
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/StringHelper.java274
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/SyntaxConstants.java24
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/TripleKeyCache.java26
-rw-r--r--plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Triplet.java67
-rw-r--r--plugins/org.eclipse.xtend.backend/todo.txt100
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/.classpath7
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/.project28
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/build.properties4
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/JavaExtensionFunction.java52
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldDefinitionConverter.java318
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExpressionConverter.java397
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExtensionConverter.java111
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendHelper.java19
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendRegistry.java159
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/TypeToBackendType.java167
-rw-r--r--plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/XtendBackendContributor.java57
-rw-r--r--plugins/org.eclipse.xtend.middleend/.classpath7
-rw-r--r--plugins/org.eclipse.xtend.middleend/.cvsignore1
-rw-r--r--plugins/org.eclipse.xtend.middleend/.project28
-rw-r--r--plugins/org.eclipse.xtend.middleend/META-INF/MANIFEST.MF10
-rw-r--r--plugins/org.eclipse.xtend.middleend/build.properties4
-rw-r--r--plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/BackendTypesystemFactory.java42
-rw-r--r--plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/FunctionDefContextFactory.java23
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/.classpath7
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/.cvsignore1
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/.project28
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/META-INF/MANIFEST.MF9
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/build.properties4
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/FirstAttempt.java36
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/Person.java28
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/first.ext14
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/imported.ext4
-rw-r--r--tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/reexported.ext5
120 files changed, 5419 insertions, 0 deletions
diff --git a/plugins/org.eclipse.xtend.backend/.classpath b/plugins/org.eclipse.xtend.backend/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/.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.backend/.cvsignore b/plugins/org.eclipse.xtend.backend/.cvsignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/org.eclipse.xtend.backend/.project b/plugins/org.eclipse.xtend.backend/.project
new file mode 100644
index 0000000..5dee6dd
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.backend</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.backend/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtend.backend/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..67e0f7c
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Backend Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.backend
+Bundle-Version: 1.0.0
+Export-Package: org.eclipse.xtend.backend,
+ org.eclipse.xtend.backend.common,
+ org.eclipse.xtend.backend.expr,
+ org.eclipse.xtend.backend.functions,
+ org.eclipse.xtend.backend.iface,
+ org.eclipse.xtend.backend.types,
+ org.eclipse.xtend.backend.types.builtin,
+ org.eclipse.xtend.backend.util
+Require-Bundle: org.apache.commons.logging
diff --git a/plugins/org.eclipse.xtend.backend/build.properties b/plugins/org.eclipse.xtend.backend/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/BackendFacade.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/BackendFacade.java
new file mode 100644
index 0000000..c67a41c
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/BackendFacade.java
@@ -0,0 +1,22 @@
+package org.eclipse.xtend.backend;
+
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class BackendFacade {
+ public static ExecutionContext createExecutionContext (FunctionDefContext initialContext, BackendTypesystem typesystem) {
+ return new ExecutionContextImpl (initialContext, typesystem);
+ }
+
+ public static Object invoke (ExecutionContext ctx, String functionName, List<? extends Object> params) {
+ return ctx.getFunctionDefContext().invoke(ctx, functionName, params);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/CreationCacheImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/CreationCacheImpl.java
new file mode 100644
index 0000000..f6cf78f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/CreationCacheImpl.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend;
+
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.CreationCache;
+import org.eclipse.xtend.backend.util.DoubleKeyCache;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class CreationCacheImpl implements CreationCache {
+ private DoubleKeyCache<BackendType, List<Object>, Object> _cache = new DoubleKeyCache<BackendType, List<Object>, Object> () {
+ @Override
+ protected Object create(BackendType t, List<Object> key2) {
+ return t.create();
+ }
+ };
+
+ public Object createRaw (BackendType t, List<Object> idParams) {
+ return _cache.get (t, idParams);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/ExecutionContextImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/ExecutionContextImpl.java
new file mode 100644
index 0000000..b19a4c6
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/ExecutionContextImpl.java
@@ -0,0 +1,74 @@
+package org.eclipse.xtend.backend;
+
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.Constants;
+import org.eclipse.xtend.backend.common.ContributionStateContext;
+import org.eclipse.xtend.backend.common.CreationCache;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.FunctionInvoker;
+import org.eclipse.xtend.backend.common.GlobalVarContext;
+import org.eclipse.xtend.backend.common.LocalVarContext;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class ExecutionContextImpl implements ExecutionContext {
+ private final CreationCache _creationCache = new CreationCacheImpl ();
+ private FunctionDefContext _functionDefContext;
+ private LocalVarContext _localVarContext = new LocalVarContext ();
+ private final FunctionInvoker _functionInvoker = new FunctionInvokerImpl ();
+ private final BackendTypesystem _typeSystem;
+ private final GlobalVarContext _globalVarContext = new GlobalVarContextImpl ();
+
+ private final ContributionStateContext _contributionStateContext = new ContributionStateContext ();
+
+ public ExecutionContextImpl (FunctionDefContext initialFunctionDefContext, BackendTypesystem typesystem) {
+ _functionDefContext = initialFunctionDefContext;
+ _typeSystem = typesystem;
+ }
+
+ public CreationCache getCreationCache() {
+ return _creationCache;
+ }
+
+ public FunctionDefContext getFunctionDefContext() {
+ return _functionDefContext;
+ }
+
+ public void setFunctionDefContext(FunctionDefContext ctx) {
+ _functionDefContext = ctx;
+ }
+
+ public LocalVarContext getLocalVarContext() {
+ return _localVarContext;
+ }
+
+ public void setLocalVarContext(LocalVarContext ctx) {
+ _localVarContext = ctx;
+ }
+
+ public FunctionInvoker getFunctionInvoker() {
+ return _functionInvoker;
+ }
+
+ public BackendTypesystem getTypesystem() {
+ return _typeSystem;
+ }
+
+ public GlobalVarContext getGlobalVarContext() {
+ return _globalVarContext;
+ }
+
+ public void logNullDeRef (SourcePos pos) {
+ LogFactory.getLog (Constants.LOG_NULL_DEREF).warn ("dereferenced null (" + pos + ")");
+ }
+
+ public ContributionStateContext getContributionStateContext () {
+ return _contributionStateContext;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/FunctionInvokerImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/FunctionInvokerImpl.java
new file mode 100644
index 0000000..a158737
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/FunctionInvokerImpl.java
@@ -0,0 +1,34 @@
+package org.eclipse.xtend.backend;
+
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.common.FunctionInvoker;
+import org.eclipse.xtend.backend.util.DoubleKeyCache;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class FunctionInvokerImpl implements FunctionInvoker {
+ private final DoubleKeyCache <Function, List<?>, Object> _cache = new DoubleKeyCache<Function, List<?>, Object> () {
+ @Override
+ protected Object create (Function f, List<?> params) {
+ return f.invoke (_ctx, params.toArray());
+ }
+ };
+
+ private ExecutionContext _ctx;
+
+ public Object invoke(ExecutionContext ctx, Function f, List<?> params) {
+ if (f.isCached()) {
+ _ctx = ctx;
+ return _cache.get(f, params);
+ }
+ else {
+ return f.invoke(ctx, params.toArray());
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/GlobalVarContextImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/GlobalVarContextImpl.java
new file mode 100644
index 0000000..5012a52
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/GlobalVarContextImpl.java
@@ -0,0 +1,19 @@
+package org.eclipse.xtend.backend;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.xtend.backend.common.GlobalVarContext;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class GlobalVarContextImpl implements GlobalVarContext {
+ private final Map<String, Object> _globalVars = new HashMap<String, Object> ();
+
+ public Map<String, Object> getGlobalVars() {
+ return _globalVars;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendType.java
new file mode 100644
index 0000000..d5166df
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendType.java
@@ -0,0 +1,26 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.Collection;
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface BackendType {
+ Object create ();
+
+ boolean isAssignableFrom (BackendType other);
+
+ Object getProperty (ExecutionContext ctx, Object o, String name);
+ void setProperty (ExecutionContext ctx, Object o, String name, Object value);
+
+ Collection<? extends NamedFunction> getBuiltinOperations ();
+
+ // stuff required for reflection / meta programming
+ String getName ();
+ Collection<? extends BackendType> getSuperTypes ();
+ Map<String, ? extends Property> getProperties ();
+ Map<String, ? extends StaticProperty> getStaticProperties ();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendTypesystem.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendTypesystem.java
new file mode 100644
index 0000000..ef3ec5d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendTypesystem.java
@@ -0,0 +1,22 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface BackendTypesystem {
+ /**
+ * returns the type for a given object or, if this type system does not feel responsible, null.
+ */
+ BackendType findType (Object o);
+
+ /**
+ * returns the type for instances of a given class or, if this type system does not feel responsible, null.
+ */
+ BackendType findType (Class<?> cls);
+
+
+ void setRootTypesystem (BackendTypesystem ts);
+ BackendTypesystem getRootTypesystem ();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Constants.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Constants.java
new file mode 100644
index 0000000..2a55090
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Constants.java
@@ -0,0 +1,14 @@
+package org.eclipse.xtend.backend.common;
+
+import org.eclipse.xtend.backend.BackendFacade;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface Constants {
+ String THIS_NAME = "this";
+
+ String LOG_NULL_DEREF = BackendFacade.class.getPackage().getName() + ".NULL_DEREF";
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ContributionStateContext.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ContributionStateContext.java
new file mode 100644
index 0000000..df8d149
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ContributionStateContext.java
@@ -0,0 +1,26 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * This class serves as "black box" storage for runtime state contributors may wish to store. It is
+ * accessed by a "unique key" which must be chosen by the contributor to be guaranteed unique. The
+ * recommended best practice is to use a Class object specific to the contributor.<br>
+ *
+ * This state is re-initialized for every new ExecutionContext.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class ContributionStateContext {
+ private Map<Object, Object> _state = new HashMap<Object, Object>();
+
+ public Object retrieveState (Object uniqueKey) {
+ return _state.get (uniqueKey);
+ }
+
+ public void storeState (Object uniqueKey, Object state) {
+ _state.put (uniqueKey, state);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/CreationCache.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/CreationCache.java
new file mode 100644
index 0000000..0e73c6e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/CreationCache.java
@@ -0,0 +1,12 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.List;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface CreationCache {
+ Object createRaw (BackendType t, List<Object> idParams);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/EfficientLazyString.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/EfficientLazyString.java
new file mode 100644
index 0000000..21fee63
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/EfficientLazyString.java
@@ -0,0 +1,100 @@
+package org.eclipse.xtend.backend.common;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class is a "String" implementation that is optimized for efficient concatenation of arbitrary objects. It
+ * has the specialty of converting its contents to Strings lazily, i.e. only when the toString method is called.
+ * That allows slot-like behavior where an element that was added to the string can be modified later so that
+ * the modified version actually gets into the resulting string.
+ * <p>
+ * Another specialty is that this class can stream its contents to a Writer without the necessity of creating an
+ * intermediate string in memory.
+ * <p>
+ * One non-obvious benefit of consistent usage of this class is that mostly string constants from classes are stored
+ * here, and they are "interned". This can significantly decrease memory footprint and improve performance.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class EfficientLazyString implements CharSequence {
+ private boolean _isDirty = false;
+ private String _asString = "";
+ private final List<Object> _contents = new ArrayList<Object>();
+
+ private EfficientLazyString _parent = null;
+
+ public void append (Object o) {
+ if (o != null) {
+ setDirty();
+ _contents.add(o);
+ if (o instanceof EfficientLazyString) {
+ ((EfficientLazyString) o)._parent = this;
+ }
+ }
+ }
+
+ /**
+ * if a hierarchy of EfficientLazyStrings was toString'ed, and later on of the parts down in
+ * the tree becomes dirty again, all parents are dirty as well by implication.
+ */
+ private void setDirty () {
+ _isDirty = true;
+ if (_parent != null)
+ _parent.setDirty();
+ }
+
+ public void writeTo (Writer w) throws IOException {
+ if (_isDirty) {
+ for (Object o: _contents) {
+ if (o instanceof EfficientLazyString)
+ ((EfficientLazyString) o).writeTo(w);
+ else
+ w.write(o.toString());
+ }
+ }
+ else {
+ w.write(_asString);
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (_isDirty) {
+ final StringBuilder result = new StringBuilder (32768); // big initial capacity - this is only a temporary object, and the contents can get rather big
+
+ for (Object o: _contents)
+ result.append(o);
+
+ _asString = result.toString();
+ }
+ return _asString;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ throw new IllegalArgumentException ("EfficientLazyString can not be compared directly - compare string representations");
+ }
+
+ @Override
+ public int hashCode() {
+ throw new IllegalArgumentException ("EfficientLazyString can not be compared directly - compare string representations");
+ }
+
+ public char charAt(int index) {
+ return toString().charAt(index);
+ }
+
+ public int length() {
+ return toString().length();
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return toString().subSequence(start, end);
+ }
+}
+
+
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionContext.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionContext.java
new file mode 100644
index 0000000..1df132b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionContext.java
@@ -0,0 +1,24 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface ExecutionContext {
+ LocalVarContext getLocalVarContext ();
+ void setLocalVarContext (LocalVarContext ctx);
+
+ GlobalVarContext getGlobalVarContext ();
+
+ BackendTypesystem getTypesystem ();
+ FunctionDefContext getFunctionDefContext ();
+ void setFunctionDefContext (FunctionDefContext ctx);
+
+ FunctionInvoker getFunctionInvoker ();
+ CreationCache getCreationCache ();
+
+ void logNullDeRef (SourcePos pos);
+
+ ContributionStateContext getContributionStateContext ();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionException.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionException.java
new file mode 100644
index 0000000..55a7f32
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionException.java
@@ -0,0 +1,42 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.xtend.backend.util.Pair;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class ExecutionException extends RuntimeException {
+ private final List<Pair<SourcePos, Map<String, Object>>> _stackTrace = new ArrayList<Pair<SourcePos,Map<String,Object>>> ();
+
+
+ public ExecutionException (Exception exc) {
+ super (exc);
+ }
+
+
+ public ExecutionException (Exception exc, SourcePos sourcePos, Map<String, Object> localVars) {
+ super (exc);
+ addStackTraceElement (sourcePos, localVars);
+ }
+
+ public void addStackTraceElement (SourcePos sourcePos, Map<String, Object> localVars) {
+ _stackTrace.add (new Pair<SourcePos, Map<String, Object>> (sourcePos, localVars));
+ }
+
+ @Override
+ public String getMessage () {
+ final StringBuilder result = new StringBuilder ();
+
+ result.append (getCause().getMessage() + "\n");
+ for (Pair<SourcePos, Map<String, Object>> ste: _stackTrace)
+ result.append ("at " + ste.getFirst() + " " + ste.getSecond() + "\n");
+
+ return result.toString();
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionListener.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionListener.java
new file mode 100644
index 0000000..1bcf8f0
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionListener.java
@@ -0,0 +1,20 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ * This interface allows an interested party to register as a listener for the
+ * execution of code in the backend. The model is slightly different from the
+ * typical listener usage in that there are no "rich" events. Instead, just the
+ * current ExecutionContext is passed as a parameter.<br>
+ *
+ * So there is no data that would allow the identification of the sender or a
+ * specific receiver. The intended usage model is that the middle end registers
+ * a specific ExecutionListener instance per backend element that takes care of
+ * these mapping issues.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface ExecutionListener {
+ void preExecute (ExecutionContext ctx);
+ void postExecute (Object result, ExecutionContext ctx);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExpressionBase.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExpressionBase.java
new file mode 100644
index 0000000..405f8c9
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExpressionBase.java
@@ -0,0 +1,54 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class ExpressionBase {
+ private final SourcePos _sourcePos;
+ private final List<ExecutionListener> _listeners = new ArrayList<ExecutionListener> ();
+
+ public ExpressionBase (SourcePos sourcePos) {
+ _sourcePos = sourcePos;
+ }
+
+ public SourcePos getPos () {
+ return _sourcePos;
+ }
+
+ public void registerExecutionListener (ExecutionListener l) {
+ _listeners.add (l);
+ }
+
+ private void firePreEvent (ExecutionContext ctx) {
+ for (ExecutionListener l: _listeners)
+ l.preExecute (ctx);
+ }
+
+ private void firePostEvent (Object result, ExecutionContext ctx) {
+ for (int i=_listeners.size()-1; i >= 0; i--)
+ _listeners.get(i).postExecute (result, ctx);
+ }
+
+ public final Object evaluate (ExecutionContext ctx) {
+ try {
+ firePreEvent (ctx);
+ final Object result = evaluateInternal (ctx);
+ firePostEvent (result, ctx);
+ return result;
+ }
+ catch (ExecutionException exc) {
+ exc.addStackTraceElement (_sourcePos, ctx.getLocalVarContext().getLocalVars());
+ throw exc;
+ }
+ catch (Exception exc) {
+ throw new ExecutionException (exc, _sourcePos, ctx.getLocalVarContext().getLocalVars());
+ }
+ }
+
+ protected abstract Object evaluateInternal (ExecutionContext ctx);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Function.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Function.java
new file mode 100644
index 0000000..bdb2baa
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Function.java
@@ -0,0 +1,21 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.List;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface Function {
+ List<? extends BackendType> getParameterTypes ();
+
+ /**
+ * this method is permitted to modify the param array that is passed in
+ */
+ Object invoke (ExecutionContext ctx, Object[] params);
+ boolean isCached ();
+
+ /** returns the expression that guards this function - or null, if there is no guard.*/
+ ExpressionBase getGuard();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionDefContext.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionDefContext.java
new file mode 100644
index 0000000..82e1829
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionDefContext.java
@@ -0,0 +1,35 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * A FunctionDefContext is roughly the backend representation of a compilation unit - it stands for all
+ * functions that are visible from a given point in the code, and every function knows the FunctionDefContext
+ * that is valid within its body.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface FunctionDefContext {
+ Object invoke (ExecutionContext ctx, String functionName, List<? extends Object> params);
+
+ /**
+ * for reflection. This method returns separately registered functions, not those "built into" the
+ * type.
+ */
+ Collection<NamedFunction> getByFirstParameterType (BackendType firstParameterType);
+
+ /**
+ * for reflection. This method returns all functions, both those built-into the types and those
+ * registered separately.
+ */
+ Function getMatch (ExecutionContext ctx, String name, List<BackendType> params);
+
+ /**
+ * for dynamic matching, e.g. to determine if a function should be called on a collection itself or
+ * on all of its members. This method matches against all functions, both those built into the
+ * types and those registered separately.
+ */
+ boolean hasMatch (ExecutionContext ctx, String functionName, List<? extends Object> params);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionInvoker.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionInvoker.java
new file mode 100644
index 0000000..7d7e373
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionInvoker.java
@@ -0,0 +1,14 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.List;
+
+
+/**
+ * This abstraction takes care of caching.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface FunctionInvoker {
+ Object invoke (ExecutionContext ctx, Function f, List<?> params);
+
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/GlobalVarContext.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/GlobalVarContext.java
new file mode 100644
index 0000000..86c01d1
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/GlobalVarContext.java
@@ -0,0 +1,12 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface GlobalVarContext {
+ Map<String, Object> getGlobalVars();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/LocalVarContext.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/LocalVarContext.java
new file mode 100644
index 0000000..9aa27f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/LocalVarContext.java
@@ -0,0 +1,32 @@
+package org.eclipse.xtend.backend.common;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class LocalVarContext {
+ private final Map<String, Object> _localVars = new HashMap<String, Object>();
+
+ public LocalVarContext () {
+ }
+
+ public LocalVarContext (Object thisValue) {
+ _localVars.put(Constants.THIS_NAME, thisValue);
+ }
+
+ public Map<String, Object> getLocalVars() {
+ return _localVars;
+ }
+
+ public boolean hasThis() {
+ return _localVars.containsKey(Constants.THIS_NAME);
+ }
+
+ public Object getThis() {
+ return _localVars.get(Constants.THIS_NAME);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/NamedFunction.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/NamedFunction.java
new file mode 100644
index 0000000..55352f3
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/NamedFunction.java
@@ -0,0 +1,62 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ * This class represents the binding of a function to a name. It is a separate
+ * concept from Function itself so that the same function can have several names.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class NamedFunction {
+ private final Function _function;
+ private final String _name;
+
+ public NamedFunction (String name, Function f) {
+ _function = f;
+ _name = name;
+ }
+
+ public Function getFunction () {
+ return _function;
+ }
+
+ public String getName () {
+ return _name;
+ }
+
+ @Override
+ public int hashCode () {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((_function == null) ? 0 : _function.hashCode());
+ result = prime * result + ((_name == null) ? 0 : _name.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 NamedFunction other = (NamedFunction) obj;
+ if (_function == null) {
+ if (other._function != null)
+ return false;
+ } else if (!_function.equals(other._function))
+ return false;
+ if (_name == null) {
+ if (other._name != null)
+ return false;
+ } else if (!_name.equals(other._name))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString () {
+ return "NamedFunction [" + _name + ": " + _function + "]";
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Property.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Property.java
new file mode 100644
index 0000000..f227396
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Property.java
@@ -0,0 +1,16 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface Property {
+ String getName ();
+ BackendType getOwner ();
+
+ BackendType getType ();
+
+ Object get (ExecutionContext ctx, Object o);
+ void set (ExecutionContext ctx, Object o, Object newValue);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/SourcePos.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/SourcePos.java
new file mode 100644
index 0000000..fe65e52
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/SourcePos.java
@@ -0,0 +1,35 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class SourcePos {
+ private final String _compilationUnit;
+ private final String _callableName;
+ private final int _lineNumber;
+
+ public SourcePos (String compilationUnit, String callableName, int lineNumber) {
+ super();
+ _compilationUnit = compilationUnit;
+ _callableName = callableName;
+ _lineNumber = lineNumber;
+ }
+
+ public String getCallableName() {
+ return _callableName;
+ }
+ public String getCompilationUnit() {
+ return _compilationUnit;
+ }
+ public int getLineNumber() {
+ return _lineNumber;
+ }
+
+ @Override
+ public String toString () {
+ return "line " + _lineNumber + "@" + _callableName + " [" + _compilationUnit + "]";
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/StaticProperty.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/StaticProperty.java
new file mode 100644
index 0000000..bf33463
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/StaticProperty.java
@@ -0,0 +1,15 @@
+package org.eclipse.xtend.backend.common;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface StaticProperty {
+ String getName ();
+ BackendType getOwner ();
+
+ BackendType getType ();
+
+ Object get ();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/AndExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/AndExpression.java
new file mode 100644
index 0000000..5f017c1
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/AndExpression.java
@@ -0,0 +1,41 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ * this is not delegated to syslib because of shortcut evaluation
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class AndExpression extends ExpressionBase {
+ private final ExpressionBase _left, _right;
+
+ public AndExpression (ExpressionBase left, ExpressionBase right, SourcePos sourcePos) {
+ super(sourcePos);
+
+ _left = left;
+ _right = right;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object left = _left.evaluate(ctx);
+ if (left == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ if (Boolean.FALSE.equals (left))
+ return Boolean.FALSE;
+
+ final Object right = _right.evaluate(ctx);
+ if (right == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+ return right;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateCachedExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateCachedExpression.java
new file mode 100644
index 0000000..6815586
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateCachedExpression.java
@@ -0,0 +1,36 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+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.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CreateCachedExpression extends ExpressionBase {
+ private final BackendType _t;
+ private final List<ExpressionBase> _paramExpr;
+
+ public CreateCachedExpression (BackendType t, List<ExpressionBase> paramExpr, SourcePos sourcePos) {
+ super(sourcePos);
+
+ _t = t;
+ _paramExpr = paramExpr;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final List<Object> params = new ArrayList<Object>();
+
+ for (ExpressionBase e: _paramExpr)
+ params.add (e.evaluate(ctx));
+
+ return ctx.getCreationCache().createRaw (_t, params);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateUncachedExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateUncachedExpression.java
new file mode 100644
index 0000000..70fad46
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateUncachedExpression.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend.expr;
+
+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.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CreateUncachedExpression extends ExpressionBase {
+ private final BackendType _t;
+
+ public CreateUncachedExpression (BackendType t, SourcePos sourcePos) {
+ super(sourcePos);
+ _t = t;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ return _t.create();
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurriedFunction.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurriedFunction.java
new file mode 100644
index 0000000..966cb93
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurriedFunction.java
@@ -0,0 +1,64 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+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;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class CurriedFunction implements Function {
+ private final Function _inner;
+ private final boolean[] _isBound;
+ private final Object[] _boundValue;
+ private final List<BackendType> _paramTypes = new ArrayList<BackendType>();
+
+ public CurriedFunction (Function inner, List<ExpressionBase> boundParams, ExecutionContext ctx) {
+ _inner = inner;
+ _isBound = new boolean[inner.getParameterTypes().size()];
+ _boundValue = new Object[inner.getParameterTypes().size()];
+
+ for (int i = 0; i < boundParams.size(); i++) {
+ final ExpressionBase curParam = boundParams.get(i);
+
+ if (curParam == null) {
+ _paramTypes.add(inner.getParameterTypes().get(i));
+ } else {
+ _isBound[i] = true;
+ _boundValue[i] = boundParams.get(i).evaluate(ctx);
+ }
+ }
+ }
+
+ public ExpressionBase getGuard () {
+ return _inner.getGuard();
+ }
+
+ public List<? extends BackendType> getParameterTypes () {
+ return _paramTypes;
+ }
+
+ public Object invoke (ExecutionContext ctx, Object[] params) {
+ final List<Object> realParams = new ArrayList<Object>();
+
+ int j = 0;
+ for (int i = 0; i < _isBound.length; i++) {
+ if (_isBound[i])
+ realParams.add(_boundValue[i]);
+ else
+ realParams.add(params[j++]);
+ }
+
+ return ctx.getFunctionInvoker().invoke(ctx, _inner, realParams);
+ }
+
+ public boolean isCached () {
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurryingExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurryingExpression.java
new file mode 100644
index 0000000..aa5ccba
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurryingExpression.java
@@ -0,0 +1,35 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.List;
+
+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.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CurryingExpression extends ExpressionBase{
+ private final Function _function;
+ private final List<ExpressionBase> _boundParams;
+
+ /**
+ *
+ * @param boundParams must have the same size as the number of parameters of the function. Unbound parameters
+ * are represented by "null" entries.
+ */
+ public CurryingExpression (Function f, List<ExpressionBase> boundParams, SourcePos pos) {
+ super (pos);
+
+ _function = f;
+ _boundParams = boundParams;
+ }
+
+ @Override
+ protected Object evaluateInternal (ExecutionContext ctx) {
+ return new CurriedFunction (_function, _boundParams, ctx);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/GlobalVarExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/GlobalVarExpression.java
new file mode 100644
index 0000000..82ab063
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/GlobalVarExpression.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+/**
+ * A "global variable" is a constant that is bound outside the execution of the program. Its
+ * purpose is to e.g. make configuration properties available inside the program.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class GlobalVarExpression extends ExpressionBase {
+ private final String _varName;
+
+ public GlobalVarExpression (String varName, SourcePos sourcePos) {
+ super(sourcePos);
+ _varName = varName;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ return ctx.getGlobalVarContext().getGlobalVars().get (_varName);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/HidingLocalVarDefExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/HidingLocalVarDefExpression.java
new file mode 100644
index 0000000..cbfed30
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/HidingLocalVarDefExpression.java
@@ -0,0 +1,37 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class HidingLocalVarDefExpression extends ExpressionBase {
+ private final String _localVarName;
+ private final ExpressionBase _defExpression;
+ private final ExpressionBase _inner;
+
+ public HidingLocalVarDefExpression (String localVarName, ExpressionBase defExpression, ExpressionBase inner,
+ SourcePos sourcePos) {
+ super (sourcePos);
+ _localVarName = localVarName;
+ _defExpression = defExpression;
+ _inner = inner;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object oldValue = ctx.getLocalVarContext().getLocalVars().get(_localVarName);
+ ctx.getLocalVarContext().getLocalVars().put (_localVarName, _defExpression.evaluate(ctx));
+
+ try {
+ return _inner.evaluate(ctx);
+ }
+ finally {
+ ctx.getLocalVarContext().getLocalVars().put(_localVarName, oldValue);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/IfExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/IfExpression.java
new file mode 100644
index 0000000..d0a7af8
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/IfExpression.java
@@ -0,0 +1,37 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class IfExpression extends ExpressionBase {
+ private final ExpressionBase _cond, _if, _else;
+
+ public IfExpression (ExpressionBase cond, ExpressionBase ifResult, ExpressionBase elseResult, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _cond = cond;
+ _if = ifResult;
+ _else = elseResult;
+ }
+
+ @Override
+ public Object evaluateInternal (ExecutionContext ctx) {
+ final Object cond = _cond.evaluate(ctx);
+
+ if (cond == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ if (Boolean.TRUE.equals (cond))
+ return _if.evaluate(ctx);
+ else
+ return _else.evaluate(ctx);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InitClosureExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InitClosureExpression.java
new file mode 100644
index 0000000..172bee8
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InitClosureExpression.java
@@ -0,0 +1,36 @@
+package org.eclipse.xtend.backend.expr;
+
+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.SourcePos;
+import org.eclipse.xtend.backend.functions.Closure;
+
+
+/**
+ * This expression creates an initialized closure. A closure needs to be initialized
+ * at runtime because it contains a snapshot of the local variables that are visible
+ * during its creation
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class InitClosureExpression extends ExpressionBase {
+ private final List<String> _paramNames;
+ private final List<? extends BackendType> _paramTypes;
+ private final ExpressionBase _def;
+
+ public InitClosureExpression (List<String> paramNames, List<? extends BackendType> paramTypes, ExpressionBase def, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _paramNames = paramNames;
+ _paramTypes = paramTypes;
+ _def = def;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ return new Closure (ctx.getLocalVarContext(), ctx.getFunctionDefContext(), _paramNames, _paramTypes, _def);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnCollectionExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnCollectionExpression.java
new file mode 100644
index 0000000..7b9f346
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnCollectionExpression.java
@@ -0,0 +1,53 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class InvocationOnCollectionExpression extends ExpressionBase {
+ private final ExpressionBase _coll;
+ private final String _functionName;
+ private final List<ExpressionBase> _params;
+
+ public InvocationOnCollectionExpression (ExpressionBase coll, String functionName, List<ExpressionBase> params, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _coll = coll;
+ _functionName = functionName;
+ _params = params;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Collection<?> coll = (Collection<?>) _coll.evaluate(ctx);
+
+ if (coll == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ final List<Object> params = new ArrayList<Object>();
+ params.add (null); //placeholder
+ for (ExpressionBase expr: _params)
+ params.add (expr.evaluate (ctx));
+
+ final Collection<Object> result = (coll instanceof List) ? new ArrayList<Object> () : new HashSet<Object> ();
+
+ for (Object o: coll) {
+ params.set (0, o);
+ result.add (ctx.getFunctionDefContext().invoke (ctx, _functionName, params));
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnObjectExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnObjectExpression.java
new file mode 100644
index 0000000..d8c0525
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnObjectExpression.java
@@ -0,0 +1,34 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class InvocationOnObjectExpression extends ExpressionBase {
+ private final String _functionName;
+ private final List<? extends ExpressionBase> _params;
+
+ public InvocationOnObjectExpression (String functionName, List<? extends ExpressionBase> params, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _functionName = functionName;
+ _params = params;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final List<Object> params = new ArrayList<Object> ();
+ for (ExpressionBase expr: _params)
+ params.add (expr.evaluate(ctx));
+
+ return ctx.getFunctionDefContext().invoke (ctx, _functionName, params);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnWhateverExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnWhateverExpression.java
new file mode 100644
index 0000000..10be3fe
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnWhateverExpression.java
@@ -0,0 +1,54 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class InvocationOnWhateverExpression extends ExpressionBase {
+ private final String _functionName;
+ private final List<? extends ExpressionBase> _params;
+
+ public InvocationOnWhateverExpression (String functionName, List<? extends ExpressionBase> params, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _functionName = functionName;
+ _params = params;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final List<Object> params = new ArrayList<Object> ();
+ for (ExpressionBase expr: _params)
+ params.add (expr.evaluate(ctx));
+
+ if (params.get (0) instanceof Collection<?>) {
+ // check if this is a function on Collection itself
+ if (ctx.getFunctionDefContext().hasMatch(ctx, _functionName, params))
+ return ctx.getFunctionDefContext().invoke(ctx, _functionName, params);
+
+ final Collection<?> coll = (Collection<?>) params.get (0);
+
+ final Collection<Object> result = (coll instanceof List) ? new ArrayList<Object> () : new HashSet<Object> ();
+
+ for (Object o: coll) {
+ params.set (0, o);
+ result.add (ctx.getFunctionDefContext().invoke (ctx, _functionName, params));
+ }
+
+ return result;
+
+ }
+ else
+ return ctx.getFunctionDefContext().invoke (ctx, _functionName, params);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/ListLiteralExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/ListLiteralExpression.java
new file mode 100644
index 0000000..56cd2e5
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/ListLiteralExpression.java
@@ -0,0 +1,32 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ListLiteralExpression extends ExpressionBase {
+ private final List<ExpressionBase> _inner;
+
+ public ListLiteralExpression (List<ExpressionBase> inner, SourcePos sourcePos) {
+ super (sourcePos);
+ _inner = inner;
+ }
+
+ @Override
+ protected Object evaluateInternal (ExecutionContext ctx) {
+ final List<Object> result = new ArrayList<Object>();
+
+ for (ExpressionBase e: _inner)
+ result.add (e.evaluate(ctx));
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LiteralExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LiteralExpression.java
new file mode 100644
index 0000000..8c3003e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LiteralExpression.java
@@ -0,0 +1,24 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class LiteralExpression extends ExpressionBase {
+ private final Object _value;
+
+ public LiteralExpression (Object value, SourcePos sourcePos) {
+ super (sourcePos);
+ _value = value;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ return _value;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LocalVarEvalExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LocalVarEvalExpression.java
new file mode 100644
index 0000000..464f2e3
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LocalVarEvalExpression.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class LocalVarEvalExpression extends ExpressionBase {
+ private final String _localVarName;
+
+ public LocalVarEvalExpression (String localVarName, SourcePos sourcePos) {
+ super(sourcePos);
+ _localVarName = localVarName;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ //expects a static check to have been performed that a local variable of this name exists
+ return ctx.getLocalVarContext().getLocalVars().get (_localVarName);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/NewLocalVarDefExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/NewLocalVarDefExpression.java
new file mode 100644
index 0000000..e25073a
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/NewLocalVarDefExpression.java
@@ -0,0 +1,36 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class NewLocalVarDefExpression extends ExpressionBase {
+ private final String _localVarName;
+ private final ExpressionBase _defExpression;
+ private final ExpressionBase _inner;
+
+ public NewLocalVarDefExpression (String localVarName, ExpressionBase defExpression, ExpressionBase inner,
+ SourcePos sourcePos) {
+ super (sourcePos);
+ _localVarName = localVarName;
+ _defExpression = defExpression;
+ _inner = inner;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ ctx.getLocalVarContext().getLocalVars().put (_localVarName, _defExpression.evaluate(ctx));
+
+ try {
+ return _inner.evaluate(ctx);
+ }
+ finally {
+ ctx.getLocalVarContext().getLocalVars().remove(_localVarName);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/OrExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/OrExpression.java
new file mode 100644
index 0000000..1604d85
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/OrExpression.java
@@ -0,0 +1,41 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ * this is not delegated to syslib because of shortcut evaluation
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class OrExpression extends ExpressionBase {
+ private final ExpressionBase _left, _right;
+
+ public OrExpression (ExpressionBase left, ExpressionBase right, SourcePos sourcePos) {
+ super(sourcePos);
+
+ _left = left;
+ _right = right;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object left = _left.evaluate(ctx);
+ if (left == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ if (Boolean.TRUE.equals (left))
+ return Boolean.TRUE;
+
+ final Object right = _right.evaluate(ctx);
+ if (right == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+ return right;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnCollectionExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnCollectionExpression.java
new file mode 100644
index 0000000..3b84ce4
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnCollectionExpression.java
@@ -0,0 +1,43 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class PropertyOnCollectionExpression extends ExpressionBase {
+ private final ExpressionBase _inner;
+ private final String _propertyName;
+
+ public PropertyOnCollectionExpression (ExpressionBase inner, String propertyName, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _inner = inner;
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Collection<?> coll = (Collection<?>) _inner.evaluate(ctx);
+ if (coll == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ final Collection<Object> result = (coll instanceof List) ? new ArrayList<Object> () : new HashSet<Object> ();
+
+ for (Object o: coll)
+ result.add (ctx.getTypesystem().findType(o).getProperty(ctx, o, _propertyName));
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnObjectExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnObjectExpression.java
new file mode 100644
index 0000000..e53eebb
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnObjectExpression.java
@@ -0,0 +1,33 @@
+package org.eclipse.xtend.backend.expr;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class PropertyOnObjectExpression extends ExpressionBase {
+ private final ExpressionBase _inner;
+ private final String _propertyName;
+
+ public PropertyOnObjectExpression (ExpressionBase inner, String propertyName, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _inner = inner;
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object o = _inner.evaluate(ctx);
+ if (o == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ return ctx.getTypesystem().findType(o).getProperty(ctx, o, _propertyName);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnWhateverExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnWhateverExpression.java
new file mode 100644
index 0000000..2c2f061
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnWhateverExpression.java
@@ -0,0 +1,60 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+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.SourcePos;
+import org.eclipse.xtend.backend.types.builtin.CollectionType;
+
+
+/**
+ * This class deals with the case where the middle end can not decide statically whether
+ * a property is to be resolved on a single object or on a collection
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class PropertyOnWhateverExpression extends ExpressionBase {
+ private final ExpressionBase _inner;
+ private final String _propertyName;
+
+ public PropertyOnWhateverExpression (ExpressionBase inner, String propertyName, SourcePos sourcePos) {
+ super (sourcePos);
+
+ _inner = inner;
+ _propertyName = propertyName;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object o = _inner.evaluate(ctx);
+ if (o == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ final BackendType t = ctx.getTypesystem().findType (o);
+
+ if (CollectionType.INSTANCE.isAssignableFrom(t)) {
+ if (isProperty (t, _propertyName))
+ return t.getProperty (ctx, o, _propertyName);
+
+ final Collection<Object> result = (o instanceof List) ? new ArrayList<Object> () : new HashSet<Object> ();
+
+ for (Object obj: (Collection<?>) o)
+ result.add (ctx.getTypesystem().findType(obj).getProperty(ctx, obj, _propertyName));
+
+ return result;
+ }
+ else
+ return t.getProperty (ctx, o, _propertyName);
+ }
+
+ private boolean isProperty (BackendType t, String propName) {
+ return t.getProperties().containsKey (propName);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SequenceExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SequenceExpression.java
new file mode 100644
index 0000000..ded8d63
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SequenceExpression.java
@@ -0,0 +1,31 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class SequenceExpression extends ExpressionBase {
+ private final List<ExpressionBase> _inner;
+
+ public SequenceExpression (List<ExpressionBase> inner, SourcePos sourcePos) {
+ super (sourcePos);
+ _inner = inner;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ Object result = null;
+
+ for (ExpressionBase e: _inner)
+ result = e.evaluate(ctx);
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SetPropertyExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SetPropertyExpression.java
new file mode 100644
index 0000000..c0fb33b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SetPropertyExpression.java
@@ -0,0 +1,41 @@
+package org.eclipse.xtend.backend.expr;
+
+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.SourcePos;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class SetPropertyExpression extends ExpressionBase {
+ private final ExpressionBase _inner;
+ private final String _propertyName;
+ private final ExpressionBase _valueExpr;
+
+
+ public SetPropertyExpression (ExpressionBase inner, String propertyName, ExpressionBase valueExpr, SourcePos sourcePos) {
+ super(sourcePos);
+
+ _inner = inner;
+ _propertyName = propertyName;
+ _valueExpr = valueExpr;
+ }
+
+ @Override
+ public Object evaluateInternal(ExecutionContext ctx) {
+ final Object o = _inner.evaluate(ctx);
+ if (o == null) {
+ ctx.logNullDeRef (getPos());
+ return null;
+ }
+
+ final BackendType t = ctx.getTypesystem().findType(o);
+ final Object value = _valueExpr.evaluate(ctx);
+ t.setProperty (ctx, o, _propertyName, value);
+
+ return o;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SwitchExpression.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SwitchExpression.java
new file mode 100644
index 0000000..282f7ed
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SwitchExpression.java
@@ -0,0 +1,55 @@
+package org.eclipse.xtend.backend.expr;
+
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+import org.eclipse.xtend.backend.util.Pair;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class SwitchExpression extends ExpressionBase {
+ private final ExpressionBase _switchExpr;
+ private final List<Pair<ExpressionBase, ExpressionBase>> _cases;
+ private final ExpressionBase _defaultExpr;
+
+ public SwitchExpression (ExpressionBase switchExpr, List<Pair<ExpressionBase, ExpressionBase>> cases, ExpressionBase defaultExpr, SourcePos sourcePos) {
+ super (sourcePos);
+
+ if (switchExpr == null)
+ switchExpr = new LiteralExpression (Boolean.TRUE, sourcePos);
+
+ _switchExpr = switchExpr;
+ _cases = cases;
+ _defaultExpr = defaultExpr;
+ }
+
+ @Override
+ protected Object evaluateInternal (ExecutionContext ctx) {
+ final Object switchVal = _switchExpr.evaluate (ctx);
+
+ for (Pair<ExpressionBase, ExpressionBase> curCase: _cases) {
+ final Object curVal = curCase.getFirst().evaluate(ctx);
+
+ if (nullSafeEquals (switchVal, curVal))
+ return curCase.getSecond().evaluate(ctx);
+ }
+
+ return _defaultExpr.evaluate(ctx);
+ }
+
+ private static boolean nullSafeEquals (Object o1, Object o2) {
+ if (o1 == o2)
+ return true;
+
+ if (o1 == null || o2 == null)
+ return false;
+
+ return o1.equals (o2);
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/Closure.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/Closure.java
new file mode 100644
index 0000000..b97cb83
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/Closure.java
@@ -0,0 +1,84 @@
+package org.eclipse.xtend.backend.functions;
+
+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.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.LocalVarContext;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class Closure implements Function {
+ private final LocalVarContext _lvcAtDefinitionTime;
+ private final FunctionDefContext _fdcAtDefinitionTime;
+
+ private final List<String> _paramNames;
+ private final List<? extends BackendType> _paramTypes;
+ private final ExpressionBase _def;
+
+ public Closure (LocalVarContext lvcAtDefinitionTime, FunctionDefContext fdcAtDefinitionTime, List<String> paramNames, List<? extends BackendType> paramTypes, ExpressionBase def) {
+ //freeze local variables at definition time so they will be available in a different context at evaluation time
+ _lvcAtDefinitionTime = new LocalVarContext();
+ _lvcAtDefinitionTime.getLocalVars().putAll (lvcAtDefinitionTime.getLocalVars());
+
+ _fdcAtDefinitionTime = fdcAtDefinitionTime;
+ _paramNames = paramNames;
+ _paramTypes = paramTypes;
+ _def = def;
+ }
+
+ public String getName () {
+ return "<Closure>";
+ }
+
+
+ public boolean isCached () {
+ return false;
+ }
+
+ public List<? extends BackendType> getParameterTypes() {
+ return _paramTypes;
+ }
+
+ public Object invoke (ExecutionContext ctx, Object[] params) {
+ if (_fdcAtDefinitionTime == ctx.getFunctionDefContext())
+ return invokeWithExistingFdc (ctx, params);
+ else {
+ final FunctionDefContext oldFdc = ctx.getFunctionDefContext ();
+ try {
+ ctx.setFunctionDefContext (_fdcAtDefinitionTime);
+ return invokeWithExistingFdc(ctx, params);
+ }
+ finally {
+ ctx.setFunctionDefContext (oldFdc);
+ }
+ }
+ }
+
+ private Object invokeWithExistingFdc (ExecutionContext ctx, Object... params) {
+ // potential local variables that are hidden by parameters are not restored - but they will never be visible anyway
+ final LocalVarContext lvc = _lvcAtDefinitionTime;
+ for (int i=0; i<_paramNames.size(); i++) {
+ lvc.getLocalVars().put(_paramNames.get(i), params[i]);
+ }
+
+ final LocalVarContext oldLvc = ctx.getLocalVarContext();
+ try {
+ ctx.setLocalVarContext(lvc);
+ return _def.evaluate(ctx);
+ }
+ finally {
+ ctx.setLocalVarContext(oldLvc);
+ }
+ }
+
+ public ExpressionBase getGuard() {
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareFunctionCollection.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareFunctionCollection.java
new file mode 100644
index 0000000..90bdbcf
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareFunctionCollection.java
@@ -0,0 +1,68 @@
+package org.eclipse.xtend.backend.functions;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.xtend.backend.common.Function;
+
+
+/**
+ * This class collects functions. It removes an old one if a new one with identical signature is
+ * added, allowing overwriting. The check for "identical signature" is performed only if both
+ * functions have no guard. Functions with guards are never treated as having the same signature
+ * because an equality check would then require comparison of guards, a tricky undertaking which
+ * is left for a future version.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class DuplicateAwareFunctionCollection {
+ private final Collection<Function> _allFunctions = new HashSet<Function>();
+
+
+ /**
+ * registers a function and returns the old function of the same signature if one was replaced, and null otherwise
+ */
+ public Function register (Function f) {
+ Function result = null;
+
+ for (Function candidate: _allFunctions) {
+ if (haveSameSignature (f, candidate)) {
+ _allFunctions.remove (candidate);
+ result = candidate;
+ break;
+ }
+ }
+
+ _allFunctions.add (f);
+ return result;
+ }
+
+
+ /**
+ * checks if this collection already contains a function with identical signature.
+ */
+ public boolean contains (Function f) {
+ for (Function candidate: _allFunctions)
+ if (haveSameSignature(f, candidate))
+ return true;
+
+ return false;
+ }
+
+
+ public Collection<Function> getFunctions () {
+ return _allFunctions;
+ }
+
+
+ /**
+ * helper operation to compare two functions.
+ */
+ public static boolean haveSameSignature (Function f1, Function f2) {
+ if (f1.getGuard() != null || f2.getGuard() != null)
+ return false;
+
+ return f1.getParameterTypes().equals (f2.getParameterTypes());
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareNamedFunctionCollection.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareNamedFunctionCollection.java
new file mode 100644
index 0000000..81e5004
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareNamedFunctionCollection.java
@@ -0,0 +1,79 @@
+package org.eclipse.xtend.backend.functions;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.util.Cache;
+
+
+/**
+ * This class collects functions. It removes an old one if a new one with identical signature is
+ * added, allowing overwriting. The check for "identical signature" is performed only if both
+ * functions have no guard. Functions with guards are never treated as having the same signature
+ * because an equality check would then require comparison of guards, a tricky undertaking which
+ * is left for a future version.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class DuplicateAwareNamedFunctionCollection {
+ private final Collection<NamedFunction> _allFunctions = new HashSet<NamedFunction>();
+ private final Cache<String, Collection<NamedFunction>> _byName = new Cache<String, Collection<NamedFunction>> () {
+ @Override
+ protected Collection<NamedFunction> create (String key) {
+ return new HashSet<NamedFunction>();
+ }
+ };
+
+ /**
+ * registers a function and returns the old function of the same signature if one was replaced, and null otherwise
+ */
+ public NamedFunction register (NamedFunction f) {
+ NamedFunction result = null;
+
+ for (NamedFunction candidate: _byName.get (f.getName())) {
+ if (haveSameSignature (f, candidate)) {
+ _byName.get (f.getName()).remove (candidate);
+ _allFunctions.remove (candidate);
+ result = candidate;
+ break;
+ }
+ }
+
+ _byName.get (f.getName()).add (f);
+ _allFunctions.add (f);
+ return result;
+ }
+
+
+ /**
+ * checks if this collection already contains a function with identical signature.
+ */
+ public boolean contains (NamedFunction f) {
+ for (NamedFunction candidate: _byName.get (f.getName()))
+ if (haveSameSignature(f, candidate))
+ return true;
+
+ return false;
+ }
+
+
+ public Collection<NamedFunction> getFunctions () {
+ return _allFunctions;
+ }
+
+
+ /**
+ * helper operation to compare two functions.
+ */
+ public static boolean haveSameSignature (NamedFunction f1, NamedFunction f2) {
+ if (f1.getFunction().getGuard() != null || f2.getFunction().getGuard() != null)
+ return false;
+
+ if (! f1.getName().equals (f2.getName()))
+ return false;
+
+ return f1.getFunction().getParameterTypes().equals (f2.getFunction().getParameterTypes());
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/FunctionDefContextImpl.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/FunctionDefContextImpl.java
new file mode 100644
index 0000000..c02ea77
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/FunctionDefContextImpl.java
@@ -0,0 +1,148 @@
+package org.eclipse.xtend.backend.functions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+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.iface.BackendContributor;
+import org.eclipse.xtend.backend.util.Cache;
+import org.eclipse.xtend.backend.util.DoubleKeyCache;
+import org.eclipse.xtend.backend.util.ErrorHandler;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class FunctionDefContextImpl implements FunctionDefContext {
+
+ private final Cache<BackendType, Collection<NamedFunction>> _byFirstParameterType = new Cache<BackendType, Collection<NamedFunction>>() {
+ @Override
+ protected Collection<NamedFunction> create (BackendType key) {
+ return new ArrayList<NamedFunction>();
+ }
+ };
+
+ private final DoubleKeyCache<String, Integer, DuplicateAwareNamedFunctionCollection> _functions = new DoubleKeyCache<String, Integer, DuplicateAwareNamedFunctionCollection>() {
+ @Override
+ protected DuplicateAwareNamedFunctionCollection create(String key1, Integer key2) {
+ return new DuplicateAwareNamedFunctionCollection ();
+ }
+ };
+
+ private final DoubleKeyCache<String, List<BackendType>, Collection<Function>> _byParamTypes = new DoubleKeyCache<String, List<BackendType>, Collection<Function>>() {
+
+ @Override
+ protected Collection<Function> create (String functionName, List<BackendType> paramTypes) {
+ return new PolymorphicResolver(functionName).getBestFitCandidates (findCandidates (functionName, paramTypes));
+ }
+
+ private Collection<Function> findCandidates (String functionName, List<BackendType> paramTypes) {
+ final int paramCount = paramTypes.size();
+ final BackendType firstParamType = paramTypes.isEmpty() ? null : paramTypes.get(0);
+
+ final DuplicateAwareFunctionCollection result = new DuplicateAwareFunctionCollection ();
+
+ // get built-in operations of the typesystem
+ if (firstParamType != null) {
+ for (NamedFunction f: firstParamType.getBuiltinOperations())
+ if (functionName.equals (f.getName()) && matchesParamTypes(f.getFunction(), paramTypes))
+ result.register (f.getFunction());
+ }
+
+ // merge with registered functions
+ for (NamedFunction f: _functions.get (functionName, paramCount).getFunctions())
+ if (matchesParamTypes (f.getFunction(), paramTypes))
+ result.register (f.getFunction());
+
+ return result.getFunctions();
+ }
+
+ private boolean matchesParamTypes (Function f, List<BackendType> paramTypes) {
+ if (f.getParameterTypes().size() != paramTypes.size())
+ return false;
+
+ for (int i=0; i<f.getParameterTypes().size(); i++) {
+ if (! f.getParameterTypes().get(i).isAssignableFrom(paramTypes.get(i)))
+ return false;
+ }
+
+ return true;
+ }
+ };
+
+ public FunctionDefContextImpl (BackendContributor syslib) {
+ register (syslib);
+ }
+
+ public void register (BackendContributor bc) {
+ for (NamedFunction f: bc.getContributedFunctions())
+ register (f);
+ }
+
+ public void register (NamedFunction f) {
+ final NamedFunction old = _functions.get (f.getName(), f.getFunction().getParameterTypes().size()).register (f);
+ if (old != null && old.getFunction().getParameterTypes().size() > 0)
+ _byFirstParameterType.get (old.getFunction().getParameterTypes().get (0)).remove (old);
+
+ if (f.getFunction().getParameterTypes().size() > 0)
+ _byFirstParameterType.get (f.getFunction().getParameterTypes().get(0)).add (f);
+ }
+
+ public Object invoke (ExecutionContext ctx, String functionName, List<? extends Object> params) {
+ final Collection<Function> candidates = findFunctionCandidates (ctx, functionName, params);
+ final Function f = new PolymorphicResolver(functionName).evaluateGuards(ctx, candidates);
+ return ctx.getFunctionInvoker().invoke (ctx, f, params);
+ }
+
+ private Collection<Function> findFunctionCandidates (ExecutionContext ctx, String functionName, List<? extends Object> params) {
+ final List<BackendType> paramTypes = new ArrayList<BackendType>();
+ for (Object o: params)
+ paramTypes.add (ctx.getTypesystem().findType(o));
+
+ try {
+ return _byParamTypes.get (functionName, paramTypes);
+ } catch (RuntimeException e) {
+ ErrorHandler.handle ("Failed to resolve function '" + functionName + "' for parameter types " + paramTypes + ".", e);
+ return null; // to make the compiler happy - this is never executed
+ }
+ }
+
+ public Collection<NamedFunction> getByFirstParameterType (BackendType firstParameterType) {
+ if (firstParameterType.getBuiltinOperations().isEmpty())
+ return _byFirstParameterType.get (firstParameterType);
+
+ final List<NamedFunction> result = new ArrayList<NamedFunction> (_byFirstParameterType.get (firstParameterType));
+ result.addAll (firstParameterType.getBuiltinOperations());
+ return result;
+ }
+
+ public Function getMatch (ExecutionContext ctx, String name, List<BackendType> params) {
+ final Collection<Function> candidates = findFunctionCandidates (ctx, name, params);
+ if (candidates.isEmpty())
+ return null;
+ if (candidates.size() > 1)
+ throw new IllegalArgumentException ("several matches for function '" + name + "' and parameter types " + params + ".");
+
+ return candidates.iterator().next();
+ }
+
+ public boolean hasMatch (ExecutionContext ctx, String functionName, List<? extends Object> params) {
+ return findFunctionCandidates(ctx, functionName, params).size() > 0;
+ }
+
+ @Override
+ public String toString () {
+ return "FunctionDefContextImpl [" + _functions.getMap().values() + "]";
+ }
+}
+
+
+
+
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/PolymorphicResolver.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/PolymorphicResolver.java
new file mode 100644
index 0000000..e6dd6df
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/PolymorphicResolver.java
@@ -0,0 +1,111 @@
+package org.eclipse.xtend.backend.functions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.Function;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class PolymorphicResolver {
+ private final String _name; // for error messages
+
+ /**
+ * @param functionName the name of the functions to be resolved - used for error messages
+ */
+ public PolymorphicResolver (String functionName) {
+ _name = functionName;
+ }
+
+ /**
+ * returns the list of all best-fitting candidates by parameter types. This list can be statically
+ * cached, but it must be checked dynamically for guard matching.
+ */
+ public Collection<Function> getBestFitCandidates (Collection<Function> functions) {
+ // shortcut for a common case
+ if (functions.size() == 1)
+ return functions;
+ if (functions.isEmpty())
+ throw new IllegalArgumentException ("no matches found");
+
+ Iterator<Function> iter = functions.iterator();
+
+ Function firstBestMatch = iter.next();
+ List<Function> bestMatches2 = new ArrayList<Function> ();
+ bestMatches2.add (firstBestMatch);
+
+ while (iter.hasNext()) {
+ final Function candidate = iter.next();
+ final int compResult = _paramTypeComparator.compare (candidate, firstBestMatch);
+
+ if (compResult < 0) {
+ firstBestMatch = candidate;
+ bestMatches2 = new ArrayList<Function>();
+ bestMatches2.add (candidate);
+ }
+ else if (compResult == 0) {
+ bestMatches2.add (candidate);
+ }
+ }
+
+ return bestMatches2;
+ }
+
+ private Function evaluateGuards (ExecutionContext ctx, Function function) {
+ if (function.getGuard() == null)
+ return function;
+
+ if (Boolean.TRUE.equals (function.getGuard().evaluate(ctx)))
+ return function;
+
+ throw new IllegalArgumentException ("guard of the only implementation of " + _name + " evaluated to false");
+ }
+
+ /**
+ * chooses a function based on the evaluation of the functions' guards
+ */
+ public Function evaluateGuards (ExecutionContext ctx, Collection<Function> functions) {
+ if (functions.size() == 1)
+ return evaluateGuards (ctx, functions.iterator().next());
+
+ final List<Function> unguarded = new ArrayList<Function>();
+ Function passedInspection = null;
+
+ for (Function f: functions) {
+ if (f.getGuard() == null)
+ unguarded.add (f);
+ else {
+ if (Boolean.TRUE.equals (f.getGuard().evaluate(ctx))) {
+ if (passedInspection != null)
+ throw new IllegalArgumentException ("ambiguous call to " + _name + " - both " + passedInspection + " and " + f + " had guard expressions that evaluated to true");
+ passedInspection = f;
+ }
+ }
+ }
+
+ if (passedInspection != null)
+ return passedInspection;
+
+ if (unguarded.size() > 0)
+ return unguarded.get (unguarded.size() - 1); // this is where the overwriting of extensions is implemented
+
+ throw new IllegalArgumentException ("call to " + _name + " could not be resolved - no guard allowed passage, and there are no unguarded implementations.");
+ }
+
+
+ private static final Comparator<Function> _paramTypeComparator = new Comparator<Function>() {
+ private final TypesComparator _typesComparator = new TypesComparator ();
+
+ public int compare(Function o1, Function o2) {
+ return _typesComparator.compare (o1.getParameterTypes(), o2.getParameterTypes());
+ }
+ };
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/SourceDefinedFunction.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/SourceDefinedFunction.java
new file mode 100644
index 0000000..db3451c
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/SourceDefinedFunction.java
@@ -0,0 +1,88 @@
+package org.eclipse.xtend.backend.functions;
+
+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.common.FunctionDefContext;
+import org.eclipse.xtend.backend.common.LocalVarContext;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class SourceDefinedFunction implements Function {
+ private final String _name;
+ private final List<String> _paramNames;
+ private final List<BackendType> _paramTypes;
+ private final FunctionDefContext _defContext;
+ private final ExpressionBase _def;
+ private final boolean _cached;
+ private final ExpressionBase _guard;
+
+ public SourceDefinedFunction (String name, List<String> paramNames, List<BackendType> paramTypes, FunctionDefContext defContext, ExpressionBase def, boolean cached, ExpressionBase guard) {
+ _name = name;
+ _paramNames = paramNames;
+ _paramTypes = paramTypes;
+ _defContext = defContext;
+ _def = def;
+ _cached = cached;
+ _guard = guard;
+ }
+
+ public boolean isCached () {
+ return _cached;
+ }
+
+ public List<BackendType> getParameterTypes() {
+ return _paramTypes;
+ }
+
+ public FunctionDefContext getFunctionDefContext () {
+ return _defContext;
+ }
+
+ public Object invoke (ExecutionContext ctx, Object[] params) {
+ if (_defContext == ctx.getFunctionDefContext())
+ return invokeWithExistingFdc (ctx, params);
+ else {
+ final FunctionDefContext oldFdc = ctx.getFunctionDefContext ();
+ try {
+ ctx.setFunctionDefContext (_defContext);
+ return invokeWithExistingFdc(ctx, params);
+ }
+ finally {
+ ctx.setFunctionDefContext (oldFdc);
+ }
+ }
+ }
+
+ private Object invokeWithExistingFdc (ExecutionContext ctx, Object[] params) {
+ final LocalVarContext lvc = new LocalVarContext ();
+ for (int i=0; i<_paramNames.size(); i++) {
+ lvc.getLocalVars().put(_paramNames.get(i), params[i]);
+ }
+
+ final LocalVarContext oldLvc = ctx.getLocalVarContext();
+ try {
+ ctx.setLocalVarContext(lvc);
+ return _def.evaluate(ctx);
+ }
+ finally {
+ ctx.setLocalVarContext(oldLvc);
+ }
+ }
+
+ public ExpressionBase getGuard() {
+ return _guard;
+ }
+
+ @Override
+ public String toString () {
+ return "SourceDefinedFunction '" + _name + "' " + _paramTypes;
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/TypesComparator.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/TypesComparator.java
new file mode 100644
index 0000000..99bc9ed
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/TypesComparator.java
@@ -0,0 +1,43 @@
+package org.eclipse.xtend.backend.functions;
+
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class TypesComparator implements Comparator<List<? extends BackendType>> {
+ /**
+ *
+ * returns -1 if the second list of types is not assignable to the first
+ * list of types returns 0 if the second list of types exactly matches the
+ * first list of types returns 1 if the second list of types is assignable
+ * to the first list of types
+ */
+ public int compare(final List<? extends BackendType> types1, final List<? extends BackendType> types2) {
+ if (types1 == null || types2 == null)
+ throw new NullPointerException ();
+ if (types1.size() != types2.size ())
+ return -1;
+ boolean directMatch = true;
+ for (int i = 0, x = types1.size (); i < x; i++) {
+ final BackendType type1 = types1.get (i);
+ final BackendType type2 = types2.get (i);
+ if (type1.isAssignableFrom (type2)) {
+ if (!type1.equals (type2)) {
+ directMatch = false;
+ }
+ } else
+ return -1;
+ }
+ if (directMatch)
+ return 0;
+ else
+ return 1;
+ }
+
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/iface/BackendContributor.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/iface/BackendContributor.java
new file mode 100644
index 0000000..1b96534
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/iface/BackendContributor.java
@@ -0,0 +1,26 @@
+package org.eclipse.xtend.backend.iface;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.NamedFunction;
+
+
+//TODO add an 'init' method to pass in the string argument and the backend typesystem?
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface BackendContributor {
+
+ /**
+ * This method is used by the middle end to resolve type literals. This Contributor
+ * should return "null" if it does not feel responsible for a giben type literal.
+ */
+ BackendType convertToType (List<String> segments);
+
+ Collection<NamedFunction> getContributedFunctions ();
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/AbstractType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/AbstractType.java
new file mode 100644
index 0000000..c2e9495
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/AbstractType.java
@@ -0,0 +1,107 @@
+package org.eclipse.xtend.backend.types;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.common.NamedFunction;
+import org.eclipse.xtend.backend.common.Property;
+import org.eclipse.xtend.backend.common.StaticProperty;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class AbstractType implements BackendType {
+ private final String _name;
+ private final List<BackendType> _superTypes;
+
+ private final Map<String, Property> _properties = new HashMap<String, Property> ();
+ private final Map<String, StaticProperty> _staticProperties = new HashMap<String, StaticProperty> ();
+
+ private final List<NamedFunction> _builtinOperations = new ArrayList<NamedFunction> ();
+
+ public AbstractType(String name, BackendType... superTypes) {
+ _name = name;
+
+ if (superTypes.length == 0) {
+ _superTypes = Collections.singletonList((BackendType) ObjectType.INSTANCE);
+ }
+ else
+ _superTypes = Arrays.asList(superTypes);
+ }
+
+ public AbstractType(String name, Collection<? extends BackendType> superTypes) {
+ _name = name;
+ _superTypes = new ArrayList<BackendType> (superTypes);
+ }
+
+ protected void register (Property p) {
+ _properties.put (p.getName(), p);
+ }
+
+ protected void register (StaticProperty p) {
+ _staticProperties.put (p.getName(), p);
+ }
+
+ protected void register (String name, Function f) {
+ _builtinOperations.add (new NamedFunction (name, f));
+ }
+
+ public final Collection<? extends NamedFunction> getBuiltinOperations () {
+ return _builtinOperations;
+ }
+
+ public String getName () {
+ return _name;
+ }
+
+ public final Object getProperty (ExecutionContext ctx, Object o, String name) {
+ final Property p = _properties.get (name);
+ if (p == null)
+ throw new IllegalArgumentException ("no property " + name + " in type " + getName());
+
+ return p.get (ctx, o);
+ }
+
+ public final void setProperty (ExecutionContext ctx, Object o, String name, Object value) {
+ final Property p = _properties.get (name);
+ if (p == null)
+ throw new IllegalArgumentException ("no property " + name + " in type " + getName());
+
+ p.set (ctx, o, value);
+
+ }
+
+ public final Collection<? extends BackendType> getSuperTypes () {
+ return _superTypes;
+ }
+
+ public Object create () {
+ throw new UnsupportedOperationException ("Type " + getName() + " can not be instantiated reflectively.");
+ }
+
+ public final Map<String, ? extends Property> getProperties () {
+ return _properties;
+ }
+
+ public final Map<String, ? extends StaticProperty> getStaticProperties () {
+ return _staticProperties;
+ }
+
+ @Override
+ public String toString () {
+ return _name;
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/CompositeTypesystem.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/CompositeTypesystem.java
new file mode 100644
index 0000000..2f9b776
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/CompositeTypesystem.java
@@ -0,0 +1,124 @@
+package org.eclipse.xtend.backend.types;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.common.Function;
+import org.eclipse.xtend.backend.common.Property;
+import org.eclipse.xtend.backend.common.StaticProperty;
+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.util.Cache;
+
+
+/**
+ * This is the "normal" implementation of a backend type system - it can recursively
+ * contain other type system implementations, and it contributes the built-in types.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CompositeTypesystem implements BackendTypesystem {
+ private BackendTypesystem _rootTypesystem = this;
+ private final List<BackendTypesystem> _inner = new ArrayList<BackendTypesystem>();
+
+ private final Cache<Class<?>, BackendType> _cache = new Cache<Class<?>, BackendType>() {
+ @Override
+ protected BackendType create (Class<?> key) {
+ final BackendType builtin = findSimpleBuiltinType (key);
+ if (builtin != null)
+ return builtin;
+
+ for (BackendTypesystem ts : _inner) {
+ final BackendType result = ts.findType(key);
+ if (result != null)
+ return result;
+ }
+
+ return ObjectType.INSTANCE;
+ }
+ };
+
+ public void register (BackendTypesystem ts) {
+ _inner.add(ts);
+ ts.setRootTypesystem (getRootTypesystem());
+ }
+
+ public List<BackendTypesystem> getInner () {
+ return _inner;
+ }
+
+ public BackendType findType (Object o) {
+ if (o == null)
+ return VoidType.INSTANCE;
+
+ return findType (o.getClass());
+ }
+
+ public BackendType findType (Class<?> cls) {
+ return _cache.get (cls);
+ }
+
+ public BackendTypesystem getRootTypesystem () {
+ return _rootTypesystem;
+ }
+
+ public void setRootTypesystem (BackendTypesystem ts) {
+ _rootTypesystem = ts;
+ for (BackendTypesystem child : _inner)
+ child.setRootTypesystem(ts);
+ }
+
+ private BackendType findSimpleBuiltinType (Class<?> cls) {
+ if (cls == null)
+ return ObjectType.INSTANCE; // convenience handling e.g. for interface types whose Java supertype is 'null'
+
+ if (List.class.isAssignableFrom (cls))
+ return ListType.INSTANCE;
+ if (Set.class.isAssignableFrom(cls))
+ return SetType.INSTANCE;
+ if (Collection.class.isAssignableFrom(cls))
+ return CollectionType.INSTANCE;
+
+ if (CharSequence.class.isAssignableFrom(cls))
+ return StringType.INSTANCE;
+
+ if (cls == Boolean.class || cls == Boolean.TYPE)
+ return BooleanType.INSTANCE;
+
+ if (cls == Long.class || cls == Long.TYPE)
+ return LongType.INSTANCE;
+ if (cls == Double.class || cls == Double.TYPE)
+ return DoubleType.INSTANCE;
+
+ if (Function.class.isAssignableFrom(cls))
+ return FunctionType.INSTANCE;
+
+ if (cls == Void.TYPE)
+ return VoidType.INSTANCE;
+
+ if (BackendType.class.isAssignableFrom(cls))
+ return TypeType.INSTANCE;
+ if (Property.class.isAssignableFrom(cls))
+ return PropertyType.INSTANCE;
+ if (StaticProperty.class.isAssignableFrom(cls))
+ return StaticPropertyType.INSTANCE;
+
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BooleanType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BooleanType.java
new file mode 100644
index 0000000..09d310a
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BooleanType.java
@@ -0,0 +1,19 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class BooleanType extends AbstractType {
+ public static final BooleanType INSTANCE = new BooleanType ();
+
+ private BooleanType () {super ("boolean");}
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltInOperation.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltInOperation.java
new file mode 100644
index 0000000..46adcf7
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltInOperation.java
@@ -0,0 +1,39 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.Function;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class BuiltInOperation implements Function {
+ private final String _name;
+ private final List<BackendType> _parameterTypes;
+
+ public BuiltInOperation (String name, BackendType... paramTypes) {
+ _name = name;
+ _parameterTypes = Arrays.asList(paramTypes);
+ }
+
+ public ExpressionBase getGuard () {
+ return null;
+ }
+
+ public String getName () {
+ return _name;
+ }
+
+ public List<BackendType> getParameterTypes () {
+ return _parameterTypes;
+ }
+
+ public boolean isCached () {
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltinProperty.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltinProperty.java
new file mode 100644
index 0000000..b55a924
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltinProperty.java
@@ -0,0 +1,64 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.lang.reflect.Method;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.common.Property;
+import org.eclipse.xtend.backend.util.ErrorHandler;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public class BuiltinProperty implements Property {
+ private final BackendType _owner;
+ private final BackendType _type;
+ private final String _name;
+ private final Method _getter;
+ private final Method _setter;
+
+ public BuiltinProperty (BackendType owner, BackendType type, String name, Method getter, Method setter) {
+ _owner = owner;
+ _type = type;
+ _name = name;
+ _getter = getter;
+ _setter = setter;
+ }
+
+ public String getName () {
+ return _name;
+ }
+
+ public BackendType getOwner () {
+ return _owner;
+ }
+
+ public BackendType getType () {
+ return _type;
+ }
+
+ public Object get (ExecutionContext ctx, Object o) {
+ if (_getter == null)
+ throw new IllegalStateException ("property " + _name + " of type " + _owner.getName() + " can not be read");
+
+ try {
+ return _getter.invoke(o);
+ } catch (Exception e) {
+ ErrorHandler.handle(e);
+ return null; // to make the compiler happy - this is never executed
+ }
+ }
+
+ public void set (ExecutionContext ctx, Object o, Object newValue) {
+ if (_getter == null)
+ throw new IllegalStateException ("property " + _name + " of type " + _owner.getName() + " can not be set");
+
+ try {
+ _setter.invoke (o, newValue);
+ } catch (Exception e) {
+ ErrorHandler.handle(e);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/CollectionType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/CollectionType.java
new file mode 100644
index 0000000..c944092
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/CollectionType.java
@@ -0,0 +1,28 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.Collection;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+import org.eclipse.xtend.backend.util.ReflectionHelper;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CollectionType extends AbstractType {
+ public static final CollectionType INSTANCE = new CollectionType();
+
+ private CollectionType() {
+ super ("Collection");
+
+ register (new BuiltinProperty (CollectionType.INSTANCE, LongType.INSTANCE, "size", ReflectionHelper.getKnownMethod(Collection.class, "size"), null));
+ register (new BuiltinProperty (CollectionType.INSTANCE, BooleanType.INSTANCE, "isEmpty", ReflectionHelper.getKnownMethod(Collection.class, "isEmpty"), null));
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == ListType.INSTANCE || other == SetType.INSTANCE || other == VoidType.INSTANCE;
+ }
+}
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/DoubleType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/DoubleType.java
new file mode 100644
index 0000000..603114f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/DoubleType.java
@@ -0,0 +1,19 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class DoubleType extends AbstractType {
+ public static final DoubleType INSTANCE = new DoubleType();
+
+ private DoubleType () {super ("double"); }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/FunctionType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/FunctionType.java
new file mode 100644
index 0000000..7836d4e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/FunctionType.java
@@ -0,0 +1,45 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.Arrays;
+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.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class FunctionType extends AbstractType {
+ public static final FunctionType INSTANCE = new FunctionType ();
+
+ private FunctionType () {
+ super ("Function");
+
+ register ("invoke", new Function () {
+ public List<BackendType> getParameterTypes() {
+ return Arrays.asList(new BackendType[] {FunctionType.INSTANCE, ListType.INSTANCE});
+ }
+
+ public Object invoke (ExecutionContext ctx, Object[] params) {
+ return ctx.getFunctionInvoker().invoke(ctx, (Function) params[0], (List<?>) params[1]);
+ }
+
+ public boolean isCached() {
+ return false;
+ }
+
+ public ExpressionBase getGuard() {
+ return null;
+ }
+ });
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ListType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ListType.java
new file mode 100644
index 0000000..e3b8f10
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ListType.java
@@ -0,0 +1,26 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.ArrayList;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ListType extends AbstractType {
+ private ListType () {super ("List", CollectionType.INSTANCE); }
+
+ public static final ListType INSTANCE = new ListType ();
+
+ @Override
+ public Object create() {
+ return new ArrayList<Object>();
+ }
+
+ public boolean isAssignableFrom(BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/LongType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/LongType.java
new file mode 100644
index 0000000..367d08b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/LongType.java
@@ -0,0 +1,24 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class LongType extends AbstractType {
+ public static final LongType INSTANCE = new LongType();
+
+ private LongType () {super ("Int"); }
+
+ @Override
+ public Object create() {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ObjectType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ObjectType.java
new file mode 100644
index 0000000..ebb8f77
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ObjectType.java
@@ -0,0 +1,19 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ObjectType extends AbstractType {
+ private ObjectType() {super ("Object"); }
+
+ public static ObjectType INSTANCE = new ObjectType();
+
+ public boolean isAssignableFrom (BackendType other) {
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/PropertyType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/PropertyType.java
new file mode 100644
index 0000000..2151ed6
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/PropertyType.java
@@ -0,0 +1,27 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.Property;
+import org.eclipse.xtend.backend.types.AbstractType;
+import org.eclipse.xtend.backend.util.ReflectionHelper;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class PropertyType extends AbstractType {
+ public static final PropertyType INSTANCE = new PropertyType ();
+
+ private PropertyType () {
+ super ("Property");
+
+ register (new BuiltinProperty (this, StringType.INSTANCE, "name", ReflectionHelper.getKnownMethod(Property.class, "getName"), null));
+ register (new BuiltinProperty (this, TypeType.INSTANCE, "returnType", ReflectionHelper.getKnownMethod(Property.class, "getType"), null));
+ register (new BuiltinProperty (this, TypeType.INSTANCE, "owner", ReflectionHelper.getKnownMethod(Property.class, "getOwner"), null));
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/SetType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/SetType.java
new file mode 100644
index 0000000..cfe7e23
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/SetType.java
@@ -0,0 +1,28 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.HashSet;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class SetType extends AbstractType {
+ private SetType () {
+ super ("Set", CollectionType.INSTANCE);
+ }
+
+ public static final SetType INSTANCE = new SetType ();
+
+ @Override
+ public Object create() {
+ return new HashSet<Object>();
+ }
+
+ public boolean isAssignableFrom(BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StaticPropertyType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StaticPropertyType.java
new file mode 100644
index 0000000..f224344
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StaticPropertyType.java
@@ -0,0 +1,30 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.Property;
+import org.eclipse.xtend.backend.types.AbstractType;
+import org.eclipse.xtend.backend.util.ReflectionHelper;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class StaticPropertyType extends AbstractType {
+ public static final StaticPropertyType INSTANCE = new StaticPropertyType ();
+
+ private StaticPropertyType () {
+ super ("Property");
+
+ register (new BuiltinProperty (this, StringType.INSTANCE, "name", ReflectionHelper.getKnownMethod(Property.class, "getName"), null));
+ register (new BuiltinProperty (this, TypeType.INSTANCE, "returnType", ReflectionHelper.getKnownMethod(Property.class, "getType"), null));
+ register (new BuiltinProperty (this, TypeType.INSTANCE, "owner", ReflectionHelper.getKnownMethod(Property.class, "getOwner"), null));
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
+
+
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StringType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StringType.java
new file mode 100644
index 0000000..88128cb
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StringType.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ * The canonical, internal representation of a string object is "anything that implements CharSequence", i.e.
+ * a function that accepts a parameter of type string must accept any CharSequence. This is done to
+ * enable internal optimizations like lazy concatenation and streaming.<p>
+ *
+ * This has the consequence that functions may need to convert a given CharSequence to whatever more specific
+ * string representation they need internally.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class StringType extends AbstractType {
+ public static final StringType INSTANCE = new StringType();
+
+ private StringType () {super ("String"); }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/TypeType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/TypeType.java
new file mode 100644
index 0000000..2dccc2e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/TypeType.java
@@ -0,0 +1,45 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.types.AbstractType;
+import org.eclipse.xtend.backend.util.ReflectionHelper;
+
+
+/**
+ * This class represents the type of a type. It serves as an entry point for meta programming.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class TypeType extends AbstractType {
+ public static final TypeType INSTANCE = new TypeType ();
+
+ private TypeType () {
+ super ("Type");
+
+ register (new BuiltinProperty (this, StringType.INSTANCE, "name", ReflectionHelper.getKnownMethod (BackendType.class, "getName"), null));
+ register (new BuiltinProperty (this, ListType.INSTANCE, "superTypes", ReflectionHelper.getKnownMethod (BackendType.class, "getSuperTypes"), null));
+ register (new BuiltinProperty (this, ListType.INSTANCE, "allProperties", ReflectionHelper.getKnownMethod (BackendType.class, "getProperties"), null));
+ register (new BuiltinProperty (this, ListType.INSTANCE, "allStaticProperties", ReflectionHelper.getKnownMethod (BackendType.class, "getStaticProperties"), null));
+
+ register (new BuiltinProperty (this, ListType.INSTANCE, "allOperations", null, null) {
+ @Override
+ public Object get (ExecutionContext ctx, Object o) {
+ final BackendType t = (BackendType) o;
+ final List<Object> result = new ArrayList<Object>();
+ result.addAll (ctx.getFunctionDefContext().getByFirstParameterType(t));
+ result.addAll (t.getBuiltinOperations());
+ return result;
+ }
+ });
+ }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this || other == VoidType.INSTANCE;
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/VoidType.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/VoidType.java
new file mode 100644
index 0000000..b0a486b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/VoidType.java
@@ -0,0 +1,21 @@
+package org.eclipse.xtend.backend.types.builtin;
+
+import org.eclipse.xtend.backend.common.BackendType;
+import org.eclipse.xtend.backend.types.AbstractType;
+
+
+/**
+ * This type receives special treatment because it is the only type that can not
+ * be determined based on the Java class of an object.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class VoidType extends AbstractType {
+ public static final VoidType INSTANCE = new VoidType();
+
+ private VoidType () {super ("Void"); }
+
+ public boolean isAssignableFrom (BackendType other) {
+ return other == this;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Cache.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Cache.java
new file mode 100644
index 0000000..c0c9d92
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Cache.java
@@ -0,0 +1,28 @@
+package org.eclipse.xtend.backend.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class Cache<K,V> {
+ private final Map<K, V> _cache = new HashMap<K, V>();
+
+ public V get (K key) {
+ if (_cache.containsKey(key))
+ return _cache.get (key);
+
+ final V result = create (key);
+ _cache.put (key, result);
+ return result;
+ }
+
+ protected abstract V create (K key);
+
+ public Map<K, V> getMap () {
+ return _cache;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/CollectionHelper.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/CollectionHelper.java
new file mode 100644
index 0000000..8c8374b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/CollectionHelper.java
@@ -0,0 +1,14 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class CollectionHelper {
+ public static Object[] withoutFirst (Object[] o) {
+ final Object[] result = new Object[o.length - 1];
+ System.arraycopy(o, 1, result, 0, result.length);
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/DoubleKeyCache.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/DoubleKeyCache.java
new file mode 100644
index 0000000..cfd0234
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/DoubleKeyCache.java
@@ -0,0 +1,30 @@
+package org.eclipse.xtend.backend.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class DoubleKeyCache<K1, K2, V> {
+ private final Map<Pair<K1, K2>, V> _cache = new HashMap<Pair <K1, K2>, V>();
+
+ public V get (K1 key1, K2 key2) {
+ final Pair<K1, K2> key = new Pair<K1, K2> (key1, key2);
+
+ if (_cache.containsKey (key))
+ return _cache.get (key);
+
+ final V result = create (key1, key2);
+ _cache.put (key, result);
+ return result;
+ }
+
+ protected abstract V create (K1 key1, K2 key2);
+
+ public Map<Pair<K1, K2>, V> getMap () {
+ return _cache;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ErrorHandler.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ErrorHandler.java
new file mode 100644
index 0000000..18dae51
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ErrorHandler.java
@@ -0,0 +1,27 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ * This class serves as the single handler for dealing with exceptions that prevent
+ * continued execution and can not be meaningfully handled locally.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ErrorHandler {
+ public static void handle (Exception exc) {
+ if (exc instanceof FatalException)
+ throw (FatalException) exc;
+
+ throw new FatalException (exc);
+ }
+
+ public static void handle (String msg, Exception exc) {
+ if (exc instanceof FatalException) {
+ final FatalException fe = (FatalException) exc;
+ fe.addMessage(msg);
+ throw fe;
+ }
+
+ throw new FatalException (msg, exc);
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/FatalException.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/FatalException.java
new file mode 100644
index 0000000..49f9da8
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/FatalException.java
@@ -0,0 +1,31 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class FatalException extends RuntimeException {
+ private String _message = "";
+
+ public FatalException (Exception inner) {
+ super (inner);
+ }
+
+ public FatalException (String message, Exception inner) {
+ super (inner);
+ _message = message;
+ }
+
+ public void addMessage (String message) {
+ if (_message == "")
+ _message = message;
+ else
+ _message = message + ":\n" + _message;
+ }
+
+ @Override
+ public String getMessage () {
+ return _message;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/NullWriter.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/NullWriter.java
new file mode 100644
index 0000000..0abcbb0
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/NullWriter.java
@@ -0,0 +1,25 @@
+package org.eclipse.xtend.backend.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+
+/**
+ * This writer ignores all written data.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class NullWriter extends Writer {
+
+ @Override
+ public void close () throws IOException {
+ }
+
+ @Override
+ public void flush () throws IOException {
+ }
+
+ @Override
+ public void write (char[] cbuf, int off, int len) throws IOException {
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Pair.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Pair.java
new file mode 100644
index 0000000..a549014
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Pair.java
@@ -0,0 +1,60 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class Pair<T1, T2> {
+ private final T1 _o1;
+ private final T2 _o2;
+
+ public Pair (T1 o1, T2 o2) {
+ _o1 = o1;
+ _o2 = o2;
+ }
+
+ public T1 getFirst() {
+ return _o1;
+ }
+
+ public T2 getSecond() {
+ return _o2;
+ }
+
+ @Override
+ public String toString () {
+ return "[" + _o1 + ", " + _o2 + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + ((_o1 == null) ? 0 : _o1.hashCode());
+ result = PRIME * result + ((_o2 == null) ? 0 : _o2.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 Pair<?, ?> other = (Pair<?, ?>) obj;
+ if (_o1 == null) {
+ if (other._o1 != null)
+ return false;
+ } else if (!_o1.equals(other._o1))
+ return false;
+ if (_o2 == null) {
+ if (other._o2 != null)
+ return false;
+ } else if (!_o2.equals(other._o2))
+ return false;
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ReflectionHelper.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ReflectionHelper.java
new file mode 100644
index 0000000..c63896f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ReflectionHelper.java
@@ -0,0 +1,22 @@
+package org.eclipse.xtend.backend.util;
+
+import java.lang.reflect.Method;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ReflectionHelper {
+ /**
+ * retrieve a well-known method from a class, disregarding any thrown exceptions
+ */
+ public static Method getKnownMethod (Class<?> cls, String name, Class<?>... paramTypes) {
+ try {
+ return cls.getMethod(name, paramTypes);
+ } catch (Exception e) {
+ ErrorHandler.handle(e);
+ return null; // to make the compiler happy - this is never executed
+ }
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ResourceToList.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ResourceToList.java
new file mode 100644
index 0000000..0ae62e1
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ResourceToList.java
@@ -0,0 +1,62 @@
+package org.eclipse.xtend.backend.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * This class converts the contents of a resource to a list. It removes empty lines (i.e. lines containing
+ * only whitespace), and it trims leading and trailing whitespace. It also removes comments, i.e. parts of
+ * a line following a '#' character.<br>
+ *
+ * The contents of the file are read using the default locale of the platform.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class ResourceToList {
+ final List<String> _result = new ArrayList<String>();
+
+ /**
+ * @param in may be null, in which case the resulting list is empty.
+ */
+ public ResourceToList (InputStream in) {
+ if (in == null)
+ return;
+
+ final BufferedReader br = new BufferedReader (new InputStreamReader (in));
+
+ String line = null;
+ try {
+ while ((line = br.readLine()) != null)
+ processLine (line);
+ }
+ catch (IOException e) {
+ ErrorHandler.handle(e);
+ }
+ }
+
+ private void processLine (String line) {
+ line = stripComment (line);
+ line = line.trim ();
+ if (line.isEmpty())
+ return;
+
+ _result.add (line);
+ }
+
+ private String stripComment (String line) {
+ final int startComment = line.indexOf ('#');
+ if (startComment < 0)
+ return line;
+
+ return line.substring (startComment);
+ }
+
+ public List<String> getResult () {
+ return _result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/StringHelper.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/StringHelper.java
new file mode 100644
index 0000000..2e5433d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/StringHelper.java
@@ -0,0 +1,274 @@
+package org.eclipse.xtend.backend.util;
+
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+
+
+/**
+ * This class is a collection of helper functions for string handling.
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class StringHelper {
+ private static final NumberFormat _numFormat = NumberFormat.getNumberInstance();
+
+ /**
+ * formats a number using the default locale settings.
+ */
+ public static String prettyPrint(long num) {
+ return _numFormat.format(num);
+ }
+
+ /**
+ * formats a number using the default locale settings.
+ */
+ public static String prettyPrint(Number num) {
+ return _numFormat.format(num);
+ }
+
+ /**
+ * formats a date using the default locale settings.
+ */
+ public static String prettyPrint(Date date) {
+ return DateFormat.getDateTimeInstance().format(date);
+ }
+
+ /**
+ * returns a new string in which one search string is replaced by another.
+ */
+ public static String replace(String src, String search, String replace) {
+ if (src == null)
+ return src;
+ if (search == null || search.length() == 0)
+ throw new IllegalArgumentException("Search string must not be empty");
+
+ String result = src;
+ int ind = 0;
+ while ((ind = result.indexOf(search, ind)) >= 0) {
+ result = result.substring(0, ind) + replace + result.substring(ind + search.length());
+ ind += replace.length();
+ }
+
+ return result;
+ }
+
+ /**
+ * replaces special characters that affect formatting with non-formatting
+ * character sequences.
+ * <ul>
+ * <li> \ -> \\
+ * <li> &lt;tab&gt; -> \t
+ * <li> &lt;CR&gt; -> \r
+ * <li> &lt;Newline&gt; -> \n
+ * </ul>
+ */
+ public static String escape(String src) {
+ String result = replace(src, "\\", "\\\\");
+ result = replace(result, "\t", "\\t");
+ result = replace(result, "\r", "\\r");
+ result = replace(result, "\n", "\\n");
+ result = replace(result, "\"", "\\\"");
+
+ return result;
+ }
+
+ /**
+ * undoes the operations of <code>escape</code>
+ */
+ public static String unescape(String src) {
+ if (src == null)
+ return null;
+
+ final StringBuffer result = new StringBuffer();
+ for (int i = 0; i < src.length(); i++) {
+ final char curChar = src.charAt(i);
+
+ if (curChar != '\\') {
+ result.append(curChar);
+ continue;
+ }
+ // increment i to skip to the character after '\\'
+ i++;
+ if (i >= src.length())
+ throw new IllegalArgumentException("String ends with '\\'");
+
+ result.append(unescapeChar(src.charAt(i)));
+ }
+
+ return result.toString();
+ }
+
+ private static char unescapeChar(char escapedChar) {
+ switch (escapedChar) {
+ case '\\':
+ return '\\';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case '"':
+ return '"';
+ }
+ throw new IllegalArgumentException("unsupported string format: '\\" + escapedChar + "' is not supported.");
+ }
+
+ /**
+ * truncates a string regardless of its length. This method is a workaround
+ * for a shortcoming of String.substring (int, int) that is unable to handle
+ * the case where the number of characters would extend beyond the end of
+ * the string.
+ */
+ public static String truncate(String str, int maxLen) {
+ if (str == null || str.length() < maxLen)
+ return str;
+ if (maxLen < 0)
+ return "";
+ return str.substring(0, maxLen);
+ }
+
+ /**
+ * same as String.substring, except that this version handles the case
+ * robustly when the index is out of bounds.
+ */
+ public static String substring(String str, int beginIndex) {
+ if (str == null)
+ return null;
+ if (beginIndex < 0)
+ return str;
+ if (beginIndex >= str.length())
+ return "";
+
+ return str.substring(beginIndex);
+ }
+
+ /**
+ * same as String.substring, except that this version handles the case
+ * robustly when one or both of the indexes is out of bounds.
+ */
+ public static String substring(String str, int beginIndex, int endIndex) {
+ if (str == null)
+ return null;
+ if (beginIndex > endIndex)
+ return "";
+ if (beginIndex < 0)
+ beginIndex = 0;
+ if (endIndex > str.length())
+ endIndex = str.length();
+
+ return str.substring(beginIndex, endIndex);
+ }
+
+ /**
+ * removes a number of characters from the beginning and the end of a string
+ */
+ public static String strip(String s, int numStart, int numEnd) {
+ if (s == null)
+ return s;
+
+ return substring(s, numStart, s.length() - numEnd);
+ }
+
+ /**
+ * returns the number of occurrences of a character in a string
+ */
+ public static int numMatches(String s, char ch) {
+ if (s == null)
+ return 0;
+
+ int result = 0;
+ for (int i = 0; i < s.length(); i++)
+ if (s.charAt(i) == ch)
+ result++;
+
+ return result;
+ }
+
+ /**
+ * returns the number of occurrences of a substring in a string
+ */
+ public static int numMatches(String s, String search) {
+ if (s == null || search == null || "".equals(s) || "".equals(search))
+ return 0;
+
+ int result = 0;
+ int curIndex = 0;
+ while (true) {
+ curIndex = s.indexOf(search, curIndex);
+ if (curIndex == -1)
+ break;
+
+ curIndex++;
+ result++;
+ }
+ return result;
+ }
+
+ /**
+ * tests if a string starts with any one of a collection of prefixes
+ */
+ public static boolean startsWithAny(String str, Collection<String> prefixes) {
+ if (str == null)
+ return false;
+
+ for (Iterator<String> iter = prefixes.iterator(); iter.hasNext();) {
+ if (str.startsWith(iter.next()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * tests if a string starts with any one of a collection of prefixes
+ */
+ public static boolean startsWithAny(String str, String[] prefixes) {
+ if (str == null)
+ return false;
+
+ for (int i = 0; i < prefixes.length; i++) {
+ if (str.startsWith(prefixes[i]))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * tests if a string ends with any one of a collection of prefixes
+ */
+ public static boolean endsWithAny(String str, Collection<String> prefixes) {
+ if (str == null)
+ return false;
+
+ for (Iterator<String> iter = prefixes.iterator(); iter.hasNext();) {
+ if (str.endsWith(iter.next()))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * tests if a string ends with any one of a collection of prefixes
+ */
+ public static boolean endsWithAny(String str, String[] prefixes) {
+ if (str == null)
+ return false;
+
+ for (int i = 0; i < prefixes.length; i++) {
+ if (str.endsWith(prefixes[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static String firstUpper(String str) {
+ return str.substring(0, 1).toUpperCase().concat(str.substring(1));
+ }
+
+ public static String firstLower(String str) {
+ return str.substring(0, 1).toLowerCase().concat(str.substring(1));
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/SyntaxConstants.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/SyntaxConstants.java
new file mode 100644
index 0000000..e0142ac
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/SyntaxConstants.java
@@ -0,0 +1,24 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public interface SyntaxConstants {
+ String NS_DELIM = "::";
+ String THIS = "this";
+
+ // special function names
+ String CONCAT = "concat";
+
+ String FOREACH_WITHOUT_ITERATOR = "forEach";
+ String FOREACH_WITH_ITERATOR = "forEachWithIterator";
+
+ // function names for operator overloading
+ String OPERATOR_PLUS = "operatorPlus";
+ String OPERATOR_MINUS = "operatorMinus";
+ String OPERATOR_MULT = "operatorMult";
+ String OPERATOR_DIV = "operatorDiv";
+ String OPERATOR_MOD = "operatorMod";
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/TripleKeyCache.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/TripleKeyCache.java
new file mode 100644
index 0000000..f1999ca
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/TripleKeyCache.java
@@ -0,0 +1,26 @@
+package org.eclipse.xtend.backend.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public abstract class TripleKeyCache<K1, K2, K3, V> {
+ private final Map<Triplet<K1, K2, K3>, V> _cache = new HashMap<Triplet <K1, K2, K3>, V>();
+
+ public V get (K1 key1, K2 key2, K3 key3) {
+ final Triplet<K1, K2, K3> key = new Triplet<K1, K2, K3> (key1, key2, key3);
+
+ if (_cache.containsKey (key))
+ return _cache.get (key);
+
+ final V result = create (key1, key2, key3);
+ _cache.put (key, result);
+ return result;
+ }
+
+ protected abstract V create (K1 key1, K2 key2, K3 key3);
+}
diff --git a/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Triplet.java b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Triplet.java
new file mode 100644
index 0000000..e495c3c
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Triplet.java
@@ -0,0 +1,67 @@
+package org.eclipse.xtend.backend.util;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class Triplet<T1, T2, T3> {
+ private final T1 _o1;
+ private final T2 _o2;
+ private final T3 _o3;
+
+ public Triplet (T1 o1, T2 o2, T3 o3) {
+ _o1 = o1;
+ _o2 = o2;
+ _o3 = o3;
+ }
+
+ public T1 getFirst() {
+ return _o1;
+ }
+
+ public T2 getSecond() {
+ return _o2;
+ }
+
+ public T3 getThird() {
+ return _o3;
+ }
+
+ @Override
+ public int hashCode() {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + ((_o1 == null) ? 0 : _o1.hashCode());
+ result = PRIME * result + ((_o2 == null) ? 0 : _o2.hashCode());
+ result = PRIME * result + ((_o3 == null) ? 0 : _o3.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 Triplet<?, ?, ?> other = (Triplet<?, ?, ?>) obj;
+ if (_o1 == null) {
+ if (other._o1 != null)
+ return false;
+ } else if (!_o1.equals(other._o1))
+ return false;
+ if (_o2 == null) {
+ if (other._o2 != null)
+ return false;
+ } else if (!_o2.equals(other._o2))
+ return false;
+ if (_o3 == null) {
+ if (other._o3 != null)
+ return false;
+ } else if (!_o3.equals(other._o3))
+ return false;
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.backend/todo.txt b/plugins/org.eclipse.xtend.backend/todo.txt
new file mode 100644
index 0000000..96a34e2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.backend/todo.txt
@@ -0,0 +1,100 @@
+todo
+----
+Adapter für Xpand und Xtend
+
+make classes final where meaningful
+Check: SourcePos-Infos in Fehlern, Exceptions in ExpressionBase ordentlich gewrappt
+
+Outlets: Funktionen "registerOutlet" parallel zu "file" --> Outlets registrieren (inkl. Default-Outlet),
+ Convenience mit Primitives und "richtige" Outlets. Outlet: Liefert Writer für identifizierenden
+ String (d.h. Filenamen)
+
+BackendContributor: init-Methode statt Constructor-Parameter
+static properties; enums
+
+Marker-Interface / Annotation "FunctionDefs" o.ä. --> generische Unterscheidung für Java-Importer, ob Klasse
+ als Bean oder als "Funktionen-Container"
+
+JavaBeansType: Interfaces als Supertypen
+
+syslib
+testen, insbes. syslib
+
+DefinitionType in FunctionType mergen
+
+globalVars rauswerfen?
+
+dead code elimination?
+
+isInstance
+
+AOP
+
+Buddy Policy für syslib und backend
+
+syslib-Funktion: allFunctions (List<Type>) --> auch Funktionen ohne Parameter zur Laufzeit
+ finden (oder built-in? --> syslib-Aufruf verlässt den Scope)
+Function-Match (z.B. &myFunc (String, Foo) --> spät binden! --> dynamisch durchgereichter Kram
+ wird gematcht
+Currying
+Map als Builtin-Typ
+Typesystem je Compilationunit
+Properties über getter/setter abbilden (z.B. im mm keine property mehr)?
+Eigene Properties definieren (d.h. generische Map dafür an jedem Objekt)?
+"final" (auch als Hint für Optimierung --> wird nicht durch dynamische Exytensions
+ erweitert --> Tail Recursion geht nur dort)
+Initialisierung der Functions mit FunctionDefContext: Nicht zwingend eager
+ in voller Tiefe, sondern lazy beim ersten Einstieg in eine neue CompilationUnit
+zusätzlich zu statisch unterschiedenem this / Collection-Sonderfall außerdem
+ den generischen Fall --> aber nur dann (Ref-Typ "Object"), wenn es statisch
+ nicht entscheidbar ist. --> volle Rückwärtskompatibilität
+globale Type-Registry für alle zurückgegebenen Objekte --> nach beliebigem Rumreichen
+ kann man an ihnen zumindest die eingebauten Operations aufrufen, auf ihre Properties
+ zugreifen
+
+Konzept für stufenweises Überschreiben - syslib --> built-in operation --> Extension (oder so)
+
+toString() überschreibbar, trotz lazy evaluation
+Debugger: ein Source-Primitive kann aus mehreren Runtime-Primitives bestehen - in der RT
+ markieren, wo neuer Source-Primitive beginnt? Oder einfach Mapping in Rückrichtung
+ und vergleichen?
+tail recursion
+replace/add von Extensions im dynamischen Scope
+
+equals auf Type-Implementierungen
+
+
+Decisions
+---------
+Overwriting / hiding of functions is only posible for functions without guards (to avoid
+ the necessity of comparing guards for equality)
+IteratorType is now handled via the Java type system
+
+Ideen für die Zukunft
+---------------------
+"async" -Keyword --> Ausnutzung von Multicore???
+
+
+statisch behandeln
+----------------
+hasThis etc. im FunctionDefContext statisch handeln?
+"this"-Mehrdeutigkeit (welche Reihenfolge?)
+Collection-Resolution-Mehrdeutigkeit
+
+
+done
+----
+Interface ExecutionContextAware für Java-Extensions
+cached
+PolymorphicResolver
+int / long: gnädig bei Java-Extensions
+double / float: gnädig bei Java-Extensions
+Array / List
+optimierter String --> an Schnittstellen ggf. konvertieren
+optimierter String --> hierarchische Dirty-Propagation nach oben
+JavaBeansTypesystem
+Konzept für FunctionType - braucht der Parametertypen!?
+metaType etc.
+EMF-Typesystem
+setExecutionContext bei ExecutionContextAware nicht als exportierte Funktion behandeln
+
diff --git a/plugins/org.eclipse.xtend.middleend.old/.classpath b/plugins/org.eclipse.xtend.middleend.old/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/.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.old/.project b/plugins/org.eclipse.xtend.middleend.old/.project
new file mode 100644
index 0000000..a2042d7
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.middleend.old</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.old/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtend.middleend.old/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..61ef8ab
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Old Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.middleend.old
+Bundle-Version: 1.0.0
+Require-Bundle: org.eclipse.xtend.backend,
+ org.eclipse.emf.ecore,
+ org.eclipse.xtend.middleend,
+ org.eclipse.xtend.backend.emftypes,
+ org.eclipse.xtend.backend.syslib,
+ org.eclipse.xtend,
+ org.eclipse.xpand,
+ org.eclipse.xtend.typesystem.emf
+Export-Package: org.eclipse.xtend.middleend.old
diff --git a/plugins/org.eclipse.xtend.middleend.old/build.properties b/plugins/org.eclipse.xtend.middleend.old/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/JavaExtensionFunction.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/JavaExtensionFunction.java
new file mode 100644
index 0000000..5a8a4db
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/JavaExtensionFunction.java
@@ -0,0 +1,52 @@
+package org.eclipse.xtend.middleend.old;
+
+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.old/src/org/eclipse/xtend/middleend/old/OldDefinitionConverter.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldDefinitionConverter.java
new file mode 100644
index 0000000..de37f8f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldDefinitionConverter.java
@@ -0,0 +1,318 @@
+package org.eclipse.xtend.middleend.old;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+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.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.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.functions.FunctionDefContextImpl;
+import org.eclipse.xtend.backend.functions.SourceDefinedFunction;
+import org.eclipse.xtend.backend.syslib.XtendIterator;
+import org.eclipse.xtend.backend.types.builtin.ObjectType;
+import org.eclipse.xtend.backend.util.SyntaxConstants;
+import org.eclipse.xtend.expression.AnalysationIssue;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.typesystem.ParameterizedType;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single template
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class OldDefinitionConverter {
+ private ExecutionContext _ctx;
+ private final TypeToBackendType _typeConverter;
+
+ private String _definitionName;
+
+ private int _localVarCounter = 0;
+
+
+ public OldDefinitionConverter (ExecutionContext ctx, TypeToBackendType typeConverter) {
+ _ctx = ctx;
+ _typeConverter = typeConverter;
+ }
+
+
+ /**
+ * converts an extension to a function, taking care of mutual registration with its fdc
+ */
+ public NamedFunction create (XpandDefinition def, FunctionDefContextImpl fdc) {
+ final NamedFunction result = createUnregistered (def, fdc);
+ fdc.register (result);
+ return result;
+ }
+
+ private NamedFunction createUnregistered (XpandDefinition def, FunctionDefContextImpl fdc) {
+ if (def instanceof Definition)
+ return new NamedFunction (def.getName(), createNormalDefinition ((Definition) def, fdc));
+
+ throw new IllegalArgumentException ("unsupported definition type " + def.getClass().getName());
+ }
+
+ //TODO imported namespaces (probably one level up)
+ //TODO included extensions (probably one level up)
+
+ private Function createNormalDefinition (Definition def, FunctionDefContext fdc) {
+ final ExecutionContext 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 = _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 = _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, convertStatmentSequence (def.getBody(), def), false, null);
+ }
+ finally {
+ _ctx = oldCtx;
+ }
+ }
+
+ private ExpressionBase convertStatmentSequence (Statement[] statements, SyntaxElement oldPos) {
+ final List<ExpressionBase> parts = new ArrayList<ExpressionBase> ();
+
+ for (Statement stmt: statements)
+ parts.add(convertStatement (stmt));
+
+ final SourcePos newPos = OldExpressionConverter.getSourcePos (oldPos, _definitionName);
+ final ExpressionBase paramExpr = new LiteralExpression (parts, newPos);
+
+ return new InvocationOnObjectExpression (SyntaxConstants.CONCAT, Collections.singletonList (paramExpr), newPos);
+ }
+
+ private ExpressionBase convertStatement (Statement stmt) {
+ if (stmt instanceof ErrorStatement)
+ return convertErrorStatement((ErrorStatement) stmt);
+ if (stmt instanceof ExpandStatement)
+ return convertExpandStatement ((ExpandStatement) stmt);
+ if (stmt instanceof ExpressionStatement)
+ return convertExpressionStatement ((ExpressionStatement) stmt);
+ if (stmt instanceof FileStatement)
+ return convertFileStatement ((FileStatement) stmt);
+ if (stmt instanceof ForEachStatement)
+ return convertForEachStatement ((ForEachStatement) stmt);
+ if (stmt instanceof IfStatement)
+ return convertIfStatement ((IfStatement) stmt);
+ if (stmt instanceof LetStatement)
+ return convertLetStatement ((LetStatement) stmt);
+ if (stmt instanceof ProtectStatement)
+ return convertProtectStatement ((ProtectStatement) stmt);
+ 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) {
+ //TODO mitloggen, was aufgerufen wird --> in den fdc ziehen
+
+ 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 ExpressionBase invocationExpression = new InvocationOnObjectExpression (stmt.getDefinition().getValue(), params, getSourcePos(stmt));
+ final ExpressionBase loopBody = new InitClosureExpression (Arrays.asList(closureParamName), Arrays.asList(ObjectType.INSTANCE), invocationExpression, getSourcePos(stmt));
+
+ if (separator == null)
+ return new InvocationOnObjectExpression (SyntaxConstants.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, loopBody), getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (SyntaxConstants.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, loopBody, separator), 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));
+
+ return new InvocationOnObjectExpression (stmt.getDefinition().getValue(), params, getSourcePos(stmt));
+ }
+ }
+
+
+ private String createUniqueLocalVarName () {
+ return "$localVar_" + _localVarCounter++;
+ }
+
+
+ private ExpressionBase convertExpressionStatement (ExpressionStatement stmt) {
+ return convertExpression (stmt.getExpression());
+ }
+
+ private ExpressionBase convertForEachStatement (ForEachStatement stmt) {
+ final ExecutionContext oldContext = _ctx;
+
+ final ExpressionBase separator = (stmt.getSeparator() != null) ? convertExpression (stmt.getSeparator()) : null;
+ final ExpressionBase target = convertExpression (stmt.getTarget());
+
+ final Type collType = stmt.getTarget().analyze(oldContext, new HashSet<AnalysationIssue>());
+ 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 = _ctx.cloneWithVariable (new Variable (varName, eleType));
+ try {
+ body = convertStatmentSequence (stmt.getBody(), stmt);
+ }
+ 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 (SyntaxConstants.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, closureCreation), getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (SyntaxConstants.FOREACH_WITHOUT_ITERATOR, Arrays.asList(target, closureCreation, separator), getSourcePos (stmt));
+ }
+ else {
+ // forEach with an iterator
+ _ctx = _ctx.cloneWithVariable (new Variable (varName, eleType));
+ _ctx = _ctx.cloneWithVariable (new Variable (stmt.getIteratorName().getValue(), _ctx.getTypeForName (IteratorType.TYPE_NAME)));
+ try {
+ body = convertStatmentSequence (stmt.getBody(), stmt);
+ }
+ 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 (SyntaxConstants.FOREACH_WITH_ITERATOR, Arrays.asList(target, closureCreation), getSourcePos (stmt));
+ else
+ return new InvocationOnObjectExpression (SyntaxConstants.FOREACH_WITH_ITERATOR, Arrays.asList(target, closureCreation, separator), getSourcePos (stmt));
+ }
+ }
+
+ private ExpressionBase convertIfStatement (IfStatement stmt) {
+ if (stmt.getCondition() != null) {
+ final ExpressionBase condExpr = convertExpression (stmt.getCondition());
+ final ExpressionBase ifExpr = convertStatement (stmt.getUpperIf());
+ final ExpressionBase elseExpr = stmt.getElseIf() != null ? convertStatement (stmt.getElseIf()) : new LiteralExpression (null, getSourcePos (stmt));
+
+ return new IfExpression (condExpr, ifExpr, elseExpr, getSourcePos (stmt));
+ }
+ else {
+ // the else part is an IfStatement with null condition
+ return convertStatmentSequence (stmt.getBody(), stmt);
+ }
+ }
+
+
+ private ExpressionBase convertLetStatement (LetStatement stmt) {
+ final String varName = stmt.getVarName().getValue();
+ final Type type = stmt.getVarValue().analyze (_ctx, new HashSet<AnalysationIssue> ());
+
+ final ExecutionContext oldContext = _ctx;
+ _ctx = _ctx.cloneWithVariable (new Variable (varName, type));
+
+ try {
+ final ExpressionBase def = convertExpression (stmt.getVarValue());
+ final ExpressionBase body = convertStatmentSequence (stmt.getBody(), stmt);
+
+ 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) {
+ throw new UnsupportedOperationException(); //TODO implement FileStatement
+ }
+
+ private ExpressionBase convertProtectStatement (ProtectStatement stmt) {
+ throw new UnsupportedOperationException(); //TODO implement ProtectStatement
+ }
+
+ private ExpressionBase convertTextStatement (TextStatement stmt) {
+ //TODO isDeleteLine
+ 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.old/src/org/eclipse/xtend/middleend/old/OldExpressionConverter.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExpressionConverter.java
new file mode 100644
index 0000000..6b6c5e3
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExpressionConverter.java
@@ -0,0 +1,397 @@
+package org.eclipse.xtend.middleend.old;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+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.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.expression.parser.SyntaxConstants;
+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.common.BackendType;
+import org.eclipse.xtend.backend.common.ExpressionBase;
+import org.eclipse.xtend.backend.common.SourcePos;
+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.types.builtin.ObjectType;
+import org.eclipse.xtend.backend.util.Pair;
+import org.eclipse.xtend.expression.AnalysationIssue;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.typesystem.StaticProperty;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single expression
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+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;
+ }
+
+ 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 new org.eclipse.xtend.backend.expr.GlobalVarExpression (((GlobalVarExpression) expr).getVarName(), getSourcePos(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)
+ 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 (e.analyze(_ctx, new HashSet<AnalysationIssue>()));
+
+ 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 (_ctx.getExtensionForTypes (functionName, paramTypes.toArray (new Type[0])) != null)
+ return new InvocationOnObjectExpression (functionName, params, sourcePos);
+ else {
+ final ExpressionBase thisExpression = new LocalVarEvalExpression (org.eclipse.xtend.backend.util.SyntaxConstants.THIS, sourcePos);
+ final Type thisType = (Type) _ctx.getVariable (ExecutionContext.IMPLICIT_VARIABLE).getValue();
+ return createInvocationOnTargetExpression(functionName, thisExpression, thisType, params, paramTypes, sourcePos);
+ }
+ }
+ else
+ return new InvocationOnObjectExpression (functionName, params, sourcePos);
+ }
+ else
+ return createInvocationOnTargetExpression(functionName, convert (expr.getTarget()), expr.getTarget ().analyze (_ctx, new HashSet<AnalysationIssue> ()), params, paramTypes, sourcePos);
+ }
+
+ /**
+ * transform built-in operator names from the old to the new special names
+ */
+ private String transformFunctionName (String functionName) {
+ //TODO missing operators: !, ...
+ //TODO make "!" a built-in operation?
+
+ if ("+".equals (functionName))
+ return org.eclipse.xtend.backend.util.SyntaxConstants.OPERATOR_PLUS;
+ if ("-".equals (functionName))
+ return org.eclipse.xtend.backend.util.SyntaxConstants.OPERATOR_MINUS;
+ if ("*".equals (functionName))
+ return org.eclipse.xtend.backend.util.SyntaxConstants.OPERATOR_MULT;
+ if ("/".equals (functionName))
+ return org.eclipse.xtend.backend.util.SyntaxConstants.OPERATOR_DIV;
+ if ("%".equals (functionName))
+ return org.eclipse.xtend.backend.util.SyntaxConstants.OPERATOR_MOD;
+
+ return functionName;
+ }
+
+ private ExpressionBase createInvocationOnTargetExpression (String functionName, ExpressionBase targetExpression, Type targetType, List<ExpressionBase> params, List<Type> paramTypes, 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 (_ctx.getExtensionForTypes (functionName, paramTypeArray) != null)
+ // check if there is a function that directly matches the collection
+ return new InvocationOnObjectExpression (functionName, allParams, 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, sourcePos);
+
+ // otherwise we know that it is not a collection and can avoid repeating this logic at runtime
+ return new InvocationOnObjectExpression (functionName, allParams, 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.util.SyntaxConstants.THIS, sourcePos);
+ return new InvocationOnObjectExpression ("typeSelect", Arrays.asList (thisExpr, typeExpr), sourcePos);
+ }
+ else
+ return new InvocationOnObjectExpression ("typeSelect", Arrays.asList(convert (expr.getTarget()), typeExpr), 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 = expr.getVarExpression().analyze(_ctx, new HashSet<AnalysationIssue>());
+
+ 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) {
+ return new org.eclipse.xtend.backend.expr.IfExpression (
+ convert (expr.getCondition()),
+ convert (expr.getThenPart()),
+ convert (expr.getElsePart()),
+ 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 (Arrays.asList (expr.getName().getValue().split(SyntaxConstants.NS_DELIM))), 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.util.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 = expr.getTarget().analyze (_ctx, new HashSet<AnalysationIssue>());
+ 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 ("size".equals (varName) || "isEmpty".equals (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 (Arrays.asList(expr.getTypeName()));
+ 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.util.SyntaxConstants.THIS, sourcePos);
+ return new InvocationOnObjectExpression (functionName, Arrays.asList (thisExpr, closureExpr), sourcePos);
+ }
+ else
+ return new InvocationOnObjectExpression (functionName, Arrays.asList(convert (expr.getTarget()), closureExpr), 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 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 ("implies", Arrays.asList(left, right), 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.old/src/org/eclipse/xtend/middleend/old/OldExtensionConverter.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExtensionConverter.java
new file mode 100644
index 0000000..a4a836f
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExtensionConverter.java
@@ -0,0 +1,111 @@
+package org.eclipse.xtend.middleend.old;
+
+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.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.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.expr.CreateCachedExpression;
+import org.eclipse.xtend.backend.expr.LocalVarEvalExpression;
+import org.eclipse.xtend.backend.expr.NewLocalVarDefExpression;
+import org.eclipse.xtend.backend.functions.FunctionDefContextImpl;
+import org.eclipse.xtend.backend.functions.SourceDefinedFunction;
+import org.eclipse.xtend.backend.util.SyntaxConstants;
+import org.eclipse.xtend.expression.AnalysationIssue;
+import org.eclipse.xtend.expression.ExecutionContext;
+import org.eclipse.xtend.expression.Variable;
+import org.eclipse.xtend.typesystem.Type;
+
+
+/**
+ * converts a single extension function
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class OldExtensionConverter {
+ private final ExecutionContext _ctx;
+ private final TypeToBackendType _typeConverter;
+
+
+ public OldExtensionConverter (ExecutionContext ctx, TypeToBackendType typeConverter) {
+ _ctx = ctx;
+ _typeConverter = typeConverter;
+ }
+
+
+ /**
+ * converts an extension to a function, taking care of mutual registration with its fdc
+ */
+ public NamedFunction create (Extension extension, FunctionDefContextImpl fdc) {
+ final NamedFunction result = new NamedFunction (extension.getName(), createUnregistered(extension, fdc));
+ fdc.register (result);
+ return result;
+ }
+
+ private Function createUnregistered (Extension extension, FunctionDefContextImpl 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.old/src/org/eclipse/xtend/middleend/old/OldXtendHelper.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendHelper.java
new file mode 100644
index 0000000..413b7b4
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendHelper.java
@@ -0,0 +1,19 @@
+package org.eclipse.xtend.middleend.old;
+
+import org.eclipse.internal.xtend.expression.parser.SyntaxConstants;
+import org.eclipse.internal.xtend.xtend.XtendFile;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+final class OldXtendHelper {
+ public static String normalizeXtendResourceName (String xtendName) {
+ 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;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendRegistry.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendRegistry.java
new file mode 100644
index 0000000..371733e
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendRegistry.java
@@ -0,0 +1,159 @@
+package org.eclipse.xtend.middleend.old;
+
+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.FunctionDefContextFactory;
+import org.eclipse.internal.xtend.xtend.XtendFile;
+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.common.NamedFunction;
+import org.eclipse.xtend.backend.functions.FunctionDefContextImpl;
+import org.eclipse.xtend.backend.types.CompositeTypesystem;
+import org.eclipse.xtend.backend.util.Cache;
+import org.eclipse.xtend.expression.ExecutionContext;
+
+
+/**
+ * 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)
+ */
+final class OldXtendRegistry {
+ private final ExecutionContext _ctx;
+ private final CompositeTypesystem _ts;
+
+ private final Cache<String, FunctionDefContextImpl> _functionDefContexts = new Cache<String, FunctionDefContextImpl> () {
+ @Override
+ protected FunctionDefContextImpl 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>>();
+
+
+ public OldXtendRegistry (ExecutionContext ctx, CompositeTypesystem ts) {
+ _ctx = ctx;
+ _ts = ts;
+ }
+
+
+ private FunctionDefContextImpl getFunctionDefContext (String xtendName) {
+ return _functionDefContexts.get (OldXtendHelper.normalizeXtendResourceName (xtendName));
+ }
+
+
+ /**
+ * parses and converts an Xtend file and all other files it depends on.
+ */
+ public void registerExtension (String xtendFile) {
+ xtendFile = OldXtendHelper.normalizeXtendResourceName (xtendFile);
+
+ if (_definedFunctionsByResource.containsKey(xtendFile))
+ return;
+
+ final XtendFile file = (XtendFile) _ctx.getResourceManager().loadResource (xtendFile, XtendFile.FILE_EXTENSION);
+ if (file == null)
+ throw new IllegalArgumentException ("could not find extension '" + xtendFile + "'");
+
+ final ExecutionContext ctx = _ctx.cloneWithResource (file);
+
+ final TypeToBackendType typeConverter = new TypeToBackendType (_ts, ctx);
+ final OldExtensionConverter extensionFactory = new OldExtensionConverter (ctx, typeConverter);
+
+ for (Extension ext: file.getExtensions())
+ ext.init (ctx);
+
+ final List<NamedFunction> defined = new ArrayList<NamedFunction>();
+ final List<NamedFunction> exported = new ArrayList<NamedFunction>();
+
+ final FunctionDefContextImpl fdc = getFunctionDefContext (xtendFile);
+
+ for (Extension ext: file.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: file.getImportedExtensions())
+ registerExtension (imported);
+
+ // make all imported extensions visible for the scope of this compilation unit
+ for (String importedResource: file.getImportedExtensions()) {
+ for (NamedFunction f: _locallyExportedFunctionsByResource.get (OldXtendHelper.normalizeXtendResourceName (importedResource)))
+ fdc.register (f);
+ }
+
+ 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);
+ }
+ }
+
+ private void getReexported (String xtendFile, Collection<NamedFunction> result, Set<String> harvestedCompilationUnits, Set<String> processedCompilationUnits) {
+ xtendFile = OldXtendHelper.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 Collection<NamedFunction> getContributedFunctions (String xtendFile) {
+ return _exportedFunctionsByResource.get (xtendFile);
+ }
+}
+
+
+
+
+
+
+
diff --git a/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/TypeToBackendType.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/TypeToBackendType.java
new file mode 100644
index 0000000..8161fa8
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/TypeToBackendType.java
@@ -0,0 +1,167 @@
+package org.eclipse.xtend.middleend.old;
+
+import java.lang.reflect.Field;
+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.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)
+ */
+final class TypeToBackendType {
+ private final CompositeTypesystem _backendTypes;
+ private final EmfTypesystem _emfTypes;
+ private final ExecutionContext _ctx;
+
+ public TypeToBackendType (CompositeTypesystem backendTypes, ExecutionContext ctx) {
+ _backendTypes = backendTypes;
+ _ctx = ctx;
+
+ EmfTypesystem ets = null;
+ for (BackendTypesystem bts: _backendTypes.getInner()) {
+ if (bts instanceof EmfTypesystem)
+ ets = (EmfTypesystem) bts;
+ }
+
+ _emfTypes = ets;
+ }
+
+ public 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.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.old/src/org/eclipse/xtend/middleend/old/XtendBackendContributor.java b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/XtendBackendContributor.java
new file mode 100644
index 0000000..a6ba34b
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/XtendBackendContributor.java
@@ -0,0 +1,57 @@
+package org.eclipse.xtend.middleend.old;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipose.xtend.middleend.FunctionDefContextFactory;
+import org.eclipse.xtend.backend.common.BackendType;
+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.SourceDefinedFunction;
+import org.eclipse.xtend.backend.iface.BackendContributor;
+import org.eclipse.xtend.backend.types.CompositeTypesystem;
+import org.eclipse.xtend.expression.ExecutionContextImpl;
+import org.eclipse.xtend.typesystem.MetaModel;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class XtendBackendContributor implements BackendContributor {
+ private final OldXtendRegistry _registry;
+ private final String _xtendFile;
+ private final BackendTypesystem _ts;
+
+ public XtendBackendContributor (String xtendFile, Collection<MetaModel> mms, CompositeTypesystem ts) {
+ _xtendFile = OldXtendHelper.normalizeXtendResourceName (xtendFile);
+ _ts = ts;
+
+ final ExecutionContextImpl ctx = new ExecutionContextImpl ();
+ for (MetaModel mm: mms)
+ ctx.registerMetaModel (mm);
+ ctx.setFileEncoding("iso-8859-1"); //TODO really set the encoding
+
+ //TODO redesign to allow reuse of the registry?
+ _registry = new OldXtendRegistry ( ctx, ts);
+ _registry.registerExtension(xtendFile);
+ }
+
+ public BackendType convertToType (List<String> segments) {
+ return null;
+ }
+
+ public Collection<NamedFunction> getContributedFunctions () {
+ return _registry.getContributedFunctions (_xtendFile);
+ }
+
+ public FunctionDefContext getFunctionDefContext () {
+ if (getContributedFunctions().isEmpty())
+ return new FunctionDefContextFactory(_ts).create();
+
+ return ((SourceDefinedFunction) getContributedFunctions().iterator().next().getFunction()).getFunctionDefContext();
+ }
+}
+
+
diff --git a/plugins/org.eclipse.xtend.middleend/.classpath b/plugins/org.eclipse.xtend.middleend/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/.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/.cvsignore b/plugins/org.eclipse.xtend.middleend/.cvsignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/org.eclipse.xtend.middleend/.project b/plugins/org.eclipse.xtend.middleend/.project
new file mode 100644
index 0000000..3372582
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.middleend</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/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtend.middleend/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..fe67abc
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Middleend Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.middleend
+Bundle-Version: 1.0.0
+Require-Bundle: org.eclipse.xtend.backend,
+ org.eclipse.xtend.backend.syslib,
+ org.eclipse.xtend.backend.emftypes,
+ org.eclipse.xtend.backend.javatypes
+Export-Package: org.eclipose.xtend.middleend
diff --git a/plugins/org.eclipse.xtend.middleend/build.properties b/plugins/org.eclipse.xtend.middleend/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/BackendTypesystemFactory.java b/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/BackendTypesystemFactory.java
new file mode 100644
index 0000000..d7602ec
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/BackendTypesystemFactory.java
@@ -0,0 +1,42 @@
+package org.eclipose.xtend.middleend;
+
+import java.io.InputStream;
+
+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.backend.types.java.GlobalJavaBeansTypesystem;
+import org.eclipse.xtend.backend.util.ErrorHandler;
+import org.eclipse.xtend.backend.util.ResourceToList;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class BackendTypesystemFactory {
+ public static final String BACKEND_TYPESYSTEM_RESOURCE = "/xtend.backend.typesystems";
+
+ public CompositeTypesystem create () {
+ final CompositeTypesystem result = new CompositeTypesystem ();
+
+ final InputStream in = getClass().getResourceAsStream (BACKEND_TYPESYSTEM_RESOURCE);
+ if (in == null) {
+ result.register (new EmfTypesystem ());
+ result.register (new GlobalJavaBeansTypesystem ());
+ }
+ else {
+ for (String s: new ResourceToList (in).getResult()) {
+ try {
+ final Class<?> cls = Class.forName (s);
+ final Object o = cls.newInstance();
+ result.register ((BackendTypesystem) o);
+ } catch (Exception e) {
+ ErrorHandler.handle(e);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/FunctionDefContextFactory.java b/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/FunctionDefContextFactory.java
new file mode 100644
index 0000000..2cff521
--- /dev/null
+++ b/plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/FunctionDefContextFactory.java
@@ -0,0 +1,23 @@
+package org.eclipose.xtend.middleend;
+
+import org.eclipse.xtend.backend.common.BackendTypesystem;
+import org.eclipse.xtend.backend.functions.FunctionDefContextImpl;
+import org.eclipse.xtend.backend.syslib.SyslibContributor;
+
+
+/**
+ *
+ * @author Arno Haase (http://www.haase-consulting.com)
+ */
+public final class FunctionDefContextFactory {
+ private final SyslibContributor _syslib;
+
+ public FunctionDefContextFactory (BackendTypesystem ts) {
+ _syslib = new SyslibContributor (ts);
+ }
+
+ public FunctionDefContextImpl create () {
+ return new FunctionDefContextImpl (_syslib);
+ }
+
+}
diff --git a/tests/org.eclipse.xtend.middleend.old.test/.classpath b/tests/org.eclipse.xtend.middleend.old.test/.classpath
new file mode 100644
index 0000000..751c8f2
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/.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/tests/org.eclipse.xtend.middleend.old.test/.cvsignore b/tests/org.eclipse.xtend.middleend.old.test/.cvsignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/tests/org.eclipse.xtend.middleend.old.test/.project b/tests/org.eclipse.xtend.middleend.old.test/.project
new file mode 100644
index 0000000..1fff577
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.xtend.middleend.old.test</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/tests/org.eclipse.xtend.middleend.old.test/META-INF/MANIFEST.MF b/tests/org.eclipse.xtend.middleend.old.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..4ece6b5
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Test Plug-in
+Bundle-SymbolicName: org.eclipse.xtend.middleend.old.test
+Bundle-Version: 1.0.0
+Require-Bundle: org.eclipse.xtend.backend,
+ org.eclipse.xtend.middleend.old,
+ org.eclipse.xtend.middleend,
+ org.eclipse.xtend
diff --git a/tests/org.eclipse.xtend.middleend.old.test/build.properties b/tests/org.eclipse.xtend.middleend.old.test/build.properties
new file mode 100644
index 0000000..34d2e4d
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/FirstAttempt.java b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/FirstAttempt.java
new file mode 100644
index 0000000..b7bff04
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/FirstAttempt.java
@@ -0,0 +1,36 @@
+package org.eclipse.xtend.middleend.old.first;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipose.xtend.middleend.BackendTypesystemFactory;
+import org.eclipse.internal.xtend.type.impl.java.JavaBeansMetaModel;
+import org.eclipse.xtend.backend.BackendFacade;
+import org.eclipse.xtend.backend.common.ExecutionContext;
+import org.eclipse.xtend.backend.types.CompositeTypesystem;
+import org.eclipse.xtend.middleend.old.XtendBackendContributor;
+import org.eclipse.xtend.typesystem.MetaModel;
+
+
+public class FirstAttempt {
+ public static void main (String[] args) {
+ final List<MetaModel> mms = new ArrayList<MetaModel> ();
+ mms.add (new JavaBeansMetaModel ());
+
+ final CompositeTypesystem ts = new BackendTypesystemFactory().create();
+
+ final XtendBackendContributor bc = new XtendBackendContributor ("org::eclipse::xtend::middleend::old::first::first", mms, ts);
+
+ final ExecutionContext ctx = BackendFacade.createExecutionContext (bc.getFunctionDefContext(), ts);
+ System.err.println (BackendFacade.invoke (ctx, "test", Arrays.asList ("Arno")));
+ System.err.println (BackendFacade.invoke (ctx, "testColl", Arrays.asList (Arrays.asList (1L, "Hallo"))));
+ System.err.println (BackendFacade.invoke (ctx, "reexp", Arrays.asList (2L)));
+
+ final Person p = new Person ();
+ p.setFirstName ("Testa");
+ p.setName ("Testarossa");
+
+ System.err.println (BackendFacade.invoke (ctx, "testPerson", Arrays.asList(p)));
+ }
+}
diff --git a/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/Person.java b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/Person.java
new file mode 100644
index 0000000..37453a3
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/Person.java
@@ -0,0 +1,28 @@
+package org.eclipse.xtend.middleend.old.first;
+
+
+public class Person {
+ private String _name;
+ private String _firstName;
+
+ public String getName () {
+ return _name;
+ }
+ public void setName (String name) {
+ _name = name;
+ }
+ public String getFirstName () {
+ return _firstName;
+ }
+ public void setFirstName (String firstName) {
+ _firstName = firstName;
+ }
+
+ public String retrieveTheFullName () {
+ return _firstName + " " + _name;
+ }
+
+ public Person getMother () { // to test for endless recursion during type initialization
+ return null;
+ }
+}
diff --git a/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/first.ext b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/first.ext
new file mode 100644
index 0000000..b2938bc
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/first.ext
@@ -0,0 +1,14 @@
+import org::eclipse::xtend::middleend::old::first;
+
+extension org::eclipse::xtend::middleend::old::first::imported reexport;
+
+test (Object s): test2 (s);
+test2 (Object s): "Hallo, " + s + ": " + 3*(4+5) + " - " + other (99);
+
+testColl (Collection c): c.typeSelect (String).collect (e|"a " + e + " b");
+
+testPerson (Person p): p + " - " + p.firstName + " " + p.name + " - " + p.retrieveTheFullName() + " - " + p.getFirstName();
+
+toString (Person p): "[" + p.firstName + " " + p.name + "]";
+
+
diff --git a/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/imported.ext b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/imported.ext
new file mode 100644
index 0000000..f8b011d
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/imported.ext
@@ -0,0 +1,4 @@
+
+extension org::eclipse::xtend::middleend::old::first::reexported reexport;
+
+other(Object o): "imported " + o + "!";
diff --git a/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/reexported.ext b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/reexported.ext
new file mode 100644
index 0000000..fb453be
--- /dev/null
+++ b/tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/reexported.ext
@@ -0,0 +1,5 @@
+
+extension org::eclipse::xtend::middleend::old::first::imported reexport;
+extension org::eclipse::xtend::middleend::old::first::first reexport;
+
+reexp(Integer i): 3*i+4; \ No newline at end of file