From cc2b24f2d9c6fa5ae561dd2b9467e271eafe418c Mon Sep 17 00:00:00 2001 From: bkolb Date: Fri, 11 Jan 2008 11:18:55 +0000 Subject: initial --- plugins/org.eclipse.xtend.backend/.classpath | 7 + plugins/org.eclipse.xtend.backend/.cvsignore | 1 + plugins/org.eclipse.xtend.backend/.project | 28 ++ .../org.eclipse.xtend.backend/META-INF/MANIFEST.MF | 14 + plugins/org.eclipse.xtend.backend/build.properties | 4 + .../org/eclipse/xtend/backend/BackendFacade.java | 22 ++ .../eclipse/xtend/backend/CreationCacheImpl.java | 25 ++ .../xtend/backend/ExecutionContextImpl.java | 74 ++++ .../eclipse/xtend/backend/FunctionInvokerImpl.java | 34 ++ .../xtend/backend/GlobalVarContextImpl.java | 19 + .../eclipse/xtend/backend/common/BackendType.java | 26 ++ .../xtend/backend/common/BackendTypesystem.java | 22 ++ .../eclipse/xtend/backend/common/Constants.java | 14 + .../backend/common/ContributionStateContext.java | 26 ++ .../xtend/backend/common/CreationCache.java | 12 + .../xtend/backend/common/EfficientLazyString.java | 100 ++++++ .../xtend/backend/common/ExecutionContext.java | 24 ++ .../xtend/backend/common/ExecutionException.java | 42 +++ .../xtend/backend/common/ExecutionListener.java | 20 ++ .../xtend/backend/common/ExpressionBase.java | 54 +++ .../org/eclipse/xtend/backend/common/Function.java | 21 ++ .../xtend/backend/common/FunctionDefContext.java | 35 ++ .../xtend/backend/common/FunctionInvoker.java | 14 + .../xtend/backend/common/GlobalVarContext.java | 12 + .../xtend/backend/common/LocalVarContext.java | 32 ++ .../xtend/backend/common/NamedFunction.java | 62 ++++ .../org/eclipse/xtend/backend/common/Property.java | 16 + .../eclipse/xtend/backend/common/SourcePos.java | 35 ++ .../xtend/backend/common/StaticProperty.java | 15 + .../eclipse/xtend/backend/expr/AndExpression.java | 41 +++ .../xtend/backend/expr/CreateCachedExpression.java | 36 ++ .../backend/expr/CreateUncachedExpression.java | 25 ++ .../xtend/backend/expr/CurriedFunction.java | 64 ++++ .../xtend/backend/expr/CurryingExpression.java | 35 ++ .../xtend/backend/expr/GlobalVarExpression.java | 25 ++ .../backend/expr/HidingLocalVarDefExpression.java | 37 ++ .../eclipse/xtend/backend/expr/IfExpression.java | 37 ++ .../xtend/backend/expr/InitClosureExpression.java | 36 ++ .../expr/InvocationOnCollectionExpression.java | 53 +++ .../backend/expr/InvocationOnObjectExpression.java | 34 ++ .../expr/InvocationOnWhateverExpression.java | 54 +++ .../xtend/backend/expr/ListLiteralExpression.java | 32 ++ .../xtend/backend/expr/LiteralExpression.java | 24 ++ .../xtend/backend/expr/LocalVarEvalExpression.java | 25 ++ .../backend/expr/NewLocalVarDefExpression.java | 36 ++ .../eclipse/xtend/backend/expr/OrExpression.java | 41 +++ .../expr/PropertyOnCollectionExpression.java | 43 +++ .../backend/expr/PropertyOnObjectExpression.java | 33 ++ .../backend/expr/PropertyOnWhateverExpression.java | 60 ++++ .../xtend/backend/expr/SequenceExpression.java | 31 ++ .../xtend/backend/expr/SetPropertyExpression.java | 41 +++ .../xtend/backend/expr/SwitchExpression.java | 55 +++ .../eclipse/xtend/backend/functions/Closure.java | 84 +++++ .../DuplicateAwareFunctionCollection.java | 68 ++++ .../DuplicateAwareNamedFunctionCollection.java | 79 ++++ .../backend/functions/FunctionDefContextImpl.java | 148 ++++++++ .../backend/functions/PolymorphicResolver.java | 111 ++++++ .../backend/functions/SourceDefinedFunction.java | 88 +++++ .../xtend/backend/functions/TypesComparator.java | 43 +++ .../xtend/backend/iface/BackendContributor.java | 26 ++ .../eclipse/xtend/backend/types/AbstractType.java | 107 ++++++ .../xtend/backend/types/CompositeTypesystem.java | 124 +++++++ .../xtend/backend/types/builtin/BooleanType.java | 19 + .../backend/types/builtin/BuiltInOperation.java | 39 ++ .../backend/types/builtin/BuiltinProperty.java | 64 ++++ .../backend/types/builtin/CollectionType.java | 28 ++ .../xtend/backend/types/builtin/DoubleType.java | 19 + .../xtend/backend/types/builtin/FunctionType.java | 45 +++ .../xtend/backend/types/builtin/ListType.java | 26 ++ .../xtend/backend/types/builtin/LongType.java | 24 ++ .../xtend/backend/types/builtin/ObjectType.java | 19 + .../xtend/backend/types/builtin/PropertyType.java | 27 ++ .../xtend/backend/types/builtin/SetType.java | 28 ++ .../backend/types/builtin/StaticPropertyType.java | 30 ++ .../xtend/backend/types/builtin/StringType.java | 25 ++ .../xtend/backend/types/builtin/TypeType.java | 45 +++ .../xtend/backend/types/builtin/VoidType.java | 21 ++ .../src/org/eclipse/xtend/backend/util/Cache.java | 28 ++ .../xtend/backend/util/CollectionHelper.java | 14 + .../eclipse/xtend/backend/util/DoubleKeyCache.java | 30 ++ .../eclipse/xtend/backend/util/ErrorHandler.java | 27 ++ .../eclipse/xtend/backend/util/FatalException.java | 31 ++ .../org/eclipse/xtend/backend/util/NullWriter.java | 25 ++ .../src/org/eclipse/xtend/backend/util/Pair.java | 60 ++++ .../xtend/backend/util/ReflectionHelper.java | 22 ++ .../eclipse/xtend/backend/util/ResourceToList.java | 62 ++++ .../eclipse/xtend/backend/util/StringHelper.java | 274 ++++++++++++++ .../xtend/backend/util/SyntaxConstants.java | 24 ++ .../eclipse/xtend/backend/util/TripleKeyCache.java | 26 ++ .../org/eclipse/xtend/backend/util/Triplet.java | 67 ++++ plugins/org.eclipse.xtend.backend/todo.txt | 100 ++++++ plugins/org.eclipse.xtend.middleend.old/.classpath | 7 + plugins/org.eclipse.xtend.middleend.old/.project | 28 ++ .../META-INF/MANIFEST.MF | 14 + .../build.properties | 4 + .../xtend/middleend/old/JavaExtensionFunction.java | 52 +++ .../middleend/old/OldDefinitionConverter.java | 318 +++++++++++++++++ .../middleend/old/OldExpressionConverter.java | 397 +++++++++++++++++++++ .../xtend/middleend/old/OldExtensionConverter.java | 111 ++++++ .../xtend/middleend/old/OldXtendHelper.java | 19 + .../xtend/middleend/old/OldXtendRegistry.java | 159 +++++++++ .../xtend/middleend/old/TypeToBackendType.java | 167 +++++++++ .../middleend/old/XtendBackendContributor.java | 57 +++ plugins/org.eclipse.xtend.middleend/.classpath | 7 + plugins/org.eclipse.xtend.middleend/.cvsignore | 1 + plugins/org.eclipse.xtend.middleend/.project | 28 ++ .../META-INF/MANIFEST.MF | 10 + .../org.eclipse.xtend.middleend/build.properties | 4 + .../xtend/middleend/BackendTypesystemFactory.java | 42 +++ .../xtend/middleend/FunctionDefContextFactory.java | 23 ++ .../.classpath | 7 + .../.cvsignore | 1 + .../org.eclipse.xtend.middleend.old.test/.project | 28 ++ .../META-INF/MANIFEST.MF | 9 + .../build.properties | 4 + .../xtend/middleend/old/first/FirstAttempt.java | 36 ++ .../eclipse/xtend/middleend/old/first/Person.java | 28 ++ .../eclipse/xtend/middleend/old/first/first.ext | 14 + .../eclipse/xtend/middleend/old/first/imported.ext | 4 + .../xtend/middleend/old/first/reexported.ext | 5 + 120 files changed, 5419 insertions(+) create mode 100644 plugins/org.eclipse.xtend.backend/.classpath create mode 100644 plugins/org.eclipse.xtend.backend/.cvsignore create mode 100644 plugins/org.eclipse.xtend.backend/.project create mode 100644 plugins/org.eclipse.xtend.backend/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.xtend.backend/build.properties create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/BackendFacade.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/CreationCacheImpl.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/ExecutionContextImpl.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/FunctionInvokerImpl.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/GlobalVarContextImpl.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/BackendTypesystem.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Constants.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ContributionStateContext.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/CreationCache.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/EfficientLazyString.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionContext.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionException.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExecutionListener.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/ExpressionBase.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Function.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionDefContext.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/FunctionInvoker.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/GlobalVarContext.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/LocalVarContext.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/NamedFunction.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/Property.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/SourcePos.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/common/StaticProperty.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/AndExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateCachedExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CreateUncachedExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurriedFunction.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/CurryingExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/GlobalVarExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/HidingLocalVarDefExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/IfExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InitClosureExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnCollectionExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnObjectExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/InvocationOnWhateverExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/ListLiteralExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LiteralExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/LocalVarEvalExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/NewLocalVarDefExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/OrExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnCollectionExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnObjectExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/PropertyOnWhateverExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SequenceExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SetPropertyExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/expr/SwitchExpression.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/Closure.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareFunctionCollection.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/DuplicateAwareNamedFunctionCollection.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/FunctionDefContextImpl.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/PolymorphicResolver.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/SourceDefinedFunction.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/functions/TypesComparator.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/iface/BackendContributor.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/AbstractType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/CompositeTypesystem.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BooleanType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltInOperation.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/BuiltinProperty.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/CollectionType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/DoubleType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/FunctionType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ListType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/LongType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/ObjectType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/PropertyType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/SetType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StaticPropertyType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/StringType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/TypeType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/types/builtin/VoidType.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Cache.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/CollectionHelper.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/DoubleKeyCache.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ErrorHandler.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/FatalException.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/NullWriter.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Pair.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ReflectionHelper.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/ResourceToList.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/StringHelper.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/SyntaxConstants.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/TripleKeyCache.java create mode 100644 plugins/org.eclipse.xtend.backend/src/org/eclipse/xtend/backend/util/Triplet.java create mode 100644 plugins/org.eclipse.xtend.backend/todo.txt create mode 100644 plugins/org.eclipse.xtend.middleend.old/.classpath create mode 100644 plugins/org.eclipse.xtend.middleend.old/.project create mode 100644 plugins/org.eclipse.xtend.middleend.old/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.xtend.middleend.old/build.properties create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/JavaExtensionFunction.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldDefinitionConverter.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExpressionConverter.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldExtensionConverter.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendHelper.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/OldXtendRegistry.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/TypeToBackendType.java create mode 100644 plugins/org.eclipse.xtend.middleend.old/src/org/eclipse/xtend/middleend/old/XtendBackendContributor.java create mode 100644 plugins/org.eclipse.xtend.middleend/.classpath create mode 100644 plugins/org.eclipse.xtend.middleend/.cvsignore create mode 100644 plugins/org.eclipse.xtend.middleend/.project create mode 100644 plugins/org.eclipse.xtend.middleend/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.xtend.middleend/build.properties create mode 100644 plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/BackendTypesystemFactory.java create mode 100644 plugins/org.eclipse.xtend.middleend/src/org/eclipose/xtend/middleend/FunctionDefContextFactory.java create mode 100644 tests/org.eclipse.xtend.middleend.old.test/.classpath create mode 100644 tests/org.eclipse.xtend.middleend.old.test/.cvsignore create mode 100644 tests/org.eclipse.xtend.middleend.old.test/.project create mode 100644 tests/org.eclipse.xtend.middleend.old.test/META-INF/MANIFEST.MF create mode 100644 tests/org.eclipse.xtend.middleend.old.test/build.properties create mode 100644 tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/FirstAttempt.java create mode 100644 tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/Person.java create mode 100644 tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/first.ext create mode 100644 tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/imported.ext create mode 100644 tests/org.eclipse.xtend.middleend.old.test/src/org/eclipse/xtend/middleend/old/first/reexported.ext diff --git a/plugins/org.eclipse.xtend.backend/.classpath b/plugins/org.eclipse.xtend.backend/.classpath new file mode 100644 index 00000000..751c8f2e --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.xtend.backend/.cvsignore b/plugins/org.eclipse.xtend.backend/.cvsignore new file mode 100644 index 00000000..ba077a40 --- /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 00000000..5dee6dd7 --- /dev/null +++ b/plugins/org.eclipse.xtend.backend/.project @@ -0,0 +1,28 @@ + + + org.eclipse.xtend.backend + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + 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 00000000..67e0f7cd --- /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 00000000..34d2e4d2 --- /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 00000000..c67a41c9 --- /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 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 00000000..f6cf78fd --- /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, Object> _cache = new DoubleKeyCache, Object> () { + @Override + protected Object create(BackendType t, List key2) { + return t.create(); + } + }; + + public Object createRaw (BackendType t, List 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 00000000..b19a4c61 --- /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 00000000..a1587376 --- /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 , Object> _cache = new DoubleKeyCache, 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 00000000..5012a52f --- /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 _globalVars = new HashMap (); + + public Map 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 00000000..d5166dfa --- /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 getBuiltinOperations (); + + // stuff required for reflection / meta programming + String getName (); + Collection getSuperTypes (); + Map getProperties (); + Map 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 00000000..ef3ec5d6 --- /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 00000000..2a55090f --- /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 00000000..df8d1495 --- /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.
+ * + * This state is re-initialized for every new ExecutionContext. + * + * @author Arno Haase (http://www.haase-consulting.com) + */ +public class ContributionStateContext { + private Map _state = new HashMap(); + + 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 00000000..0e73c6ec --- /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 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 00000000..21fee63c --- /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. + *

+ * Another specialty is that this class can stream its contents to a Writer without the necessity of creating an + * intermediate string in memory. + *

+ * 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 _contents = new ArrayList(); + + 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 00000000..1df132b4 --- /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 00000000..55a7f320 --- /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>> _stackTrace = new ArrayList>> (); + + + public ExecutionException (Exception exc) { + super (exc); + } + + + public ExecutionException (Exception exc, SourcePos sourcePos, Map localVars) { + super (exc); + addStackTraceElement (sourcePos, localVars); + } + + public void addStackTraceElement (SourcePos sourcePos, Map localVars) { + _stackTrace.add (new Pair> (sourcePos, localVars)); + } + + @Override + public String getMessage () { + final StringBuilder result = new StringBuilder (); + + result.append (getCause().getMessage() + "\n"); + for (Pair> 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 00000000..1bcf8f0d --- /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.
+ * + * 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 00000000..405f8c9f --- /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 _listeners = new ArrayList (); + + 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 00000000..bdb2baa5 --- /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 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 00000000..82e1829e --- /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 params); + + /** + * for reflection. This method returns separately registered functions, not those "built into" the + * type. + */ + Collection 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 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 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 00000000..7d7e3736 --- /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 00000000..86c01d11 --- /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 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 00000000..9aa27f2b --- /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 _localVars = new HashMap(); + + public LocalVarContext () { + } + + public LocalVarContext (Object thisValue) { + _localVars.put(Constants.THIS_NAME, thisValue); + } + + public Map 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 00000000..55352f3a --- /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 00000000..f2273966 --- /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 00000000..fe65e529 --- /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 00000000..bf334630 --- /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 00000000..5f017c12 --- /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 00000000..68155865 --- /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 _paramExpr; + + public CreateCachedExpression (BackendType t, List paramExpr, SourcePos sourcePos) { + super(sourcePos); + + _t = t; + _paramExpr = paramExpr; + } + + @Override + public Object evaluateInternal(ExecutionContext ctx) { + final List params = new ArrayList(); + + 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 00000000..70fad460 --- /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 00000000..966cb931 --- /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 _paramTypes = new ArrayList(); + + public CurriedFunction (Function inner, List 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 getParameterTypes () { + return _paramTypes; + } + + public Object invoke (ExecutionContext ctx, Object[] params) { + final List realParams = new ArrayList(); + + 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 00000000..aa5ccbab --- /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 _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 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 00000000..82ab063d --- /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 00000000..cbfed307 --- /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 00000000..d0a7af8b --- /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 00000000..172bee8c --- /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 _paramNames; + private final List _paramTypes; + private final ExpressionBase _def; + + public InitClosureExpression (List paramNames, List 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 00000000..7b9f346f --- /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 _params; + + public InvocationOnCollectionExpression (ExpressionBase coll, String functionName, List 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 params = new ArrayList(); + params.add (null); //placeholder + for (ExpressionBase expr: _params) + params.add (expr.evaluate (ctx)); + + final Collection result = (coll instanceof List) ? new ArrayList () : new HashSet (); + + 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 00000000..d8c05259 --- /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 _params; + + public InvocationOnObjectExpression (String functionName, List params, SourcePos sourcePos) { + super (sourcePos); + + _functionName = functionName; + _params = params; + } + + @Override + public Object evaluateInternal(ExecutionContext ctx) { + final List params = new ArrayList (); + 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 00000000..10be3fec --- /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 _params; + + public InvocationOnWhateverExpression (String functionName, List params, SourcePos sourcePos) { + super (sourcePos); + + _functionName = functionName; + _params = params; + } + + @Override + public Object evaluateInternal(ExecutionContext ctx) { + final List params = new ArrayList (); + 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 result = (coll instanceof List) ? new ArrayList () : new HashSet (); + + 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 00000000..56cd2e56 --- /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 _inner; + + public ListLiteralExpression (List inner, SourcePos sourcePos) { + super (sourcePos); + _inner = inner; + } + + @Override + protected Object evaluateInternal (ExecutionContext ctx) { + final List result = new ArrayList(); + + 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 00000000..8c3003ee --- /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 00000000..464f2e32 --- /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 00000000..e25073a2 --- /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 00000000..1604d85d --- /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 00000000..3b84ce4e --- /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 result = (coll instanceof List) ? new ArrayList () : new HashSet (); + + 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 00000000..e53eebb0 --- /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 00000000..2c2f061a --- /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 result = (o instanceof List) ? new ArrayList () : new HashSet (); + + 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 00000000..ded8d63c --- /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 _inner; + + public SequenceExpression (List 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 00000000..c0fb33b6 --- /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 00000000..282f7ed6 --- /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> _cases; + private final ExpressionBase _defaultExpr; + + public SwitchExpression (ExpressionBase switchExpr, List> 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 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 00000000..b97cb83a --- /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 _paramNames; + private final List _paramTypes; + private final ExpressionBase _def; + + public Closure (LocalVarContext lvcAtDefinitionTime, FunctionDefContext fdcAtDefinitionTime, List paramNames, List 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 ""; + } + + + public boolean isCached () { + return false; + } + + public List 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 00000000..90bdbcf3 --- /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 _allFunctions = new HashSet(); + + + /** + * 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 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 00000000..81e50048 --- /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 _allFunctions = new HashSet(); + private final Cache> _byName = new Cache> () { + @Override + protected Collection create (String key) { + return new HashSet(); + } + }; + + /** + * 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 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 00000000..c02ea772 --- /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> _byFirstParameterType = new Cache>() { + @Override + protected Collection create (BackendType key) { + return new ArrayList(); + } + }; + + private final DoubleKeyCache _functions = new DoubleKeyCache() { + @Override + protected DuplicateAwareNamedFunctionCollection create(String key1, Integer key2) { + return new DuplicateAwareNamedFunctionCollection (); + } + }; + + private final DoubleKeyCache, Collection> _byParamTypes = new DoubleKeyCache, Collection>() { + + @Override + protected Collection create (String functionName, List paramTypes) { + return new PolymorphicResolver(functionName).getBestFitCandidates (findCandidates (functionName, paramTypes)); + } + + private Collection findCandidates (String functionName, List 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 paramTypes) { + if (f.getParameterTypes().size() != paramTypes.size()) + return false; + + for (int i=0; i 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 params) { + final Collection candidates = findFunctionCandidates (ctx, functionName, params); + final Function f = new PolymorphicResolver(functionName).evaluateGuards(ctx, candidates); + return ctx.getFunctionInvoker().invoke (ctx, f, params); + } + + private Collection findFunctionCandidates (ExecutionContext ctx, String functionName, List params) { + final List paramTypes = new ArrayList(); + 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 getByFirstParameterType (BackendType firstParameterType) { + if (firstParameterType.getBuiltinOperations().isEmpty()) + return _byFirstParameterType.get (firstParameterType); + + final List result = new ArrayList (_byFirstParameterType.get (firstParameterType)); + result.addAll (firstParameterType.getBuiltinOperations()); + return result; + } + + public Function getMatch (ExecutionContext ctx, String name, List params) { + final Collection 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 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 00000000..e6dd6df7 --- /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 getBestFitCandidates (Collection functions) { + // shortcut for a common case + if (functions.size() == 1) + return functions; + if (functions.isEmpty()) + throw new IllegalArgumentException ("no matches found"); + + Iterator iter = functions.iterator(); + + Function firstBestMatch = iter.next(); + List bestMatches2 = new ArrayList (); + 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(); + 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 functions) { + if (functions.size() == 1) + return evaluateGuards (ctx, functions.iterator().next()); + + final List unguarded = new ArrayList(); + 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 _paramTypeComparator = new Comparator() { + 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 00000000..db3451c3 --- /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 _paramNames; + private final List _paramTypes; + private final FunctionDefContext _defContext; + private final ExpressionBase _def; + private final boolean _cached; + private final ExpressionBase _guard; + + public SourceDefinedFunction (String name, List paramNames, List 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 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 00000000..99bc9edf --- /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> { + /** + * + * 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 types1, final List 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 00000000..1b965346 --- /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 segments); + + Collection 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 00000000..c2e9495a --- /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 _superTypes; + + private final Map _properties = new HashMap (); + private final Map _staticProperties = new HashMap (); + + private final List _builtinOperations = new ArrayList (); + + 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 superTypes) { + _name = name; + _superTypes = new ArrayList (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 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 getSuperTypes () { + return _superTypes; + } + + public Object create () { + throw new UnsupportedOperationException ("Type " + getName() + " can not be instantiated reflectively."); + } + + public final Map getProperties () { + return _properties; + } + + public final Map 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 00000000..2f9b7767 --- /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 _inner = new ArrayList(); + + private final Cache, BackendType> _cache = new Cache, 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 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 00000000..09d310ad --- /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 00000000..46adcf70 --- /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 _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 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 00000000..b55a9246 --- /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 00000000..c9440921 --- /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 00000000..603114f0 --- /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 00000000..7836d4ea --- /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 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 00000000..e3b8f105 --- /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(); + } + + 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 00000000..367d08b5 --- /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 00000000..ebb8f77e --- /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 00000000..2151ed62 --- /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 00000000..cfe7e238 --- /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(); + } + + 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 00000000..f224344f --- /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 00000000..88128cb4 --- /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.

+ * + * 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 00000000..2dccc2ec --- /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 result = new ArrayList(); + 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 00000000..b0a486b7 --- /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 00000000..c0c9d924 --- /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 { + private final Map _cache = new HashMap(); + + 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 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 00000000..8c8374bb --- /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 00000000..cfd02342 --- /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 { + private final Map, V> _cache = new HashMap, V>(); + + public V get (K1 key1, K2 key2) { + final Pair key = new Pair (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, 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 00000000..18dae512 --- /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 00000000..49f9da89 --- /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 00000000..0abcbb08 --- /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 00000000..a549014f --- /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 { + 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 00000000..c63896f2 --- /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 00000000..0ae62e14 --- /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.
+ * + * 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 _result = new ArrayList(); + + /** + * @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 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 00000000..2e5433de --- /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. + *
    + *
  • \ -> \\ + *
  • <tab> -> \t + *
  • <CR> -> \r + *
  • <Newline> -> \n + *
+ */ + 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 escape + */ + 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 prefixes) { + if (str == null) + return false; + + for (Iterator 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 prefixes) { + if (str == null) + return false; + + for (Iterator 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 00000000..e0142ac3 --- /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 00000000..f1999cae --- /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 { + private final Map, V> _cache = new HashMap, V>(); + + public V get (K1 key1, K2 key2, K3 key3) { + final Triplet key = new Triplet (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 00000000..e495c3c5 --- /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 { + 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 00000000..96a34e27 --- /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) --> 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 00000000..751c8f2e --- /dev/null +++ b/plugins/org.eclipse.xtend.middleend.old/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.xtend.middleend.old/.project b/plugins/org.eclipse.xtend.middleend.old/.project new file mode 100644 index 00000000..a2042d70 --- /dev/null +++ b/plugins/org.eclipse.xtend.middleend.old/.project @@ -0,0 +1,28 @@ + + + org.eclipse.xtend.middleend.old + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + 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 00000000..61ef8ab0 --- /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 00000000..34d2e4d2 --- /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 00000000..5a8a4db6 --- /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 _paramTypes; + + public JavaExtensionFunction (Method mtd, boolean cached, List paramTypes) { + _mtd = mtd; + _cached = cached; + _paramTypes = paramTypes; + } + + public ExpressionBase getGuard () { + return null; + } + + public String getName () { + return _mtd.getName(); + } + + public List 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 00000000..de37f8f6 --- /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 paramNames = new ArrayList(); + final List paramTypes = new ArrayList(); + + 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 parts = new ArrayList (); + + 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 params = new ArrayList (); + 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 params = new ArrayList(); + 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()); + 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 paramNames = Arrays.asList (varName, stmt.getIteratorName().getValue()); + final List 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 ()); + + 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 00000000..6b6c5e3c --- /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 params = new ArrayList (); + for (Expression e: expr.getParams ()) + params.add (convert (e)); + + final List paramTypes = new ArrayList(); + for (Expression e: expr.getParams()) + paramTypes.add (e.analyze(_ctx, new HashSet())); + + 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 ()), 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 params, List paramTypes, SourcePos sourcePos) { + final List paramsWithoutFirst = params; + final List allParams = new ArrayList (); + 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> cases = new ArrayList>(); + for (Case c: expr.getCases()) + cases.add (new Pair (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 inner = new ArrayList(); + + 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()); + + 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()); + 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 getInner (ChainExpression expr) { + final List result = new ArrayList(); + + 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 00000000..a4a836f6 --- /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 getParameterTypes (Extension extension) { + final List unconvertedParamTypes = extension.getParameterTypes(); + + final List result = new ArrayList(); + for (Type t: unconvertedParamTypes) + result.add (_typeConverter.convertToBackendType(t)); + + return result; + } + + private ExpressionBase convertExpression (Expression expr, List localVarNames, List localVarTypes, String extensionName) { + ExecutionContext ctx = _ctx.cloneWithoutVariables(); + + for (int i=0; i paramExprs = new ArrayList (); + 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()); + 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 00000000..413b7b45 --- /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 00000000..371733e1 --- /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 _functionDefContexts = new Cache () { + @Override + protected FunctionDefContextImpl create (String compilationUnit) { + return new FunctionDefContextFactory (_ts).create(); + } + }; + + + /** + * all functions actually defined in a given compilation unit + */ + private final Map> _definedFunctionsByResource = new HashMap >(); + + /** + * all functions exported by a compilation unit, i.e. those functions visible to others that import it + */ + private final Map> _exportedFunctionsByResource = new HashMap >(); + + /** + * all locally defined functions that are exported by a compilation unit. This is an artifact to cleanly handle + * reexports. + */ + private final Map> _locallyExportedFunctionsByResource = new HashMap >(); + + + 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 defined = new ArrayList(); + final List exported = new ArrayList(); + + 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 (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 visitedForReexport = new HashSet(); + visitedForReexport.add (xtendFile); + final List reexported = new ArrayList(); + getReexported (xtendFile, reexported, visitedForReexport, new HashSet()); + + for (NamedFunction f: reexported) { + exported.add (f); + fdc.register (f); + } + } + + private void getReexported (String xtendFile, Collection result, Set harvestedCompilationUnits, Set 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 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 00000000..8161fa85 --- /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 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 00000000..a6ba34bf --- /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 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 segments) { + return null; + } + + public Collection 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 00000000..751c8f2e --- /dev/null +++ b/plugins/org.eclipse.xtend.middleend/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.xtend.middleend/.cvsignore b/plugins/org.eclipse.xtend.middleend/.cvsignore new file mode 100644 index 00000000..ba077a40 --- /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 00000000..33725820 --- /dev/null +++ b/plugins/org.eclipse.xtend.middleend/.project @@ -0,0 +1,28 @@ + + + org.eclipse.xtend.middleend + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + 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 00000000..fe67abce --- /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 00000000..34d2e4d2 --- /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 00000000..d7602ece --- /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 00000000..2cff5214 --- /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 00000000..751c8f2e --- /dev/null +++ b/tests/org.eclipse.xtend.middleend.old.test/.classpath @@ -0,0 +1,7 @@ + + + + + + + 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 00000000..ba077a40 --- /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 00000000..1fff5771 --- /dev/null +++ b/tests/org.eclipse.xtend.middleend.old.test/.project @@ -0,0 +1,28 @@ + + + org.eclipse.xtend.middleend.old.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + 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 00000000..4ece6b5b --- /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 00000000..34d2e4d2 --- /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 00000000..b7bff04b --- /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 mms = new ArrayList (); + 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 00000000..37453a38 --- /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 00000000..b2938bc1 --- /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 00000000..f8b011de --- /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 00000000..fb453bea --- /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 -- cgit v1.2.3