From c2624ea05e323605f731707269876e22e7211833 Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Tue, 12 Aug 2008 16:14:43 +0000 Subject: [PATCH] First drop of SPEL --- .../common/CompositeStringExpression.java | 68 + .../DefaultNonTemplateParserContext.java | 24 + .../common/DefaultTemplateParserContext.java | 24 + .../expression/common/ExpressionUtils.java | 54 + .../expression/common/LiteralExpression.java | 56 + .../common/TemplateAwareExpressionParser.java | 1 + .../expression/spel/ast/ArgList.java | 69 + .../expression/spel/ast/Assign.java | 54 + .../expression/spel/ast/BooleanLiteral.java | 40 + .../spel/ast/CompoundExpression.java | 120 + .../spel/ast/ConstructorReference.java | 312 + .../expression/spel/ast/DateLiteral.java | 76 + .../expression/spel/ast/Dot.java | 46 + .../spel/ast/ExpressionListNode.java | 75 + .../spel/ast/FunctionReference.java | 157 + .../expression/spel/ast/Identifier.java | 41 + .../expression/spel/ast/Indexer.java | 156 + .../expression/spel/ast/IntLiteral.java | 54 + .../expression/spel/ast/Lambda.java | 83 + .../expression/spel/ast/ListInitializer.java | 67 + .../expression/spel/ast/Literal.java | 56 + .../spel/ast/LocalFunctionReference.java | 88 + .../spel/ast/LocalVariableReference.java | 64 + .../expression/spel/ast/MapEntry.java | 65 + .../expression/spel/ast/MapInitializer.java | 63 + .../expression/spel/ast/MethodReference.java | 323 + .../expression/spel/ast/NullLiteral.java | 36 + .../expression/spel/ast/Operator.java | 70 + .../expression/spel/ast/OperatorAnd.java | 65 + .../expression/spel/ast/OperatorBetween.java | 66 + .../spel/ast/OperatorDistanceTo.java | 109 + .../expression/spel/ast/OperatorDivide.java | 63 + .../expression/spel/ast/OperatorEquality.java | 58 + .../spel/ast/OperatorGreaterThan.java | 58 + .../spel/ast/OperatorGreaterThanOrEqual.java | 58 + .../expression/spel/ast/OperatorIn.java | 60 + .../spel/ast/OperatorInequality.java | 58 + .../expression/spel/ast/OperatorIs.java | 55 + .../expression/spel/ast/OperatorLessThan.java | 58 + .../spel/ast/OperatorLessThanOrEqual.java | 58 + .../expression/spel/ast/OperatorLike.java | 68 + .../expression/spel/ast/OperatorMatches.java | 58 + .../expression/spel/ast/OperatorMinus.java | 95 + .../expression/spel/ast/OperatorModulus.java | 63 + .../expression/spel/ast/OperatorMultiply.java | 87 + .../expression/spel/ast/OperatorNot.java | 51 + .../expression/spel/ast/OperatorOr.java | 63 + .../expression/spel/ast/OperatorPlus.java | 88 + .../spel/ast/OperatorSoundsLike.java | 113 + .../expression/spel/ast/Placeholder.java | 46 + .../expression/spel/ast/Projection.java | 98 + .../spel/ast/PropertyOrFieldReference.java | 239 + .../spel/ast/QualifiedIdentifier.java | 69 + .../expression/spel/ast/RealLiteral.java | 34 + .../expression/spel/ast/Reference.java | 88 + .../expression/spel/ast/Selection.java | 146 + .../expression/spel/ast/SpelNode.java | 110 + .../expression/spel/ast/StringLiteral.java | 42 + .../expression/spel/ast/Ternary.java | 60 + .../expression/spel/ast/TypeReference.java | 64 + .../spel/ast/VariableReference.java | 70 + .../spel/generated/SpringExpressions.g | 375 + .../spel/generated/SpringExpressions.tokens | 92 + .../generated/SpringExpressionsLexer.java | 3018 +++++++ .../generated/SpringExpressionsParser.java | 7531 +++++++++++++++++ .../spel/generated/SpringExpressions__.g | 174 + .../spel/internal/EmptySpelNode.java | 39 + .../spel/internal/InternalELException.java | 35 + .../spel/internal/KeyValuePair.java | 33 + .../spel/internal/SpelTreeAdaptor.java | 220 + .../SpringExpressionsLexerExtender.java | 81 + .../SpringExpressionsParserExtender.java | 78 + .../expression/spel/internal/TypeCode.java | 103 + .../expression/spel/internal/Utils.java | 76 + .../spel/internal/VariableScope.java | 57 + .../internal/WrappedExpressionException.java | 35 + .../spel/processors/AverageProcessor.java | 57 + .../spel/processors/CountProcessor.java | 35 + .../spel/processors/CutProcessor.java | 54 + .../spel/processors/DataProcessor.java | 35 + .../spel/processors/DistinctProcessor.java | 43 + .../spel/processors/MaxProcessor.java | 47 + .../spel/processors/MinProcessor.java | 47 + .../spel/processors/NonNullProcessor.java | 42 + .../spel/processors/SortProcessor.java | 66 + .../expression/spel/processors/package.html | 14 + .../ReflectionConstructorExecutor.java | 68 + .../ReflectionConstructorResolver.java | 66 + .../reflection/ReflectionMethodExecutor.java | 64 + .../reflection/ReflectionMethodResolver.java | 63 + .../ReflectionPropertyReaderExecutor.java | 56 + ...nPropertyReaderExecutorForArrayLength.java | 21 + .../ReflectionPropertyResolver.java | 202 + .../ReflectionPropertyWriterExecutor.java | 58 + .../spel/reflection/ReflectionUtils.java | 612 ++ .../spel/standard/StandardComparator.java | 78 + .../standard/StandardEvaluationContext.java | 193 + .../StandardIndividualTypeConverter.java | 48 + .../spel/standard/StandardTypeConverter.java | 283 + .../spel/standard/StandardTypeLocator.java | 81 + .../spel/standard/StandardTypeUtilities.java | 102 + .../expression/spel/AllTests.java | 49 + .../spel/BooleanExpressionTests.java | 57 + .../spel/ConstructorInvocationTests.java | 104 + .../spel/DefaultComparatorUnitTests.java | 47 + .../expression/spel/EvaluationTests.java | 650 ++ .../spel/ExpressionLanguageScenarioTests.java | 430 + .../expression/spel/ExpressionTestCase.java | 298 + .../spel/MethodInvocationTests.java | 113 + .../expression/spel/OperatorTests.java | 73 + .../expression/spel/ParsingTests.java | 463 + .../expression/spel/PerformanceTests.java | 296 + .../expression/spel/PropertyAccessTests.java | 138 + .../spel/ScenariosForSpringSecurity.java | 292 + .../spel/TemplateExpressionParsing.java | 61 + 115 files changed, 22313 insertions(+) create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultNonTemplateParserContext.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultTemplateParserContext.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ArgList.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Assign.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/DateLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Dot.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ExpressionListNode.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Lambda.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ListInitializer.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Literal.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalFunctionReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalVariableReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapEntry.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapInitializer.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Operator.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorAnd.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDistanceTo.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDivide.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorEquality.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThan.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThanOrEqual.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIn.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorInequality.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIs.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThan.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThanOrEqual.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLike.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMinus.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorModulus.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMultiply.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorOr.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorPlus.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorSoundsLike.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Placeholder.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Projection.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Reference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/SpelNode.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.tokens create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressionsLexer.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressionsParser.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions__.g create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/EmptySpelNode.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/InternalELException.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/KeyValuePair.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpelTreeAdaptor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsLexerExtender.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsParserExtender.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/TypeCode.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/Utils.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/VariableScope.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/WrappedExpressionException.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/AverageProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CountProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CutProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DataProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DistinctProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MaxProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MinProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/NonNullProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/SortProcessor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/package.html create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorExecutor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorResolver.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodExecutor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodResolver.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutorForArrayLength.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyResolver.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyWriterExecutor.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionUtils.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardComparator.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardEvaluationContext.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardIndividualTypeConverter.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeConverter.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeLocator.java create mode 100644 org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeUtilities.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/AllTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/BooleanExpressionTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/ConstructorInvocationTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/DefaultComparatorUnitTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionLanguageScenarioTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestCase.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/OperatorTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/ParsingTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/PerformanceTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/ScenariosForSpringSecurity.java create mode 100644 org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsing.java diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java new file mode 100644 index 00000000000..16870658000 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/CompositeStringExpression.java @@ -0,0 +1,68 @@ +package org.springframework.expression.common; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; + +/** + * Represents a template expression broken into pieces. Each piece will be an Expression but pure text parts to the + * template will be represented as LiteralExpression objects. An example of a template expression might be:
+ * "Hello ${getName()}"
+ * 
which will be represented as a CompositeStringExpression of two parts. The first part being a + * LiteralExpression representing 'Hello ' and the second part being a real expression that will call getName() when + * invoked. + * @author Andy Clement + */ +public class CompositeStringExpression implements Expression { + + private String expressionString; + + /** + * The array of expressions that make up the composite expression + */ + private Expression[] expressions; + + public CompositeStringExpression(String expressionString, Expression[] expressions) { + this.expressionString = expressionString; + this.expressions = expressions; + } + + public String getExpressionString() { + return expressionString; + } + + public String getValue() throws EvaluationException { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < expressions.length; i++) { + // TODO (asc) is stringify ok for the non literal components? or should the converters be used? see another case below + sb.append(expressions[i].getValue()); + } + return sb.toString(); + } + + public String getValue(EvaluationContext context) throws EvaluationException { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < expressions.length; i++) { + sb.append(expressions[i].getValue(context)); + } + return sb.toString(); + } + + public Class getValueType(EvaluationContext context) throws EvaluationException { + return String.class; + } + + public void setValue(EvaluationContext context, Object value) throws EvaluationException { + throw new EvaluationException(expressionString, "Cannot call setValue() on a composite expression"); + } + + public Object getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { + Object value = getValue(context); + return ExpressionUtils.convert(context, value, expectedResultType); + } + + public Object getValue(Class expectedResultType) throws EvaluationException { + Object value = getValue(); + return ExpressionUtils.convert(null, value, expectedResultType); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultNonTemplateParserContext.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultNonTemplateParserContext.java new file mode 100644 index 00000000000..62c0d4f45d3 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultNonTemplateParserContext.java @@ -0,0 +1,24 @@ +package org.springframework.expression.common; + +import org.springframework.expression.ParserContext; + +public class DefaultNonTemplateParserContext implements ParserContext { + + public static final DefaultNonTemplateParserContext INSTANCE = new DefaultNonTemplateParserContext(); + + private DefaultNonTemplateParserContext() { + } + + public String getExpressionPrefix() { + return null; + } + + public String getExpressionSuffix() { + return null; + } + + public boolean isTemplate() { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultTemplateParserContext.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultTemplateParserContext.java new file mode 100644 index 00000000000..c459929048e --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/DefaultTemplateParserContext.java @@ -0,0 +1,24 @@ +package org.springframework.expression.common; + +import org.springframework.expression.ParserContext; + +public class DefaultTemplateParserContext implements ParserContext { + + public static final DefaultTemplateParserContext INSTANCE = new DefaultTemplateParserContext(); + + private DefaultTemplateParserContext() { + } + + public String getExpressionPrefix() { + return "${"; + } + + public String getExpressionSuffix() { + return "}"; + } + + public boolean isTemplate() { + return true; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java new file mode 100644 index 00000000000..42d76d5dc0a --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.common; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.TypeUtils; + +/** + * Common utility functions that may be used by any Expression Language provider. + * + * @author Andy Clement + */ +public class ExpressionUtils { + + /** + * Determines if there is a type converter available in the specified context and attempts to use it to convert the supplied + * value to the specified type. Throws an exception if conversion is not possible. + * + * @param context the evaluation context that may define a type converter + * @param value the value to convert (may be null) + * @param toType the type to attempt conversion to + * @return the converted value + * @throws EvaluationException if there is a problem during conversion or conversion of the value to the specified type is not supported + */ + public static Object convert(EvaluationContext context, Object value, Class toType) throws EvaluationException { + if (value==null || toType.isAssignableFrom(value.getClass())) { + return value; + } + if (context!=null) { + TypeUtils typeUtils = context.getTypeUtils(); + if (typeUtils != null) { + TypeConverter typeConverter = typeUtils.getTypeConverter(); + return typeConverter.convertValue(value,toType); + } + } + throw new EvaluationException("Cannot convert value '"+value+"' to type '"+toType.getName()+"'"); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java new file mode 100644 index 00000000000..d2d6b050510 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/LiteralExpression.java @@ -0,0 +1,56 @@ +package org.springframework.expression.common; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; + +/** + * A very simple hardcoded implementation of the Expression interface that represents a string literal. It is used with + * CompositeStringExpression when representing a template expression which is made up of pieces - some being real + * expressions to be handled by an EL implementation like Spel, and some being just textual elements. + * + * @author Andy Clement + * + */ +public class LiteralExpression implements Expression { + + /** + * Fixed literal value of this expression + */ + private String literalValue; + + public LiteralExpression(String literalValue) { + this.literalValue = literalValue; + } + + public String getExpressionString() { + return new StringBuilder().append("'").append(literalValue).append("'").toString(); + } + + public Object getValue() throws EvaluationException { + return literalValue; + } + + public Object getValue(EvaluationContext context) throws EvaluationException { + return literalValue; + } + + public Class getValueType(EvaluationContext context) throws EvaluationException { + return String.class; + } + + public void setValue(EvaluationContext context, Object value) throws EvaluationException { + throw new EvaluationException(this.literalValue, "Cannot call setValue() on a LiteralExpression"); + } + + public Object getValue(EvaluationContext context, Class expectedResultType) throws EvaluationException { + Object value = getValue(context); + return ExpressionUtils.convert(context, value, expectedResultType); + } + + public Object getValue(Class expectedResultType) throws EvaluationException { + Object value = getValue(); + return ExpressionUtils.convert(null, value, expectedResultType); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java new file mode 100644 index 00000000000..d9099e26903 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java @@ -0,0 +1 @@ +package org.springframework.expression.common; import java.util.LinkedList; import java.util.List; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParseException; import org.springframework.expression.ParserContext; import sun.tools.jstat.ParserException; /** * An expression parser that understands templates. It can be subclassed by expression parsers that do not offer first * class support for templating. * * @author Keith Donald * @author Andy Clement */ public abstract class TemplateAwareExpressionParser implements ExpressionParser { public Expression parseExpression(String expressionString) throws ParseException { return parseExpression(expressionString, DefaultNonTemplateParserContext.INSTANCE); } public final Expression parseExpression(String expressionString, ParserContext context) throws ParseException { if (context == null) { context = DefaultNonTemplateParserContext.INSTANCE; } if (context.isTemplate()) { return parseTemplate(expressionString, context); } else { return doParseExpression(expressionString, context); } } private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException { // TODO what about zero length expressions? Expression[] expressions = parseExpressions(expressionString, context); if (expressions.length == 1) { return expressions[0]; } else { return new CompositeStringExpression(expressionString, expressions); } } // helper methods /** * Helper that parses given expression string using the configured parser. The expression string can contain any * number of expressions all contained in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static * pieces of text will also be returned as Expressions that just return that static piece of text. As a result, * evaluating all returned expressions and concatenating the results produces the complete evaluated string. * Unwrapping is only done of the outermost delimiters found, so the string 'hello ${foo${abc}}' would break into * the pieces 'hello ' and 'foo${abc}'. This means that expression languages that used ${..} as part of their * functionality are supported without any problem * * @param expressionString the expression string * @return the parsed expressions * @throws ParserException when the expressions cannot be parsed */ private final Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException { // TODO this needs to handle nested delimiters for cases where the expression uses the delim chars List expressions = new LinkedList(); int startIdx = 0; String prefix = context.getExpressionPrefix(); String suffix = context.getExpressionSuffix(); while (startIdx < expressionString.length()) { int prefixIndex = expressionString.indexOf(prefix, startIdx); if (prefixIndex >= startIdx) { // a inner expression was found - this is a composite if (prefixIndex > startIdx) { expressions.add(new LiteralExpression(expressionString.substring(startIdx, prefixIndex))); startIdx = prefixIndex; } int nextPrefixIndex = expressionString.indexOf(prefix, prefixIndex + prefix.length()); int suffixIndex; if (nextPrefixIndex == -1) { // this is the last expression in the expression string suffixIndex = expressionString.lastIndexOf(suffix); } else { // another expression exists after this one in the expression string suffixIndex = expressionString.lastIndexOf(suffix, nextPrefixIndex); } if (suffixIndex < (prefixIndex + prefix.length())) { throw new ParseException(expressionString, "No ending suffix '" + suffix + "' for expression starting at character " + prefixIndex + ": " + expressionString.substring(prefixIndex), null); } else if (suffixIndex == prefixIndex + prefix.length()) { throw new ParseException(expressionString, "No expression defined within delimiter '" + prefix + suffix + "' at character " + prefixIndex, null); } else { String expr = expressionString.substring(prefixIndex + prefix.length(), suffixIndex); expressions.add(doParseExpression(expr, context)); startIdx = suffixIndex +suffix.length(); } } else { if (startIdx == 0) { expressions.add(doParseExpression(expressionString, context)); } else { // no more ${expressions} found in string, add rest as static text expressions.add(new LiteralExpression(expressionString.substring(startIdx))); } startIdx = expressionString.length(); } } return expressions.toArray(new Expression[expressions.size()]); } protected abstract Expression doParseExpression(String expressionString, ParserContext context) throws ParseException; } \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ArgList.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ArgList.java new file mode 100644 index 00000000000..5030f2962e2 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ArgList.java @@ -0,0 +1,69 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents the list of arguments supplied to a lambda expression. For an expression "{|x,y| $x > $y ? $x : $y }" the + * argument list is x,y + * + * @author Andy Clement + * + */ +public class ArgList extends SpelNode { + + public ArgList(Token payload) { + super(payload); + } + + /** + * @return a list of the argument names captured in this ArgList + */ + public List getArgumentNames() { + if (getChildCount() == 0) + return Collections.emptyList(); + List result = new ArrayList(); + for (int i = 0; i < getChildCount(); i++) { + result.add(getChild(i).getText()); + } + return result; + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + return sb.toString(); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + throw new SpelException(SpelMessages.ARGLIST_SHOULD_NOT_BE_EVALUATED); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Assign.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Assign.java new file mode 100644 index 00000000000..18c7dbeaab1 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Assign.java @@ -0,0 +1,54 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents assignment. An alternative to calling setValue() for an expression is to use an assign. + *

+ * Example: 'someNumberProperty=42' + * + * @author Andy Clement + * + */ +public class Assign extends SpelNode { + + public Assign(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object newValue = getChild(1).getValue(state); + getChild(0).setValue(state, newValue); + return newValue; + } + + @Override + public String toStringAST() { + return new StringBuilder().append(getChild(0).toStringAST()).append("=").append(getChild(1).toStringAST()) + .toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java new file mode 100644 index 00000000000..791663e5408 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/BooleanLiteral.java @@ -0,0 +1,40 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; + +/** + * Represents the literal values TRUE and FALSE. + * + * @author Andy Clement + * + */ +public class BooleanLiteral extends Literal { + + private final Boolean value; + + public BooleanLiteral(Token payload, boolean value) { + super(payload); + this.value = value; + } + + @Override + public Boolean getLiteralValue() { + return value; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java new file mode 100644 index 00000000000..e3a29b5bc7d --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java @@ -0,0 +1,120 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a DOT separated expression sequence, such as 'property1.property2.methodOne()' + * + * @author Andy Clement + * + */ +public class CompoundExpression extends SpelNode { + + public CompoundExpression(Token payload) { + super(payload); + } + + /** + * Evalutes a compound expression. This involves evaluating each piece in turn and the return value from each piece + * is the active context object for the subsequent piece. + * + * @param state the state in which the expression is being evaluated + * @return the final value from the last piece of the compound expression + */ + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object result = null; + SpelNode nextNode = null; + try { + nextNode = getChild(0); + result = nextNode.getValue(state); + for (int i = 1; i < getChildCount(); i++) { + try { + state.pushActiveContextObject(result); + nextNode = getChild(i); + result = nextNode.getValue(state); + } finally { + state.popActiveContextObject(); + } + } + } catch (SpelException ee) { + // Correct the position for the error before rethrowing + ee.setPosition(nextNode.getCharPositionInLine()); + throw ee; + } + return result; + } + + @Override + public void setValue(ExpressionState state, Object value) throws EvaluationException { + if (getChildCount() == 1) { + getChild(0).setValue(state, value); + return; + } + Object ctx = getChild(0).getValue(state); + for (int i = 1; i < getChildCount() - 1; i++) { + try { + state.pushActiveContextObject(ctx); + ctx = getChild(i).getValue(state); + } finally { + state.popActiveContextObject(); + } + } + try { + state.pushActiveContextObject(ctx); + getChild(getChildCount() - 1).setValue(state, value); + } finally { + state.popActiveContextObject(); + } + } + + @Override + public boolean isWritable(ExpressionState state) throws EvaluationException { + if (getChildCount() == 1) { + return getChild(0).isWritable(state); + } + Object ctx = getChild(0).getValue(state); + for (int i = 1; i < getChildCount() - 1; i++) { + try { + state.pushActiveContextObject(ctx); + ctx = getChild(i).getValue(state); + } finally { + state.popActiveContextObject(); + } + } + try { + state.pushActiveContextObject(ctx); + return getChild(getChildCount() - 1).isWritable(state); + } finally { + state.popActiveContextObject(); + } + } + + @Override + public String toStringAST() { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < getChildCount(); i++) { + sb.append(getChild(i).toStringAST()); + } + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java new file mode 100644 index 00000000000..c4195a64ca5 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ConstructorReference.java @@ -0,0 +1,312 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.lang.reflect.Array; +import java.util.List; + +import org.antlr.runtime.Token; +import org.springframework.expression.AccessException; +import org.springframework.expression.ConstructorExecutor; +import org.springframework.expression.ConstructorResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.TypeCode; +import org.springframework.expression.spel.internal.Utils; + +/** + * Represents the invocation of a constructor. Either a constructor on a regular type or construction of an array. When + * an array is constructed, an initializer can be specified. + *

+ * Examples:
+ * new String('hello world')
+ * new int[]{1,2,3,4}
+ * new int[3] new int[3]{1,2,3} + * + * @author Andy Clement + * + */ +public class ConstructorReference extends SpelNode { + + /** + * The resolver/executor model {@link ConstructorResolver} supports the caching of executor objects that can run + * some discovered constructor repeatedly without searching for it each time. This flag controls whether caching + * occurs and is primarily exposed for testing. + */ + public static boolean useCaching = true; + + /** + * The cached executor that may be reused on subsequent evaluations. + */ + private ConstructorExecutor cachedExecutor; + + /** + * If true then this is an array constructor, for example, 'new String[]', rather than a simple constructor 'new + * String()' + */ + private final boolean isArrayConstructor; + + public ConstructorReference(Token payload, boolean isArrayConstructor) { + super(payload); + this.isArrayConstructor = isArrayConstructor; + } + + /** + * Implements getValue() - delegating to the code for building an array or a simple type. + */ + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + if (isArrayConstructor) { + return createArray(state); + } else { + return createNewInstance(state); + } + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("new "); + + int index = 0; + sb.append(getChild(index++).toStringAST()); + + if (!isArrayConstructor) { + sb.append("("); + for (int i = index; i < getChildCount(); i++) { + if (i > index) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + sb.append(")"); + } else { + // Next child is EXPRESSIONLIST token with children that are the + // expressions giving array size + sb.append("["); + SpelNode arrayRank = getChild(index++); + for (int i = 0; i < arrayRank.getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(arrayRank.getChild(i).toStringAST()); + } + sb.append("]"); + if (index < getChildCount()) + sb.append(" ").append(getChild(index).toStringAST()); + } + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + + /** + * Create an array and return it. The children of this node indicate the type of array, the array ranks and any optional initializer that might have been supplied. + * + * @param state the expression state within which this expression is being evaluated + * @return the new array + * @throws EvaluationException if there is a problem creating the array + */ + private Object createArray(ExpressionState state) throws EvaluationException { + Object intendedArrayType = getChild(0).getValue(state); + if (!(intendedArrayType instanceof String)) { + throw new SpelException(getChild(0).getCharPositionInLine(),SpelMessages.TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION,Utils.formatClassnameForMessage(intendedArrayType.getClass())); + } + String type = (String) intendedArrayType; + Class componentType = null; + TypeCode arrayTypeCode = TypeCode.forName(type); + if (arrayTypeCode == TypeCode.OBJECT) { + componentType = state.findType(type); + } else { + componentType = arrayTypeCode.getType(); + } + + Object newArray = null; + + if (getChild(1).getChildCount() == 0) { // are the array ranks defined? + if (getChildCount() < 3) { + throw new SpelException(getCharPositionInLine(), SpelMessages.NO_SIZE_OR_INITIALIZER_FOR_ARRAY_CONSTRUCTION); + } + // no array ranks so use the size of the initializer to determine array size + int arraySize = getChild(2).getChildCount(); + newArray = Array.newInstance(componentType, arraySize); + } else { + // Array ranks are specified but is it a single or multiple dimension array? + int dimensions = getChild(1).getChildCount(); + if (dimensions == 1) { + Object o = getChild(1).getValue(state); + int arraySize = state.toInteger(o); + if (getChildCount() == 3) { + // Check initializer length matches array size length + int initializerLength = getChild(2).getChildCount(); + if (initializerLength != arraySize) { + throw new SpelException(getChild(2).getCharPositionInLine(), SpelMessages.INITIALIZER_LENGTH_INCORRECT, + initializerLength, arraySize); + } + } + newArray = Array.newInstance(componentType, arraySize); + } else { + // Multi-dimensional - hold onto your hat ! + int[] dims = new int[dimensions]; + for (int d=0; d[] argumentTypes = new Class[getChildCount() - 1]; + for (int i = 0; i < arguments.length; i++) { + Object childValue = getChild(i + 1).getValue(state); + arguments[i] = childValue; + argumentTypes[i] = childValue.getClass(); + } + + if (cachedExecutor != null) { + try { + return cachedExecutor.execute(state.getEvaluationContext(), arguments); + } catch (AccessException ae) { + // this is OK - it may have gone stale due to a class change, + // let's try to get a new one and call it before giving up + } + } + + // either there was no accessor or it no longer exists + String typename = (String) getChild(0).getValue(state); + cachedExecutor = findExecutorForConstructor(typename, argumentTypes, state); + try { + return cachedExecutor.execute(state.getEvaluationContext(), arguments); + } catch (AccessException ae) { + throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_CONSTRUCTOR_INVOCATION, typename, ae.getMessage()); + } finally { + if (!useCaching) { + cachedExecutor = null; + } + } + } + + /** + * Go through the list of registered constructor resolvers and see if any can find a constructor that takes the specified set of arguments. + * + * @param typename the type trying to be constructed + * @param argumentTypes the types of the arguments supplied that the constructor must take + * @param state the current state of the expression + * @return a reusable ConstructorExecutor that can be invoked to run the constructor or null + * @throws SpelException if there is a problem locating the constructor + */ + public ConstructorExecutor findExecutorForConstructor(String typename, Class[] argumentTypes, ExpressionState state) throws SpelException { + EvaluationContext eContext = state.getEvaluationContext(); + List cResolvers = eContext.getConstructorResolvers(); + if (cResolvers != null) { + for (ConstructorResolver ctorResolver : cResolvers) { + try { + ConstructorExecutor cEx = ctorResolver.resolve(state.getEvaluationContext(), typename, + argumentTypes); + if (cEx != null) { + return cEx; + } + } catch (AccessException e) { + Throwable cause = e.getCause(); + if (cause instanceof SpelException) { + throw (SpelException) cause; + } else { + throw new SpelException(cause, SpelMessages.PROBLEM_LOCATING_CONSTRUCTOR, typename, Utils + .formatMethodForMessage("", argumentTypes)); + } + } + } + } + throw new SpelException(SpelMessages.CONSTRUCTOR_NOT_FOUND, typename, Utils.formatMethodForMessage("", + argumentTypes)); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/DateLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/DateLiteral.java new file mode 100644 index 00000000000..49935fdd26f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/DateLiteral.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a date literal value in an expression (a java.util.Date object). + * + * @author Andy Clement + * + */ +public class DateLiteral extends SpelNode { + + private DateFormat formatter = null; + private Date formattedDate = null; + + public DateLiteral(Token payload) { + super(payload); + } + + @Override + public Date getValue(ExpressionState state) throws EvaluationException { + if (formatter == null) { + if (getChildCount() > 1) { + formatter = new SimpleDateFormat((String) getChild(1).getValue(state)); + } else { + formatter = DateFormat.getDateTimeInstance(); + } + } + String valueToParse = (String) getChild(0).getValue(state); + try { + formattedDate = formatter.parse(valueToParse); + } catch (ParseException e) { + throw new SpelException(getCharPositionInLine(), e, SpelMessages.DATE_CANNOT_BE_PARSED, valueToParse, + (formatter instanceof SimpleDateFormat ? ((SimpleDateFormat) formatter).toLocalizedPattern() + : formatter)); + } + return formattedDate; + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("date("); + sb.append(getChild(0).toStringAST()); + if (getChildCount() > 1) { + sb.append(",").append(getChild(1).toStringAST()); + } + sb.append(")"); + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Dot.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Dot.java new file mode 100644 index 00000000000..6231a4a13ee --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Dot.java @@ -0,0 +1,46 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * This is used for preserving positional information from the input expression. + * + * @author Andy Clement + * + */ +public class Dot extends SpelNode { + // TODO Keep Dot for the positional information or remove it? + + public Dot(Token payload) { + super(payload); + } + + @Override + public String toStringAST() { + return "."; + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + // This makes Dot a do-nothing operation, but this is not free in terms of computation + return state.getActiveContextObject(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ExpressionListNode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ExpressionListNode.java new file mode 100644 index 00000000000..7272d1770b9 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ExpressionListNode.java @@ -0,0 +1,75 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a list of expressions of the form "(expression1;expression2;expression3)". The expressions are always + * evaluated from left to right, due to possible side effects that earlier expressions may have that influence the + * evaluation of later expressions (defining functions, setting variables, etc). + * + * @author Andy Clement + * + */ +public class ExpressionListNode extends SpelNode { + + public ExpressionListNode(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object result = null; + for (int i = 0; i < getChildCount(); i++) { + result = getChild(i).getValue(state); + } + return result; + } + + @Override + public boolean isWritable(ExpressionState state) throws EvaluationException { + boolean isWritable = false; + if (getChildCount() > 0) { + // Evaluate all but the last one + for (int i = 0; i < getChildCount() - 1; i++) { + getChild(i).getValue(state); + } + isWritable = getChild(getChildCount() - 1).isWritable(state); + } + return isWritable; + } + + @Override + public String toStringAST() { + StringBuffer sb = new StringBuffer(); + if (getChildCount() == 1) { + sb.append(getChild(0).toStringAST()); + } else { + sb.append("("); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(";"); + sb.append(getChild(i).toStringAST()); + } + sb.append(")"); + } + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java new file mode 100644 index 00000000000..5a9eb7c8064 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FunctionReference.java @@ -0,0 +1,157 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * A function reference is of the form "#someFunction(a,b,c)". Functions may be defined in the context prior to the + * expression being evaluated or within the expression itself using a lambda function definition. For example: Lambda + * function definition in an expression: "(#max = {|x,y|$x>$y?$x:$y};max(2,3))" Calling context defined function: + * "#isEven(37)" + * + * Functions are very simplistic, the arguments are not part of the definition (right now), so the names must be unique. + * + * @author Andy Clement + * + */ +public class FunctionReference extends SpelNode { + + private final String name; + + public FunctionReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object o = state.lookupVariable(name); + if (o == null) { + throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name); + } + if (!(o instanceof Lambda || o instanceof Method)) { + throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass()); + } + + // FUNCTION REF NEEDS TO DO ARG CONVERSION?? + if (o instanceof Lambda) { + return executeLambdaFunction(state, (Lambda) o); + } else { // o instanceof Method + return executeFunctionJLRMethod(state, (Method) o); + } + } + + /* Execute a function represented as a java.lang.reflect.Method */ + private Object executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException { + Object[] functionArgs = getArguments(state); + if (m.getParameterTypes().length != functionArgs.length) { + throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m + .getParameterTypes().length); + } + + // Check if arguments need converting + Class[] expectedParams = m.getParameterTypes(); + Object[] argsToPass = new Object[functionArgs.length]; + TypeConverter converter = state.getEvaluationContext().getTypeUtils().getTypeConverter(); + for (int arg=0; arg args = lambdaExpression.getArguments(); + if (args.size() != functionArgs.length) { + throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, args + .size()); + } + Map argMap = new HashMap(); + for (int i = 0; i < args.size(); i++) { + argMap.put(args.get(i), functionArgs[i]); + } + try { + state.enterScope(argMap); + return ((SpelNode) lambdaExpression.getExpression()).getValue(state); + } finally { + state.exitScope(); + } + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder("#").append(name); + sb.append("("); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + sb.append(")"); + return sb.toString(); + } + + // to 'assign' to a function don't use the () suffix and so it is just a variable reference + @Override + public boolean isWritable(ExpressionState expressionState) throws EvaluationException { + return false; + } + + /** + * Compute the arguments to the function, they are the children of this expression node. + * @return an array of argument values for the function call + */ + private Object[] getArguments(ExpressionState state) throws EvaluationException { + // Compute arguments to the function + Object[] arguments = new Object[getChildCount()]; + for (int i = 0; i < arguments.length; i++) { + arguments[i] = getChild(i).getValue(state); + } + return arguments; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java new file mode 100644 index 00000000000..65510c5aaca --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Identifier.java @@ -0,0 +1,41 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +public class Identifier extends SpelNode { + + private final String id; + + public Identifier(Token payload) { + super(payload); + id = payload.getText(); + } + + @Override + public String toStringAST() { + return id; + } + + @Override + public String getValue(ExpressionState state) throws SpelException { + return id; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java new file mode 100644 index 00000000000..c2382cbcb69 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -0,0 +1,156 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.Collection; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +// TODO 2 support multidimensional arrays +// TODO 3 support correct syntax for multidimensional [][][] and not [,,,] +/** + * An Indexer can index into some proceeding structure to access a particular piece of it. Supported structures are: + * strings/collections (lists/sets)/arrays + * + * @author Andy Clement + */ +public class Indexer extends SpelNode { + + public Indexer(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object ctx = state.getActiveContextObject(); + Object index = getChild(0).getValue(state); + + // Indexing into a Map + if (ctx instanceof Map) { + return ((Map) ctx).get(index); + } + + int idx = state.toInteger(index); + + if (ctx.getClass().isArray()) { + return accessArrayElement(ctx, idx); + } else if (ctx instanceof Collection) { + Collection c = (Collection) ctx; + if (idx >= c.size()) { + throw new SpelException(SpelMessages.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx); + } + int pos = 0; + for (Object o : c) { + if (pos == idx) { + return o; + } + pos++; + } + // } else if (ctx instanceof Map) { + // Map c = (Map) ctx; + // // This code would allow a key/value pair to be pulled out by index from a map + // if (idx >= c.size()) { + // throw new ELException(ELMessages.COLLECTION_INDEX_OUT_OF_BOUNDS,c.size(),idx); + // } + // Set keys = c.keySet(); + // int pos = 0; + // for (Object k : keys) { + // if (pos==idx) { + // return new KeyValuePair(k,c.get(k)); + // } + // pos++; + // } + } else if (ctx instanceof String) { + String ctxString = (String) ctx; + if (idx >= ctxString.length()) { + throw new SpelException(SpelMessages.STRING_INDEX_OUT_OF_BOUNDS, ctxString.length(), idx); + } + return String.valueOf(ctxString.charAt(idx)); + } + throw new SpelException(SpelMessages.INDEXING_NOT_SUPPORTED_FOR_TYPE, ctx.getClass().getName()); + } + + private Object accessArrayElement(Object ctx, int idx) throws SpelException { + Class arrayComponentType = ctx.getClass().getComponentType(); + if (arrayComponentType == Integer.TYPE) { + int[] array = (int[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Boolean.TYPE) { + boolean[] array = (boolean[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Character.TYPE) { + char[] array = (char[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Long.TYPE) { + long[] array = (long[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Short.TYPE) { + short[] array = (short[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Double.TYPE) { + double[] array = (double[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Float.TYPE) { + float[] array = (float[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else if (arrayComponentType == Byte.TYPE) { + byte[] array = (byte[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } else { + Object[] array = (Object[]) ctx; + checkAccess(array.length, idx); + return array[idx]; + } + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + sb.append("]"); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + + private void checkAccess(int arrayLength, int index) throws SpelException { + if (index > arrayLength) { + throw new SpelException(getCharPositionInLine(), SpelMessages.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java new file mode 100644 index 00000000000..fc62b517e0f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java @@ -0,0 +1,54 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; + +public class IntLiteral extends Literal { + + private static String[] suffixes = {"UL" , "LU" , "ul" , "lu" , "uL" , "lU" , "U" , "L" , "u" , "l" }; + + private Integer value; + + public IntLiteral(Token payload) { + super(payload); + // TODO properly support longs and unsigned numbers + String toParse = payload.getText(); + try { + value = Integer.parseInt(toParse); + } catch (NumberFormatException nfe) { + for (int i=0;i $y ? $x : $y }". It is possible for an expression to have zero + * arguments in which case this expression node only has one child. + * + * @author Andy Clement + */ +public class Lambda extends SpelNode { + + public Lambda(Token payload) { + super(payload); + // payload.setText("LambdaExpression"); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + return this; + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + if (getChildCount() == 1) { // there are no arguments + sb.append("{|| "); + sb.append(getChild(0).toStringAST()); + sb.append(" }"); + } else { + sb.append("{|"); + sb.append(getChild(0).toStringAST()); + sb.append("| "); + sb.append(getChild(1).toStringAST()); + sb.append(" }"); + } + return sb.toString(); + } + + @Override + public String toString() { + return toStringAST(); + } + + public List getArguments() { + // Only one child means there are no arguments + if (getChildCount() < 2) { + return Collections.emptyList(); + } + ArgList args = (ArgList) getChild(0); + return args.getArgumentNames(); + } + + public Object getExpression() { + return (getChildCount() > 1 ? getChild(1) : getChild(0)); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ListInitializer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ListInitializer.java new file mode 100644 index 00000000000..73f995a5159 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/ListInitializer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +public class ListInitializer extends SpelNode { + + public ListInitializer(Token payload) { + super(payload); + } + + /** + * Evaluate the list initializer, returning a List + */ + @Override + public List getValue(ExpressionState state) throws EvaluationException { + List result = new ArrayList(); + for (int i = 0; i < getChildCount(); i++) { + Object element = getChild(i).getValue(state); + result.add(element); + } + return result; + } + + /** + * Return string form of this node {,,} + */ + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) { + sb.append(","); + } + sb.append(getChild(i).toStringAST()); + } + sb.append("}"); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Literal.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Literal.java new file mode 100644 index 00000000000..f72865ef41f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Literal.java @@ -0,0 +1,56 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Common superclass for nodes representing literals (boolean, string, number, etc). + * + * @author Andy Clement + * + */ +public abstract class Literal extends SpelNode { + + public Literal(Token payload) { + super(payload); + } + + public abstract Object getLiteralValue(); + + @Override + public final Object getValue(ExpressionState state) throws SpelException { + return getLiteralValue(); + } + + @Override + public String toString() { + return getLiteralValue().toString(); + } + + @Override + public String toStringAST() { + return toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalFunctionReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalFunctionReference.java new file mode 100644 index 00000000000..b14f9675557 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalFunctionReference.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Local functions are references like $fn() where fn is the 'local' to lookup in the local scope Example: "(#sqrt={|n| + * T(Math).sqrt($n)};#delegate={|f,n| $f($n)};#delegate(#sqrt,4))" + * + * @author Andy Clement + */ +public class LocalFunctionReference extends SpelNode { + + private final String name; + + public LocalFunctionReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object o = state.lookupLocalVariable(name); + if (o == null) { + throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name); + } + if (!(o instanceof Lambda)) { + throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass().getName()); + } + + Object[] arguments = new Object[getChildCount()]; + for (int i = 0; i < arguments.length; i++) { + arguments[i] = getChild(i).getValue(state); + } + Lambda lambdaExpression = (Lambda) o; + List args = lambdaExpression.getArguments(); + Map argMap = new HashMap(); + if (args.size() != arguments.length) { + throw new SpelException(getCharPositionInLine(), SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, + arguments.length, args.size()); + } + for (int i = 0; i < args.size(); i++) { + argMap.put(args.get(i), arguments[i]); + } + try { + state.enterScope(argMap); + return ((SpelNode) lambdaExpression.getExpression()).getValue(state); + } finally { + state.exitScope(); + } + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder("$").append(name); + sb.append("("); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + sb.append(")"); + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalVariableReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalVariableReference.java new file mode 100644 index 00000000000..6cffeb01e7c --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/LocalVariableReference.java @@ -0,0 +1,64 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * A variable reference such as $someVar. Local variables are only visible at the current scoping level or below within + * an expression. Calling a function introduces a new nested scope. + * + * @author Andy Clement + * + */ +public class LocalVariableReference extends SpelNode { + + private final String name; + + public LocalVariableReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + Object result = state.lookupLocalVariable(name); + if (result == null) { + throw new SpelException(getCharPositionInLine(), SpelMessages.LOCAL_VARIABLE_NOT_DEFINED, name); + } + return result; + } + + @Override + public void setValue(ExpressionState state, Object value) throws SpelException { + // Object oldValue = state.lookupVariable(name); + state.setLocalVariable(name, value); + } + + @Override + public String toStringAST() { + return new StringBuilder("$").append(name).toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return true; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapEntry.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapEntry.java new file mode 100644 index 00000000000..3fe1e3b891c --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapEntry.java @@ -0,0 +1,65 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents an entry in a map initializer structure like "#{'a':3,'b':2}" Both "'a':3" and "'b':2" would be MapEntry + * instances. + * + * @author Andy Clement + * + */ +public class MapEntry extends SpelNode { + + public MapEntry(Token payload) { + super(payload); + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + String k = getChild(0).toStringAST(); + String v = getChild(1).toStringAST(); + sb.append(k).append(":").append(v); + return sb.toString(); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + throw new SpelException(SpelMessages.MAPENTRY_SHOULD_NOT_BE_EVALUATED); + } + + /** + * Return the value of the key for this map entry. + */ + public Object getKeyValue(ExpressionState state) throws EvaluationException { + return getChild(0).getValue(state); + } + + /** + * Return the value of the value for this map entry. + */ + public Object getValueValue(ExpressionState state) throws EvaluationException { + return getChild(1).getValue(state); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapInitializer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapInitializer.java new file mode 100644 index 00000000000..76b659aff4f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MapInitializer.java @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.HashMap; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +public class MapInitializer extends SpelNode { + + public MapInitializer(Token payload) { + super(payload); + } + + @Override + public Map getValue(ExpressionState state) throws EvaluationException { + Map result = new HashMap(); + for (int i = 0; i < getChildCount(); i++) { + MapEntry mEntry = (MapEntry) getChild(i); + result.put(mEntry.getKeyValue(state), mEntry.getValueValue(state)); + } + return result; + } + + /** + * Return string form of this node #{a:b,c:d,...} + */ + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("#{"); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(", "); + sb.append(getChild(i).toStringAST()); + } + sb.append("}"); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java new file mode 100644 index 00000000000..95aa2bc7f52 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -0,0 +1,323 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.MethodExecutor; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.Utils; +import org.springframework.expression.spel.processors.AverageProcessor; +import org.springframework.expression.spel.processors.CountProcessor; +import org.springframework.expression.spel.processors.CutProcessor; +import org.springframework.expression.spel.processors.DataProcessor; +import org.springframework.expression.spel.processors.DistinctProcessor; +import org.springframework.expression.spel.processors.MaxProcessor; +import org.springframework.expression.spel.processors.MinProcessor; +import org.springframework.expression.spel.processors.NonNullProcessor; +import org.springframework.expression.spel.processors.SortProcessor; + +public class MethodReference extends SpelNode { + + private static Map registeredProcessers = new HashMap(); + + private final String name; + private MethodExecutor fastInvocationAccessor; // TODO should this be nulled if executing in a different context or is it OK to keep? + + static { + registeredProcessers.put("count", new CountProcessor()); + registeredProcessers.put("max", new MaxProcessor()); + registeredProcessers.put("min", new MinProcessor()); + registeredProcessers.put("average", new AverageProcessor()); + registeredProcessers.put("sort", new SortProcessor()); + registeredProcessers.put("nonnull", new NonNullProcessor()); + registeredProcessers.put("distinct", new DistinctProcessor()); + registeredProcessers.put("cut", new CutProcessor()); + } + + public MethodReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @SuppressWarnings("unchecked") + private Object invokeDataProcessor(Object[] arguments, ExpressionState state) throws EvaluationException { + DataProcessor processor = registeredProcessers.get(name); + + Object target = state.getActiveContextObject(); + + // Prepare the input, translating arrays to lists + boolean wasArray = false; + Class arrayElementType = null; + Collection dataToProcess = null; + if (target instanceof Collection) { + dataToProcess = (Collection) target; + } else { + wasArray = true; + arrayElementType = target.getClass().getComponentType(); + if (arrayElementType.equals(Integer.TYPE)) { + int[] data = (int[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Byte.TYPE)) { + byte[] data = (byte[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Character.TYPE)) { + char[] data = (char[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Double.TYPE)) { + double[] data = (double[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Long.TYPE)) { + long[] data = (long[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Float.TYPE)) { + float[] data = (float[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Short.TYPE)) { + short[] data = (short[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else if (arrayElementType.equals(Boolean.TYPE)) { + boolean[] data = (boolean[]) target; + dataToProcess = new ArrayList(); + for (int i = 0; i < data.length; i++) { + dataToProcess.add(data[i]); + } + } else { + dataToProcess = Arrays.asList((Object[]) target); + } + } + + Object result = processor.process(dataToProcess, arguments, state); + + // Convert the result back if necessary + if (wasArray && (result instanceof Collection)) { + Collection c = (Collection) result; + + if (arrayElementType.equals(Integer.TYPE)) { + int[] newArray = (int[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Integer) i).intValue(); + return newArray; + } else if (arrayElementType.equals(Byte.TYPE)) { + byte[] newArray = (byte[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Byte) i).byteValue(); + return newArray; + } else if (arrayElementType.equals(Character.TYPE)) { + char[] newArray = (char[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Character) i).charValue(); + return newArray; + } else if (arrayElementType.equals(Double.TYPE)) { + double[] newArray = (double[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Double) i).doubleValue(); + return newArray; + } else if (arrayElementType.equals(Long.TYPE)) { + long[] newArray = (long[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Long) i).longValue(); + return newArray; + } else if (arrayElementType.equals(Float.TYPE)) { + float[] newArray = (float[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Float) i).floatValue(); + return newArray; + } else if (arrayElementType.equals(Short.TYPE)) { + short[] newArray = (short[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Short) i).shortValue(); + return newArray; + } else if (arrayElementType.equals(Boolean.TYPE)) { + boolean[] newArray = (boolean[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) + newArray[idx++] = ((Boolean) i).booleanValue(); + return newArray; + } else { + Object[] newArray = (Object[]) Array.newInstance(arrayElementType, c.size()); + int idx = 0; + for (Object i : c) { + newArray[idx++] = i; + } + return newArray; + } + } + return result; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object currentContext = state.getActiveContextObject(); + Object[] arguments = new Object[getChildCount()]; + for (int i = 0; i < arguments.length; i++) { + arguments[i] = getChild(i).getValue(state); + } + if (currentContext == null) { + throw new SpelException(getCharPositionInLine(), SpelMessages.ATTEMPTED_METHOD_CALL_ON_NULL_CONTEXT_OBJECT, + formatMethodForMessage(name, getTypes(arguments))); + } + + boolean usingProcessor = registeredProcessers.containsKey(name); + if ((currentContext.getClass().isArray() && usingProcessor) + || (currentContext instanceof Collection && registeredProcessers.containsKey(name))) { + return invokeDataProcessor(arguments, state); + } + + if (fastInvocationAccessor != null) { + try { + return fastInvocationAccessor.execute(state.getEvaluationContext(), state.getActiveContextObject(), + arguments); + } catch (AccessException ae) { + // this is OK - it may have gone stale due to a class change, let's get a new one and retry before + // giving up + } + } + // either there was no accessor or it no longer existed + fastInvocationAccessor = findAccessorForMethod(name, getTypes(arguments), state); + try { + return fastInvocationAccessor.execute(state.getEvaluationContext(), state.getActiveContextObject(), + arguments); + } catch (AccessException ae) { + ae.printStackTrace(); + throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_METHOD_INVOCATION, name, + state.getActiveContextObject().getClass().getName(), ae.getMessage()); + } + } + + private Class[] getTypes(Object... arguments) { + if (arguments == null) + return null; + Class[] argumentTypes = new Class[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + argumentTypes[i] = arguments[i].getClass(); + } + return argumentTypes; + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append(name).append("("); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append(","); + sb.append(getChild(i).toStringAST()); + } + sb.append(")"); + return sb.toString(); + } + + /** + * Produce a nice string for a given method name with specified arguments. + * @param name the name of the method + * @param argumentTypes the types of the arguments to the method + * @return nicely formatted string, eg. foo(String,int) + */ + private String formatMethodForMessage(String name, Class... argumentTypes) { + StringBuilder sb = new StringBuilder(); + sb.append(name); + sb.append("("); + if (argumentTypes != null) { + for (int i = 0; i < argumentTypes.length; i++) { + if (i > 0) + sb.append(","); + sb.append(argumentTypes[i].getClass()); + } + } + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + + public final MethodExecutor findAccessorForMethod(String name, Class[] argumentTypes, ExpressionState state) + throws SpelException { + Object contextObject = state.getActiveContextObject(); + EvaluationContext eContext = state.getEvaluationContext(); + if (contextObject == null) { + throw new SpelException(SpelMessages.ATTEMPTED_METHOD_CALL_ON_NULL_CONTEXT_OBJECT, Utils + .formatMethodForMessage(name, argumentTypes)); + } + List mResolvers = eContext.getMethodResolvers(); + if (mResolvers != null) { + for (MethodResolver methodResolver : mResolvers) { + try { + MethodExecutor cEx = methodResolver.resolve(state.getEvaluationContext(), contextObject, name, + argumentTypes); + if (cEx != null) + return cEx; + } catch (AccessException e) { + Throwable cause = e.getCause(); + if (cause instanceof SpelException) { + throw (SpelException) cause; + } else { + throw new SpelException(cause, SpelMessages.PROBLEM_LOCATING_METHOD, name, contextObject.getClass()); + } + } + } + } + throw new SpelException(SpelMessages.METHOD_NOT_FOUND, Utils.formatMethodForMessage(name, argumentTypes), Utils + .formatClassnameForMessage(contextObject instanceof Class ? ((Class) contextObject) : contextObject + .getClass())); + // (contextObject instanceof Class ? ((Class) contextObject).getName() : contextObject.getClass() + // .getName())); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java new file mode 100644 index 00000000000..62e0a41749e --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/NullLiteral.java @@ -0,0 +1,36 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; + +public class NullLiteral extends Literal { + + public NullLiteral(Token payload) { + super(payload); + } + + @Override + public String getLiteralValue() { + return null; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Operator.java new file mode 100644 index 00000000000..df254fbe286 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Common supertype for operators that operate on either one or two operands. In the case of multiply or divide there + * would be two operands, but for unary plus or minus, there is only one. + * + * @author Andy Clement + */ +public abstract class Operator extends SpelNode { + + public Operator(Token payload) { + super(payload); + } + + /** + * Operator expressions can never be written to + */ + @Override + public final boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + + public SpelNode getLeftOperand() { + return getChild(0); + } + + public SpelNode getRightOperand() { + return getChild(1); + } + + public abstract String getOperatorName(); + + /** + * String format for all operators is the same '(' [operand] [operator] [operand] ')' + */ + @Override + public String toStringAST() { + StringBuffer sb = new StringBuffer(); + if (getChildCount() > 0) + sb.append("("); + sb.append(getChild(0).toStringAST()); + for (int i = 1; i < getChildCount(); i++) { + sb.append(" ").append(getOperatorName()).append(" "); + sb.append(getChild(i).toStringAST()); + } + if (getChildCount() > 0) + sb.append(")"); + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorAnd.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorAnd.java new file mode 100644 index 00000000000..6ef1006c437 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorAnd.java @@ -0,0 +1,65 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents the boolean AND operation. + * + * @author Andy Clement + */ +public class OperatorAnd extends Operator { + + public OperatorAnd(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "and"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + boolean leftValue; + boolean rightValue; + + try { + leftValue = state.toBoolean(getLeftOperand().getValue(state)); + } catch (SpelException ee) { + ee.setPosition(getLeftOperand().getCharPositionInLine()); + throw ee; + } + + if (leftValue == false) { + return false; // no need to evaluate right operand + } + + try { + rightValue = state.toBoolean(getRightOperand().getValue(state)); + } catch (SpelException ee) { + ee.setPosition(getRightOperand().getCharPositionInLine()); + throw ee; + } + + return /* leftValue && */rightValue; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java new file mode 100644 index 00000000000..01bcfc19033 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorBetween.java @@ -0,0 +1,66 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.List; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents the between operator. The left operand to between must be a single value and the right operand must be a + * list - this operator returns true if the left operand is between (using the registered comparator) the two elements + * in the list. + * + * @author Andy Clement + */ +public class OperatorBetween extends Operator { + + public OperatorBetween(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "between"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (!(right instanceof List) || ((List) right).size() != 2) { + throw new SpelException(getRightOperand().getCharPositionInLine(), + SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST); + } + List l = (List) right; + Object low = l.get(0); + Object high = l.get(1); + TypeComparator comparator = state.getTypeComparator(); + try { + // TODO between is inclusive, is that OK + return (comparator.compare(left, low) >= 0 && comparator.compare(left, high) <= 0); + } catch (SpelException ee) { + ee.setPosition(getCharPositionInLine()); + throw ee; + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDistanceTo.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDistanceTo.java new file mode 100644 index 00000000000..bc16b5739db --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDistanceTo.java @@ -0,0 +1,109 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +// TODO is the operator 'distanceto' any use...? +/** + * The distanceto operator uses an implementation of the levenshtein distance measurement for determining the 'edit + * distance' between two strings (the two operands to distanceto). http://en.wikipedia.org/wiki/Levenshtein_distance + * @author Andy Clement + * + */ +public class OperatorDistanceTo extends Operator { + + private final static boolean DEBUG = false; + + public OperatorDistanceTo(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "distanceto"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + try { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + return computeDistanceTo((String) left, (String) right); + } catch (SpelException ee) { + throw ee; + } + } + + private int computeDistanceTo(String from, String to) { + if (from.equals(to)) + return 0; + int[][] d = new int[from.length() + 1][to.length() + 1]; + + for (int i = 0; i <= from.length(); i++) + d[i][0] = i; + + for (int j = 0; j <= to.length(); j++) + d[0][j] = j; + + for (int i = 1; i <= from.length(); i++) { + for (int j = 1; j <= to.length(); j++) { + int cost; + if (from.charAt(i - 1) == to.charAt(j - 1)) + cost = 0; + else + cost = 1; + d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);// del,ins,subst + + } + } + if (DEBUG) { + // Display the table of values + System.out.print(" "); + for (int j = 0; j < from.length(); j++) { + System.out.print(from.charAt(j) + " "); + } + System.out.println(); + for (int j = 0; j < to.length() + 1; j++) { + System.out.print((j > 0 ? to.charAt(j - 1) : " ") + " "); + for (int i = 0; i < from.length() + 1; i++) { + System.out.print(d[i][j]); + if (i == from.length() && j == to.length()) + System.out.print("<"); + else if (i == from.length() - 1 && j == to.length()) + System.out.print(">"); + else + System.out.print(" "); + } + System.out.println(); + } + } + return d[from.length()][to.length()]; + } + + private int min(int i, int j, int k) { + int min = i; + if (j < min) + min = j; + if (k < min) + min = k; + return min; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDivide.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDivide.java new file mode 100644 index 00000000000..a594ba3ae79 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDivide.java @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements division operator + * + * @author Andy Clement + */ +public class OperatorDivide extends Operator { + + public OperatorDivide(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "/"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object operandOne = getLeftOperand().getValue(state); + Object operandTwo = getRightOperand().getValue(state); + if (operandOne instanceof Number && operandTwo instanceof Number) { + Number op1 = (Number) operandOne; + Number op2 = (Number) operandTwo; + if (op1 instanceof Double || op2 instanceof Double) { + Double result = op1.doubleValue() / op2.doubleValue(); + return result; + } else if (op1 instanceof Float || op2 instanceof Float) { + Float result = op1.floatValue() / op2.floatValue(); + return result; + } else if (op1 instanceof Long || op2 instanceof Long) { + Long result = op1.longValue() / op2.longValue(); + return result; + } else { // TODO what about non-int result of the division? + Integer result = op1.intValue() / op2.intValue(); + return result; + } + } + return state.operate(Operation.DIVIDE, operandOne, operandTwo); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorEquality.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorEquality.java new file mode 100644 index 00000000000..15c59db05ef --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorEquality.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements equality operator. + * + * @author Andy Clement + */ +public class OperatorEquality extends Operator { + + public OperatorEquality(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "=="; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() == op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() == op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() == op2.longValue(); + } else { + return op1.intValue() == op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) == 0; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThan.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThan.java new file mode 100644 index 00000000000..4600f4ba849 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThan.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements greater than operator. + * + * @author Andy Clement + */ +public class OperatorGreaterThan extends Operator { + + public OperatorGreaterThan(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return ">"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() > op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() > op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() > op2.longValue(); + } else { + return op1.intValue() > op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) > 0; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThanOrEqual.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThanOrEqual.java new file mode 100644 index 00000000000..0c840c254aa --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorGreaterThanOrEqual.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements greater than or equal operator. + * + * @author Andy Clement + */ +public class OperatorGreaterThanOrEqual extends Operator { + + public OperatorGreaterThanOrEqual(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return ">="; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() >= op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() >= op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() >= op2.longValue(); + } else { + return op1.intValue() >= op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) >= 0; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIn.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIn.java new file mode 100644 index 00000000000..58d0593822f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIn.java @@ -0,0 +1,60 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.Collection; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents the 'in' operator and returns true if the left operand can be found within the collection passed as the + * right operand. + * + * @author Andy Clement + */ +public class OperatorIn extends Operator { + + public OperatorIn(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "in"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (right instanceof Collection) { + Collection c = (Collection) right; + for (Object element : c) { + if (state.getTypeComparator().compare(left, element) == 0) { + return true; + } + } + return false; + } + throw new SpelException(SpelMessages.OPERATOR_IN_CANNOT_DETERMINE_MEMBERSHIP, left.getClass().getName(), right + .getClass().getName()); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorInequality.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorInequality.java new file mode 100644 index 00000000000..2ba0a94ac94 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorInequality.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the not-equal operator + * + * @author Andy Clement + */ +public class OperatorInequality extends Operator { + + public OperatorInequality(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "!="; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() != op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() != op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() != op2.longValue(); + } else { + return op1.intValue() != op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) != 0; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIs.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIs.java new file mode 100644 index 00000000000..1e9d72592e7 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorIs.java @@ -0,0 +1,55 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * The operator 'is' checks if an object is of the class specified in the right hand operand, in the same way that + * instanceof does in Java. + * + * @author Andy Clement + * + */ +public class OperatorIs extends Operator { + // TODO should 'is' change to 'instanceof' ? + + public OperatorIs(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "is"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (!(right instanceof Class)) { + throw new SpelException(getRightOperand().getCharPositionInLine(), + SpelMessages.IS_OPERATOR_NEEDS_CLASS_OPERAND, right.getClass().getName()); + } + // TODO Could this defer to type utilities? What would be the benefit? + return (((Class) right).isAssignableFrom(left.getClass())); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThan.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThan.java new file mode 100644 index 00000000000..dfdd6d99349 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThan.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the less than operator + * + * @author Andy Clement + */ +public class OperatorLessThan extends Operator { + + public OperatorLessThan(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "<"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() < op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() < op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() < op2.longValue(); + } else { + return op1.intValue() < op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) < 0; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThanOrEqual.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThanOrEqual.java new file mode 100644 index 00000000000..66ad8c1ba59 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLessThanOrEqual.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the less than or equal operator + * + * @author Andy Clement + */ +public class OperatorLessThanOrEqual extends Operator { + + public OperatorLessThanOrEqual(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + return op1.doubleValue() <= op2.doubleValue(); + } else if (op1 instanceof Float || op2 instanceof Float) { + return op1.floatValue() <= op2.floatValue(); + } else if (op1 instanceof Long || op2 instanceof Long) { + return op1.longValue() <= op2.longValue(); + } else { + return op1.intValue() <= op2.intValue(); + } + } + return state.getTypeComparator().compare(left, right) <= 0; + } + + @Override + public String getOperatorName() { + return "<="; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLike.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLike.java new file mode 100644 index 00000000000..e30f0010cac --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorLike.java @@ -0,0 +1,68 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the like operator. The expected operands for like are a string and a pattern (JDK regex). The operator + * will return true if the string matches the regex. + * + * @author Andy Clement + */ +public class OperatorLike extends Operator { + + public OperatorLike(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "like"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + SpelNode leftOp = getLeftOperand(); + SpelNode rightOp = getRightOperand(); + Object left = leftOp.getValue(state); + Object right = getRightOperand().getValue(state); + try { + if (!(left instanceof String)) { + throw new SpelException(leftOp.getCharPositionInLine(), + SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR, left); + } + if (!(right instanceof String)) { + throw new SpelException(rightOp.getCharPositionInLine(), + SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR, right); + } + Pattern pattern = Pattern.compile((String) right); + Matcher matcher = pattern.matcher((String) left); + return matcher.matches(); + } catch (PatternSyntaxException pse) { + throw new SpelException(rightOp.getCharPositionInLine(), pse, SpelMessages.INVALID_PATTERN, right); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java new file mode 100644 index 00000000000..946fc428342 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMatches.java @@ -0,0 +1,58 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +// TODO what should be the difference between like and matches? +/** + * Implements the matches operator. + * + * @author Andy Clement + */ +public class OperatorMatches extends Operator { + + public OperatorMatches(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + try { + Pattern pattern = Pattern.compile((String) right); + Matcher matcher = pattern.matcher((String) left); + return matcher.matches(); + } catch (PatternSyntaxException pse) { + throw new SpelException(pse, SpelMessages.INVALID_PATTERN, right); + } + } + + @Override + public String getOperatorName() { + return "matches"; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMinus.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMinus.java new file mode 100644 index 00000000000..dea69a22dad --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMinus.java @@ -0,0 +1,95 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the minus operator. If there is only one operand it is a unary minus. + * + * @author Andy Clement + */ +public class OperatorMinus extends Operator { + + public OperatorMinus(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "-"; + } + + @Override + public String toStringAST() { + if (getRightOperand() == null) { // unary minus + return new StringBuilder().append("-").append(getLeftOperand()).toString(); + } + return super.toStringAST(); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + SpelNode leftOp = getLeftOperand(); + SpelNode rightOp = getRightOperand(); + if (rightOp == null) {// If only one operand, then this is unary minus + Object left = leftOp.getValue(state); + if (left instanceof Number) { + Number n = (Number) left; + if (left instanceof Double) { + Double result = 0 - n.doubleValue(); + return result; + } else if (left instanceof Float) { + Float result = 0 - n.floatValue(); + return result; + } else if (left instanceof Long) { + Long result = 0 - n.longValue(); + return result; + } else { + Integer result = 0 - n.intValue(); + return result; + } + } + throw new SpelException(SpelMessages.CANNOT_NEGATE_TYPE, left.getClass().getName()); + } else { + Object left = leftOp.getValue(state); + Object right = rightOp.getValue(state); + if (left instanceof Number && right instanceof Number) { + Number op1 = (Number) left; + Number op2 = (Number) right; + if (op1 instanceof Double || op2 instanceof Double) { + Double result = op1.doubleValue() - op2.doubleValue(); + return result; + } else if (op1 instanceof Float || op2 instanceof Float) { + Float result = op1.floatValue() - op2.floatValue(); + return result; + } else if (op1 instanceof Long || op2 instanceof Long) { + Long result = op1.longValue() - op2.longValue(); + return result; + } else { + Integer result = op1.intValue() - op2.intValue(); + return result; + } + } + return state.operate(Operation.SUBTRACT, left, right); + } + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorModulus.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorModulus.java new file mode 100644 index 00000000000..7e33f1aa4f0 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorModulus.java @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the modulus operator. + * + * @author Andy Clement + */ +public class OperatorModulus extends Operator { + + public OperatorModulus(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "%"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object operandOne = getLeftOperand().getValue(state); + Object operandTwo = getRightOperand().getValue(state); + if (operandOne instanceof Number && operandTwo instanceof Number) { + Number op1 = (Number) operandOne; + Number op2 = (Number) operandTwo; + if (op1 instanceof Double || op2 instanceof Double) { + Double result = op1.doubleValue() % op2.doubleValue(); + return result; + } else if (op1 instanceof Float || op2 instanceof Float) { + Float result = op1.floatValue() % op2.floatValue(); + return result; + } else if (op1 instanceof Long || op2 instanceof Long) { + Long result = op1.longValue() % op2.longValue(); + return result; + } else { + Integer result = op1.intValue() % op2.intValue(); + return result; + } + } + return state.operate(Operation.MODULUS, operandOne, operandTwo); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMultiply.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMultiply.java new file mode 100644 index 00000000000..45b60fdd8df --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMultiply.java @@ -0,0 +1,87 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.spel.ExpressionState; + +/** + * Implements the multiply operator. Conversions and promotions: + * http://java.sun.com/docs/books/jls/third_edition/html/conversions.html Section 5.6.2: + * + * If any of the operands is of a reference type, unboxing conversion (¤5.1.8) is performed. Then:
+ * If either operand is of type double, the other is converted to double.
+ * Otherwise, if either operand is of type float, the other is converted to float.
+ * Otherwise, if either operand is of type long, the other is converted to long.
+ * Otherwise, both operands are converted to type int. + * + * @author Andy Clement + */ +public class OperatorMultiply extends Operator { + + public OperatorMultiply(Token payload) { + super(payload); + } + + /** + * Implements multiply directly here for some types of operand, otherwise delegates to any registered overloader for + * types it does not recognize. Supported types here are: + *
    + *
  • integers + *
  • doubles + *
  • string and int ('abc' * 2 == 'abcabc') + *
+ */ + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + // TODO could have an 'int only' arithmetic mode for super fast expression evaluation + Object operandOne = getLeftOperand().getValue(state); + Object operandTwo = getRightOperand().getValue(state); + if (operandOne instanceof Number && operandTwo instanceof Number) { + Number op1 = (Number) operandOne; + Number op2 = (Number) operandTwo; + if (op1 instanceof Double || op2 instanceof Double) { + Double result = op1.doubleValue() * op2.doubleValue(); + return result; + } else if (op1 instanceof Float || op2 instanceof Float) { + Float result = op1.floatValue() * op2.floatValue(); + return result; + } else if (op1 instanceof Long || op2 instanceof Long) { + Long result = op1.longValue() * op2.longValue(); + return result; + } else { // promote to int + Integer result = op1.intValue() * op2.intValue(); + return result; + } + } else if (operandOne instanceof String && operandTwo instanceof Integer) { + int repeats = ((Integer) operandTwo).intValue(); + StringBuilder result = new StringBuilder(); + for (int i = 0; i < repeats; i++) { + result.append(operandOne); + } + return result.toString(); + } + return state.operate(Operation.MULTIPLY, operandOne, operandTwo); + } + + @Override + public String getOperatorName() { + return "*"; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java new file mode 100644 index 00000000000..78513dbc966 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorNot.java @@ -0,0 +1,51 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +public class OperatorNot extends SpelNode { // Not is a unary operator so do not extend BinaryOperator + + public OperatorNot(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + try { + boolean value = state.toBoolean(getChild(0).getValue(state)); + return !value; + } catch (SpelException see) { + see.setPosition(getChild(0).getCharPositionInLine()); + throw see; + } + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("!").append(getChild(0).toStringAST()); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorOr.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorOr.java new file mode 100644 index 00000000000..ecd6df2de51 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorOr.java @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents the boolean OR operation. + * + * @author Andy Clement + */ +public class OperatorOr extends Operator { + + public OperatorOr(Token payload) { + super(payload); + } + + @Override + public String getOperatorName() { + return "or"; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + boolean leftValue; + boolean rightValue; + try { + leftValue = state.toBoolean(getLeftOperand().getValue(state)); + } catch (SpelException see) { + see.setPosition(getLeftOperand().getCharPositionInLine()); + throw see; + } + + if (leftValue == true) + return true; // no need to evaluate right operand + + try { + rightValue = state.toBoolean(getRightOperand().getValue(state)); + } catch (SpelException see) { + see.setPosition(getRightOperand().getCharPositionInLine()); + throw see; + } + + return leftValue || rightValue; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorPlus.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorPlus.java new file mode 100644 index 00000000000..2863e7b7c4d --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorPlus.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.spel.ExpressionState; + +public class OperatorPlus extends Operator { + + public OperatorPlus(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + SpelNode leftOp = getLeftOperand(); + SpelNode rightOp = getRightOperand(); + if (rightOp == null) { // If only one operand, then this is unary plus + Object operandOne = leftOp.getValue(state); + if (operandOne instanceof Number) { + return new Integer(((Number) operandOne).intValue()); + } + return state.operate(Operation.ADD, operandOne, null); + } else { + Object operandOne = leftOp.getValue(state); + Object operandTwo = rightOp.getValue(state); + if (operandOne instanceof Number && operandTwo instanceof Number) { + Number op1 = (Number) operandOne; + Number op2 = (Number) operandTwo; + if (op1 instanceof Double || op2 instanceof Double) { + Double result = op1.doubleValue() + op2.doubleValue(); + return result; + } else if (op1 instanceof Float || op2 instanceof Float) { + Float result = op1.floatValue() + op2.floatValue(); + return result; + } else if (op1 instanceof Long || op2 instanceof Long) { + Long result = op1.longValue() + op2.longValue(); + return result; + } else { // TODO what about overflow? + Integer result = op1.intValue() + op2.intValue(); + return result; + } + } else if (operandOne instanceof String && operandTwo instanceof String) { + return new StringBuilder((String) operandOne).append((String) operandTwo).toString(); + } else if (operandOne instanceof String && operandTwo instanceof Integer) { + String l = (String) operandOne; + Integer i = (Integer) operandTwo; + + // implements character + int (ie. a + 1 = b) + if (l.length() == 1) { + Character c = new Character((char) (new Character(l.charAt(0)) + i)); + return c.toString(); + } + + return new StringBuilder((String) operandOne).append(((Integer) operandTwo).toString()).toString(); + } + return state.operate(Operation.ADD, operandOne, operandTwo); + } + } + + @Override + public String getOperatorName() { + return "+"; + } + + @Override + public String toStringAST() { + if (getRightOperand() == null) { // unary plus + return new StringBuilder().append("+").append(getLeftOperand()).toString(); + } + return super.toStringAST(); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorSoundsLike.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorSoundsLike.java new file mode 100644 index 00000000000..c82bb4a21ee --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorSoundsLike.java @@ -0,0 +1,113 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +public class OperatorSoundsLike extends Operator { + + public OperatorSoundsLike(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object left = getLeftOperand().getValue(state); + Object right = getRightOperand().getValue(state); + if (!(left instanceof String)) { + throw new SpelException(getCharPositionInLine(), SpelMessages.SOUNDSLIKE_NEEDS_STRING_OPERAND, left.getClass() + .getName()); + } + if (!(right instanceof String)) { + throw new SpelException(getCharPositionInLine(), SpelMessages.SOUNDSLIKE_NEEDS_STRING_OPERAND, right.getClass() + .getName()); + } + String leftSoundex = computeSoundex((String) left); + String rightSoundex = computeSoundex((String) right); + return state.getTypeComparator().compare(leftSoundex, rightSoundex) == 0; + } + + // TODO OPTIMIZE better algorithm implementation is possible for soundex + private String computeSoundex(String input) { + if (input == null || input.length() == 0) + return "0000"; + input = input.toUpperCase(); + StringBuilder soundex = new StringBuilder(); + soundex.append(input.charAt(0)); + for (int i = 1; i < input.length(); i++) { + char ch = input.charAt(i); + if ("HW".indexOf(ch) != -1) + continue; // remove HWs now + if ("BFPV".indexOf(ch) != -1) { + soundex.append("1"); + } else if ("CGJKQSXZ".indexOf(ch) != -1) { + soundex.append("2"); + } else if ("DT".indexOf(ch) != -1) { + soundex.append("3"); + } else if ("L".indexOf(ch) != -1) { + soundex.append("4"); + } else if ("MN".indexOf(ch) != -1) { + soundex.append("5"); + } else if ("R".indexOf(ch) != -1) { + soundex.append("6"); + + } else { + soundex.append(ch); + } + } + StringBuilder shorterSoundex = new StringBuilder(); + shorterSoundex.append(soundex.charAt(0)); + for (int i = 1; i < soundex.length(); i++) { + if ((i + 1) < soundex.length() && soundex.charAt(i) == soundex.charAt(i + 1)) + continue; + if ("AEIOUY".indexOf(soundex.charAt(i)) != -1) + continue; + shorterSoundex.append(soundex.charAt(i)); + } + shorterSoundex.append("0000"); + return shorterSoundex.substring(0, 4); + } + + // wikipedia: + // The Soundex code for a name consists of a letter followed by three numbers: the letter is the first letter of the + // name, and the numbers encode the remaining consonants. Similar sounding consonants share the same number so, for + // example, the labial B, F, P and V are all encoded as 1. Vowels can affect the coding, but are never coded + // directly unless they appear at the start of the name. + // The exact algorithm is as follows: + // Retain the first letter of the string + // Remove all occurrences of the following letters, unless it is the first letter: a, e, h, i, o, u, w, y + // Assign numbers to the remaining letters (after the first) as follows: + // b, f, p, v = 1 + // c, g, j, k, q, s, x, z = 2 + // d, t = 3 + // l = 4 + // m, n = 5 + // r = 6 + // If two or more letters with the same number were adjacent in the original name (before step 1), or adjacent + // except for any intervening h and w (American census only), then omit all but the first. + // Return the first four characters, right-padding with zeroes if there are fewer than four. + // Using this algorithm, both "Robert" and "Rupert" return the same string "R163" while "Rubin" yields "R150". + + @Override + public String getOperatorName() { + return "soundslike"; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Placeholder.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Placeholder.java new file mode 100644 index 00000000000..d6929931b50 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Placeholder.java @@ -0,0 +1,46 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * PlaceHolder nodes are created for tokens that come through from the grammar purely to give us additional positional + * information for messages/etc. + * + * @author Andy Clement + * + */ +public class Placeholder extends SpelNode { + + public Placeholder(Token payload) { + super(payload); + } + + @Override + public String getValue(ExpressionState state) throws SpelException { + throw new SpelException(getCharPositionInLine(), SpelMessages.PLACEHOLDER_SHOULD_NEVER_BE_EVALUATED); + } + + @Override + public String toStringAST() { + return getText(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Projection.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Projection.java new file mode 100644 index 00000000000..f2c054c72a2 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Projection.java @@ -0,0 +1,98 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.KeyValuePair; + +/** + * Represents projection, where a given operation is performed on all elements in some input sequence, returning + * a new sequence of the same size. For example: + * "{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}" returns "[n, y, n, y, n, y, n, y, n, y]" + * + * @author Andy Clement + * + */ +public class Projection extends SpelNode { + + public Projection(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object operand = state.getActiveContextObject(); + + // When the input is a map, we push a special context object on the stack + // before calling the specified operation. This special context object + // has two fields 'key' and 'value' that refer to the map entries key + // and value, and they can be referenced in the operation + // eg. {'a':'y','b':'n'}.!{value=='y'?key:null}" == ['a', null] + if (operand instanceof Map) { + Map mapdata = (Map) operand; + List result = new ArrayList(); + for (Object k : mapdata.keySet()) { + try { + state.pushActiveContextObject(new KeyValuePair(k, mapdata.get(k))); + result.add(getChild(0).getValue(state)); + } finally { + state.popActiveContextObject(); + } + } + return result; + } else if (operand instanceof Collection) { + List data = new ArrayList(); + data.addAll((Collection) operand); + List result = new ArrayList(); + int idx = 0; + for (Object element : data) { + try { + state.pushActiveContextObject(element); + state.enterScope("index", idx); + result.add(getChild(0).getValue(state)); + } finally { + state.exitScope(); + state.popActiveContextObject(); + } + idx++; + } + return result; + } else { + throw new SpelException(SpelMessages.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.getClass().getName()); + } + } + + @Override + public String toStringAST() { + StringBuffer sb = new StringBuffer(); + return sb.append("!{").append(getChild(0).toStringAST()).append("}").toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java new file mode 100644 index 00000000000..bbe83e97706 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -0,0 +1,239 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.runtime.Token; +import org.springframework.expression.AccessException; +import org.springframework.expression.CacheablePropertyAccessor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.PropertyReaderExecutor; +import org.springframework.expression.PropertyWriterExecutor; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.Utils; + +/** + * Represents a simple property or field reference. + * + * @author Andy Clement + */ +public class PropertyOrFieldReference extends SpelNode { + + public static boolean useCaching = true; + + private final Object name; + private PropertyReaderExecutor cachedReaderExecutor; + private PropertyWriterExecutor cachedWriterExecutor; + + public PropertyOrFieldReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + return readProperty(state, name); + } + + @Override + public void setValue(ExpressionState state, Object newValue) throws SpelException { + writeProperty(state, name, newValue); + } + + @Override + public boolean isWritable(ExpressionState state) throws SpelException { + return isWritableProperty(name, state); + } + + @Override + public String toStringAST() { + return name.toString(); + } + + /** + * Attempt to read the named property from the current context object. + * + * @param state the evaluation state + * @param name the name of the property + * @return the value of the property + * @throws SpelException if any problem accessing the property or it cannot be found + */ + private Object readProperty(ExpressionState state, Object name) throws SpelException { + Object contextObject = state.getActiveContextObject(); + EvaluationContext eContext = state.getEvaluationContext(); + + if (cachedReaderExecutor != null) { + try { + return cachedReaderExecutor.execute(state.getEvaluationContext(), contextObject); + } catch (AccessException ae) { + // this is OK - it may have gone stale due to a class change, + // let's try to get a new one and call it before giving up + } + } + + Class contextObjectClass = getObjectClass(contextObject); + + List accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state); + + // Go through the accessors that may be able to resolve it. If they are a cacheable accessor then + // get the accessor and use it. If they are not cacheable but report they can read the property + // then ask them to read it + if (accessorsToTry != null) { + try { + for (PropertyAccessor accessor : accessorsToTry) { + if (accessor instanceof CacheablePropertyAccessor) { + cachedReaderExecutor = ((CacheablePropertyAccessor)accessor).getReaderAccessor(eContext, contextObject, name); + if (cachedReaderExecutor != null) { + try { + return cachedReaderExecutor.execute(state.getEvaluationContext(), contextObject); + } catch (AccessException ae) { + cachedReaderExecutor = null; + throw ae; + } finally { + if (!useCaching) { + cachedReaderExecutor = null; + } + } + } + } else { + if (accessor.canRead(eContext, contextObject, name)) { + Object value = accessor.read(eContext, contextObject, name); + return value; + } + } + } + } catch (AccessException ae) { + throw new SpelException(ae, SpelMessages.EXCEPTION_DURING_PROPERTY_READ, name, ae.getMessage()); + } + } + throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, name, Utils.formatClassnameForMessage(contextObjectClass)); + } + + + private void writeProperty(ExpressionState state, Object name, Object newValue) throws SpelException { + Object contextObject = state.getActiveContextObject(); + EvaluationContext eContext = state.getEvaluationContext(); + + if (cachedWriterExecutor != null) { + try { + cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue); + return; + } catch (AccessException ae) { + // this is OK - it may have gone stale due to a class change, + // let's try to get a new one and call it before giving up + } + } + + Class contextObjectClass = getObjectClass(contextObject); + + List accessorsToTry = getPropertyAccessorsToTry(contextObjectClass, state); + if (accessorsToTry != null) { + try { + for (PropertyAccessor accessor : accessorsToTry) { + if (accessor instanceof CacheablePropertyAccessor) { + cachedWriterExecutor = ((CacheablePropertyAccessor)accessor).getWriterAccessor(eContext, contextObject, name); + if (cachedWriterExecutor != null) { + try { + cachedWriterExecutor.execute(state.getEvaluationContext(), contextObject, newValue); + return; + } catch (AccessException ae) { + cachedWriterExecutor = null; + throw ae; + } finally { + if (!useCaching) { + cachedWriterExecutor = null; + } + } + } + } else { + if (accessor.canWrite(eContext, contextObject, name)) { + accessor.write(eContext, contextObject, name, newValue); + return; + } + } + } + } catch (AccessException ae) { + throw new SpelException(getCharPositionInLine(), ae, SpelMessages.EXCEPTION_DURING_PROPERTY_WRITE, name, ae.getMessage()); + } + } + throw new SpelException(SpelMessages.PROPERTY_OR_FIELD_SETTER_NOT_FOUND, name, Utils + .formatClassnameForMessage(contextObjectClass)); + } + + public boolean isWritableProperty(Object name, ExpressionState state) throws SpelException { + Object contextObject = state.getActiveContextObject(); + EvaluationContext eContext = state.getEvaluationContext(); + if (contextObject == null) { + throw new SpelException(SpelMessages.ATTEMPTED_PROPERTY_FIELD_REF_ON_NULL_CONTEXT_OBJECT, name); + } + List resolversToTry = getPropertyAccessorsToTry( + (contextObject instanceof Class) ? ((Class) contextObject) : contextObject.getClass(), state); + if (resolversToTry != null) { + for (PropertyAccessor pfResolver : resolversToTry) { + try { + if (pfResolver.canWrite(eContext, contextObject, name)) { + return true; + } + } catch (AccessException ae) { + // let others try + } + } + } + return false; + } + + /** + * Determines the set of property resolvers that should be used to try and access a property on the specified target + * type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact + * matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at + * the start of the list. In addition, there are specific resolvers that exactly name the class in question and + * resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the + * specific resolvers set and will be tried after exactly matching accessors but before generic accessors. + * + * @param targetType the type upon which property access is being attempted + * @return a list of resolvers that should be tried in order to access the property + */ + private List getPropertyAccessorsToTry(Class targetType, ExpressionState state) { + List specificAccessors = new ArrayList(); + List generalAccessors = new ArrayList(); + for (PropertyAccessor resolver : state.getPropertyAccessors()) { + Class[] targets = resolver.getSpecificTargetClasses(); + if (targets == null) { // generic resolver that says it can be used for any type + generalAccessors.add(resolver); + } else { + int pos = 0; + for (int i = 0; i < targets.length; i++) { + Class clazz = targets[i]; + if (clazz == targetType) { // put exact matches on the front to be tried first? + specificAccessors.add(pos++, resolver); + } else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the specificAccessor list + generalAccessors.add(resolver); + } + } + } + } + List resolvers = new ArrayList(); + resolvers.addAll(specificAccessors); + resolvers.addAll(generalAccessors); + return resolvers; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java new file mode 100644 index 00000000000..e5a0ce56f49 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java @@ -0,0 +1,69 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a dot separated sequence of strings that indicate a package qualified type reference. + *

+ * Example: "java.lang.String" as in the expression "new java.lang.String('hello')" + * + * @author Andy Clement + * + */ +public class QualifiedIdentifier extends SpelNode { + + private String value; + + public QualifiedIdentifier(Token payload) { + super(payload); + // value = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + // Cache the concatenation of child identifiers + if (value == null) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append("."); + sb.append(getChild(i).getValue(state)); + } + value = sb.toString(); + } + return value; + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + if (value != null) { + sb.append(value); + } else { + for (int i = 0; i < getChildCount(); i++) { + if (i > 0) + sb.append("."); + sb.append(getChild(i).toStringAST()); + } + } + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java new file mode 100644 index 00000000000..b4fcb2bf3d9 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/RealLiteral.java @@ -0,0 +1,34 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; + +public class RealLiteral extends Literal { + + private final Double value; + + public RealLiteral(Token payload) { + super(payload); + value = Double.parseDouble(payload.getText()); + } + + @Override + public Double getLiteralValue() { + return value; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Reference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Reference.java new file mode 100644 index 00000000000..a3cdb679874 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Reference.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.generated.SpringExpressionsLexer; + +/** + * Represent a object reference of the form '@(:)' + * + */ +public class Reference extends SpelNode { + + private boolean contextAndObjectDetermined = false; + private SpelNode contextNode = null; + private SpelNode objectNode = null; + + public Reference(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + + ensureContextAndNameDetermined(); + Object contextName = (contextNode == null ? null : contextNode.getValue(state)); + Object objectName = (objectNode == null ? null : objectNode.getValue(state)); + + Object referencedValue = state.lookupReference(contextName, objectName); + + return referencedValue; + } + + /** + * Work out which represents the context and which the object. This would be trivial except for parser recovery + * situations where the expression was incomplete. We need to do our best here to recover so that we can offer + * suitable code completion suggestions. + */ + private void ensureContextAndNameDetermined() { + if (contextAndObjectDetermined) + return; + contextAndObjectDetermined = true; + int colon = -1; + for (int i = 0; i < getChildCount(); i++) { + if (getChild(i).getToken().getType() == SpringExpressionsLexer.COLON) { + colon = i; + } + } + if (colon != -1) { + contextNode = getChild(colon - 1); + objectNode = getChild(colon + 1); + } else { + objectNode = getChild(0); + } + if (objectNode.getToken().getType() != SpringExpressionsLexer.QUALIFIED_IDENTIFIER) { + objectNode = null; + } + } + + @Override + public String toStringAST() { + ensureContextAndNameDetermined(); + StringBuilder sb = new StringBuilder(); + sb.append("@("); + if (contextNode != null) { + sb.append(contextNode.toStringAST()).append(":"); + } + sb.append(objectNode.toStringAST()); + sb.append(")"); + return sb.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java new file mode 100644 index 00000000000..1fc580ea840 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java @@ -0,0 +1,146 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.KeyValuePair; + +/** + * Represents selection over a map or collection. For example: {1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'} returns + * [2, 4, 6, 8, 10] + * + * Basically a subset of the input data is returned based on the evaluation of the expression supplied as selection + * criteria. + * + * @author Andy Clement + */ +public class Selection extends SpelNode { + + public final static int ALL = 0; // ?{} + public final static int FIRST = 1; // ^{} + public final static int LAST = 2; // ${} + + private final int variant; + + public Selection(Token payload, int variant) { + super(payload); + this.variant = variant; + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object operand = state.getActiveContextObject(); + SpelNode selectionCriteria = getChild(0); + if (operand instanceof Map) { + Map mapdata = (Map) operand; + List result = new ArrayList(); + for (Object k : mapdata.keySet()) { + try { + Object kvpair = new KeyValuePair(k, mapdata.get(k)); + state.pushActiveContextObject(kvpair); + Object o = selectionCriteria.getValue(state); + if (o instanceof Boolean) { + if (((Boolean) o).booleanValue() == true) { + if (variant == FIRST) + return kvpair; + result.add(kvpair); + } + } else { + throw new SpelException(selectionCriteria.getCharPositionInLine(), + SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST()); + } + } finally { + state.popActiveContextObject(); + } + if ((variant == FIRST || variant == LAST) && result.size() == 0) { + return null; + } + if (variant == LAST) { + return result.get(result.size() - 1); + } + } + return result; + } else if (operand instanceof Collection) { + List data = new ArrayList(); + data.addAll((Collection) operand); + List result = new ArrayList(); + int idx = 0; + for (Object element : data) { + try { + state.pushActiveContextObject(element); + state.enterScope("index", idx); + Object o = selectionCriteria.getValue(state); + if (o instanceof Boolean) { + if (((Boolean) o).booleanValue() == true) { + if (variant == FIRST) + return element; + result.add(element); + } + } else { + throw new SpelException(selectionCriteria.getCharPositionInLine(), + SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);// ,selectionCriteria.stringifyAST()); + } + idx++; + } finally { + state.exitScope(); + state.popActiveContextObject(); + } + } + if ((variant == FIRST || variant == LAST) && result.size() == 0) { + return null; + } + if (variant == LAST) { + return result.get(result.size() - 1); + } + return result; + } else { + throw new SpelException(getCharPositionInLine(), SpelMessages.INVALID_TYPE_FOR_SELECTION, + (operand == null ? "null" : operand.getClass().getName())); + } + } + + @Override + public String toStringAST() { + StringBuffer sb = new StringBuffer(); + switch (variant) { + case ALL: + sb.append("?{"); + break; + case FIRST: + sb.append("^{"); + break; + case LAST: + sb.append("${"); + break; + } + return sb.append(getChild(0).toStringAST()).append("}").toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/SpelNode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/SpelNode.java new file mode 100644 index 00000000000..67b4454f666 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/SpelNode.java @@ -0,0 +1,110 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.io.Serializable; + +import org.antlr.runtime.Token; +import org.antlr.runtime.tree.CommonTree; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.generated.SpringExpressionsParser; + +/** + * The common supertype of all AST nodes in a parsed Spring Expression Language format expression. + * + * @author Andy Clement + * + */ +public abstract class SpelNode extends CommonTree implements Serializable { + + /** + * The Antlr parser uses this constructor to build SpelNodes. + * + * @param payload the token for the node that has been parsed + */ + protected SpelNode(Token payload) { + super(payload); + } + + /** + * Evaluate the expression node in the context of the supplied expression state and return the value. + * + * @param expressionState the current expression state (includes the context) + * @return the value of this node evaluated against the specified state + */ + public abstract Object getValue(ExpressionState expressionState) throws EvaluationException; + + /** + * Determine if this expression node will support a setValue() call. + * + * @param expressionState the current expression state (includes the context) + * @return true if the expression node will allow setValue() + * @throws EvaluationException if something went wrong trying to determine if the node supports writing + */ + public boolean isWritable(ExpressionState expressionState) throws EvaluationException { + return false; + } + + /** + * Evaluate the expression to a node and then set the new value on that node. For example, if the expression + * evaluates to a property reference then the property will be set to the new value. + * + * @param expressionState the current expression state (includes the context) + * @param newValue the new value + * @throws EvaluationException if any problem occurs evaluating the expression or setting the new value + */ + public void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException { + throw new SpelException(getCharPositionInLine(), SpelMessages.SETVALUE_NOT_SUPPORTED, getClass(), getTokenName()); + } + + /** + * @return return the token this node represents + */ + protected String getTokenName() { + if (getToken() == null) { + return "UNKNOWN"; + } + return SpringExpressionsParser.tokenNames[getToken().getType()]; + } + + /** + * @return the string form of this AST node + */ + public abstract String toStringAST(); + + /** + * Helper method that returns a SpelNode rather than an Antlr Tree node. + * + * @return the child node cast to a SpelNode + */ + @Override + public SpelNode getChild(int index) { + return (SpelNode) super.getChild(index); + } + + /** + * Determine the class of the object passed in, unless it is already a class object. + * @param o the object that the caller wants the class of + * @return the class of the object if it is not already a class object, or null if the object is null + */ + public Class getObjectClass(Object o) { + if (o==null) return null; + return (o instanceof Class) ? ((Class) o) : o.getClass(); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java new file mode 100644 index 00000000000..70159878895 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java @@ -0,0 +1,42 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; + +public class StringLiteral extends Literal { + + private String value; + + public StringLiteral(Token payload) { + super(payload); + value = payload.getText(); + // TODO should these have been skipped being created by the parser rules? or not? + value = value.substring(1, value.length() - 1); + value = value.replaceAll("''", "'"); + } + + @Override + public String getLiteralValue() { + return value; + } + + @Override + public String toString() { + return new StringBuilder("'").append(getLiteralValue()).append("'").toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java new file mode 100644 index 00000000000..3675e4ff214 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Ternary.java @@ -0,0 +1,60 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a ternary expression, for example: "someCheck()?true:false". + * + * @author Andy Clement + */ +public class Ternary extends SpelNode { + + public Ternary(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + Object condition = getChild(0).getValue(state); + try { + boolean b = state.toBoolean(condition); + if (b) + return getChild(1).getValue(state); + else + return getChild(2).getValue(state); + } catch (SpelException see) { + see.setPosition(getChild(0).getCharPositionInLine()); + throw see; + } + } + + @Override + public String toStringAST() { + return new StringBuilder().append(getChild(0).toStringAST()).append(" ? ").append(getChild(1).toStringAST()) + .append(" : ").append(getChild(2).toStringAST()).toString(); + } + + // TODO 3 should this say TRUE if the left or the right are writable??? + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java new file mode 100644 index 00000000000..1298ed3e88f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeReference.java @@ -0,0 +1,64 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.internal.TypeCode; + +/** + * Represents a reference to a type, for example "T(String)" or "T(com.somewhere.Foo)" + * + * @author Andy Clement + * + */ +public class TypeReference extends SpelNode { + + public TypeReference(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws EvaluationException { + // TODO OPTIMIZE cache the type reference once found? + String typename = (String) getChild(0).getValue(state); + if (typename.indexOf(".") == -1 && Character.isLowerCase(typename.charAt(0))) { + TypeCode tc = TypeCode.forName(typename); + if (tc != TypeCode.OBJECT) { + // it is a primitive type + return tc.getType(); + } + } + return state.findType(typename); + } + + @Override + public String toStringAST() { + StringBuilder sb = new StringBuilder(); + sb.append("T("); + sb.append(getChild(0).toStringAST()); + sb.append(")"); + return sb.toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return false; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java new file mode 100644 index 00000000000..5acb96034c8 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/VariableReference.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +/** + * Represents a variable reference, eg. #someVar. Note this is different to a *local* variable like $someVar + * + * @author Andy Clement + * + */ +public class VariableReference extends SpelNode { + + // Well known variables: + private final static String THIS = "this"; // currently active context object + private final static String ROOT = "root"; // root context object + + private final String name; + + public VariableReference(Token payload) { + super(payload); + name = payload.getText(); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + if (name.equals(THIS)) + return state.getActiveContextObject(); + if (name.equals(ROOT)) + return state.getRootContextObject(); + Object result = state.lookupVariable(name); + if (result == null) { + throw new SpelException(getCharPositionInLine(), SpelMessages.VARIABLE_NOT_FOUND, name); + } + return result; + } + + @Override + public void setValue(ExpressionState state, Object value) throws SpelException { + // Object oldValue = state.lookupVariable(name); + state.setVariable(name, value); + } + + @Override + public String toStringAST() { + return new StringBuilder("#").append(name).toString(); + } + + @Override + public boolean isWritable(ExpressionState expressionState) throws SpelException { + return !(name.equals(THIS) || name.equals(ROOT)); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g new file mode 100644 index 00000000000..47b497e26b3 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g @@ -0,0 +1,375 @@ +grammar SpringExpressions; + +options { + language = Java; + output=AST; + k=2; + //caseSensitive = false; + //backtrack=true; +} + +tokens { + EXPRESSIONLIST; + INTEGER_LITERAL; + EXPRESSION; + QUALIFIED_IDENTIFIER; + REFERENCE; + PROPERTY_OR_FIELD; + INDEXER; + ARGLIST; + CONSTRUCTOR; + DATE_LITERAL; + HOLDER; + CONSTRUCTOR_ARRAY; + NAMED_ARGUMENT; + FUNCTIONREF; + TYPEREF; + RANGE; + VARIABLEREF; + LIST_INITIALIZER; + MAP_INITIALIZER; + LOCALVAR; + LOCALFUNC; + MAP_ENTRY; + METHOD; + ADD; + SUBTRACT; +// MULTIPLY; +// DIVIDE; +// MODULUS; + NUMBER; +} + +// applies only to the parser: +@header {package org.springframework.expression.spel.generated;} + +// applies only to the lexer: +@lexer::header {package org.springframework.expression.spel.generated;} + +@rulecatch { + catch(RecognitionException e) { + //reportError(e); + throw e; + } +} + +expr: expression EOF!; + +exprList + : LPAREN expression (SEMI expression)+ (SEMIRPAREN | RPAREN) + -> ^(EXPRESSIONLIST expression+); + +SEMIRPAREN : ';)'; // recoveryrelated: allows us to cope with a rogue superfluous semicolon before the rparen in an expression list + +expression : + logicalOrExpression + ( (ASSIGN^ logicalOrExpression) + | (DEFAULT^ logicalOrExpression) + | (QMARK^ expression COLON! expression))?; + +parenExpr : LPAREN! expression RPAREN!;// (ROGUE! | RPAREN!); + + +logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*; + +logicalAndExpression : relationalExpression (AND^ relationalExpression)*; + +relationalExpression : sumExpression (relationalOperator^ sumExpression)?; + +sumExpression + : productExpression ( (PLUS^ | MINUS^) productExpression)*; +// : left=productExpression (PLUS right+=productExpression)+ -> ^(ADD $left $right) +// | left=productExpression (MINUS right+=productExpression)+ -> ^(SUBTRACT $left $right) +// | productExpression; + +// TODO could really do with changing ast node types here +productExpression + : powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; +// : left=powerExpr (STAR right+=powerExpr) -> ^(MULTIPLY $left $right) +// | left=powerExpr (DIV right+=powerExpr) -> ^(DIVIDE $left $right) +// | left=powerExpr (MOD right+=powerExpr) -> ^(MODULUS $left $right) +// | powerExpr; + +powerExpr : unaryExpression (POWER^ unaryExpression)? ; + +unaryExpression + : (PLUS^ | MINUS^ | BANG^) unaryExpression + | primaryExpression ; + +primaryExpression + : startNode (node)? -> ^(EXPRESSION startNode (node)?); + +startNode + : + (LPAREN expression SEMI) => exprList + | parenExpr + | methodOrProperty + | functionOrVar + | localFunctionOrVar + | reference + | indexer + | literal + | type + | constructor + | projection + | selection + | firstSelection + | lastSelection + | listInitializer + | mapInitializer + | lambda +// | attribute + ; + +node: + ( methodOrProperty + | functionOrVar + | indexer + | projection + | selection + | firstSelection + | lastSelection + | exprList + | DOT + )+ + ; + +functionOrVar + : (POUND ID LPAREN) => function + | var + ; + +function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); + +var : POUND id=ID -> ^(VARIABLEREF[$id]); + +localFunctionOrVar + : (DOLLAR ID LPAREN) => localFunction + | localVar + ; + +localFunction : DOLLAR id=ID methodArgs -> ^(LOCALFUNC[$id] methodArgs); +localVar: DOLLAR id=ID -> ^(LOCALVAR[$id]); + +methodOrProperty + : (ID LPAREN) => id=ID methodArgs -> ^(METHOD[$id] methodArgs) + | property + ; + +// may have to preserve these commas to make it easier to offer suggestions in the right place +// mod at 9th feb 19:13 - added the second 'COMMA?' to allow for code completion "foo(A," +// TODO need to preserve commas and then check for badly formed call later (optimizing tree walk) to disallow "foo(a,b,c,)" +methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; + +// If we match ID then create a node called PROPERTY_OR_FIELD and copy the id info into it. +// this means the propertyOrField.text is what id.text would have been, rather than having to +// access id as a child of the new node. +property: id=ID -> ^(PROPERTY_OR_FIELD[$id]); + +// start - in this block there are changes to help parser recovery and code completion + +// fiddled with to support better code completion +// we preserve the colon and rparen to give positional info and the qualifiedId is optional to cope with +// code completing in @() (which is really an invalid expression) +reference + : AT pos=LPAREN (cn=contextName COLON)? (q=qualifiedId)? RPAREN + -> ^(REFERENCE[$pos] ($cn COLON)? $q? RPAREN); +// what I really want here is: was there a colon? position of the right paren + +// end - in this block there are changes to help parser recovery and code completion + +//indexer: LBRACKET r1=range (COMMA r2=range)* RBRACKET -> ^(INDEXER $r1 ($r2)*); +indexer: LBRACKET r1=argument (COMMA r2=argument)* RBRACKET -> ^(INDEXER $r1 ($r2)*); + +//range: INTEGER_LITERAL UPTO^ INTEGER_LITERAL | +// argument; + // TODO make expression conditional with ? if want completion for when the RCURLY is missing +projection: PROJECT^ expression RCURLY!; + +selection: SELECT^ expression RCURLY!; + +firstSelection: SELECT_FIRST^ expression RCURLY!; + +lastSelection: SELECT_LAST^ expression RCURLY!; + +// TODO cope with array types +type: TYPE qualifiedId RPAREN -> ^(TYPEREF qualifiedId); +//type: TYPE tn=qualifiedId (LBRACKET RBRACKET)? (COMMA qid=qualifiedId)? RPAREN + +//attribute +// : AT! LBRACKET! tn:qualifiedId! (ctorArgs)? RBRACKET! +// { #attribute = #([EXPR, tn_AST.getText(), "Spring.Expressions.AttributeNode"], #attribute); } +// ; + +lambda + : LAMBDA (argList)? PIPE expression RCURLY -> ^(LAMBDA (argList)? expression); + +argList : (id+=ID (COMMA id+=ID)*) -> ^(ARGLIST ($id)*); + +constructor + : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) + | arrayConstructor + ; + +arrayConstructor + : 'new' qualifiedId arrayRank (listInitializer)? + -> ^(CONSTRUCTOR_ARRAY qualifiedId arrayRank (listInitializer)?) + ; + +arrayRank + : LBRACKET (expression (COMMA expression)*)? RBRACKET -> ^(EXPRESSIONLIST expression*); + +listInitializer + : LCURLY expression (COMMA expression)* RCURLY -> ^(LIST_INITIALIZER expression*); + +//arrayInitializer +// : LCURLY expression (COMMA expression)* RCURLY -> ^(ARRAY_INITIALIZER expression*); + +mapInitializer + : POUND LCURLY mapEntry (COMMA mapEntry)* RCURLY -> ^(MAP_INITIALIZER mapEntry*); + +mapEntry + : expression COLON expression -> ^(MAP_ENTRY expression*); + +ctorArgs + : LPAREN! (namedArgument (COMMA! namedArgument)*)? RPAREN!; + +argument : expression; + +namedArgument + : (ID ASSIGN) => id=ID ASSIGN expression + -> ^(NAMED_ARGUMENT[$id] expression) + | argument ; + +qualifiedId : ID (DOT ID)* -> ^(QUALIFIED_IDENTIFIER ID*); + +contextName : ID (DIV ID)* -> ^(QUALIFIED_IDENTIFIER ID*); + +literal + : INTEGER_LITERAL + | STRING_LITERAL + | DQ_STRING_LITERAL + | boolLiteral + | NULL_LITERAL + | HEXADECIMAL_INTEGER_LITERAL + | REAL_LITERAL + | dateLiteral + ; + +boolLiteral: TRUE | FALSE; + +dateLiteral: 'date' LPAREN d=STRING_LITERAL (COMMA f=STRING_LITERAL)? RPAREN -> ^(DATE_LITERAL $d ($f)?); + +INTEGER_LITERAL + : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +HEXADECIMAL_INTEGER_LITERAL : '0x' (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +relationalOperator + : EQUAL + | NOT_EQUAL + | LESS_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN + | GREATER_THAN_OR_EQUAL + | IN + | IS + | BETWEEN + | LIKE + | MATCHES + | SOUNDSLIKE + | DISTANCETO + ; + +ASSIGN: '='; +EQUAL: '=='; +NOT_EQUAL: '!='; +LESS_THAN: '<'; +LESS_THAN_OR_EQUAL: '<='; +GREATER_THAN: '>'; +GREATER_THAN_OR_EQUAL: '>='; +SOUNDSLIKE + : 'soundslike'; +DISTANCETO + : 'distanceto'; +IN: 'in'; +IS: 'is'; +BETWEEN:'between'; +LIKE: 'like'; +MATCHES:'matches'; +NULL_LITERAL: 'null'; + +SEMI: ';'; +DOT: '.'; +COMMA: ','; +LPAREN: '('; +RPAREN: ')'; +LCURLY: '{'; +RCURLY: '}'; +LBRACKET: '['; +RBRACKET: ']'; +PIPE: '|'; + +AND: 'and'; +OR: 'or'; +FALSE: 'false'; +TRUE: 'true'; + +PLUS: '+'; +MINUS: '-'; +DIV: '/'; +STAR: '*'; +MOD: '%'; +POWER: '^'; +BANG: '!'; +POUND: '#'; +QMARK: '?'; +DEFAULT: '??'; +LAMBDA: '{|'; +PROJECT: '!{'; +SELECT: '?{'; +SELECT_FIRST: '^{'; +SELECT_LAST: '${'; +TYPE: 'T('; + +STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; +DQ_STRING_LITERAL: '"'! (~'"')* '"'!; +ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*; +DOT_ESCAPED: '\\.'; +//DOUBLE_DOT: ':'; +WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ; +DOLLAR: '$'; +AT: '@'; +UPTO: '..'; +COLON: ':'; + + /* + // real - use syntactic predicates (guess mode) + : ('.' DECIMAL_DIGIT) => + in= '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ '.' DECIMAL_DIGIT) => + in=(DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ (EXPONENT_PART)) => + in= (DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)) => + in= (DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX) +*/ + +REAL_LITERAL : + ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); + +fragment APOS : '\''! '\''; +fragment DECIMAL_DIGIT : '0'..'9' ; +fragment INTEGER_TYPE_SUFFIX : ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' ); +fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; + +fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; +fragment SIGN : '+' | '-' ; +// TODO what is M or m? +fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd' | 'M' | 'm' ; diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.tokens b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.tokens new file mode 100644 index 00000000000..7db0833928d --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.tokens @@ -0,0 +1,92 @@ +COMMA=51 +GREATER_THAN_OR_EQUAL=79 +EXPRESSIONLIST=4 +GREATER_THAN=78 +MINUS=41 +NUMBER=29 +ARGLIST=11 +BANG=46 +LESS_THAN=76 +METHOD=26 +FALSE=70 +PROPERTY_OR_FIELD=9 +INDEXER=10 +CONSTRUCTOR_ARRAY=15 +NULL_LITERAL=66 +NAMED_ARGUMENT=16 +PIPE=62 +DOT=47 +AND=39 +EXPRESSION=6 +LCURLY=63 +DATE_LITERAL=13 +REAL_TYPE_SUFFIX=92 +QUALIFIED_IDENTIFIER=7 +SELECT=57 +STRING_LITERAL=64 +SUBTRACT=28 +RBRACKET=54 +RPAREN=33 +BETWEEN=82 +SIGN=93 +PLUS=40 +INTEGER_LITERAL=5 +AT=52 +RANGE=19 +SOUNDSLIKE=85 +WS=89 +DOLLAR=50 +LESS_THAN_OR_EQUAL=77 +HEXADECIMAL_INTEGER_LITERAL=67 +LAMBDA=61 +SEMI=31 +EQUAL=74 +DOT_ESCAPED=88 +QMARK=36 +COLON=37 +PROJECT=55 +DIV=43 +REAL_LITERAL=68 +ADD=27 +TRUE=69 +EXPONENT_PART=91 +POUND=48 +HOLDER=14 +SELECT_FIRST=58 +TYPE=60 +MAP_ENTRY=25 +SELECT_LAST=59 +LBRACKET=53 +MOD=44 +FUNCTIONREF=17 +OR=38 +RCURLY=56 +ASSIGN=34 +LPAREN=30 +HEX_DIGIT=73 +LIST_INITIALIZER=21 +APOS=87 +ID=49 +NOT_EQUAL=75 +POWER=45 +TYPEREF=18 +DISTANCETO=86 +DECIMAL_DIGIT=71 +IS=81 +SEMIRPAREN=32 +DQ_STRING_LITERAL=65 +LIKE=83 +MAP_INITIALIZER=22 +LOCALFUNC=24 +IN=80 +CONSTRUCTOR=12 +INTEGER_TYPE_SUFFIX=72 +MATCHES=84 +UPTO=90 +REFERENCE=8 +DEFAULT=35 +LOCALVAR=23 +STAR=42 +VARIABLEREF=20 +'date'=95 +'new'=94 diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressionsLexer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressionsLexer.java new file mode 100644 index 00000000000..85ca385d5fc --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressionsLexer.java @@ -0,0 +1,3018 @@ +// $ANTLR 3.0.1 /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g 2008-08-11 16:02:48 +package org.springframework.expression.spel.generated; + +import org.antlr.runtime.*; +import java.util.Stack; +import java.util.List; +import java.util.ArrayList; + +public class SpringExpressionsLexer extends Lexer { + public static final int GREATER_THAN_OR_EQUAL=79; + public static final int COMMA=51; + public static final int GREATER_THAN=78; + public static final int EXPRESSIONLIST=4; + public static final int MINUS=41; + public static final int NUMBER=29; + public static final int ARGLIST=11; + public static final int BANG=46; + public static final int LESS_THAN=76; + public static final int METHOD=26; + public static final int FALSE=70; + public static final int PROPERTY_OR_FIELD=9; + public static final int INDEXER=10; + public static final int CONSTRUCTOR_ARRAY=15; + public static final int NULL_LITERAL=66; + public static final int NAMED_ARGUMENT=16; + public static final int PIPE=62; + public static final int DOT=47; + public static final int EXPRESSION=6; + public static final int AND=39; + public static final int LCURLY=63; + public static final int DATE_LITERAL=13; + public static final int STRING_LITERAL=64; + public static final int SELECT=57; + public static final int QUALIFIED_IDENTIFIER=7; + public static final int REAL_TYPE_SUFFIX=92; + public static final int RBRACKET=54; + public static final int SUBTRACT=28; + public static final int BETWEEN=82; + public static final int RPAREN=33; + public static final int SIGN=93; + public static final int PLUS=40; + public static final int INTEGER_LITERAL=5; + public static final int AT=52; + public static final int RANGE=19; + public static final int SOUNDSLIKE=85; + public static final int WS=89; + public static final int DOLLAR=50; + public static final int LESS_THAN_OR_EQUAL=77; + public static final int T94=94; + public static final int HEXADECIMAL_INTEGER_LITERAL=67; + public static final int LAMBDA=61; + public static final int SEMI=31; + public static final int EQUAL=74; + public static final int DOT_ESCAPED=88; + public static final int QMARK=36; + public static final int COLON=37; + public static final int PROJECT=55; + public static final int DIV=43; + public static final int REAL_LITERAL=68; + public static final int ADD=27; + public static final int TRUE=69; + public static final int EXPONENT_PART=91; + public static final int POUND=48; + public static final int HOLDER=14; + public static final int SELECT_FIRST=58; + public static final int TYPE=60; + public static final int MAP_ENTRY=25; + public static final int SELECT_LAST=59; + public static final int LBRACKET=53; + public static final int MOD=44; + public static final int FUNCTIONREF=17; + public static final int OR=38; + public static final int RCURLY=56; + public static final int ASSIGN=34; + public static final int LPAREN=30; + public static final int HEX_DIGIT=73; + public static final int LIST_INITIALIZER=21; + public static final int APOS=87; + public static final int ID=49; + public static final int NOT_EQUAL=75; + public static final int T95=95; + public static final int POWER=45; + public static final int TYPEREF=18; + public static final int DISTANCETO=86; + public static final int DECIMAL_DIGIT=71; + public static final int IS=81; + public static final int SEMIRPAREN=32; + public static final int DQ_STRING_LITERAL=65; + public static final int LIKE=83; + public static final int MAP_INITIALIZER=22; + public static final int LOCALFUNC=24; + public static final int IN=80; + public static final int CONSTRUCTOR=12; + public static final int INTEGER_TYPE_SUFFIX=72; + public static final int MATCHES=84; + public static final int EOF=-1; + public static final int UPTO=90; + public static final int REFERENCE=8; + public static final int Tokens=96; + public static final int DEFAULT=35; + public static final int LOCALVAR=23; + public static final int STAR=42; + public static final int VARIABLEREF=20; + public SpringExpressionsLexer() {;} + public SpringExpressionsLexer(CharStream input) { + super(input); + } + public String getGrammarFileName() { return "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g"; } + + // $ANTLR start T94 + public final void mT94() throws RecognitionException { + try { + int _type = T94; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:8:5: ( 'new' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:8:7: 'new' + { + match("new"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end T94 + + // $ANTLR start T95 + public final void mT95() throws RecognitionException { + try { + int _type = T95; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:9:5: ( 'date' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:9:7: 'date' + { + match("date"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end T95 + + // $ANTLR start SEMIRPAREN + public final void mSEMIRPAREN() throws RecognitionException { + try { + int _type = SEMIRPAREN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:62:12: ( ';)' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:62:14: ';)' + { + match(";)"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SEMIRPAREN + + // $ANTLR start INTEGER_LITERAL + public final void mINTEGER_LITERAL() throws RecognitionException { + try { + int _type = INTEGER_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:2: ( ( DECIMAL_DIGIT )+ ( INTEGER_TYPE_SUFFIX )? ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:4: ( DECIMAL_DIGIT )+ ( INTEGER_TYPE_SUFFIX )? + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:4: ( DECIMAL_DIGIT )+ + int cnt1=0; + loop1: + do { + int alt1=2; + int LA1_0 = input.LA(1); + + if ( ((LA1_0>='0' && LA1_0<='9')) ) { + alt1=1; + } + + + switch (alt1) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:5: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt1 >= 1 ) break loop1; + EarlyExitException eee = + new EarlyExitException(1, input); + throw eee; + } + cnt1++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:21: ( INTEGER_TYPE_SUFFIX )? + int alt2=2; + int LA2_0 = input.LA(1); + + if ( (LA2_0=='L'||LA2_0=='U'||LA2_0=='l'||LA2_0=='u') ) { + alt2=1; + } + switch (alt2) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:264:22: INTEGER_TYPE_SUFFIX + { + mINTEGER_TYPE_SUFFIX(); + + } + break; + + } + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end INTEGER_LITERAL + + // $ANTLR start HEXADECIMAL_INTEGER_LITERAL + public final void mHEXADECIMAL_INTEGER_LITERAL() throws RecognitionException { + try { + int _type = HEXADECIMAL_INTEGER_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:29: ( '0x' ( HEX_DIGIT )+ ( INTEGER_TYPE_SUFFIX )? ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:31: '0x' ( HEX_DIGIT )+ ( INTEGER_TYPE_SUFFIX )? + { + match("0x"); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:36: ( HEX_DIGIT )+ + int cnt3=0; + loop3: + do { + int alt3=2; + int LA3_0 = input.LA(1); + + if ( ((LA3_0>='0' && LA3_0<='9')||(LA3_0>='A' && LA3_0<='F')||(LA3_0>='a' && LA3_0<='f')) ) { + alt3=1; + } + + + switch (alt3) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:37: HEX_DIGIT + { + mHEX_DIGIT(); + + } + break; + + default : + if ( cnt3 >= 1 ) break loop3; + EarlyExitException eee = + new EarlyExitException(3, input); + throw eee; + } + cnt3++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:49: ( INTEGER_TYPE_SUFFIX )? + int alt4=2; + int LA4_0 = input.LA(1); + + if ( (LA4_0=='L'||LA4_0=='U'||LA4_0=='l'||LA4_0=='u') ) { + alt4=1; + } + switch (alt4) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:266:50: INTEGER_TYPE_SUFFIX + { + mINTEGER_TYPE_SUFFIX(); + + } + break; + + } + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end HEXADECIMAL_INTEGER_LITERAL + + // $ANTLR start ASSIGN + public final void mASSIGN() throws RecognitionException { + try { + int _type = ASSIGN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:284:7: ( '=' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:284:9: '=' + { + match('='); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end ASSIGN + + // $ANTLR start EQUAL + public final void mEQUAL() throws RecognitionException { + try { + int _type = EQUAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:285:6: ( '==' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:285:8: '==' + { + match("=="); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end EQUAL + + // $ANTLR start NOT_EQUAL + public final void mNOT_EQUAL() throws RecognitionException { + try { + int _type = NOT_EQUAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:286:10: ( '!=' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:286:12: '!=' + { + match("!="); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end NOT_EQUAL + + // $ANTLR start LESS_THAN + public final void mLESS_THAN() throws RecognitionException { + try { + int _type = LESS_THAN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:287:10: ( '<' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:287:12: '<' + { + match('<'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LESS_THAN + + // $ANTLR start LESS_THAN_OR_EQUAL + public final void mLESS_THAN_OR_EQUAL() throws RecognitionException { + try { + int _type = LESS_THAN_OR_EQUAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:288:19: ( '<=' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:288:21: '<=' + { + match("<="); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LESS_THAN_OR_EQUAL + + // $ANTLR start GREATER_THAN + public final void mGREATER_THAN() throws RecognitionException { + try { + int _type = GREATER_THAN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:289:13: ( '>' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:289:15: '>' + { + match('>'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end GREATER_THAN + + // $ANTLR start GREATER_THAN_OR_EQUAL + public final void mGREATER_THAN_OR_EQUAL() throws RecognitionException { + try { + int _type = GREATER_THAN_OR_EQUAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:290:22: ( '>=' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:290:24: '>=' + { + match(">="); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end GREATER_THAN_OR_EQUAL + + // $ANTLR start SOUNDSLIKE + public final void mSOUNDSLIKE() throws RecognitionException { + try { + int _type = SOUNDSLIKE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:292:2: ( 'soundslike' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:292:4: 'soundslike' + { + match("soundslike"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SOUNDSLIKE + + // $ANTLR start DISTANCETO + public final void mDISTANCETO() throws RecognitionException { + try { + int _type = DISTANCETO; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:294:2: ( 'distanceto' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:294:4: 'distanceto' + { + match("distanceto"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DISTANCETO + + // $ANTLR start IN + public final void mIN() throws RecognitionException { + try { + int _type = IN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:295:3: ( 'in' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:295:9: 'in' + { + match("in"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end IN + + // $ANTLR start IS + public final void mIS() throws RecognitionException { + try { + int _type = IS; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:296:3: ( 'is' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:296:9: 'is' + { + match("is"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end IS + + // $ANTLR start BETWEEN + public final void mBETWEEN() throws RecognitionException { + try { + int _type = BETWEEN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:297:8: ( 'between' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:297:9: 'between' + { + match("between"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end BETWEEN + + // $ANTLR start LIKE + public final void mLIKE() throws RecognitionException { + try { + int _type = LIKE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:298:5: ( 'like' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:298:9: 'like' + { + match("like"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LIKE + + // $ANTLR start MATCHES + public final void mMATCHES() throws RecognitionException { + try { + int _type = MATCHES; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:299:8: ( 'matches' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:299:9: 'matches' + { + match("matches"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end MATCHES + + // $ANTLR start NULL_LITERAL + public final void mNULL_LITERAL() throws RecognitionException { + try { + int _type = NULL_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:300:13: ( 'null' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:300:15: 'null' + { + match("null"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end NULL_LITERAL + + // $ANTLR start SEMI + public final void mSEMI() throws RecognitionException { + try { + int _type = SEMI; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:302:5: ( ';' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:302:7: ';' + { + match(';'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SEMI + + // $ANTLR start DOT + public final void mDOT() throws RecognitionException { + try { + int _type = DOT; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:303:4: ( '.' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:303:9: '.' + { + match('.'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DOT + + // $ANTLR start COMMA + public final void mCOMMA() throws RecognitionException { + try { + int _type = COMMA; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:304:6: ( ',' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:304:8: ',' + { + match(','); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end COMMA + + // $ANTLR start LPAREN + public final void mLPAREN() throws RecognitionException { + try { + int _type = LPAREN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:305:7: ( '(' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:305:9: '(' + { + match('('); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LPAREN + + // $ANTLR start RPAREN + public final void mRPAREN() throws RecognitionException { + try { + int _type = RPAREN; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:306:7: ( ')' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:306:9: ')' + { + match(')'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end RPAREN + + // $ANTLR start LCURLY + public final void mLCURLY() throws RecognitionException { + try { + int _type = LCURLY; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:307:7: ( '{' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:307:9: '{' + { + match('{'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LCURLY + + // $ANTLR start RCURLY + public final void mRCURLY() throws RecognitionException { + try { + int _type = RCURLY; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:308:7: ( '}' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:308:9: '}' + { + match('}'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end RCURLY + + // $ANTLR start LBRACKET + public final void mLBRACKET() throws RecognitionException { + try { + int _type = LBRACKET; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:309:9: ( '[' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:309:11: '[' + { + match('['); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LBRACKET + + // $ANTLR start RBRACKET + public final void mRBRACKET() throws RecognitionException { + try { + int _type = RBRACKET; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:310:9: ( ']' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:310:11: ']' + { + match(']'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end RBRACKET + + // $ANTLR start PIPE + public final void mPIPE() throws RecognitionException { + try { + int _type = PIPE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:311:5: ( '|' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:311:7: '|' + { + match('|'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end PIPE + + // $ANTLR start AND + public final void mAND() throws RecognitionException { + try { + int _type = AND; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:313:4: ( 'and' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:313:9: 'and' + { + match("and"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end AND + + // $ANTLR start OR + public final void mOR() throws RecognitionException { + try { + int _type = OR; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:314:3: ( 'or' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:314:9: 'or' + { + match("or"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end OR + + // $ANTLR start FALSE + public final void mFALSE() throws RecognitionException { + try { + int _type = FALSE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:315:6: ( 'false' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:315:9: 'false' + { + match("false"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end FALSE + + // $ANTLR start TRUE + public final void mTRUE() throws RecognitionException { + try { + int _type = TRUE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:316:5: ( 'true' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:316:9: 'true' + { + match("true"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end TRUE + + // $ANTLR start PLUS + public final void mPLUS() throws RecognitionException { + try { + int _type = PLUS; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:318:5: ( '+' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:318:7: '+' + { + match('+'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end PLUS + + // $ANTLR start MINUS + public final void mMINUS() throws RecognitionException { + try { + int _type = MINUS; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:319:6: ( '-' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:319:8: '-' + { + match('-'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end MINUS + + // $ANTLR start DIV + public final void mDIV() throws RecognitionException { + try { + int _type = DIV; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:320:4: ( '/' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:320:6: '/' + { + match('/'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DIV + + // $ANTLR start STAR + public final void mSTAR() throws RecognitionException { + try { + int _type = STAR; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:321:5: ( '*' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:321:7: '*' + { + match('*'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end STAR + + // $ANTLR start MOD + public final void mMOD() throws RecognitionException { + try { + int _type = MOD; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:322:4: ( '%' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:322:6: '%' + { + match('%'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end MOD + + // $ANTLR start POWER + public final void mPOWER() throws RecognitionException { + try { + int _type = POWER; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:323:6: ( '^' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:323:8: '^' + { + match('^'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end POWER + + // $ANTLR start BANG + public final void mBANG() throws RecognitionException { + try { + int _type = BANG; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:324:5: ( '!' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:324:7: '!' + { + match('!'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end BANG + + // $ANTLR start POUND + public final void mPOUND() throws RecognitionException { + try { + int _type = POUND; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:325:6: ( '#' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:325:8: '#' + { + match('#'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end POUND + + // $ANTLR start QMARK + public final void mQMARK() throws RecognitionException { + try { + int _type = QMARK; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:326:6: ( '?' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:326:8: '?' + { + match('?'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end QMARK + + // $ANTLR start DEFAULT + public final void mDEFAULT() throws RecognitionException { + try { + int _type = DEFAULT; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:327:8: ( '??' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:327:10: '??' + { + match("??"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DEFAULT + + // $ANTLR start LAMBDA + public final void mLAMBDA() throws RecognitionException { + try { + int _type = LAMBDA; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:328:7: ( '{|' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:328:9: '{|' + { + match("{|"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end LAMBDA + + // $ANTLR start PROJECT + public final void mPROJECT() throws RecognitionException { + try { + int _type = PROJECT; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:329:8: ( '!{' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:329:10: '!{' + { + match("!{"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end PROJECT + + // $ANTLR start SELECT + public final void mSELECT() throws RecognitionException { + try { + int _type = SELECT; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:330:7: ( '?{' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:330:9: '?{' + { + match("?{"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SELECT + + // $ANTLR start SELECT_FIRST + public final void mSELECT_FIRST() throws RecognitionException { + try { + int _type = SELECT_FIRST; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:331:13: ( '^{' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:331:15: '^{' + { + match("^{"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SELECT_FIRST + + // $ANTLR start SELECT_LAST + public final void mSELECT_LAST() throws RecognitionException { + try { + int _type = SELECT_LAST; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:332:12: ( '${' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:332:14: '${' + { + match("${"); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end SELECT_LAST + + // $ANTLR start TYPE + public final void mTYPE() throws RecognitionException { + try { + int _type = TYPE; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:333:5: ( 'T(' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:333:7: 'T(' + { + match("T("); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end TYPE + + // $ANTLR start STRING_LITERAL + public final void mSTRING_LITERAL() throws RecognitionException { + try { + int _type = STRING_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:335:15: ( '\\'' ( APOS | ~ '\\'' )* '\\'' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:335:17: '\\'' ( APOS | ~ '\\'' )* '\\'' + { + match('\''); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:335:23: ( APOS | ~ '\\'' )* + loop5: + do { + int alt5=3; + int LA5_0 = input.LA(1); + + if ( (LA5_0=='\'') ) { + int LA5_1 = input.LA(2); + + if ( (LA5_1=='\'') ) { + alt5=1; + } + + + } + else if ( ((LA5_0>='\u0000' && LA5_0<='&')||(LA5_0>='(' && LA5_0<='\uFFFE')) ) { + alt5=2; + } + + + switch (alt5) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:335:24: APOS + { + mAPOS(); + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:335:29: ~ '\\'' + { + if ( (input.LA(1)>='\u0000' && input.LA(1)<='&')||(input.LA(1)>='(' && input.LA(1)<='\uFFFE') ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + break; + + default : + break loop5; + } + } while (true); + + match('\''); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end STRING_LITERAL + + // $ANTLR start DQ_STRING_LITERAL + public final void mDQ_STRING_LITERAL() throws RecognitionException { + try { + int _type = DQ_STRING_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:336:18: ( '\"' (~ '\"' )* '\"' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:336:20: '\"' (~ '\"' )* '\"' + { + match('\"'); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:336:25: (~ '\"' )* + loop6: + do { + int alt6=2; + int LA6_0 = input.LA(1); + + if ( ((LA6_0>='\u0000' && LA6_0<='!')||(LA6_0>='#' && LA6_0<='\uFFFE')) ) { + alt6=1; + } + + + switch (alt6) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:336:26: ~ '\"' + { + if ( (input.LA(1)>='\u0000' && input.LA(1)<='!')||(input.LA(1)>='#' && input.LA(1)<='\uFFFE') ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + break; + + default : + break loop6; + } + } while (true); + + match('\"'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DQ_STRING_LITERAL + + // $ANTLR start ID + public final void mID() throws RecognitionException { + try { + int _type = ID; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:3: ( ( 'a' .. 'z' | 'A' .. 'Z' | '_' ) ( 'a' .. 'z' | 'A' .. 'Z' | '_' | '0' .. '9' | DOT_ESCAPED )* ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:5: ( 'a' .. 'z' | 'A' .. 'Z' | '_' ) ( 'a' .. 'z' | 'A' .. 'Z' | '_' | '0' .. '9' | DOT_ESCAPED )* + { + if ( (input.LA(1)>='A' && input.LA(1)<='Z')||input.LA(1)=='_'||(input.LA(1)>='a' && input.LA(1)<='z') ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:29: ( 'a' .. 'z' | 'A' .. 'Z' | '_' | '0' .. '9' | DOT_ESCAPED )* + loop7: + do { + int alt7=6; + switch ( input.LA(1) ) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + alt7=1; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + { + alt7=2; + } + break; + case '_': + { + alt7=3; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + alt7=4; + } + break; + case '\\': + { + alt7=5; + } + break; + + } + + switch (alt7) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:30: 'a' .. 'z' + { + matchRange('a','z'); + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:39: 'A' .. 'Z' + { + matchRange('A','Z'); + + } + break; + case 3 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:48: '_' + { + match('_'); + + } + break; + case 4 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:52: '0' .. '9' + { + matchRange('0','9'); + + } + break; + case 5 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:337:61: DOT_ESCAPED + { + mDOT_ESCAPED(); + + } + break; + + default : + break loop7; + } + } while (true); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end ID + + // $ANTLR start DOT_ESCAPED + public final void mDOT_ESCAPED() throws RecognitionException { + try { + int _type = DOT_ESCAPED; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:338:12: ( '\\\\.' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:338:14: '\\\\.' + { + match("\\."); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DOT_ESCAPED + + // $ANTLR start WS + public final void mWS() throws RecognitionException { + try { + int _type = WS; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:340:3: ( ( ' ' | '\\t' | '\\n' | '\\r' )+ ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:340:5: ( ' ' | '\\t' | '\\n' | '\\r' )+ + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:340:5: ( ' ' | '\\t' | '\\n' | '\\r' )+ + int cnt8=0; + loop8: + do { + int alt8=2; + int LA8_0 = input.LA(1); + + if ( ((LA8_0>='\t' && LA8_0<='\n')||LA8_0=='\r'||LA8_0==' ') ) { + alt8=1; + } + + + switch (alt8) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g: + { + if ( (input.LA(1)>='\t' && input.LA(1)<='\n')||input.LA(1)=='\r'||input.LA(1)==' ' ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + break; + + default : + if ( cnt8 >= 1 ) break loop8; + EarlyExitException eee = + new EarlyExitException(8, input); + throw eee; + } + cnt8++; + } while (true); + + channel=HIDDEN; + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end WS + + // $ANTLR start DOLLAR + public final void mDOLLAR() throws RecognitionException { + try { + int _type = DOLLAR; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:341:7: ( '$' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:341:9: '$' + { + match('$'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end DOLLAR + + // $ANTLR start AT + public final void mAT() throws RecognitionException { + try { + int _type = AT; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:342:3: ( '@' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:342:5: '@' + { + match('@'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end AT + + // $ANTLR start UPTO + public final void mUPTO() throws RecognitionException { + try { + int _type = UPTO; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:343:5: ( '..' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:343:7: '..' + { + match(".."); + + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end UPTO + + // $ANTLR start COLON + public final void mCOLON() throws RecognitionException { + try { + int _type = COLON; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:344:6: ( ':' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:344:8: ':' + { + match(':'); + + } + + this.type = _type; + } + finally { + } + } + // $ANTLR end COLON + + // $ANTLR start REAL_LITERAL + public final void mREAL_LITERAL() throws RecognitionException { + try { + int _type = REAL_LITERAL; + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:361:14: ( ( '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) | ( ( DECIMAL_DIGIT )+ '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) | ( ( DECIMAL_DIGIT )+ ( EXPONENT_PART ) ( REAL_TYPE_SUFFIX )? ) | ( ( DECIMAL_DIGIT )+ ( REAL_TYPE_SUFFIX ) ) ) + int alt19=4; + alt19 = dfa19.predict(input); + switch (alt19) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:3: ( '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:3: ( '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:4: '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? + { + match('.'); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:8: ( DECIMAL_DIGIT )+ + int cnt9=0; + loop9: + do { + int alt9=2; + int LA9_0 = input.LA(1); + + if ( ((LA9_0>='0' && LA9_0<='9')) ) { + alt9=1; + } + + + switch (alt9) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:9: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt9 >= 1 ) break loop9; + EarlyExitException eee = + new EarlyExitException(9, input); + throw eee; + } + cnt9++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:25: ( EXPONENT_PART )? + int alt10=2; + int LA10_0 = input.LA(1); + + if ( (LA10_0=='E'||LA10_0=='e') ) { + alt10=1; + } + switch (alt10) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:26: EXPONENT_PART + { + mEXPONENT_PART(); + + } + break; + + } + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:42: ( REAL_TYPE_SUFFIX )? + int alt11=2; + int LA11_0 = input.LA(1); + + if ( (LA11_0=='D'||LA11_0=='F'||LA11_0=='M'||LA11_0=='d'||LA11_0=='f'||LA11_0=='m') ) { + alt11=1; + } + switch (alt11) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:362:43: REAL_TYPE_SUFFIX + { + mREAL_TYPE_SUFFIX(); + + } + break; + + } + + + } + + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:2: ( ( DECIMAL_DIGIT )+ '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:2: ( ( DECIMAL_DIGIT )+ '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:3: ( DECIMAL_DIGIT )+ '.' ( DECIMAL_DIGIT )+ ( EXPONENT_PART )? ( REAL_TYPE_SUFFIX )? + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:3: ( DECIMAL_DIGIT )+ + int cnt12=0; + loop12: + do { + int alt12=2; + int LA12_0 = input.LA(1); + + if ( ((LA12_0>='0' && LA12_0<='9')) ) { + alt12=1; + } + + + switch (alt12) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:4: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt12 >= 1 ) break loop12; + EarlyExitException eee = + new EarlyExitException(12, input); + throw eee; + } + cnt12++; + } while (true); + + match('.'); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:24: ( DECIMAL_DIGIT )+ + int cnt13=0; + loop13: + do { + int alt13=2; + int LA13_0 = input.LA(1); + + if ( ((LA13_0>='0' && LA13_0<='9')) ) { + alt13=1; + } + + + switch (alt13) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:25: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt13 >= 1 ) break loop13; + EarlyExitException eee = + new EarlyExitException(13, input); + throw eee; + } + cnt13++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:41: ( EXPONENT_PART )? + int alt14=2; + int LA14_0 = input.LA(1); + + if ( (LA14_0=='E'||LA14_0=='e') ) { + alt14=1; + } + switch (alt14) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:42: EXPONENT_PART + { + mEXPONENT_PART(); + + } + break; + + } + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:58: ( REAL_TYPE_SUFFIX )? + int alt15=2; + int LA15_0 = input.LA(1); + + if ( (LA15_0=='D'||LA15_0=='F'||LA15_0=='M'||LA15_0=='d'||LA15_0=='f'||LA15_0=='m') ) { + alt15=1; + } + switch (alt15) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:363:59: REAL_TYPE_SUFFIX + { + mREAL_TYPE_SUFFIX(); + + } + break; + + } + + + } + + + } + break; + case 3 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:2: ( ( DECIMAL_DIGIT )+ ( EXPONENT_PART ) ( REAL_TYPE_SUFFIX )? ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:2: ( ( DECIMAL_DIGIT )+ ( EXPONENT_PART ) ( REAL_TYPE_SUFFIX )? ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:3: ( DECIMAL_DIGIT )+ ( EXPONENT_PART ) ( REAL_TYPE_SUFFIX )? + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:3: ( DECIMAL_DIGIT )+ + int cnt16=0; + loop16: + do { + int alt16=2; + int LA16_0 = input.LA(1); + + if ( ((LA16_0>='0' && LA16_0<='9')) ) { + alt16=1; + } + + + switch (alt16) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:4: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt16 >= 1 ) break loop16; + EarlyExitException eee = + new EarlyExitException(16, input); + throw eee; + } + cnt16++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:20: ( EXPONENT_PART ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:21: EXPONENT_PART + { + mEXPONENT_PART(); + + } + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:36: ( REAL_TYPE_SUFFIX )? + int alt17=2; + int LA17_0 = input.LA(1); + + if ( (LA17_0=='D'||LA17_0=='F'||LA17_0=='M'||LA17_0=='d'||LA17_0=='f'||LA17_0=='m') ) { + alt17=1; + } + switch (alt17) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:364:37: REAL_TYPE_SUFFIX + { + mREAL_TYPE_SUFFIX(); + + } + break; + + } + + + } + + + } + break; + case 4 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:2: ( ( DECIMAL_DIGIT )+ ( REAL_TYPE_SUFFIX ) ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:2: ( ( DECIMAL_DIGIT )+ ( REAL_TYPE_SUFFIX ) ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:3: ( DECIMAL_DIGIT )+ ( REAL_TYPE_SUFFIX ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:3: ( DECIMAL_DIGIT )+ + int cnt18=0; + loop18: + do { + int alt18=2; + int LA18_0 = input.LA(1); + + if ( ((LA18_0>='0' && LA18_0<='9')) ) { + alt18=1; + } + + + switch (alt18) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:4: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt18 >= 1 ) break loop18; + EarlyExitException eee = + new EarlyExitException(18, input); + throw eee; + } + cnt18++; + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:20: ( REAL_TYPE_SUFFIX ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:365:21: REAL_TYPE_SUFFIX + { + mREAL_TYPE_SUFFIX(); + + } + + + } + + + } + break; + + } + this.type = _type; + } + finally { + } + } + // $ANTLR end REAL_LITERAL + + // $ANTLR start APOS + public final void mAPOS() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:367:15: ( '\\'' '\\'' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:367:17: '\\'' '\\'' + { + match('\''); + match('\''); + + } + + } + finally { + } + } + // $ANTLR end APOS + + // $ANTLR start DECIMAL_DIGIT + public final void mDECIMAL_DIGIT() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:368:24: ( '0' .. '9' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:368:26: '0' .. '9' + { + matchRange('0','9'); + + } + + } + finally { + } + } + // $ANTLR end DECIMAL_DIGIT + + // $ANTLR start INTEGER_TYPE_SUFFIX + public final void mINTEGER_TYPE_SUFFIX() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:30: ( ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' ) ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:32: ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' ) + { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:32: ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' ) + int alt20=10; + switch ( input.LA(1) ) { + case 'U': + { + int LA20_1 = input.LA(2); + + if ( (LA20_1=='L') ) { + alt20=1; + } + else { + alt20=7;} + } + break; + case 'L': + { + int LA20_2 = input.LA(2); + + if ( (LA20_2=='U') ) { + alt20=2; + } + else { + alt20=8;} + } + break; + case 'u': + { + switch ( input.LA(2) ) { + case 'l': + { + alt20=3; + } + break; + case 'L': + { + alt20=5; + } + break; + default: + alt20=9;} + + } + break; + case 'l': + { + switch ( input.LA(2) ) { + case 'U': + { + alt20=6; + } + break; + case 'u': + { + alt20=4; + } + break; + default: + alt20=10;} + + } + break; + default: + NoViableAltException nvae = + new NoViableAltException("369:32: ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' )", 20, 0, input); + + throw nvae; + } + + switch (alt20) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:34: 'UL' + { + match("UL"); + + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:41: 'LU' + { + match("LU"); + + + } + break; + case 3 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:48: 'ul' + { + match("ul"); + + + } + break; + case 4 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:55: 'lu' + { + match("lu"); + + + } + break; + case 5 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:62: 'uL' + { + match("uL"); + + + } + break; + case 6 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:69: 'lU' + { + match("lU"); + + + } + break; + case 7 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:76: 'U' + { + match('U'); + + } + break; + case 8 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:82: 'L' + { + match('L'); + + } + break; + case 9 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:88: 'u' + { + match('u'); + + } + break; + case 10 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:369:94: 'l' + { + match('l'); + + } + break; + + } + + + } + + } + finally { + } + } + // $ANTLR end INTEGER_TYPE_SUFFIX + + // $ANTLR start HEX_DIGIT + public final void mHEX_DIGIT() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:370:20: ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g: + { + if ( (input.LA(1)>='0' && input.LA(1)<='9')||(input.LA(1)>='A' && input.LA(1)<='F')||(input.LA(1)>='a' && input.LA(1)<='f') ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + + } + finally { + } + } + // $ANTLR end HEX_DIGIT + + // $ANTLR start EXPONENT_PART + public final void mEXPONENT_PART() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:24: ( 'e' ( SIGN )* ( DECIMAL_DIGIT )+ | 'E' ( SIGN )* ( DECIMAL_DIGIT )+ ) + int alt25=2; + int LA25_0 = input.LA(1); + + if ( (LA25_0=='e') ) { + alt25=1; + } + else if ( (LA25_0=='E') ) { + alt25=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("372:10: fragment EXPONENT_PART : ( 'e' ( SIGN )* ( DECIMAL_DIGIT )+ | 'E' ( SIGN )* ( DECIMAL_DIGIT )+ );", 25, 0, input); + + throw nvae; + } + switch (alt25) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:26: 'e' ( SIGN )* ( DECIMAL_DIGIT )+ + { + match('e'); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:31: ( SIGN )* + loop21: + do { + int alt21=2; + int LA21_0 = input.LA(1); + + if ( (LA21_0=='+'||LA21_0=='-') ) { + alt21=1; + } + + + switch (alt21) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:32: SIGN + { + mSIGN(); + + } + break; + + default : + break loop21; + } + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:40: ( DECIMAL_DIGIT )+ + int cnt22=0; + loop22: + do { + int alt22=2; + int LA22_0 = input.LA(1); + + if ( ((LA22_0>='0' && LA22_0<='9')) ) { + alt22=1; + } + + + switch (alt22) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:41: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt22 >= 1 ) break loop22; + EarlyExitException eee = + new EarlyExitException(22, input); + throw eee; + } + cnt22++; + } while (true); + + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:59: 'E' ( SIGN )* ( DECIMAL_DIGIT )+ + { + match('E'); + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:64: ( SIGN )* + loop23: + do { + int alt23=2; + int LA23_0 = input.LA(1); + + if ( (LA23_0=='+'||LA23_0=='-') ) { + alt23=1; + } + + + switch (alt23) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:65: SIGN + { + mSIGN(); + + } + break; + + default : + break loop23; + } + } while (true); + + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:73: ( DECIMAL_DIGIT )+ + int cnt24=0; + loop24: + do { + int alt24=2; + int LA24_0 = input.LA(1); + + if ( ((LA24_0>='0' && LA24_0<='9')) ) { + alt24=1; + } + + + switch (alt24) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:372:74: DECIMAL_DIGIT + { + mDECIMAL_DIGIT(); + + } + break; + + default : + if ( cnt24 >= 1 ) break loop24; + EarlyExitException eee = + new EarlyExitException(24, input); + throw eee; + } + cnt24++; + } while (true); + + + } + break; + + } + } + finally { + } + } + // $ANTLR end EXPONENT_PART + + // $ANTLR start SIGN + public final void mSIGN() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:373:15: ( '+' | '-' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g: + { + if ( input.LA(1)=='+'||input.LA(1)=='-' ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + + } + finally { + } + } + // $ANTLR end SIGN + + // $ANTLR start REAL_TYPE_SUFFIX + public final void mREAL_TYPE_SUFFIX() throws RecognitionException { + try { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:375:27: ( 'F' | 'f' | 'D' | 'd' | 'M' | 'm' ) + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g: + { + if ( input.LA(1)=='D'||input.LA(1)=='F'||input.LA(1)=='M'||input.LA(1)=='d'||input.LA(1)=='f'||input.LA(1)=='m' ) { + input.consume(); + + } + else { + MismatchedSetException mse = + new MismatchedSetException(null,input); + recover(mse); throw mse; + } + + + } + + } + finally { + } + } + // $ANTLR end REAL_TYPE_SUFFIX + + public void mTokens() throws RecognitionException { + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:8: ( T94 | T95 | SEMIRPAREN | INTEGER_LITERAL | HEXADECIMAL_INTEGER_LITERAL | ASSIGN | EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL | SOUNDSLIKE | DISTANCETO | IN | IS | BETWEEN | LIKE | MATCHES | NULL_LITERAL | SEMI | DOT | COMMA | LPAREN | RPAREN | LCURLY | RCURLY | LBRACKET | RBRACKET | PIPE | AND | OR | FALSE | TRUE | PLUS | MINUS | DIV | STAR | MOD | POWER | BANG | POUND | QMARK | DEFAULT | LAMBDA | PROJECT | SELECT | SELECT_FIRST | SELECT_LAST | TYPE | STRING_LITERAL | DQ_STRING_LITERAL | ID | DOT_ESCAPED | WS | DOLLAR | AT | UPTO | COLON | REAL_LITERAL ) + int alt26=60; + alt26 = dfa26.predict(input); + switch (alt26) { + case 1 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:10: T94 + { + mT94(); + + } + break; + case 2 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:14: T95 + { + mT95(); + + } + break; + case 3 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:18: SEMIRPAREN + { + mSEMIRPAREN(); + + } + break; + case 4 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:29: INTEGER_LITERAL + { + mINTEGER_LITERAL(); + + } + break; + case 5 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:45: HEXADECIMAL_INTEGER_LITERAL + { + mHEXADECIMAL_INTEGER_LITERAL(); + + } + break; + case 6 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:73: ASSIGN + { + mASSIGN(); + + } + break; + case 7 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:80: EQUAL + { + mEQUAL(); + + } + break; + case 8 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:86: NOT_EQUAL + { + mNOT_EQUAL(); + + } + break; + case 9 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:96: LESS_THAN + { + mLESS_THAN(); + + } + break; + case 10 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:106: LESS_THAN_OR_EQUAL + { + mLESS_THAN_OR_EQUAL(); + + } + break; + case 11 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:125: GREATER_THAN + { + mGREATER_THAN(); + + } + break; + case 12 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:138: GREATER_THAN_OR_EQUAL + { + mGREATER_THAN_OR_EQUAL(); + + } + break; + case 13 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:160: SOUNDSLIKE + { + mSOUNDSLIKE(); + + } + break; + case 14 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:171: DISTANCETO + { + mDISTANCETO(); + + } + break; + case 15 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:182: IN + { + mIN(); + + } + break; + case 16 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:185: IS + { + mIS(); + + } + break; + case 17 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:188: BETWEEN + { + mBETWEEN(); + + } + break; + case 18 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:196: LIKE + { + mLIKE(); + + } + break; + case 19 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:201: MATCHES + { + mMATCHES(); + + } + break; + case 20 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:209: NULL_LITERAL + { + mNULL_LITERAL(); + + } + break; + case 21 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:222: SEMI + { + mSEMI(); + + } + break; + case 22 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:227: DOT + { + mDOT(); + + } + break; + case 23 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:231: COMMA + { + mCOMMA(); + + } + break; + case 24 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:237: LPAREN + { + mLPAREN(); + + } + break; + case 25 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:244: RPAREN + { + mRPAREN(); + + } + break; + case 26 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:251: LCURLY + { + mLCURLY(); + + } + break; + case 27 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:258: RCURLY + { + mRCURLY(); + + } + break; + case 28 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:265: LBRACKET + { + mLBRACKET(); + + } + break; + case 29 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:274: RBRACKET + { + mRBRACKET(); + + } + break; + case 30 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:283: PIPE + { + mPIPE(); + + } + break; + case 31 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:288: AND + { + mAND(); + + } + break; + case 32 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:292: OR + { + mOR(); + + } + break; + case 33 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:295: FALSE + { + mFALSE(); + + } + break; + case 34 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:301: TRUE + { + mTRUE(); + + } + break; + case 35 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:306: PLUS + { + mPLUS(); + + } + break; + case 36 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:311: MINUS + { + mMINUS(); + + } + break; + case 37 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:317: DIV + { + mDIV(); + + } + break; + case 38 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:321: STAR + { + mSTAR(); + + } + break; + case 39 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:326: MOD + { + mMOD(); + + } + break; + case 40 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:330: POWER + { + mPOWER(); + + } + break; + case 41 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:336: BANG + { + mBANG(); + + } + break; + case 42 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:341: POUND + { + mPOUND(); + + } + break; + case 43 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:347: QMARK + { + mQMARK(); + + } + break; + case 44 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:353: DEFAULT + { + mDEFAULT(); + + } + break; + case 45 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:361: LAMBDA + { + mLAMBDA(); + + } + break; + case 46 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:368: PROJECT + { + mPROJECT(); + + } + break; + case 47 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:376: SELECT + { + mSELECT(); + + } + break; + case 48 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:383: SELECT_FIRST + { + mSELECT_FIRST(); + + } + break; + case 49 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:396: SELECT_LAST + { + mSELECT_LAST(); + + } + break; + case 50 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:408: TYPE + { + mTYPE(); + + } + break; + case 51 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:413: STRING_LITERAL + { + mSTRING_LITERAL(); + + } + break; + case 52 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:428: DQ_STRING_LITERAL + { + mDQ_STRING_LITERAL(); + + } + break; + case 53 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:446: ID + { + mID(); + + } + break; + case 54 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:449: DOT_ESCAPED + { + mDOT_ESCAPED(); + + } + break; + case 55 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:461: WS + { + mWS(); + + } + break; + case 56 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:464: DOLLAR + { + mDOLLAR(); + + } + break; + case 57 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:471: AT + { + mAT(); + + } + break; + case 58 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:474: UPTO + { + mUPTO(); + + } + break; + case 59 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:479: COLON + { + mCOLON(); + + } + break; + case 60 : + // /Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g:1:485: REAL_LITERAL + { + mREAL_LITERAL(); + + } + break; + + } + + } + + + protected DFA19 dfa19 = new DFA19(this); + protected DFA26 dfa26 = new DFA26(this); + static final String DFA19_eotS = + "\6\uffff"; + static final String DFA19_eofS = + "\6\uffff"; + static final String DFA19_minS = + "\1\56\1\uffff\1\56\3\uffff"; + static final String DFA19_maxS = + "\1\71\1\uffff\1\155\3\uffff"; + static final String DFA19_acceptS = + "\1\uffff\1\1\1\uffff\1\4\1\3\1\2"; + static final String DFA19_specialS = + "\6\uffff}>"; + static final String[] DFA19_transitionS = { + "\1\1\1\uffff\12\2", + "", + "\1\5\1\uffff\12\2\12\uffff\1\3\1\4\1\3\6\uffff\1\3\26\uffff"+ + "\1\3\1\4\1\3\6\uffff\1\3", + "", + "", + "" + }; + + static final short[] DFA19_eot = DFA.unpackEncodedString(DFA19_eotS); + static final short[] DFA19_eof = DFA.unpackEncodedString(DFA19_eofS); + static final char[] DFA19_min = DFA.unpackEncodedStringToUnsignedChars(DFA19_minS); + static final char[] DFA19_max = DFA.unpackEncodedStringToUnsignedChars(DFA19_maxS); + static final short[] DFA19_accept = DFA.unpackEncodedString(DFA19_acceptS); + static final short[] DFA19_special = DFA.unpackEncodedString(DFA19_specialS); + static final short[][] DFA19_transition; + + static { + int numStates = DFA19_transitionS.length; + DFA19_transition = new short[numStates][]; + for (int i=0; i"; + static final String[] DFA26_transitionS = { + "\2\52\2\uffff\1\52\22\uffff\1\52\1\7\1\47\1\42\1\44\1\40\1\uffff"+ + "\1\46\1\21\1\22\1\37\1\34\1\20\1\35\1\17\1\36\1\4\11\5\1\54"+ + "\1\3\1\10\1\6\1\11\1\43\1\53\23\50\1\45\6\50\1\25\1\51\1\26"+ + "\1\41\1\50\1\uffff\1\30\1\14\1\50\1\2\1\50\1\32\2\50\1\13\2"+ + "\50\1\15\1\16\1\1\1\31\3\50\1\12\1\33\6\50\1\23\1\27\1\24", + "\1\55\17\uffff\1\56", + "\1\57\7\uffff\1\60", + "\1\61", + "\1\65\1\uffff\12\5\12\uffff\3\65\6\uffff\1\65\26\uffff\3\65"+ + "\6\uffff\1\65\12\uffff\1\63", + "\1\65\1\uffff\12\5\12\uffff\3\65\6\uffff\1\65\26\uffff\3\65"+ + "\6\uffff\1\65", + "\1\66", + "\1\70\75\uffff\1\71", + "\1\73", + "\1\75", + "\1\77", + "\1\100\4\uffff\1\101", + "\1\102", + "\1\103", + "\1\104", + "\1\105\1\uffff\12\65", + "", + "", + "", + "\1\107", + "", + "", + "", + "", + "\1\111", + "\1\112", + "\1\113", + "\1\114", + "", + "", + "", + "", + "", + "\1\115", + "", + "\1\117\73\uffff\1\120", + "\1\122", + "\1\124", + "", + "", + "", + "", + "", + "", + "", + "\1\125", + "\1\126", + "\1\127", + "\1\130", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "\1\131", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\134", + "\1\135", + "\1\136", + "", + "", + "", + "", + "\1\137", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\141", + "\1\142", + "", + "", + "", + "", + "", + "", + "", + "", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\144", + "\1\145", + "\1\146", + "\1\147", + "", + "", + "\1\150", + "\1\151", + "\1\152", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "", + "\1\154", + "\1\155", + "", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\160", + "\1\161", + "\1\162", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\164", + "", + "\1\165", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "", + "", + "\1\167", + "\1\170", + "\1\171", + "", + "\1\172", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "", + "\1\174", + "\1\175", + "\1\176", + "\1\177", + "", + "\1\u0080", + "\1\u0081", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\1\u0084", + "\1\u0085", + "", + "", + "\1\u0086", + "\1\u0087", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "\12\50\7\uffff\32\50\1\uffff\1\50\2\uffff\1\50\1\uffff\32\50", + "", + "" + }; + + static final short[] DFA26_eot = DFA.unpackEncodedString(DFA26_eotS); + static final short[] DFA26_eof = DFA.unpackEncodedString(DFA26_eofS); + static final char[] DFA26_min = DFA.unpackEncodedStringToUnsignedChars(DFA26_minS); + static final char[] DFA26_max = DFA.unpackEncodedStringToUnsignedChars(DFA26_maxS); + static final short[] DFA26_accept = DFA.unpackEncodedString(DFA26_acceptS); + static final short[] DFA26_special = DFA.unpackEncodedString(DFA26_specialS); + static final short[][] DFA26_transition; + + static { + int numStates = DFA26_transitionS.length; + DFA26_transition = new short[numStates][]; + for (int i=0; i", "", "", "", "EXPRESSIONLIST", + "INTEGER_LITERAL", "EXPRESSION", "QUALIFIED_IDENTIFIER", "REFERENCE", "PROPERTY_OR_FIELD", "INDEXER", + "ARGLIST", "CONSTRUCTOR", "DATE_LITERAL", "HOLDER", "CONSTRUCTOR_ARRAY", "NAMED_ARGUMENT", "FUNCTIONREF", + "TYPEREF", "RANGE", "VARIABLEREF", "LIST_INITIALIZER", "MAP_INITIALIZER", "LOCALVAR", "LOCALFUNC", + "MAP_ENTRY", "METHOD", "ADD", "SUBTRACT", "NUMBER", "LPAREN", "SEMI", "SEMIRPAREN", "RPAREN", "ASSIGN", + "DEFAULT", "QMARK", "COLON", "OR", "AND", "PLUS", "MINUS", "STAR", "DIV", "MOD", "POWER", "BANG", "DOT", + "POUND", "ID", "DOLLAR", "COMMA", "AT", "LBRACKET", "RBRACKET", "PROJECT", "RCURLY", "SELECT", + "SELECT_FIRST", "SELECT_LAST", "TYPE", "LAMBDA", "PIPE", "LCURLY", "STRING_LITERAL", "DQ_STRING_LITERAL", + "NULL_LITERAL", "HEXADECIMAL_INTEGER_LITERAL", "REAL_LITERAL", "TRUE", "FALSE", "DECIMAL_DIGIT", + "INTEGER_TYPE_SUFFIX", "HEX_DIGIT", "EQUAL", "NOT_EQUAL", "LESS_THAN", "LESS_THAN_OR_EQUAL", + "GREATER_THAN", "GREATER_THAN_OR_EQUAL", "IN", "IS", "BETWEEN", "LIKE", "MATCHES", "SOUNDSLIKE", + "DISTANCETO", "APOS", "DOT_ESCAPED", "WS", "UPTO", "EXPONENT_PART", "REAL_TYPE_SUFFIX", "SIGN", "'new'", + "'date'" }; + public static final int COMMA = 51; + public static final int GREATER_THAN_OR_EQUAL = 79; + public static final int EXPRESSIONLIST = 4; + public static final int GREATER_THAN = 78; + public static final int MINUS = 41; + public static final int NUMBER = 29; + public static final int ARGLIST = 11; + public static final int BANG = 46; + public static final int LESS_THAN = 76; + public static final int METHOD = 26; + public static final int FALSE = 70; + public static final int PROPERTY_OR_FIELD = 9; + public static final int INDEXER = 10; + public static final int CONSTRUCTOR_ARRAY = 15; + public static final int NULL_LITERAL = 66; + public static final int NAMED_ARGUMENT = 16; + public static final int PIPE = 62; + public static final int DOT = 47; + public static final int AND = 39; + public static final int EXPRESSION = 6; + public static final int LCURLY = 63; + public static final int DATE_LITERAL = 13; + public static final int REAL_TYPE_SUFFIX = 92; + public static final int QUALIFIED_IDENTIFIER = 7; + public static final int SELECT = 57; + public static final int STRING_LITERAL = 64; + public static final int SUBTRACT = 28; + public static final int RBRACKET = 54; + public static final int RPAREN = 33; + public static final int BETWEEN = 82; + public static final int SIGN = 93; + public static final int PLUS = 40; + public static final int INTEGER_LITERAL = 5; + public static final int AT = 52; + public static final int RANGE = 19; + public static final int SOUNDSLIKE = 85; + public static final int WS = 89; + public static final int DOLLAR = 50; + public static final int LESS_THAN_OR_EQUAL = 77; + public static final int HEXADECIMAL_INTEGER_LITERAL = 67; + public static final int LAMBDA = 61; + public static final int SEMI = 31; + public static final int EQUAL = 74; + public static final int DOT_ESCAPED = 88; + public static final int QMARK = 36; + public static final int COLON = 37; + public static final int PROJECT = 55; + public static final int DIV = 43; + public static final int REAL_LITERAL = 68; + public static final int ADD = 27; + public static final int TRUE = 69; + public static final int EXPONENT_PART = 91; + public static final int POUND = 48; + public static final int HOLDER = 14; + public static final int SELECT_FIRST = 58; + public static final int TYPE = 60; + public static final int MAP_ENTRY = 25; + public static final int SELECT_LAST = 59; + public static final int LBRACKET = 53; + public static final int MOD = 44; + public static final int FUNCTIONREF = 17; + public static final int OR = 38; + public static final int RCURLY = 56; + public static final int ASSIGN = 34; + public static final int LPAREN = 30; + public static final int HEX_DIGIT = 73; + public static final int LIST_INITIALIZER = 21; + public static final int APOS = 87; + public static final int ID = 49; + public static final int NOT_EQUAL = 75; + public static final int POWER = 45; + public static final int TYPEREF = 18; + public static final int DISTANCETO = 86; + public static final int DECIMAL_DIGIT = 71; + public static final int IS = 81; + public static final int SEMIRPAREN = 32; + public static final int DQ_STRING_LITERAL = 65; + public static final int LIKE = 83; + public static final int MAP_INITIALIZER = 22; + public static final int LOCALFUNC = 24; + public static final int IN = 80; + public static final int CONSTRUCTOR = 12; + public static final int INTEGER_TYPE_SUFFIX = 72; + public static final int MATCHES = 84; + public static final int EOF = -1; + public static final int UPTO = 90; + public static final int REFERENCE = 8; + public static final int DEFAULT = 35; + public static final int LOCALVAR = 23; + public static final int STAR = 42; + public static final int VARIABLEREF = 20; + + public SpringExpressionsParser(TokenStream input) { + super(input); + ruleMemo = new HashMap[53 + 1]; + } + + protected TreeAdaptor adaptor = new CommonTreeAdaptor(); + + public void setTreeAdaptor(TreeAdaptor adaptor) { + this.adaptor = adaptor; + } + + public TreeAdaptor getTreeAdaptor() { + return adaptor; + } + + public String[] getTokenNames() { + return tokenNames; + } + + public String getGrammarFileName() { + return "/Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g"; + } + + public static class expr_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start expr + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:56:1: + // expr : expression EOF ; + public final expr_return expr() throws RecognitionException { + expr_return retval = new expr_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token EOF2 = null; + expression_return expression1 = null; + + Object EOF2_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:56:5: + // ( expression EOF ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:56:7: + // expression EOF + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_expression_in_expr173); + expression1 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression1.getTree()); + EOF2 = (Token) input.LT(1); + match(input, EOF, FOLLOW_EOF_in_expr175); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end expr + + public static class exprList_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start exprList + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:58:1: + // exprList : LPAREN expression ( SEMI expression )+ ( SEMIRPAREN | RPAREN ) -> ^( EXPRESSIONLIST ( expression )+ ) + // ; + public final exprList_return exprList() throws RecognitionException { + exprList_return retval = new exprList_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LPAREN3 = null; + Token SEMI5 = null; + Token SEMIRPAREN7 = null; + Token RPAREN8 = null; + expression_return expression4 = null; + + expression_return expression6 = null; + + Object LPAREN3_tree = null; + Object SEMI5_tree = null; + Object SEMIRPAREN7_tree = null; + Object RPAREN8_tree = null; + RewriteRuleTokenStream stream_SEMI = new RewriteRuleTokenStream(adaptor, "token SEMI"); + RewriteRuleTokenStream stream_RPAREN = new RewriteRuleTokenStream(adaptor, "token RPAREN"); + RewriteRuleTokenStream stream_LPAREN = new RewriteRuleTokenStream(adaptor, "token LPAREN"); + RewriteRuleTokenStream stream_SEMIRPAREN = new RewriteRuleTokenStream(adaptor, "token SEMIRPAREN"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:5: + // ( LPAREN expression ( SEMI expression )+ ( SEMIRPAREN | RPAREN ) -> ^( EXPRESSIONLIST ( expression )+ ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:7: + // LPAREN expression ( SEMI expression )+ ( SEMIRPAREN | RPAREN ) + { + LPAREN3 = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_exprList188); + if (failed) + return retval; + if (backtracking == 0) + stream_LPAREN.add(LPAREN3); + + pushFollow(FOLLOW_expression_in_exprList190); + expression4 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression4.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:25: + // ( SEMI expression )+ + int cnt1 = 0; + loop1: do { + int alt1 = 2; + int LA1_0 = input.LA(1); + + if ((LA1_0 == SEMI)) { + alt1 = 1; + } + + switch (alt1) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:26: + // SEMI expression + { + SEMI5 = (Token) input.LT(1); + match(input, SEMI, FOLLOW_SEMI_in_exprList193); + if (failed) + return retval; + if (backtracking == 0) + stream_SEMI.add(SEMI5); + + pushFollow(FOLLOW_expression_in_exprList195); + expression6 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression6.getTree()); + + } + break; + + default: + if (cnt1 >= 1) + break loop1; + if (backtracking > 0) { + failed = true; + return retval; + } + EarlyExitException eee = new EarlyExitException(1, input); + throw eee; + } + cnt1++; + } while (true); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:44: + // ( SEMIRPAREN | RPAREN ) + int alt2 = 2; + int LA2_0 = input.LA(1); + + if ((LA2_0 == SEMIRPAREN)) { + alt2 = 1; + } else if ((LA2_0 == RPAREN)) { + alt2 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException("59:44: ( SEMIRPAREN | RPAREN )", 2, 0, input); + + throw nvae; + } + switch (alt2) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:45: + // SEMIRPAREN + { + SEMIRPAREN7 = (Token) input.LT(1); + match(input, SEMIRPAREN, FOLLOW_SEMIRPAREN_in_exprList200); + if (failed) + return retval; + if (backtracking == 0) + stream_SEMIRPAREN.add(SEMIRPAREN7); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:59:58: + // RPAREN + { + RPAREN8 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_exprList204); + if (failed) + return retval; + if (backtracking == 0) + stream_RPAREN.add(RPAREN8); + + } + break; + + } + + // AST REWRITE + // elements: expression + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 60:7: -> ^( EXPRESSIONLIST ( expression )+ ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:60:10: + // ^( EXPRESSIONLIST ( expression )+ ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(EXPRESSIONLIST, "EXPRESSIONLIST"), + root_1); + + if (!(stream_expression.hasNext())) { + throw new RewriteEarlyExitException(); + } + while (stream_expression.hasNext()) { + adaptor.addChild(root_1, stream_expression.next()); + + } + stream_expression.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end exprList + + public static class expression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start expression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:64:1: + // expression : logicalOrExpression ( ( ASSIGN logicalOrExpression ) | ( DEFAULT logicalOrExpression ) | ( QMARK + // expression COLON expression ) )? ; + public final expression_return expression() throws RecognitionException { + expression_return retval = new expression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token ASSIGN10 = null; + Token DEFAULT12 = null; + Token QMARK14 = null; + Token COLON16 = null; + logicalOrExpression_return logicalOrExpression9 = null; + + logicalOrExpression_return logicalOrExpression11 = null; + + logicalOrExpression_return logicalOrExpression13 = null; + + expression_return expression15 = null; + + expression_return expression17 = null; + + Object ASSIGN10_tree = null; + Object DEFAULT12_tree = null; + Object QMARK14_tree = null; + Object COLON16_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:64:12: + // ( logicalOrExpression ( ( ASSIGN logicalOrExpression ) | ( DEFAULT logicalOrExpression ) | ( QMARK + // expression COLON expression ) )? ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:65:5: + // logicalOrExpression ( ( ASSIGN logicalOrExpression ) | ( DEFAULT logicalOrExpression ) | ( QMARK + // expression COLON expression ) )? + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_logicalOrExpression_in_expression248); + logicalOrExpression9 = logicalOrExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, logicalOrExpression9.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:66:5: + // ( ( ASSIGN logicalOrExpression ) | ( DEFAULT logicalOrExpression ) | ( QMARK expression COLON + // expression ) )? + int alt3 = 4; + switch (input.LA(1)) { + case ASSIGN: { + alt3 = 1; + } + break; + case DEFAULT: { + alt3 = 2; + } + break; + case QMARK: { + alt3 = 3; + } + break; + } + + switch (alt3) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:66:7: + // ( ASSIGN logicalOrExpression ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:66:7: + // ( ASSIGN logicalOrExpression ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:66:8: + // ASSIGN logicalOrExpression + { + ASSIGN10 = (Token) input.LT(1); + match(input, ASSIGN, FOLLOW_ASSIGN_in_expression257); + if (failed) + return retval; + if (backtracking == 0) { + ASSIGN10_tree = (Object) adaptor.create(ASSIGN10); + root_0 = (Object) adaptor.becomeRoot(ASSIGN10_tree, root_0); + } + pushFollow(FOLLOW_logicalOrExpression_in_expression260); + logicalOrExpression11 = logicalOrExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, logicalOrExpression11.getTree()); + + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:67:6: + // ( DEFAULT logicalOrExpression ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:67:6: + // ( DEFAULT logicalOrExpression ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:67:7: + // DEFAULT logicalOrExpression + { + DEFAULT12 = (Token) input.LT(1); + match(input, DEFAULT, FOLLOW_DEFAULT_in_expression270); + if (failed) + return retval; + if (backtracking == 0) { + DEFAULT12_tree = (Object) adaptor.create(DEFAULT12); + root_0 = (Object) adaptor.becomeRoot(DEFAULT12_tree, root_0); + } + pushFollow(FOLLOW_logicalOrExpression_in_expression273); + logicalOrExpression13 = logicalOrExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, logicalOrExpression13.getTree()); + + } + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:68:6: + // ( QMARK expression COLON expression ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:68:6: + // ( QMARK expression COLON expression ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:68:7: + // QMARK expression COLON expression + { + QMARK14 = (Token) input.LT(1); + match(input, QMARK, FOLLOW_QMARK_in_expression283); + if (failed) + return retval; + if (backtracking == 0) { + QMARK14_tree = (Object) adaptor.create(QMARK14); + root_0 = (Object) adaptor.becomeRoot(QMARK14_tree, root_0); + } + pushFollow(FOLLOW_expression_in_expression286); + expression15 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression15.getTree()); + COLON16 = (Token) input.LT(1); + match(input, COLON, FOLLOW_COLON_in_expression288); + if (failed) + return retval; + pushFollow(FOLLOW_expression_in_expression291); + expression17 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression17.getTree()); + + } + + } + break; + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end expression + + public static class parenExpr_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start parenExpr + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:70:1: + // parenExpr : LPAREN expression RPAREN ; + public final parenExpr_return parenExpr() throws RecognitionException { + parenExpr_return retval = new parenExpr_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LPAREN18 = null; + Token RPAREN20 = null; + expression_return expression19 = null; + + Object LPAREN18_tree = null; + Object RPAREN20_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:70:11: + // ( LPAREN expression RPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:70:13: + // LPAREN expression RPAREN + { + root_0 = (Object) adaptor.nil(); + + LPAREN18 = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_parenExpr302); + if (failed) + return retval; + pushFollow(FOLLOW_expression_in_parenExpr305); + expression19 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression19.getTree()); + RPAREN20 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_parenExpr307); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end parenExpr + + public static class logicalOrExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start logicalOrExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:73:1: + // logicalOrExpression : logicalAndExpression ( OR logicalAndExpression )* ; + public final logicalOrExpression_return logicalOrExpression() throws RecognitionException { + logicalOrExpression_return retval = new logicalOrExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token OR22 = null; + logicalAndExpression_return logicalAndExpression21 = null; + + logicalAndExpression_return logicalAndExpression23 = null; + + Object OR22_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:73:21: + // ( logicalAndExpression ( OR logicalAndExpression )* ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:73:23: + // logicalAndExpression ( OR logicalAndExpression )* + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_logicalAndExpression_in_logicalOrExpression318); + logicalAndExpression21 = logicalAndExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, logicalAndExpression21.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:73:44: + // ( OR logicalAndExpression )* + loop4: do { + int alt4 = 2; + int LA4_0 = input.LA(1); + + if ((LA4_0 == OR)) { + alt4 = 1; + } + + switch (alt4) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:73:45: + // OR logicalAndExpression + { + OR22 = (Token) input.LT(1); + match(input, OR, FOLLOW_OR_in_logicalOrExpression321); + if (failed) + return retval; + if (backtracking == 0) { + OR22_tree = (Object) adaptor.create(OR22); + root_0 = (Object) adaptor.becomeRoot(OR22_tree, root_0); + } + pushFollow(FOLLOW_logicalAndExpression_in_logicalOrExpression324); + logicalAndExpression23 = logicalAndExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, logicalAndExpression23.getTree()); + + } + break; + + default: + break loop4; + } + } while (true); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end logicalOrExpression + + public static class logicalAndExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start logicalAndExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:75:1: + // logicalAndExpression : relationalExpression ( AND relationalExpression )* ; + public final logicalAndExpression_return logicalAndExpression() throws RecognitionException { + logicalAndExpression_return retval = new logicalAndExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token AND25 = null; + relationalExpression_return relationalExpression24 = null; + + relationalExpression_return relationalExpression26 = null; + + Object AND25_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:75:22: + // ( relationalExpression ( AND relationalExpression )* ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:75:24: + // relationalExpression ( AND relationalExpression )* + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_relationalExpression_in_logicalAndExpression358); + relationalExpression24 = relationalExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, relationalExpression24.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:75:45: + // ( AND relationalExpression )* + loop5: do { + int alt5 = 2; + int LA5_0 = input.LA(1); + + if ((LA5_0 == AND)) { + alt5 = 1; + } + + switch (alt5) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:75:46: + // AND relationalExpression + { + AND25 = (Token) input.LT(1); + match(input, AND, FOLLOW_AND_in_logicalAndExpression361); + if (failed) + return retval; + if (backtracking == 0) { + AND25_tree = (Object) adaptor.create(AND25); + root_0 = (Object) adaptor.becomeRoot(AND25_tree, root_0); + } + pushFollow(FOLLOW_relationalExpression_in_logicalAndExpression364); + relationalExpression26 = relationalExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, relationalExpression26.getTree()); + + } + break; + + default: + break loop5; + } + } while (true); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end logicalAndExpression + + public static class relationalExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start relationalExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:77:1: + // relationalExpression : sumExpression ( relationalOperator sumExpression )? ; + public final relationalExpression_return relationalExpression() throws RecognitionException { + relationalExpression_return retval = new relationalExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + sumExpression_return sumExpression27 = null; + + relationalOperator_return relationalOperator28 = null; + + sumExpression_return sumExpression29 = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:77:22: + // ( sumExpression ( relationalOperator sumExpression )? ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:77:24: + // sumExpression ( relationalOperator sumExpression )? + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_sumExpression_in_relationalExpression375); + sumExpression27 = sumExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, sumExpression27.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:77:38: + // ( relationalOperator sumExpression )? + int alt6 = 2; + int LA6_0 = input.LA(1); + + if (((LA6_0 >= EQUAL && LA6_0 <= DISTANCETO))) { + alt6 = 1; + } + switch (alt6) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:77:39: + // relationalOperator sumExpression + { + pushFollow(FOLLOW_relationalOperator_in_relationalExpression378); + relationalOperator28 = relationalOperator(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + root_0 = (Object) adaptor.becomeRoot(relationalOperator28.getTree(), root_0); + pushFollow(FOLLOW_sumExpression_in_relationalExpression381); + sumExpression29 = sumExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, sumExpression29.getTree()); + + } + break; + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end relationalExpression + + public static class sumExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start sumExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:79:1: + // sumExpression : productExpression ( ( PLUS | MINUS ) productExpression )* ; + public final sumExpression_return sumExpression() throws RecognitionException { + sumExpression_return retval = new sumExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token PLUS31 = null; + Token MINUS32 = null; + productExpression_return productExpression30 = null; + + productExpression_return productExpression33 = null; + + Object PLUS31_tree = null; + Object MINUS32_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:2: + // ( productExpression ( ( PLUS | MINUS ) productExpression )* ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:4: + // productExpression ( ( PLUS | MINUS ) productExpression )* + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_productExpression_in_sumExpression392); + productExpression30 = productExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, productExpression30.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:22: + // ( ( PLUS | MINUS ) productExpression )* + loop8: do { + int alt8 = 2; + int LA8_0 = input.LA(1); + + if (((LA8_0 >= PLUS && LA8_0 <= MINUS))) { + alt8 = 1; + } + + switch (alt8) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:24: + // ( PLUS | MINUS ) productExpression + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:24: + // ( PLUS | MINUS ) + int alt7 = 2; + int LA7_0 = input.LA(1); + + if ((LA7_0 == PLUS)) { + alt7 = 1; + } else if ((LA7_0 == MINUS)) { + alt7 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException("80:24: ( PLUS | MINUS )", 7, 0, input); + + throw nvae; + } + switch (alt7) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:25: + // PLUS + { + PLUS31 = (Token) input.LT(1); + match(input, PLUS, FOLLOW_PLUS_in_sumExpression397); + if (failed) + return retval; + if (backtracking == 0) { + PLUS31_tree = (Object) adaptor.create(PLUS31); + root_0 = (Object) adaptor.becomeRoot(PLUS31_tree, root_0); + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:80:33: + // MINUS + { + MINUS32 = (Token) input.LT(1); + match(input, MINUS, FOLLOW_MINUS_in_sumExpression402); + if (failed) + return retval; + if (backtracking == 0) { + MINUS32_tree = (Object) adaptor.create(MINUS32); + root_0 = (Object) adaptor.becomeRoot(MINUS32_tree, root_0); + } + + } + break; + + } + + pushFollow(FOLLOW_productExpression_in_sumExpression406); + productExpression33 = productExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, productExpression33.getTree()); + + } + break; + + default: + break loop8; + } + } while (true); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end sumExpression + + public static class productExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start productExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:86:1: + // productExpression : powerExpr ( ( STAR | DIV | MOD ) powerExpr )* ; + public final productExpression_return productExpression() throws RecognitionException { + productExpression_return retval = new productExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token STAR35 = null; + Token DIV36 = null; + Token MOD37 = null; + powerExpr_return powerExpr34 = null; + + powerExpr_return powerExpr38 = null; + + Object STAR35_tree = null; + Object DIV36_tree = null; + Object MOD37_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:2: + // ( powerExpr ( ( STAR | DIV | MOD ) powerExpr )* ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:4: + // powerExpr ( ( STAR | DIV | MOD ) powerExpr )* + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_powerExpr_in_productExpression421); + powerExpr34 = powerExpr(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, powerExpr34.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:14: + // ( ( STAR | DIV | MOD ) powerExpr )* + loop10: do { + int alt10 = 2; + int LA10_0 = input.LA(1); + + if (((LA10_0 >= STAR && LA10_0 <= MOD))) { + alt10 = 1; + } + + switch (alt10) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:15: + // ( STAR | DIV | MOD ) powerExpr + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:15: + // ( STAR | DIV | MOD ) + int alt9 = 3; + switch (input.LA(1)) { + case STAR: { + alt9 = 1; + } + break; + case DIV: { + alt9 = 2; + } + break; + case MOD: { + alt9 = 3; + } + break; + default: + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException("87:15: ( STAR | DIV | MOD )", 9, 0, + input); + + throw nvae; + } + + switch (alt9) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:16: + // STAR + { + STAR35 = (Token) input.LT(1); + match(input, STAR, FOLLOW_STAR_in_productExpression425); + if (failed) + return retval; + if (backtracking == 0) { + STAR35_tree = (Object) adaptor.create(STAR35); + root_0 = (Object) adaptor.becomeRoot(STAR35_tree, root_0); + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:24: + // DIV + { + DIV36 = (Token) input.LT(1); + match(input, DIV, FOLLOW_DIV_in_productExpression430); + if (failed) + return retval; + if (backtracking == 0) { + DIV36_tree = (Object) adaptor.create(DIV36); + root_0 = (Object) adaptor.becomeRoot(DIV36_tree, root_0); + } + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:87:30: + // MOD + { + MOD37 = (Token) input.LT(1); + match(input, MOD, FOLLOW_MOD_in_productExpression434); + if (failed) + return retval; + if (backtracking == 0) { + MOD37_tree = (Object) adaptor.create(MOD37); + root_0 = (Object) adaptor.becomeRoot(MOD37_tree, root_0); + } + + } + break; + + } + + pushFollow(FOLLOW_powerExpr_in_productExpression438); + powerExpr38 = powerExpr(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, powerExpr38.getTree()); + + } + break; + + default: + break loop10; + } + } while (true); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end productExpression + + public static class powerExpr_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start powerExpr + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:93:1: + // powerExpr : unaryExpression ( POWER unaryExpression )? ; + public final powerExpr_return powerExpr() throws RecognitionException { + powerExpr_return retval = new powerExpr_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token POWER40 = null; + unaryExpression_return unaryExpression39 = null; + + unaryExpression_return unaryExpression41 = null; + + Object POWER40_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:93:12: + // ( unaryExpression ( POWER unaryExpression )? ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:93:14: + // unaryExpression ( POWER unaryExpression )? + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_unaryExpression_in_powerExpr454); + unaryExpression39 = unaryExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, unaryExpression39.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:93:30: + // ( POWER unaryExpression )? + int alt11 = 2; + int LA11_0 = input.LA(1); + + if ((LA11_0 == POWER)) { + alt11 = 1; + } + switch (alt11) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:93:31: + // POWER unaryExpression + { + POWER40 = (Token) input.LT(1); + match(input, POWER, FOLLOW_POWER_in_powerExpr457); + if (failed) + return retval; + if (backtracking == 0) { + POWER40_tree = (Object) adaptor.create(POWER40); + root_0 = (Object) adaptor.becomeRoot(POWER40_tree, root_0); + } + pushFollow(FOLLOW_unaryExpression_in_powerExpr460); + unaryExpression41 = unaryExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, unaryExpression41.getTree()); + + } + break; + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end powerExpr + + public static class unaryExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start unaryExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:95:1: + // unaryExpression : ( ( PLUS | MINUS | BANG ) unaryExpression | primaryExpression ); + public final unaryExpression_return unaryExpression() throws RecognitionException { + unaryExpression_return retval = new unaryExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token PLUS42 = null; + Token MINUS43 = null; + Token BANG44 = null; + unaryExpression_return unaryExpression45 = null; + + primaryExpression_return primaryExpression46 = null; + + Object PLUS42_tree = null; + Object MINUS43_tree = null; + Object BANG44_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:2: + // ( ( PLUS | MINUS | BANG ) unaryExpression | primaryExpression ) + int alt13 = 2; + int LA13_0 = input.LA(1); + + if (((LA13_0 >= PLUS && LA13_0 <= MINUS) || LA13_0 == BANG)) { + alt13 = 1; + } else if ((LA13_0 == INTEGER_LITERAL || LA13_0 == LPAREN || (LA13_0 >= POUND && LA13_0 <= DOLLAR) + || (LA13_0 >= AT && LA13_0 <= LBRACKET) || LA13_0 == PROJECT + || (LA13_0 >= SELECT && LA13_0 <= LAMBDA) || (LA13_0 >= LCURLY && LA13_0 <= FALSE) || (LA13_0 >= 94 && LA13_0 <= 95))) { + alt13 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "95:1: unaryExpression : ( ( PLUS | MINUS | BANG ) unaryExpression | primaryExpression );", 13, + 0, input); + + throw nvae; + } + switch (alt13) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:4: + // ( PLUS | MINUS | BANG ) unaryExpression + { + root_0 = (Object) adaptor.nil(); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:4: + // ( PLUS | MINUS | BANG ) + int alt12 = 3; + switch (input.LA(1)) { + case PLUS: { + alt12 = 1; + } + break; + case MINUS: { + alt12 = 2; + } + break; + case BANG: { + alt12 = 3; + } + break; + default: + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException("96:4: ( PLUS | MINUS | BANG )", 12, 0, input); + + throw nvae; + } + + switch (alt12) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:5: + // PLUS + { + PLUS42 = (Token) input.LT(1); + match(input, PLUS, FOLLOW_PLUS_in_unaryExpression474); + if (failed) + return retval; + if (backtracking == 0) { + PLUS42_tree = (Object) adaptor.create(PLUS42); + root_0 = (Object) adaptor.becomeRoot(PLUS42_tree, root_0); + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:13: + // MINUS + { + MINUS43 = (Token) input.LT(1); + match(input, MINUS, FOLLOW_MINUS_in_unaryExpression479); + if (failed) + return retval; + if (backtracking == 0) { + MINUS43_tree = (Object) adaptor.create(MINUS43); + root_0 = (Object) adaptor.becomeRoot(MINUS43_tree, root_0); + } + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:96:22: + // BANG + { + BANG44 = (Token) input.LT(1); + match(input, BANG, FOLLOW_BANG_in_unaryExpression484); + if (failed) + return retval; + if (backtracking == 0) { + BANG44_tree = (Object) adaptor.create(BANG44); + root_0 = (Object) adaptor.becomeRoot(BANG44_tree, root_0); + } + + } + break; + + } + + pushFollow(FOLLOW_unaryExpression_in_unaryExpression488); + unaryExpression45 = unaryExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, unaryExpression45.getTree()); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:97:4: + // primaryExpression + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_primaryExpression_in_unaryExpression494); + primaryExpression46 = primaryExpression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, primaryExpression46.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end unaryExpression + + public static class primaryExpression_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start primaryExpression + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:99:1: + // primaryExpression : startNode ( node )? -> ^( EXPRESSION startNode ( node )? ) ; + public final primaryExpression_return primaryExpression() throws RecognitionException { + primaryExpression_return retval = new primaryExpression_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + startNode_return startNode47 = null; + + node_return node48 = null; + + RewriteRuleSubtreeStream stream_node = new RewriteRuleSubtreeStream(adaptor, "rule node"); + RewriteRuleSubtreeStream stream_startNode = new RewriteRuleSubtreeStream(adaptor, "rule startNode"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:5: + // ( startNode ( node )? -> ^( EXPRESSION startNode ( node )? ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:7: + // startNode ( node )? + { + pushFollow(FOLLOW_startNode_in_primaryExpression508); + startNode47 = startNode(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_startNode.add(startNode47.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:17: + // ( node )? + int alt14 = 2; + int LA14_0 = input.LA(1); + + if ((LA14_0 == LPAREN || (LA14_0 >= DOT && LA14_0 <= ID) || LA14_0 == LBRACKET || LA14_0 == PROJECT || (LA14_0 >= SELECT && LA14_0 <= SELECT_LAST))) { + alt14 = 1; + } + switch (alt14) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:18: + // node + { + pushFollow(FOLLOW_node_in_primaryExpression511); + node48 = node(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_node.add(node48.getTree()); + + } + break; + + } + + // AST REWRITE + // elements: startNode, node + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 100:25: -> ^( EXPRESSION startNode ( node )? ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:28: + // ^( EXPRESSION startNode ( node )? ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(EXPRESSION, "EXPRESSION"), root_1); + + adaptor.addChild(root_1, stream_startNode.next()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:100:51: + // ( node )? + if (stream_node.hasNext()) { + adaptor.addChild(root_1, stream_node.next()); + + } + stream_node.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end primaryExpression + + public static class startNode_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start startNode + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:102:1: + // startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | + // localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection + // | lastSelection | listInitializer | mapInitializer | lambda ); + public final startNode_return startNode() throws RecognitionException { + startNode_return retval = new startNode_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + exprList_return exprList49 = null; + + parenExpr_return parenExpr50 = null; + + methodOrProperty_return methodOrProperty51 = null; + + functionOrVar_return functionOrVar52 = null; + + localFunctionOrVar_return localFunctionOrVar53 = null; + + reference_return reference54 = null; + + indexer_return indexer55 = null; + + literal_return literal56 = null; + + type_return type57 = null; + + constructor_return constructor58 = null; + + projection_return projection59 = null; + + selection_return selection60 = null; + + firstSelection_return firstSelection61 = null; + + lastSelection_return lastSelection62 = null; + + listInitializer_return listInitializer63 = null; + + mapInitializer_return mapInitializer64 = null; + + lambda_return lambda65 = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:103:5: + // ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | + // localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | + // firstSelection | lastSelection | listInitializer | mapInitializer | lambda ) + int alt15 = 17; + switch (input.LA(1)) { + case LPAREN: { + switch (input.LA(2)) { + case PLUS: { + int LA15_23 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 23, input); + + throw nvae; + } + } + break; + case MINUS: { + int LA15_24 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 24, input); + + throw nvae; + } + } + break; + case BANG: { + int LA15_25 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 25, input); + + throw nvae; + } + } + break; + case LPAREN: { + int LA15_26 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 26, input); + + throw nvae; + } + } + break; + case ID: { + int LA15_27 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 27, input); + + throw nvae; + } + } + break; + case POUND: { + int LA15_28 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 28, input); + + throw nvae; + } + } + break; + case DOLLAR: { + int LA15_29 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 29, input); + + throw nvae; + } + } + break; + case AT: { + int LA15_30 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 30, input); + + throw nvae; + } + } + break; + case LBRACKET: { + int LA15_31 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 31, input); + + throw nvae; + } + } + break; + case INTEGER_LITERAL: { + int LA15_32 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 32, input); + + throw nvae; + } + } + break; + case STRING_LITERAL: { + int LA15_33 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 33, input); + + throw nvae; + } + } + break; + case DQ_STRING_LITERAL: { + int LA15_34 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 34, input); + + throw nvae; + } + } + break; + case TRUE: + case FALSE: { + int LA15_35 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 35, input); + + throw nvae; + } + } + break; + case NULL_LITERAL: { + int LA15_36 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 36, input); + + throw nvae; + } + } + break; + case HEXADECIMAL_INTEGER_LITERAL: { + int LA15_37 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 37, input); + + throw nvae; + } + } + break; + case REAL_LITERAL: { + int LA15_38 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 38, input); + + throw nvae; + } + } + break; + case 95: { + int LA15_39 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 39, input); + + throw nvae; + } + } + break; + case TYPE: { + int LA15_40 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 40, input); + + throw nvae; + } + } + break; + case 94: { + int LA15_41 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 41, input); + + throw nvae; + } + } + break; + case PROJECT: { + int LA15_42 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 42, input); + + throw nvae; + } + } + break; + case SELECT: { + int LA15_43 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 43, input); + + throw nvae; + } + } + break; + case SELECT_FIRST: { + int LA15_44 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 44, input); + + throw nvae; + } + } + break; + case SELECT_LAST: { + int LA15_45 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 45, input); + + throw nvae; + } + } + break; + case LCURLY: { + int LA15_46 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 46, input); + + throw nvae; + } + } + break; + case LAMBDA: { + int LA15_47 = input.LA(3); + + if ((synpred1())) { + alt15 = 1; + } else if ((true)) { + alt15 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 47, input); + + throw nvae; + } + } + break; + default: + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 1, input); + + throw nvae; + } + + } + break; + case ID: { + alt15 = 3; + } + break; + case POUND: { + int LA15_3 = input.LA(2); + + if ((LA15_3 == ID)) { + alt15 = 4; + } else if ((LA15_3 == LCURLY)) { + alt15 = 16; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 3, input); + + throw nvae; + } + } + break; + case DOLLAR: { + alt15 = 5; + } + break; + case AT: { + alt15 = 6; + } + break; + case LBRACKET: { + alt15 = 7; + } + break; + case INTEGER_LITERAL: + case STRING_LITERAL: + case DQ_STRING_LITERAL: + case NULL_LITERAL: + case HEXADECIMAL_INTEGER_LITERAL: + case REAL_LITERAL: + case TRUE: + case FALSE: + case 95: { + alt15 = 8; + } + break; + case TYPE: { + alt15 = 9; + } + break; + case 94: { + alt15 = 10; + } + break; + case PROJECT: { + alt15 = 11; + } + break; + case SELECT: { + alt15 = 12; + } + break; + case SELECT_FIRST: { + alt15 = 13; + } + break; + case SELECT_LAST: { + alt15 = 14; + } + break; + case LCURLY: { + alt15 = 15; + } + break; + case LAMBDA: { + alt15 = 17; + } + break; + default: + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "102:1: startNode : ( ( LPAREN expression SEMI )=> exprList | parenExpr | methodOrProperty | functionOrVar | localFunctionOrVar | reference | indexer | literal | type | constructor | projection | selection | firstSelection | lastSelection | listInitializer | mapInitializer | lambda );", + 15, 0, input); + + throw nvae; + } + + switch (alt15) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:104:5: + // ( LPAREN expression SEMI )=> exprList + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_exprList_in_startNode554); + exprList49 = exprList(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, exprList49.getTree()); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:105:7: + // parenExpr + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_parenExpr_in_startNode563); + parenExpr50 = parenExpr(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, parenExpr50.getTree()); + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:106:7: + // methodOrProperty + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_methodOrProperty_in_startNode571); + methodOrProperty51 = methodOrProperty(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, methodOrProperty51.getTree()); + + } + break; + case 4: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:107:7: + // functionOrVar + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_functionOrVar_in_startNode580); + functionOrVar52 = functionOrVar(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, functionOrVar52.getTree()); + + } + break; + case 5: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:108:7: + // localFunctionOrVar + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_localFunctionOrVar_in_startNode588); + localFunctionOrVar53 = localFunctionOrVar(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, localFunctionOrVar53.getTree()); + + } + break; + case 6: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:109:7: + // reference + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_reference_in_startNode596); + reference54 = reference(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, reference54.getTree()); + + } + break; + case 7: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:110:7: + // indexer + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_indexer_in_startNode604); + indexer55 = indexer(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, indexer55.getTree()); + + } + break; + case 8: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:111:7: + // literal + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_literal_in_startNode612); + literal56 = literal(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, literal56.getTree()); + + } + break; + case 9: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:112:7: + // type + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_type_in_startNode620); + type57 = type(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, type57.getTree()); + + } + break; + case 10: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:113:7: + // constructor + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_constructor_in_startNode628); + constructor58 = constructor(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, constructor58.getTree()); + + } + break; + case 11: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:114:7: + // projection + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_projection_in_startNode636); + projection59 = projection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, projection59.getTree()); + + } + break; + case 12: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:115:7: + // selection + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_selection_in_startNode645); + selection60 = selection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, selection60.getTree()); + + } + break; + case 13: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:116:7: + // firstSelection + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_firstSelection_in_startNode654); + firstSelection61 = firstSelection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, firstSelection61.getTree()); + + } + break; + case 14: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:117:7: + // lastSelection + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_lastSelection_in_startNode662); + lastSelection62 = lastSelection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, lastSelection62.getTree()); + + } + break; + case 15: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:118:7: + // listInitializer + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_listInitializer_in_startNode670); + listInitializer63 = listInitializer(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, listInitializer63.getTree()); + + } + break; + case 16: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:119:7: + // mapInitializer + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_mapInitializer_in_startNode678); + mapInitializer64 = mapInitializer(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, mapInitializer64.getTree()); + + } + break; + case 17: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:120:7: + // lambda + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_lambda_in_startNode686); + lambda65 = lambda(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, lambda65.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end startNode + + public static class node_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start node + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:124:1: + // node : ( methodOrProperty | functionOrVar | indexer | projection | selection | firstSelection | lastSelection | + // exprList | DOT )+ ; + public final node_return node() throws RecognitionException { + node_return retval = new node_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token DOT74 = null; + methodOrProperty_return methodOrProperty66 = null; + + functionOrVar_return functionOrVar67 = null; + + indexer_return indexer68 = null; + + projection_return projection69 = null; + + selection_return selection70 = null; + + firstSelection_return firstSelection71 = null; + + lastSelection_return lastSelection72 = null; + + exprList_return exprList73 = null; + + Object DOT74_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:124:5: + // ( ( methodOrProperty | functionOrVar | indexer | projection | selection | firstSelection | lastSelection + // | exprList | DOT )+ ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:125:2: + // ( methodOrProperty | functionOrVar | indexer | projection | selection | firstSelection | lastSelection | + // exprList | DOT )+ + { + root_0 = (Object) adaptor.nil(); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:125:2: + // ( methodOrProperty | functionOrVar | indexer | projection | selection | firstSelection | + // lastSelection | exprList | DOT )+ + int cnt16 = 0; + loop16: do { + int alt16 = 10; + switch (input.LA(1)) { + case ID: { + alt16 = 1; + } + break; + case POUND: { + alt16 = 2; + } + break; + case LBRACKET: { + alt16 = 3; + } + break; + case PROJECT: { + alt16 = 4; + } + break; + case SELECT: { + alt16 = 5; + } + break; + case SELECT_FIRST: { + alt16 = 6; + } + break; + case SELECT_LAST: { + alt16 = 7; + } + break; + case LPAREN: { + alt16 = 8; + } + break; + case DOT: { + alt16 = 9; + } + break; + + } + + switch (alt16) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:125:4: + // methodOrProperty + { + pushFollow(FOLLOW_methodOrProperty_in_node707); + methodOrProperty66 = methodOrProperty(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, methodOrProperty66.getTree()); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:126:4: + // functionOrVar + { + pushFollow(FOLLOW_functionOrVar_in_node713); + functionOrVar67 = functionOrVar(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, functionOrVar67.getTree()); + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:127:7: + // indexer + { + pushFollow(FOLLOW_indexer_in_node721); + indexer68 = indexer(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, indexer68.getTree()); + + } + break; + case 4: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:128:7: + // projection + { + pushFollow(FOLLOW_projection_in_node729); + projection69 = projection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, projection69.getTree()); + + } + break; + case 5: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:129:7: + // selection + { + pushFollow(FOLLOW_selection_in_node738); + selection70 = selection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, selection70.getTree()); + + } + break; + case 6: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:130:7: + // firstSelection + { + pushFollow(FOLLOW_firstSelection_in_node747); + firstSelection71 = firstSelection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, firstSelection71.getTree()); + + } + break; + case 7: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:131:7: + // lastSelection + { + pushFollow(FOLLOW_lastSelection_in_node756); + lastSelection72 = lastSelection(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, lastSelection72.getTree()); + + } + break; + case 8: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:132:7: + // exprList + { + pushFollow(FOLLOW_exprList_in_node765); + exprList73 = exprList(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, exprList73.getTree()); + + } + break; + case 9: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:133:7: + // DOT + { + DOT74 = (Token) input.LT(1); + match(input, DOT, FOLLOW_DOT_in_node773); + if (failed) + return retval; + if (backtracking == 0) { + DOT74_tree = (Object) adaptor.create(DOT74); + adaptor.addChild(root_0, DOT74_tree); + } + + } + break; + + default: + if (cnt16 >= 1) + break loop16; + if (backtracking > 0) { + failed = true; + return retval; + } + EarlyExitException eee = new EarlyExitException(16, input); + throw eee; + } + cnt16++; + } while (true); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end node + + public static class functionOrVar_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start functionOrVar + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:137:1: + // functionOrVar : ( ( POUND ID LPAREN )=> function | var ); + public final functionOrVar_return functionOrVar() throws RecognitionException { + functionOrVar_return retval = new functionOrVar_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + function_return function75 = null; + + var_return var76 = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:138:5: + // ( ( POUND ID LPAREN )=> function | var ) + int alt17 = 2; + int LA17_0 = input.LA(1); + + if ((LA17_0 == POUND)) { + int LA17_1 = input.LA(2); + + if ((LA17_1 == ID)) { + int LA17_2 = input.LA(3); + + if ((synpred2())) { + alt17 = 1; + } else if ((true)) { + alt17 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "137:1: functionOrVar : ( ( POUND ID LPAREN )=> function | var );", 17, 2, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "137:1: functionOrVar : ( ( POUND ID LPAREN )=> function | var );", 17, 1, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "137:1: functionOrVar : ( ( POUND ID LPAREN )=> function | var );", 17, 0, input); + + throw nvae; + } + switch (alt17) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:138:7: + // ( POUND ID LPAREN )=> function + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_function_in_functionOrVar806); + function75 = function(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, function75.getTree()); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:139:7: + // var + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_var_in_functionOrVar814); + var76 = var(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, var76.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end functionOrVar + + public static class function_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start function + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:142:1: + // function : POUND id= ID methodArgs -> ^( FUNCTIONREF[$id] methodArgs ) ; + public final function_return function() throws RecognitionException { + function_return retval = new function_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + Token POUND77 = null; + methodArgs_return methodArgs78 = null; + + Object id_tree = null; + Object POUND77_tree = null; + RewriteRuleTokenStream stream_POUND = new RewriteRuleTokenStream(adaptor, "token POUND"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + RewriteRuleSubtreeStream stream_methodArgs = new RewriteRuleSubtreeStream(adaptor, "rule methodArgs"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:142:10: + // ( POUND id= ID methodArgs -> ^( FUNCTIONREF[$id] methodArgs ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:142:12: + // POUND id= ID methodArgs + { + POUND77 = (Token) input.LT(1); + match(input, POUND, FOLLOW_POUND_in_function831); + if (failed) + return retval; + if (backtracking == 0) + stream_POUND.add(POUND77); + + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_function835); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + pushFollow(FOLLOW_methodArgs_in_function837); + methodArgs78 = methodArgs(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_methodArgs.add(methodArgs78.getTree()); + + // AST REWRITE + // elements: methodArgs + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 142:35: -> ^( FUNCTIONREF[$id] methodArgs ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:142:38: + // ^( FUNCTIONREF[$id] methodArgs ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(FUNCTIONREF, id), root_1); + + adaptor.addChild(root_1, stream_methodArgs.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end function + + public static class var_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start var + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:144:1: + // var : POUND id= ID -> ^( VARIABLEREF[$id] ) ; + public final var_return var() throws RecognitionException { + var_return retval = new var_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + Token POUND79 = null; + + Object id_tree = null; + Object POUND79_tree = null; + RewriteRuleTokenStream stream_POUND = new RewriteRuleTokenStream(adaptor, "token POUND"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:144:5: + // ( POUND id= ID -> ^( VARIABLEREF[$id] ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:144:7: + // POUND id= ID + { + POUND79 = (Token) input.LT(1); + match(input, POUND, FOLLOW_POUND_in_var858); + if (failed) + return retval; + if (backtracking == 0) + stream_POUND.add(POUND79); + + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_var862); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + // AST REWRITE + // elements: + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 144:19: -> ^( VARIABLEREF[$id] ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:144:22: + // ^( VARIABLEREF[$id] ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(VARIABLEREF, id), root_1); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end var + + public static class localFunctionOrVar_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start localFunctionOrVar + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:146:1: + // localFunctionOrVar : ( ( DOLLAR ID LPAREN )=> localFunction | localVar ); + public final localFunctionOrVar_return localFunctionOrVar() throws RecognitionException { + localFunctionOrVar_return retval = new localFunctionOrVar_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + localFunction_return localFunction80 = null; + + localVar_return localVar81 = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:147:2: + // ( ( DOLLAR ID LPAREN )=> localFunction | localVar ) + int alt18 = 2; + int LA18_0 = input.LA(1); + + if ((LA18_0 == DOLLAR)) { + int LA18_1 = input.LA(2); + + if ((LA18_1 == ID)) { + int LA18_2 = input.LA(3); + + if ((synpred3())) { + alt18 = 1; + } else if ((true)) { + alt18 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "146:1: localFunctionOrVar : ( ( DOLLAR ID LPAREN )=> localFunction | localVar );", 18, + 2, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "146:1: localFunctionOrVar : ( ( DOLLAR ID LPAREN )=> localFunction | localVar );", 18, 1, + input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "146:1: localFunctionOrVar : ( ( DOLLAR ID LPAREN )=> localFunction | localVar );", 18, 0, + input); + + throw nvae; + } + switch (alt18) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:147:4: + // ( DOLLAR ID LPAREN )=> localFunction + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_localFunction_in_localFunctionOrVar889); + localFunction80 = localFunction(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, localFunction80.getTree()); + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:148:4: + // localVar + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_localVar_in_localFunctionOrVar894); + localVar81 = localVar(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, localVar81.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end localFunctionOrVar + + public static class localFunction_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start localFunction + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:151:1: + // localFunction : DOLLAR id= ID methodArgs -> ^( LOCALFUNC[$id] methodArgs ) ; + public final localFunction_return localFunction() throws RecognitionException { + localFunction_return retval = new localFunction_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + Token DOLLAR82 = null; + methodArgs_return methodArgs83 = null; + + Object id_tree = null; + Object DOLLAR82_tree = null; + RewriteRuleTokenStream stream_DOLLAR = new RewriteRuleTokenStream(adaptor, "token DOLLAR"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + RewriteRuleSubtreeStream stream_methodArgs = new RewriteRuleSubtreeStream(adaptor, "rule methodArgs"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:151:15: + // ( DOLLAR id= ID methodArgs -> ^( LOCALFUNC[$id] methodArgs ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:151:17: + // DOLLAR id= ID methodArgs + { + DOLLAR82 = (Token) input.LT(1); + match(input, DOLLAR, FOLLOW_DOLLAR_in_localFunction904); + if (failed) + return retval; + if (backtracking == 0) + stream_DOLLAR.add(DOLLAR82); + + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_localFunction908); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + pushFollow(FOLLOW_methodArgs_in_localFunction910); + methodArgs83 = methodArgs(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_methodArgs.add(methodArgs83.getTree()); + + // AST REWRITE + // elements: methodArgs + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 151:41: -> ^( LOCALFUNC[$id] methodArgs ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:151:44: + // ^( LOCALFUNC[$id] methodArgs ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(LOCALFUNC, id), root_1); + + adaptor.addChild(root_1, stream_methodArgs.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end localFunction + + public static class localVar_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start localVar + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:152:1: + // localVar : DOLLAR id= ID -> ^( LOCALVAR[$id] ) ; + public final localVar_return localVar() throws RecognitionException { + localVar_return retval = new localVar_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + Token DOLLAR84 = null; + + Object id_tree = null; + Object DOLLAR84_tree = null; + RewriteRuleTokenStream stream_DOLLAR = new RewriteRuleTokenStream(adaptor, "token DOLLAR"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:152:9: + // ( DOLLAR id= ID -> ^( LOCALVAR[$id] ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:152:11: + // DOLLAR id= ID + { + DOLLAR84 = (Token) input.LT(1); + match(input, DOLLAR, FOLLOW_DOLLAR_in_localVar925); + if (failed) + return retval; + if (backtracking == 0) + stream_DOLLAR.add(DOLLAR84); + + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_localVar929); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + // AST REWRITE + // elements: + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 152:24: -> ^( LOCALVAR[$id] ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:152:27: + // ^( LOCALVAR[$id] ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(LOCALVAR, id), root_1); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end localVar + + public static class methodOrProperty_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start methodOrProperty + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:154:1: + // methodOrProperty : ( ( ID LPAREN )=>id= ID methodArgs -> ^( METHOD[$id] methodArgs ) | property ); + public final methodOrProperty_return methodOrProperty() throws RecognitionException { + methodOrProperty_return retval = new methodOrProperty_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + methodArgs_return methodArgs85 = null; + + property_return property86 = null; + + Object id_tree = null; + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + RewriteRuleSubtreeStream stream_methodArgs = new RewriteRuleSubtreeStream(adaptor, "rule methodArgs"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:155:2: + // ( ( ID LPAREN )=>id= ID methodArgs -> ^( METHOD[$id] methodArgs ) | property ) + int alt19 = 2; + int LA19_0 = input.LA(1); + + if ((LA19_0 == ID)) { + int LA19_1 = input.LA(2); + + if ((LA19_1 == LPAREN)) { + int LA19_2 = input.LA(3); + + if ((synpred4())) { + alt19 = 1; + } else if ((true)) { + alt19 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "154:1: methodOrProperty : ( ( ID LPAREN )=>id= ID methodArgs -> ^( METHOD[$id] methodArgs ) | property );", + 19, 2, input); + + throw nvae; + } + } else if ((LA19_1 == EOF || (LA19_1 >= SEMI && LA19_1 <= POWER) || (LA19_1 >= DOT && LA19_1 <= ID) + || LA19_1 == COMMA || (LA19_1 >= LBRACKET && LA19_1 <= SELECT_LAST) || (LA19_1 >= EQUAL && LA19_1 <= DISTANCETO))) { + alt19 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "154:1: methodOrProperty : ( ( ID LPAREN )=>id= ID methodArgs -> ^( METHOD[$id] methodArgs ) | property );", + 19, 1, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "154:1: methodOrProperty : ( ( ID LPAREN )=>id= ID methodArgs -> ^( METHOD[$id] methodArgs ) | property );", + 19, 0, input); + + throw nvae; + } + switch (alt19) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:155:4: + // ( ID LPAREN )=>id= ID methodArgs + { + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_methodOrProperty955); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + pushFollow(FOLLOW_methodArgs_in_methodOrProperty957); + methodArgs85 = methodArgs(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_methodArgs.add(methodArgs85.getTree()); + + // AST REWRITE + // elements: methodArgs + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 155:36: -> ^( METHOD[$id] methodArgs ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:155:39: + // ^( METHOD[$id] methodArgs ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(METHOD, id), root_1); + + adaptor.addChild(root_1, stream_methodArgs.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:156:4: + // property + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_property_in_methodOrProperty971); + property86 = property(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, property86.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end methodOrProperty + + public static class methodArgs_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start methodArgs + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:1: + // methodArgs : LPAREN ( argument ( COMMA argument )* ( COMMA )? )? RPAREN ; + public final methodArgs_return methodArgs() throws RecognitionException { + methodArgs_return retval = new methodArgs_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LPAREN87 = null; + Token COMMA89 = null; + Token COMMA91 = null; + Token RPAREN92 = null; + argument_return argument88 = null; + + argument_return argument90 = null; + + Object LPAREN87_tree = null; + Object COMMA89_tree = null; + Object COMMA91_tree = null; + Object RPAREN92_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:12: + // ( LPAREN ( argument ( COMMA argument )* ( COMMA )? )? RPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:15: + // LPAREN ( argument ( COMMA argument )* ( COMMA )? )? RPAREN + { + root_0 = (Object) adaptor.nil(); + + LPAREN87 = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_methodArgs986); + if (failed) + return retval; + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:23: + // ( argument ( COMMA argument )* ( COMMA )? )? + int alt22 = 2; + int LA22_0 = input.LA(1); + + if ((LA22_0 == INTEGER_LITERAL || LA22_0 == LPAREN || (LA22_0 >= PLUS && LA22_0 <= MINUS) + || LA22_0 == BANG || (LA22_0 >= POUND && LA22_0 <= DOLLAR) + || (LA22_0 >= AT && LA22_0 <= LBRACKET) || LA22_0 == PROJECT + || (LA22_0 >= SELECT && LA22_0 <= LAMBDA) || (LA22_0 >= LCURLY && LA22_0 <= FALSE) || (LA22_0 >= 94 && LA22_0 <= 95))) { + alt22 = 1; + } + switch (alt22) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:24: + // argument ( COMMA argument )* ( COMMA )? + { + pushFollow(FOLLOW_argument_in_methodArgs990); + argument88 = argument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, argument88.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:33: + // ( COMMA argument )* + loop20: do { + int alt20 = 2; + int LA20_0 = input.LA(1); + + if ((LA20_0 == COMMA)) { + int LA20_1 = input.LA(2); + + if ((LA20_1 == INTEGER_LITERAL || LA20_1 == LPAREN || (LA20_1 >= PLUS && LA20_1 <= MINUS) + || LA20_1 == BANG || (LA20_1 >= POUND && LA20_1 <= DOLLAR) + || (LA20_1 >= AT && LA20_1 <= LBRACKET) || LA20_1 == PROJECT + || (LA20_1 >= SELECT && LA20_1 <= LAMBDA) || (LA20_1 >= LCURLY && LA20_1 <= FALSE) || (LA20_1 >= 94 && LA20_1 <= 95))) { + alt20 = 1; + } + + } + + switch (alt20) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:34: + // COMMA argument + { + COMMA89 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_methodArgs993); + if (failed) + return retval; + pushFollow(FOLLOW_argument_in_methodArgs996); + argument90 = argument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, argument90.getTree()); + + } + break; + + default: + break loop20; + } + } while (true); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:52: + // ( COMMA )? + int alt21 = 2; + int LA21_0 = input.LA(1); + + if ((LA21_0 == COMMA)) { + alt21 = 1; + } + switch (alt21) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:162:53: + // COMMA + { + COMMA91 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_methodArgs1001); + if (failed) + return retval; + + } + break; + + } + + } + break; + + } + + RPAREN92 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_methodArgs1008); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end methodArgs + + public static class property_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start property + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:167:1: + // property : id= ID -> ^( PROPERTY_OR_FIELD[$id] ) ; + public final property_return property() throws RecognitionException { + property_return retval = new property_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + + Object id_tree = null; + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:167:9: + // (id= ID -> ^( PROPERTY_OR_FIELD[$id] ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:167:11: + // id= ID + { + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_property1021); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + // AST REWRITE + // elements: + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 167:17: -> ^( PROPERTY_OR_FIELD[$id] ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:167:20: + // ^( PROPERTY_OR_FIELD[$id] ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(PROPERTY_OR_FIELD, id), root_1); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end property + + public static class reference_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start reference + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:174:1: + // reference : AT pos= LPAREN (cn= contextName COLON )? (q= qualifiedId )? RPAREN -> ^( REFERENCE[$pos] ( $cn COLON + // )? ( $q)? RPAREN ) ; + public final reference_return reference() throws RecognitionException { + reference_return retval = new reference_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token pos = null; + Token AT93 = null; + Token COLON94 = null; + Token RPAREN95 = null; + contextName_return cn = null; + + qualifiedId_return q = null; + + Object pos_tree = null; + Object AT93_tree = null; + Object COLON94_tree = null; + Object RPAREN95_tree = null; + RewriteRuleTokenStream stream_RPAREN = new RewriteRuleTokenStream(adaptor, "token RPAREN"); + RewriteRuleTokenStream stream_COLON = new RewriteRuleTokenStream(adaptor, "token COLON"); + RewriteRuleTokenStream stream_LPAREN = new RewriteRuleTokenStream(adaptor, "token LPAREN"); + RewriteRuleTokenStream stream_AT = new RewriteRuleTokenStream(adaptor, "token AT"); + RewriteRuleSubtreeStream stream_contextName = new RewriteRuleSubtreeStream(adaptor, "rule contextName"); + RewriteRuleSubtreeStream stream_qualifiedId = new RewriteRuleSubtreeStream(adaptor, "rule qualifiedId"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:2: + // ( AT pos= LPAREN (cn= contextName COLON )? (q= qualifiedId )? RPAREN -> ^( REFERENCE[$pos] ( $cn COLON )? + // ( $q)? RPAREN ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:5: + // AT pos= LPAREN (cn= contextName COLON )? (q= qualifiedId )? RPAREN + { + AT93 = (Token) input.LT(1); + match(input, AT, FOLLOW_AT_in_reference1043); + if (failed) + return retval; + if (backtracking == 0) + stream_AT.add(AT93); + + pos = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_reference1047); + if (failed) + return retval; + if (backtracking == 0) + stream_LPAREN.add(pos); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:19: + // (cn= contextName COLON )? + int alt23 = 2; + int LA23_0 = input.LA(1); + + if ((LA23_0 == ID)) { + int LA23_1 = input.LA(2); + + if ((LA23_1 == COLON || LA23_1 == DIV)) { + alt23 = 1; + } + } + switch (alt23) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:20: + // cn= contextName COLON + { + pushFollow(FOLLOW_contextName_in_reference1052); + cn = contextName(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_contextName.add(cn.getTree()); + COLON94 = (Token) input.LT(1); + match(input, COLON, FOLLOW_COLON_in_reference1054); + if (failed) + return retval; + if (backtracking == 0) + stream_COLON.add(COLON94); + + } + break; + + } + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:43: + // (q= qualifiedId )? + int alt24 = 2; + int LA24_0 = input.LA(1); + + if ((LA24_0 == ID)) { + alt24 = 1; + } + switch (alt24) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:175:44: + // q= qualifiedId + { + pushFollow(FOLLOW_qualifiedId_in_reference1061); + q = qualifiedId(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_qualifiedId.add(q.getTree()); + + } + break; + + } + + RPAREN95 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_reference1065); + if (failed) + return retval; + if (backtracking == 0) + stream_RPAREN.add(RPAREN95); + + // AST REWRITE + // elements: COLON, cn, q, RPAREN + // token labels: + // rule labels: cn, retval, q + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_cn = new RewriteRuleSubtreeStream(adaptor, "token cn", + cn != null ? cn.tree : null); + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + RewriteRuleSubtreeStream stream_q = new RewriteRuleSubtreeStream(adaptor, "token q", + q != null ? q.tree : null); + + root_0 = (Object) adaptor.nil(); + // 176:4: -> ^( REFERENCE[$pos] ( $cn COLON )? ( $q)? RPAREN ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:176:7: + // ^( REFERENCE[$pos] ( $cn COLON )? ( $q)? RPAREN ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(REFERENCE, pos), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:176:25: + // ( $cn COLON )? + if (stream_COLON.hasNext() || stream_cn.hasNext()) { + adaptor.addChild(root_1, stream_cn.next()); + adaptor.addChild(root_1, stream_COLON.next()); + + } + stream_COLON.reset(); + stream_cn.reset(); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:176:38: + // ( $q)? + if (stream_q.hasNext()) { + adaptor.addChild(root_1, stream_q.next()); + + } + stream_q.reset(); + adaptor.addChild(root_1, stream_RPAREN.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end reference + + public static class indexer_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start indexer + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:1: + // indexer : LBRACKET r1= argument ( COMMA r2= argument )* RBRACKET -> ^( INDEXER $r1 ( $r2)* ) ; + public final indexer_return indexer() throws RecognitionException { + indexer_return retval = new indexer_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LBRACKET96 = null; + Token COMMA97 = null; + Token RBRACKET98 = null; + argument_return r1 = null; + + argument_return r2 = null; + + Object LBRACKET96_tree = null; + Object COMMA97_tree = null; + Object RBRACKET98_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_LBRACKET = new RewriteRuleTokenStream(adaptor, "token LBRACKET"); + RewriteRuleTokenStream stream_RBRACKET = new RewriteRuleTokenStream(adaptor, "token RBRACKET"); + RewriteRuleSubtreeStream stream_argument = new RewriteRuleSubtreeStream(adaptor, "rule argument"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:8: + // ( LBRACKET r1= argument ( COMMA r2= argument )* RBRACKET -> ^( INDEXER $r1 ( $r2)* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:10: + // LBRACKET r1= argument ( COMMA r2= argument )* RBRACKET + { + LBRACKET96 = (Token) input.LT(1); + match(input, LBRACKET, FOLLOW_LBRACKET_in_indexer1100); + if (failed) + return retval; + if (backtracking == 0) + stream_LBRACKET.add(LBRACKET96); + + pushFollow(FOLLOW_argument_in_indexer1104); + r1 = argument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_argument.add(r1.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:31: + // ( COMMA r2= argument )* + loop25: do { + int alt25 = 2; + int LA25_0 = input.LA(1); + + if ((LA25_0 == COMMA)) { + alt25 = 1; + } + + switch (alt25) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:32: + // COMMA r2= argument + { + COMMA97 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_indexer1107); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA97); + + pushFollow(FOLLOW_argument_in_indexer1111); + r2 = argument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_argument.add(r2.getTree()); + + } + break; + + default: + break loop25; + } + } while (true); + + RBRACKET98 = (Token) input.LT(1); + match(input, RBRACKET, FOLLOW_RBRACKET_in_indexer1115); + if (failed) + return retval; + if (backtracking == 0) + stream_RBRACKET.add(RBRACKET98); + + // AST REWRITE + // elements: r2, r1 + // token labels: + // rule labels: r2, retval, r1 + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_r2 = new RewriteRuleSubtreeStream(adaptor, "token r2", + r2 != null ? r2.tree : null); + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + RewriteRuleSubtreeStream stream_r1 = new RewriteRuleSubtreeStream(adaptor, "token r1", + r1 != null ? r1.tree : null); + + root_0 = (Object) adaptor.nil(); + // 182:61: -> ^( INDEXER $r1 ( $r2)* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:64: + // ^( INDEXER $r1 ( $r2)* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(INDEXER, "INDEXER"), root_1); + + adaptor.addChild(root_1, stream_r1.next()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:182:78: + // ( $r2)* + while (stream_r2.hasNext()) { + adaptor.addChild(root_1, stream_r2.next()); + + } + stream_r2.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end indexer + + public static class projection_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start projection + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:187:1: + // projection : PROJECT expression RCURLY ; + public final projection_return projection() throws RecognitionException { + projection_return retval = new projection_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token PROJECT99 = null; + Token RCURLY101 = null; + expression_return expression100 = null; + + Object PROJECT99_tree = null; + Object RCURLY101_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:187:11: + // ( PROJECT expression RCURLY ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:187:13: + // PROJECT expression RCURLY + { + root_0 = (Object) adaptor.nil(); + + PROJECT99 = (Token) input.LT(1); + match(input, PROJECT, FOLLOW_PROJECT_in_projection1142); + if (failed) + return retval; + if (backtracking == 0) { + PROJECT99_tree = (Object) adaptor.create(PROJECT99); + root_0 = (Object) adaptor.becomeRoot(PROJECT99_tree, root_0); + } + pushFollow(FOLLOW_expression_in_projection1145); + expression100 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression100.getTree()); + RCURLY101 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_projection1147); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end projection + + public static class selection_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start selection + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:189:1: + // selection : SELECT expression RCURLY ; + public final selection_return selection() throws RecognitionException { + selection_return retval = new selection_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token SELECT102 = null; + Token RCURLY104 = null; + expression_return expression103 = null; + + Object SELECT102_tree = null; + Object RCURLY104_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:189:10: + // ( SELECT expression RCURLY ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:189:12: + // SELECT expression RCURLY + { + root_0 = (Object) adaptor.nil(); + + SELECT102 = (Token) input.LT(1); + match(input, SELECT, FOLLOW_SELECT_in_selection1155); + if (failed) + return retval; + if (backtracking == 0) { + SELECT102_tree = (Object) adaptor.create(SELECT102); + root_0 = (Object) adaptor.becomeRoot(SELECT102_tree, root_0); + } + pushFollow(FOLLOW_expression_in_selection1158); + expression103 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression103.getTree()); + RCURLY104 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_selection1160); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end selection + + public static class firstSelection_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start firstSelection + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:191:1: + // firstSelection : SELECT_FIRST expression RCURLY ; + public final firstSelection_return firstSelection() throws RecognitionException { + firstSelection_return retval = new firstSelection_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token SELECT_FIRST105 = null; + Token RCURLY107 = null; + expression_return expression106 = null; + + Object SELECT_FIRST105_tree = null; + Object RCURLY107_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:191:15: + // ( SELECT_FIRST expression RCURLY ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:191:17: + // SELECT_FIRST expression RCURLY + { + root_0 = (Object) adaptor.nil(); + + SELECT_FIRST105 = (Token) input.LT(1); + match(input, SELECT_FIRST, FOLLOW_SELECT_FIRST_in_firstSelection1168); + if (failed) + return retval; + if (backtracking == 0) { + SELECT_FIRST105_tree = (Object) adaptor.create(SELECT_FIRST105); + root_0 = (Object) adaptor.becomeRoot(SELECT_FIRST105_tree, root_0); + } + pushFollow(FOLLOW_expression_in_firstSelection1171); + expression106 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression106.getTree()); + RCURLY107 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_firstSelection1173); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end firstSelection + + public static class lastSelection_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start lastSelection + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:193:1: + // lastSelection : SELECT_LAST expression RCURLY ; + public final lastSelection_return lastSelection() throws RecognitionException { + lastSelection_return retval = new lastSelection_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token SELECT_LAST108 = null; + Token RCURLY110 = null; + expression_return expression109 = null; + + Object SELECT_LAST108_tree = null; + Object RCURLY110_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:193:14: + // ( SELECT_LAST expression RCURLY ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:193:16: + // SELECT_LAST expression RCURLY + { + root_0 = (Object) adaptor.nil(); + + SELECT_LAST108 = (Token) input.LT(1); + match(input, SELECT_LAST, FOLLOW_SELECT_LAST_in_lastSelection1181); + if (failed) + return retval; + if (backtracking == 0) { + SELECT_LAST108_tree = (Object) adaptor.create(SELECT_LAST108); + root_0 = (Object) adaptor.becomeRoot(SELECT_LAST108_tree, root_0); + } + pushFollow(FOLLOW_expression_in_lastSelection1184); + expression109 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression109.getTree()); + RCURLY110 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_lastSelection1186); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end lastSelection + + public static class type_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start type + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:196:1: + // type : TYPE qualifiedId RPAREN -> ^( TYPEREF qualifiedId ) ; + public final type_return type() throws RecognitionException { + type_return retval = new type_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token TYPE111 = null; + Token RPAREN113 = null; + qualifiedId_return qualifiedId112 = null; + + Object TYPE111_tree = null; + Object RPAREN113_tree = null; + RewriteRuleTokenStream stream_RPAREN = new RewriteRuleTokenStream(adaptor, "token RPAREN"); + RewriteRuleTokenStream stream_TYPE = new RewriteRuleTokenStream(adaptor, "token TYPE"); + RewriteRuleSubtreeStream stream_qualifiedId = new RewriteRuleSubtreeStream(adaptor, "rule qualifiedId"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:196:5: + // ( TYPE qualifiedId RPAREN -> ^( TYPEREF qualifiedId ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:196:7: + // TYPE qualifiedId RPAREN + { + TYPE111 = (Token) input.LT(1); + match(input, TYPE, FOLLOW_TYPE_in_type1195); + if (failed) + return retval; + if (backtracking == 0) + stream_TYPE.add(TYPE111); + + pushFollow(FOLLOW_qualifiedId_in_type1197); + qualifiedId112 = qualifiedId(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_qualifiedId.add(qualifiedId112.getTree()); + RPAREN113 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_type1199); + if (failed) + return retval; + if (backtracking == 0) + stream_RPAREN.add(RPAREN113); + + // AST REWRITE + // elements: qualifiedId + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 196:31: -> ^( TYPEREF qualifiedId ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:196:34: + // ^( TYPEREF qualifiedId ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(TYPEREF, "TYPEREF"), root_1); + + adaptor.addChild(root_1, stream_qualifiedId.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end type + + public static class lambda_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start lambda + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:204:1: + // lambda : LAMBDA ( argList )? PIPE expression RCURLY -> ^( LAMBDA ( argList )? expression ) ; + public final lambda_return lambda() throws RecognitionException { + lambda_return retval = new lambda_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LAMBDA114 = null; + Token PIPE116 = null; + Token RCURLY118 = null; + argList_return argList115 = null; + + expression_return expression117 = null; + + Object LAMBDA114_tree = null; + Object PIPE116_tree = null; + Object RCURLY118_tree = null; + RewriteRuleTokenStream stream_RCURLY = new RewriteRuleTokenStream(adaptor, "token RCURLY"); + RewriteRuleTokenStream stream_PIPE = new RewriteRuleTokenStream(adaptor, "token PIPE"); + RewriteRuleTokenStream stream_LAMBDA = new RewriteRuleTokenStream(adaptor, "token LAMBDA"); + RewriteRuleSubtreeStream stream_argList = new RewriteRuleSubtreeStream(adaptor, "rule argList"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:4: + // ( LAMBDA ( argList )? PIPE expression RCURLY -> ^( LAMBDA ( argList )? expression ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:8: + // LAMBDA ( argList )? PIPE expression RCURLY + { + LAMBDA114 = (Token) input.LT(1); + match(input, LAMBDA, FOLLOW_LAMBDA_in_lambda1226); + if (failed) + return retval; + if (backtracking == 0) + stream_LAMBDA.add(LAMBDA114); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:15: + // ( argList )? + int alt26 = 2; + int LA26_0 = input.LA(1); + + if ((LA26_0 == ID)) { + alt26 = 1; + } + switch (alt26) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:16: + // argList + { + pushFollow(FOLLOW_argList_in_lambda1229); + argList115 = argList(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_argList.add(argList115.getTree()); + + } + break; + + } + + PIPE116 = (Token) input.LT(1); + match(input, PIPE, FOLLOW_PIPE_in_lambda1233); + if (failed) + return retval; + if (backtracking == 0) + stream_PIPE.add(PIPE116); + + pushFollow(FOLLOW_expression_in_lambda1235); + expression117 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression117.getTree()); + RCURLY118 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_lambda1237); + if (failed) + return retval; + if (backtracking == 0) + stream_RCURLY.add(RCURLY118); + + // AST REWRITE + // elements: argList, expression, LAMBDA + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 205:49: -> ^( LAMBDA ( argList )? expression ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:52: + // ^( LAMBDA ( argList )? expression ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(stream_LAMBDA.next(), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:205:61: + // ( argList )? + if (stream_argList.hasNext()) { + adaptor.addChild(root_1, stream_argList.next()); + + } + stream_argList.reset(); + adaptor.addChild(root_1, stream_expression.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end lambda + + public static class argList_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start argList + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:1: + // argList : (id+= ID ( COMMA id+= ID )* ) -> ^( ARGLIST ( $id)* ) ; + public final argList_return argList() throws RecognitionException { + argList_return retval = new argList_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token COMMA119 = null; + Token id = null; + List list_id = null; + + Object COMMA119_tree = null; + Object id_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:9: + // ( (id+= ID ( COMMA id+= ID )* ) -> ^( ARGLIST ( $id)* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:11: + // (id+= ID ( COMMA id+= ID )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:11: + // (id+= ID ( COMMA id+= ID )* ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:12: + // id+= ID ( COMMA id+= ID )* + { + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_argList1261); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + if (list_id == null) + list_id = new ArrayList(); + list_id.add(id); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:19: + // ( COMMA id+= ID )* + loop27: do { + int alt27 = 2; + int LA27_0 = input.LA(1); + + if ((LA27_0 == COMMA)) { + alt27 = 1; + } + + switch (alt27) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:20: + // COMMA id+= ID + { + COMMA119 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_argList1264); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA119); + + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_argList1268); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + if (list_id == null) + list_id = new ArrayList(); + list_id.add(id); + + } + break; + + default: + break loop27; + } + } while (true); + + } + + // AST REWRITE + // elements: id + // token labels: + // rule labels: retval + // token list labels: id + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleTokenStream stream_id = new RewriteRuleTokenStream(adaptor, "token id", list_id); + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 207:36: -> ^( ARGLIST ( $id)* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:39: + // ^( ARGLIST ( $id)* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(ARGLIST, "ARGLIST"), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:207:49: + // ( $id)* + while (stream_id.hasNext()) { + adaptor.addChild(root_1, stream_id.next()); + + } + stream_id.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end argList + + public static class constructor_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start constructor + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:209:1: + // constructor : ( ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs -> ^( CONSTRUCTOR qualifiedId ctorArgs + // ) | arrayConstructor ); + public final constructor_return constructor() throws RecognitionException { + constructor_return retval = new constructor_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token string_literal120 = null; + qualifiedId_return qualifiedId121 = null; + + ctorArgs_return ctorArgs122 = null; + + arrayConstructor_return arrayConstructor123 = null; + + Object string_literal120_tree = null; + RewriteRuleTokenStream stream_94 = new RewriteRuleTokenStream(adaptor, "token 94"); + RewriteRuleSubtreeStream stream_qualifiedId = new RewriteRuleSubtreeStream(adaptor, "rule qualifiedId"); + RewriteRuleSubtreeStream stream_ctorArgs = new RewriteRuleSubtreeStream(adaptor, "rule ctorArgs"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:210:2: + // ( ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs -> ^( CONSTRUCTOR qualifiedId ctorArgs ) | + // arrayConstructor ) + int alt28 = 2; + int LA28_0 = input.LA(1); + + if ((LA28_0 == 94)) { + int LA28_1 = input.LA(2); + + if ((LA28_1 == ID)) { + int LA28_2 = input.LA(3); + + if ((synpred5())) { + alt28 = 1; + } else if ((true)) { + alt28 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "209:1: constructor : ( ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs -> ^( CONSTRUCTOR qualifiedId ctorArgs ) | arrayConstructor );", + 28, 2, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "209:1: constructor : ( ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs -> ^( CONSTRUCTOR qualifiedId ctorArgs ) | arrayConstructor );", + 28, 1, input); + + throw nvae; + } + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "209:1: constructor : ( ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs -> ^( CONSTRUCTOR qualifiedId ctorArgs ) | arrayConstructor );", + 28, 0, input); + + throw nvae; + } + switch (alt28) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:210:4: + // ( 'new' qualifiedId LPAREN )=> 'new' qualifiedId ctorArgs + { + string_literal120 = (Token) input.LT(1); + match(input, 94, FOLLOW_94_in_constructor1304); + if (failed) + return retval; + if (backtracking == 0) + stream_94.add(string_literal120); + + pushFollow(FOLLOW_qualifiedId_in_constructor1306); + qualifiedId121 = qualifiedId(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_qualifiedId.add(qualifiedId121.getTree()); + pushFollow(FOLLOW_ctorArgs_in_constructor1308); + ctorArgs122 = ctorArgs(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_ctorArgs.add(ctorArgs122.getTree()); + + // AST REWRITE + // elements: qualifiedId, ctorArgs + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 210:61: -> ^( CONSTRUCTOR qualifiedId ctorArgs ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:210:64: + // ^( CONSTRUCTOR qualifiedId ctorArgs ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(CONSTRUCTOR, "CONSTRUCTOR"), root_1); + + adaptor.addChild(root_1, stream_qualifiedId.next()); + adaptor.addChild(root_1, stream_ctorArgs.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:211:6: + // arrayConstructor + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_arrayConstructor_in_constructor1325); + arrayConstructor123 = arrayConstructor(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, arrayConstructor123.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end constructor + + public static class arrayConstructor_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start arrayConstructor + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:214:1: + // arrayConstructor : 'new' qualifiedId arrayRank ( listInitializer )? -> ^( CONSTRUCTOR_ARRAY qualifiedId arrayRank + // ( listInitializer )? ) ; + public final arrayConstructor_return arrayConstructor() throws RecognitionException { + arrayConstructor_return retval = new arrayConstructor_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token string_literal124 = null; + qualifiedId_return qualifiedId125 = null; + + arrayRank_return arrayRank126 = null; + + listInitializer_return listInitializer127 = null; + + Object string_literal124_tree = null; + RewriteRuleTokenStream stream_94 = new RewriteRuleTokenStream(adaptor, "token 94"); + RewriteRuleSubtreeStream stream_listInitializer = new RewriteRuleSubtreeStream(adaptor, "rule listInitializer"); + RewriteRuleSubtreeStream stream_qualifiedId = new RewriteRuleSubtreeStream(adaptor, "rule qualifiedId"); + RewriteRuleSubtreeStream stream_arrayRank = new RewriteRuleSubtreeStream(adaptor, "rule arrayRank"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:215:2: + // ( 'new' qualifiedId arrayRank ( listInitializer )? -> ^( CONSTRUCTOR_ARRAY qualifiedId arrayRank ( + // listInitializer )? ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:215:4: + // 'new' qualifiedId arrayRank ( listInitializer )? + { + string_literal124 = (Token) input.LT(1); + match(input, 94, FOLLOW_94_in_arrayConstructor1336); + if (failed) + return retval; + if (backtracking == 0) + stream_94.add(string_literal124); + + pushFollow(FOLLOW_qualifiedId_in_arrayConstructor1338); + qualifiedId125 = qualifiedId(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_qualifiedId.add(qualifiedId125.getTree()); + pushFollow(FOLLOW_arrayRank_in_arrayConstructor1340); + arrayRank126 = arrayRank(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_arrayRank.add(arrayRank126.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:215:32: + // ( listInitializer )? + int alt29 = 2; + int LA29_0 = input.LA(1); + + if ((LA29_0 == LCURLY)) { + alt29 = 1; + } + switch (alt29) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:215:33: + // listInitializer + { + pushFollow(FOLLOW_listInitializer_in_arrayConstructor1343); + listInitializer127 = listInitializer(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_listInitializer.add(listInitializer127.getTree()); + + } + break; + + } + + // AST REWRITE + // elements: qualifiedId, arrayRank, listInitializer + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 216:4: -> ^( CONSTRUCTOR_ARRAY qualifiedId arrayRank ( listInitializer )? ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:216:7: + // ^( CONSTRUCTOR_ARRAY qualifiedId arrayRank ( listInitializer )? ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot( + adaptor.create(CONSTRUCTOR_ARRAY, "CONSTRUCTOR_ARRAY"), root_1); + + adaptor.addChild(root_1, stream_qualifiedId.next()); + adaptor.addChild(root_1, stream_arrayRank.next()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:216:49: + // ( listInitializer )? + if (stream_listInitializer.hasNext()) { + adaptor.addChild(root_1, stream_listInitializer.next()); + + } + stream_listInitializer.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end arrayConstructor + + public static class arrayRank_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start arrayRank + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:219:1: + // arrayRank : LBRACKET ( expression ( COMMA expression )* )? RBRACKET -> ^( EXPRESSIONLIST ( expression )* ) ; + public final arrayRank_return arrayRank() throws RecognitionException { + arrayRank_return retval = new arrayRank_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LBRACKET128 = null; + Token COMMA130 = null; + Token RBRACKET132 = null; + expression_return expression129 = null; + + expression_return expression131 = null; + + Object LBRACKET128_tree = null; + Object COMMA130_tree = null; + Object RBRACKET132_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_LBRACKET = new RewriteRuleTokenStream(adaptor, "token LBRACKET"); + RewriteRuleTokenStream stream_RBRACKET = new RewriteRuleTokenStream(adaptor, "token RBRACKET"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:5: + // ( LBRACKET ( expression ( COMMA expression )* )? RBRACKET -> ^( EXPRESSIONLIST ( expression )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:7: + // LBRACKET ( expression ( COMMA expression )* )? RBRACKET + { + LBRACKET128 = (Token) input.LT(1); + match(input, LBRACKET, FOLLOW_LBRACKET_in_arrayRank1378); + if (failed) + return retval; + if (backtracking == 0) + stream_LBRACKET.add(LBRACKET128); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:16: + // ( expression ( COMMA expression )* )? + int alt31 = 2; + int LA31_0 = input.LA(1); + + if ((LA31_0 == INTEGER_LITERAL || LA31_0 == LPAREN || (LA31_0 >= PLUS && LA31_0 <= MINUS) + || LA31_0 == BANG || (LA31_0 >= POUND && LA31_0 <= DOLLAR) + || (LA31_0 >= AT && LA31_0 <= LBRACKET) || LA31_0 == PROJECT + || (LA31_0 >= SELECT && LA31_0 <= LAMBDA) || (LA31_0 >= LCURLY && LA31_0 <= FALSE) || (LA31_0 >= 94 && LA31_0 <= 95))) { + alt31 = 1; + } + switch (alt31) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:17: + // expression ( COMMA expression )* + { + pushFollow(FOLLOW_expression_in_arrayRank1381); + expression129 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression129.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:28: + // ( COMMA expression )* + loop30: do { + int alt30 = 2; + int LA30_0 = input.LA(1); + + if ((LA30_0 == COMMA)) { + alt30 = 1; + } + + switch (alt30) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:29: + // COMMA expression + { + COMMA130 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_arrayRank1384); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA130); + + pushFollow(FOLLOW_expression_in_arrayRank1386); + expression131 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression131.getTree()); + + } + break; + + default: + break loop30; + } + } while (true); + + } + break; + + } + + RBRACKET132 = (Token) input.LT(1); + match(input, RBRACKET, FOLLOW_RBRACKET_in_arrayRank1392); + if (failed) + return retval; + if (backtracking == 0) + stream_RBRACKET.add(RBRACKET132); + + // AST REWRITE + // elements: expression + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 220:59: -> ^( EXPRESSIONLIST ( expression )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:62: + // ^( EXPRESSIONLIST ( expression )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(EXPRESSIONLIST, "EXPRESSIONLIST"), + root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:220:79: + // ( expression )* + while (stream_expression.hasNext()) { + adaptor.addChild(root_1, stream_expression.next()); + + } + stream_expression.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end arrayRank + + public static class listInitializer_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start listInitializer + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:222:1: + // listInitializer : LCURLY expression ( COMMA expression )* RCURLY -> ^( LIST_INITIALIZER ( expression )* ) ; + public final listInitializer_return listInitializer() throws RecognitionException { + listInitializer_return retval = new listInitializer_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LCURLY133 = null; + Token COMMA135 = null; + Token RCURLY137 = null; + expression_return expression134 = null; + + expression_return expression136 = null; + + Object LCURLY133_tree = null; + Object COMMA135_tree = null; + Object RCURLY137_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_RCURLY = new RewriteRuleTokenStream(adaptor, "token RCURLY"); + RewriteRuleTokenStream stream_LCURLY = new RewriteRuleTokenStream(adaptor, "token LCURLY"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:5: + // ( LCURLY expression ( COMMA expression )* RCURLY -> ^( LIST_INITIALIZER ( expression )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:7: + // LCURLY expression ( COMMA expression )* RCURLY + { + LCURLY133 = (Token) input.LT(1); + match(input, LCURLY, FOLLOW_LCURLY_in_listInitializer1417); + if (failed) + return retval; + if (backtracking == 0) + stream_LCURLY.add(LCURLY133); + + pushFollow(FOLLOW_expression_in_listInitializer1419); + expression134 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression134.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:25: + // ( COMMA expression )* + loop32: do { + int alt32 = 2; + int LA32_0 = input.LA(1); + + if ((LA32_0 == COMMA)) { + alt32 = 1; + } + + switch (alt32) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:26: + // COMMA expression + { + COMMA135 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_listInitializer1422); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA135); + + pushFollow(FOLLOW_expression_in_listInitializer1424); + expression136 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression136.getTree()); + + } + break; + + default: + break loop32; + } + } while (true); + + RCURLY137 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_listInitializer1428); + if (failed) + return retval; + if (backtracking == 0) + stream_RCURLY.add(RCURLY137); + + // AST REWRITE + // elements: expression + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 223:52: -> ^( LIST_INITIALIZER ( expression )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:55: + // ^( LIST_INITIALIZER ( expression )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(LIST_INITIALIZER, "LIST_INITIALIZER"), + root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:223:74: + // ( expression )* + while (stream_expression.hasNext()) { + adaptor.addChild(root_1, stream_expression.next()); + + } + stream_expression.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end listInitializer + + public static class mapInitializer_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start mapInitializer + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:228:1: + // mapInitializer : POUND LCURLY mapEntry ( COMMA mapEntry )* RCURLY -> ^( MAP_INITIALIZER ( mapEntry )* ) ; + public final mapInitializer_return mapInitializer() throws RecognitionException { + mapInitializer_return retval = new mapInitializer_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token POUND138 = null; + Token LCURLY139 = null; + Token COMMA141 = null; + Token RCURLY143 = null; + mapEntry_return mapEntry140 = null; + + mapEntry_return mapEntry142 = null; + + Object POUND138_tree = null; + Object LCURLY139_tree = null; + Object COMMA141_tree = null; + Object RCURLY143_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_RCURLY = new RewriteRuleTokenStream(adaptor, "token RCURLY"); + RewriteRuleTokenStream stream_LCURLY = new RewriteRuleTokenStream(adaptor, "token LCURLY"); + RewriteRuleTokenStream stream_POUND = new RewriteRuleTokenStream(adaptor, "token POUND"); + RewriteRuleSubtreeStream stream_mapEntry = new RewriteRuleSubtreeStream(adaptor, "rule mapEntry"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:5: + // ( POUND LCURLY mapEntry ( COMMA mapEntry )* RCURLY -> ^( MAP_INITIALIZER ( mapEntry )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:7: + // POUND LCURLY mapEntry ( COMMA mapEntry )* RCURLY + { + POUND138 = (Token) input.LT(1); + match(input, POUND, FOLLOW_POUND_in_mapInitializer1456); + if (failed) + return retval; + if (backtracking == 0) + stream_POUND.add(POUND138); + + LCURLY139 = (Token) input.LT(1); + match(input, LCURLY, FOLLOW_LCURLY_in_mapInitializer1458); + if (failed) + return retval; + if (backtracking == 0) + stream_LCURLY.add(LCURLY139); + + pushFollow(FOLLOW_mapEntry_in_mapInitializer1460); + mapEntry140 = mapEntry(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_mapEntry.add(mapEntry140.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:29: + // ( COMMA mapEntry )* + loop33: do { + int alt33 = 2; + int LA33_0 = input.LA(1); + + if ((LA33_0 == COMMA)) { + alt33 = 1; + } + + switch (alt33) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:30: + // COMMA mapEntry + { + COMMA141 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_mapInitializer1463); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA141); + + pushFollow(FOLLOW_mapEntry_in_mapInitializer1465); + mapEntry142 = mapEntry(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_mapEntry.add(mapEntry142.getTree()); + + } + break; + + default: + break loop33; + } + } while (true); + + RCURLY143 = (Token) input.LT(1); + match(input, RCURLY, FOLLOW_RCURLY_in_mapInitializer1469); + if (failed) + return retval; + if (backtracking == 0) + stream_RCURLY.add(RCURLY143); + + // AST REWRITE + // elements: mapEntry + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 229:54: -> ^( MAP_INITIALIZER ( mapEntry )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:57: + // ^( MAP_INITIALIZER ( mapEntry )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(MAP_INITIALIZER, "MAP_INITIALIZER"), + root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:229:75: + // ( mapEntry )* + while (stream_mapEntry.hasNext()) { + adaptor.addChild(root_1, stream_mapEntry.next()); + + } + stream_mapEntry.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end mapInitializer + + public static class mapEntry_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start mapEntry + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:231:1: + // mapEntry : expression COLON expression -> ^( MAP_ENTRY ( expression )* ) ; + public final mapEntry_return mapEntry() throws RecognitionException { + mapEntry_return retval = new mapEntry_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token COLON145 = null; + expression_return expression144 = null; + + expression_return expression146 = null; + + Object COLON145_tree = null; + RewriteRuleTokenStream stream_COLON = new RewriteRuleTokenStream(adaptor, "token COLON"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:232:5: + // ( expression COLON expression -> ^( MAP_ENTRY ( expression )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:232:7: + // expression COLON expression + { + pushFollow(FOLLOW_expression_in_mapEntry1490); + expression144 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression144.getTree()); + COLON145 = (Token) input.LT(1); + match(input, COLON, FOLLOW_COLON_in_mapEntry1492); + if (failed) + return retval; + if (backtracking == 0) + stream_COLON.add(COLON145); + + pushFollow(FOLLOW_expression_in_mapEntry1494); + expression146 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression146.getTree()); + + // AST REWRITE + // elements: expression + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 232:35: -> ^( MAP_ENTRY ( expression )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:232:38: + // ^( MAP_ENTRY ( expression )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(MAP_ENTRY, "MAP_ENTRY"), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:232:50: + // ( expression )* + while (stream_expression.hasNext()) { + adaptor.addChild(root_1, stream_expression.next()); + + } + stream_expression.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end mapEntry + + public static class ctorArgs_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start ctorArgs + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:234:1: + // ctorArgs : LPAREN ( namedArgument ( COMMA namedArgument )* )? RPAREN ; + public final ctorArgs_return ctorArgs() throws RecognitionException { + ctorArgs_return retval = new ctorArgs_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token LPAREN147 = null; + Token COMMA149 = null; + Token RPAREN151 = null; + namedArgument_return namedArgument148 = null; + + namedArgument_return namedArgument150 = null; + + Object LPAREN147_tree = null; + Object COMMA149_tree = null; + Object RPAREN151_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:2: + // ( LPAREN ( namedArgument ( COMMA namedArgument )* )? RPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:4: + // LPAREN ( namedArgument ( COMMA namedArgument )* )? RPAREN + { + root_0 = (Object) adaptor.nil(); + + LPAREN147 = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_ctorArgs1512); + if (failed) + return retval; + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:12: + // ( namedArgument ( COMMA namedArgument )* )? + int alt35 = 2; + int LA35_0 = input.LA(1); + + if ((LA35_0 == INTEGER_LITERAL || LA35_0 == LPAREN || (LA35_0 >= PLUS && LA35_0 <= MINUS) + || LA35_0 == BANG || (LA35_0 >= POUND && LA35_0 <= DOLLAR) + || (LA35_0 >= AT && LA35_0 <= LBRACKET) || LA35_0 == PROJECT + || (LA35_0 >= SELECT && LA35_0 <= LAMBDA) || (LA35_0 >= LCURLY && LA35_0 <= FALSE) || (LA35_0 >= 94 && LA35_0 <= 95))) { + alt35 = 1; + } + switch (alt35) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:13: + // namedArgument ( COMMA namedArgument )* + { + pushFollow(FOLLOW_namedArgument_in_ctorArgs1516); + namedArgument148 = namedArgument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, namedArgument148.getTree()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:27: + // ( COMMA namedArgument )* + loop34: do { + int alt34 = 2; + int LA34_0 = input.LA(1); + + if ((LA34_0 == COMMA)) { + alt34 = 1; + } + + switch (alt34) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:235:28: + // COMMA namedArgument + { + COMMA149 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_ctorArgs1519); + if (failed) + return retval; + pushFollow(FOLLOW_namedArgument_in_ctorArgs1522); + namedArgument150 = namedArgument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, namedArgument150.getTree()); + + } + break; + + default: + break loop34; + } + } while (true); + + } + break; + + } + + RPAREN151 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_ctorArgs1528); + if (failed) + return retval; + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end ctorArgs + + public static class argument_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start argument + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:237:1: + // argument : expression ; + public final argument_return argument() throws RecognitionException { + argument_return retval = new argument_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + expression_return expression152 = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:237:10: + // ( expression ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:237:12: + // expression + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_expression_in_argument1537); + expression152 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, expression152.getTree()); + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end argument + + public static class namedArgument_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start namedArgument + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:239:1: + // namedArgument : ( ( ID ASSIGN )=>id= ID ASSIGN expression -> ^( NAMED_ARGUMENT[$id] expression ) | argument ); + public final namedArgument_return namedArgument() throws RecognitionException { + namedArgument_return retval = new namedArgument_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token id = null; + Token ASSIGN153 = null; + expression_return expression154 = null; + + argument_return argument155 = null; + + Object id_tree = null; + Object ASSIGN153_tree = null; + RewriteRuleTokenStream stream_ASSIGN = new RewriteRuleTokenStream(adaptor, "token ASSIGN"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + RewriteRuleSubtreeStream stream_expression = new RewriteRuleSubtreeStream(adaptor, "rule expression"); + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:240:5: + // ( ( ID ASSIGN )=>id= ID ASSIGN expression -> ^( NAMED_ARGUMENT[$id] expression ) | argument ) + int alt36 = 2; + int LA36_0 = input.LA(1); + + if ((LA36_0 == ID)) { + int LA36_1 = input.LA(2); + + if ((LA36_1 == ASSIGN)) { + int LA36_26 = input.LA(3); + + if ((synpred6())) { + alt36 = 1; + } else if ((true)) { + alt36 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "239:1: namedArgument : ( ( ID ASSIGN )=>id= ID ASSIGN expression -> ^( NAMED_ARGUMENT[$id] expression ) | argument );", + 36, 26, input); + + throw nvae; + } + } else if ((LA36_1 == LPAREN || LA36_1 == RPAREN || (LA36_1 >= DEFAULT && LA36_1 <= QMARK) + || (LA36_1 >= OR && LA36_1 <= POWER) || (LA36_1 >= DOT && LA36_1 <= ID) || LA36_1 == COMMA + || LA36_1 == LBRACKET || LA36_1 == PROJECT || (LA36_1 >= SELECT && LA36_1 <= SELECT_LAST) || (LA36_1 >= EQUAL && LA36_1 <= DISTANCETO))) { + alt36 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "239:1: namedArgument : ( ( ID ASSIGN )=>id= ID ASSIGN expression -> ^( NAMED_ARGUMENT[$id] expression ) | argument );", + 36, 1, input); + + throw nvae; + } + } else if ((LA36_0 == INTEGER_LITERAL || LA36_0 == LPAREN || (LA36_0 >= PLUS && LA36_0 <= MINUS) + || LA36_0 == BANG || LA36_0 == POUND || LA36_0 == DOLLAR || (LA36_0 >= AT && LA36_0 <= LBRACKET) + || LA36_0 == PROJECT || (LA36_0 >= SELECT && LA36_0 <= LAMBDA) + || (LA36_0 >= LCURLY && LA36_0 <= FALSE) || (LA36_0 >= 94 && LA36_0 <= 95))) { + alt36 = 2; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "239:1: namedArgument : ( ( ID ASSIGN )=>id= ID ASSIGN expression -> ^( NAMED_ARGUMENT[$id] expression ) | argument );", + 36, 0, input); + + throw nvae; + } + switch (alt36) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:240:7: + // ( ID ASSIGN )=>id= ID ASSIGN expression + { + id = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_namedArgument1560); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(id); + + ASSIGN153 = (Token) input.LT(1); + match(input, ASSIGN, FOLLOW_ASSIGN_in_namedArgument1562); + if (failed) + return retval; + if (backtracking == 0) + stream_ASSIGN.add(ASSIGN153); + + pushFollow(FOLLOW_expression_in_namedArgument1564); + expression154 = expression(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + stream_expression.add(expression154.getTree()); + + // AST REWRITE + // elements: expression + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 241:19: -> ^( NAMED_ARGUMENT[$id] expression ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:241:22: + // ^( NAMED_ARGUMENT[$id] expression ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(NAMED_ARGUMENT, id), root_1); + + adaptor.addChild(root_1, stream_expression.next()); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:242:7: + // argument + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_argument_in_namedArgument1600); + argument155 = argument(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, argument155.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end namedArgument + + public static class qualifiedId_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start qualifiedId + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:1: + // qualifiedId : ID ( DOT ID )* -> ^( QUALIFIED_IDENTIFIER ( ID )* ) ; + public final qualifiedId_return qualifiedId() throws RecognitionException { + qualifiedId_return retval = new qualifiedId_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token ID156 = null; + Token DOT157 = null; + Token ID158 = null; + + Object ID156_tree = null; + Object DOT157_tree = null; + Object ID158_tree = null; + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + RewriteRuleTokenStream stream_DOT = new RewriteRuleTokenStream(adaptor, "token DOT"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:13: + // ( ID ( DOT ID )* -> ^( QUALIFIED_IDENTIFIER ( ID )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:15: + // ID ( DOT ID )* + { + ID156 = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_qualifiedId1612); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(ID156); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:18: + // ( DOT ID )* + loop37: do { + int alt37 = 2; + int LA37_0 = input.LA(1); + + if ((LA37_0 == DOT)) { + alt37 = 1; + } + + switch (alt37) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:19: + // DOT ID + { + DOT157 = (Token) input.LT(1); + match(input, DOT, FOLLOW_DOT_in_qualifiedId1615); + if (failed) + return retval; + if (backtracking == 0) + stream_DOT.add(DOT157); + + ID158 = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_qualifiedId1617); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(ID158); + + } + break; + + default: + break loop37; + } + } while (true); + + // AST REWRITE + // elements: ID + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 244:28: -> ^( QUALIFIED_IDENTIFIER ( ID )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:31: + // ^( QUALIFIED_IDENTIFIER ( ID )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(QUALIFIED_IDENTIFIER, + "QUALIFIED_IDENTIFIER"), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:244:54: + // ( ID )* + while (stream_ID.hasNext()) { + adaptor.addChild(root_1, stream_ID.next()); + + } + stream_ID.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end qualifiedId + + public static class contextName_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start contextName + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:1: + // contextName : ID ( DIV ID )* -> ^( QUALIFIED_IDENTIFIER ( ID )* ) ; + public final contextName_return contextName() throws RecognitionException { + contextName_return retval = new contextName_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token ID159 = null; + Token DIV160 = null; + Token ID161 = null; + + Object ID159_tree = null; + Object DIV160_tree = null; + Object ID161_tree = null; + RewriteRuleTokenStream stream_DIV = new RewriteRuleTokenStream(adaptor, "token DIV"); + RewriteRuleTokenStream stream_ID = new RewriteRuleTokenStream(adaptor, "token ID"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:13: + // ( ID ( DIV ID )* -> ^( QUALIFIED_IDENTIFIER ( ID )* ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:15: + // ID ( DIV ID )* + { + ID159 = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_contextName1636); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(ID159); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:18: + // ( DIV ID )* + loop38: do { + int alt38 = 2; + int LA38_0 = input.LA(1); + + if ((LA38_0 == DIV)) { + alt38 = 1; + } + + switch (alt38) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:19: + // DIV ID + { + DIV160 = (Token) input.LT(1); + match(input, DIV, FOLLOW_DIV_in_contextName1639); + if (failed) + return retval; + if (backtracking == 0) + stream_DIV.add(DIV160); + + ID161 = (Token) input.LT(1); + match(input, ID, FOLLOW_ID_in_contextName1641); + if (failed) + return retval; + if (backtracking == 0) + stream_ID.add(ID161); + + } + break; + + default: + break loop38; + } + } while (true); + + // AST REWRITE + // elements: ID + // token labels: + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 246:28: -> ^( QUALIFIED_IDENTIFIER ( ID )* ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:31: + // ^( QUALIFIED_IDENTIFIER ( ID )* ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(QUALIFIED_IDENTIFIER, + "QUALIFIED_IDENTIFIER"), root_1); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:246:54: + // ( ID )* + while (stream_ID.hasNext()) { + adaptor.addChild(root_1, stream_ID.next()); + + } + stream_ID.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end contextName + + public static class literal_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start literal + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:248:1: + // literal : ( INTEGER_LITERAL | STRING_LITERAL | DQ_STRING_LITERAL | boolLiteral | NULL_LITERAL | + // HEXADECIMAL_INTEGER_LITERAL | REAL_LITERAL | dateLiteral ); + public final literal_return literal() throws RecognitionException { + literal_return retval = new literal_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token INTEGER_LITERAL162 = null; + Token STRING_LITERAL163 = null; + Token DQ_STRING_LITERAL164 = null; + Token NULL_LITERAL166 = null; + Token HEXADECIMAL_INTEGER_LITERAL167 = null; + Token REAL_LITERAL168 = null; + boolLiteral_return boolLiteral165 = null; + + dateLiteral_return dateLiteral169 = null; + + Object INTEGER_LITERAL162_tree = null; + Object STRING_LITERAL163_tree = null; + Object DQ_STRING_LITERAL164_tree = null; + Object NULL_LITERAL166_tree = null; + Object HEXADECIMAL_INTEGER_LITERAL167_tree = null; + Object REAL_LITERAL168_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:249:2: + // ( INTEGER_LITERAL | STRING_LITERAL | DQ_STRING_LITERAL | boolLiteral | NULL_LITERAL | + // HEXADECIMAL_INTEGER_LITERAL | REAL_LITERAL | dateLiteral ) + int alt39 = 8; + switch (input.LA(1)) { + case INTEGER_LITERAL: { + alt39 = 1; + } + break; + case STRING_LITERAL: { + alt39 = 2; + } + break; + case DQ_STRING_LITERAL: { + alt39 = 3; + } + break; + case TRUE: + case FALSE: { + alt39 = 4; + } + break; + case NULL_LITERAL: { + alt39 = 5; + } + break; + case HEXADECIMAL_INTEGER_LITERAL: { + alt39 = 6; + } + break; + case REAL_LITERAL: { + alt39 = 7; + } + break; + case 95: { + alt39 = 8; + } + break; + default: + if (backtracking > 0) { + failed = true; + return retval; + } + NoViableAltException nvae = new NoViableAltException( + "248:1: literal : ( INTEGER_LITERAL | STRING_LITERAL | DQ_STRING_LITERAL | boolLiteral | NULL_LITERAL | HEXADECIMAL_INTEGER_LITERAL | REAL_LITERAL | dateLiteral );", + 39, 0, input); + + throw nvae; + } + + switch (alt39) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:249:4: + // INTEGER_LITERAL + { + root_0 = (Object) adaptor.nil(); + + INTEGER_LITERAL162 = (Token) input.LT(1); + match(input, INTEGER_LITERAL, FOLLOW_INTEGER_LITERAL_in_literal1662); + if (failed) + return retval; + if (backtracking == 0) { + INTEGER_LITERAL162_tree = (Object) adaptor.create(INTEGER_LITERAL162); + adaptor.addChild(root_0, INTEGER_LITERAL162_tree); + } + + } + break; + case 2: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:250:4: + // STRING_LITERAL + { + root_0 = (Object) adaptor.nil(); + + STRING_LITERAL163 = (Token) input.LT(1); + match(input, STRING_LITERAL, FOLLOW_STRING_LITERAL_in_literal1668); + if (failed) + return retval; + if (backtracking == 0) { + STRING_LITERAL163_tree = (Object) adaptor.create(STRING_LITERAL163); + adaptor.addChild(root_0, STRING_LITERAL163_tree); + } + + } + break; + case 3: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:251:4: + // DQ_STRING_LITERAL + { + root_0 = (Object) adaptor.nil(); + + DQ_STRING_LITERAL164 = (Token) input.LT(1); + match(input, DQ_STRING_LITERAL, FOLLOW_DQ_STRING_LITERAL_in_literal1673); + if (failed) + return retval; + if (backtracking == 0) { + DQ_STRING_LITERAL164_tree = (Object) adaptor.create(DQ_STRING_LITERAL164); + adaptor.addChild(root_0, DQ_STRING_LITERAL164_tree); + } + + } + break; + case 4: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:252:4: + // boolLiteral + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_boolLiteral_in_literal1678); + boolLiteral165 = boolLiteral(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, boolLiteral165.getTree()); + + } + break; + case 5: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:253:4: + // NULL_LITERAL + { + root_0 = (Object) adaptor.nil(); + + NULL_LITERAL166 = (Token) input.LT(1); + match(input, NULL_LITERAL, FOLLOW_NULL_LITERAL_in_literal1683); + if (failed) + return retval; + if (backtracking == 0) { + NULL_LITERAL166_tree = (Object) adaptor.create(NULL_LITERAL166); + adaptor.addChild(root_0, NULL_LITERAL166_tree); + } + + } + break; + case 6: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:254:4: + // HEXADECIMAL_INTEGER_LITERAL + { + root_0 = (Object) adaptor.nil(); + + HEXADECIMAL_INTEGER_LITERAL167 = (Token) input.LT(1); + match(input, HEXADECIMAL_INTEGER_LITERAL, FOLLOW_HEXADECIMAL_INTEGER_LITERAL_in_literal1688); + if (failed) + return retval; + if (backtracking == 0) { + HEXADECIMAL_INTEGER_LITERAL167_tree = (Object) adaptor.create(HEXADECIMAL_INTEGER_LITERAL167); + adaptor.addChild(root_0, HEXADECIMAL_INTEGER_LITERAL167_tree); + } + + } + break; + case 7: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:255:4: + // REAL_LITERAL + { + root_0 = (Object) adaptor.nil(); + + REAL_LITERAL168 = (Token) input.LT(1); + match(input, REAL_LITERAL, FOLLOW_REAL_LITERAL_in_literal1694); + if (failed) + return retval; + if (backtracking == 0) { + REAL_LITERAL168_tree = (Object) adaptor.create(REAL_LITERAL168); + adaptor.addChild(root_0, REAL_LITERAL168_tree); + } + + } + break; + case 8: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:256:4: + // dateLiteral + { + root_0 = (Object) adaptor.nil(); + + pushFollow(FOLLOW_dateLiteral_in_literal1699); + dateLiteral169 = dateLiteral(); + _fsp--; + if (failed) + return retval; + if (backtracking == 0) + adaptor.addChild(root_0, dateLiteral169.getTree()); + + } + break; + + } + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end literal + + public static class boolLiteral_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start boolLiteral + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:259:1: + // boolLiteral : ( TRUE | FALSE ); + public final boolLiteral_return boolLiteral() throws RecognitionException { + boolLiteral_return retval = new boolLiteral_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token set170 = null; + + Object set170_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:259:12: + // ( TRUE | FALSE ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g: + { + root_0 = (Object) adaptor.nil(); + + set170 = (Token) input.LT(1); + if ((input.LA(1) >= TRUE && input.LA(1) <= FALSE)) { + input.consume(); + if (backtracking == 0) + adaptor.addChild(root_0, adaptor.create(set170)); + errorRecovery = false; + failed = false; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + MismatchedSetException mse = new MismatchedSetException(null, input); + recoverFromMismatchedSet(input, mse, FOLLOW_set_in_boolLiteral0); + throw mse; + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end boolLiteral + + public static class dateLiteral_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start dateLiteral + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:1: + // dateLiteral : 'date' LPAREN d= STRING_LITERAL ( COMMA f= STRING_LITERAL )? RPAREN -> ^( DATE_LITERAL $d ( $f)? ) + // ; + public final dateLiteral_return dateLiteral() throws RecognitionException { + dateLiteral_return retval = new dateLiteral_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token d = null; + Token f = null; + Token string_literal171 = null; + Token LPAREN172 = null; + Token COMMA173 = null; + Token RPAREN174 = null; + + Object d_tree = null; + Object f_tree = null; + Object string_literal171_tree = null; + Object LPAREN172_tree = null; + Object COMMA173_tree = null; + Object RPAREN174_tree = null; + RewriteRuleTokenStream stream_COMMA = new RewriteRuleTokenStream(adaptor, "token COMMA"); + RewriteRuleTokenStream stream_RPAREN = new RewriteRuleTokenStream(adaptor, "token RPAREN"); + RewriteRuleTokenStream stream_LPAREN = new RewriteRuleTokenStream(adaptor, "token LPAREN"); + RewriteRuleTokenStream stream_95 = new RewriteRuleTokenStream(adaptor, "token 95"); + RewriteRuleTokenStream stream_STRING_LITERAL = new RewriteRuleTokenStream(adaptor, "token STRING_LITERAL"); + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:12: + // ( 'date' LPAREN d= STRING_LITERAL ( COMMA f= STRING_LITERAL )? RPAREN -> ^( DATE_LITERAL $d ( $f)? ) ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:14: + // 'date' LPAREN d= STRING_LITERAL ( COMMA f= STRING_LITERAL )? RPAREN + { + string_literal171 = (Token) input.LT(1); + match(input, 95, FOLLOW_95_in_dateLiteral1720); + if (failed) + return retval; + if (backtracking == 0) + stream_95.add(string_literal171); + + LPAREN172 = (Token) input.LT(1); + match(input, LPAREN, FOLLOW_LPAREN_in_dateLiteral1722); + if (failed) + return retval; + if (backtracking == 0) + stream_LPAREN.add(LPAREN172); + + d = (Token) input.LT(1); + match(input, STRING_LITERAL, FOLLOW_STRING_LITERAL_in_dateLiteral1726); + if (failed) + return retval; + if (backtracking == 0) + stream_STRING_LITERAL.add(d); + + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:45: + // ( COMMA f= STRING_LITERAL )? + int alt40 = 2; + int LA40_0 = input.LA(1); + + if ((LA40_0 == COMMA)) { + alt40 = 1; + } + switch (alt40) { + case 1: + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:46: + // COMMA f= STRING_LITERAL + { + COMMA173 = (Token) input.LT(1); + match(input, COMMA, FOLLOW_COMMA_in_dateLiteral1729); + if (failed) + return retval; + if (backtracking == 0) + stream_COMMA.add(COMMA173); + + f = (Token) input.LT(1); + match(input, STRING_LITERAL, FOLLOW_STRING_LITERAL_in_dateLiteral1733); + if (failed) + return retval; + if (backtracking == 0) + stream_STRING_LITERAL.add(f); + + } + break; + + } + + RPAREN174 = (Token) input.LT(1); + match(input, RPAREN, FOLLOW_RPAREN_in_dateLiteral1737); + if (failed) + return retval; + if (backtracking == 0) + stream_RPAREN.add(RPAREN174); + + // AST REWRITE + // elements: f, d + // token labels: d, f + // rule labels: retval + // token list labels: + // rule list labels: + if (backtracking == 0) { + retval.tree = root_0; + RewriteRuleTokenStream stream_d = new RewriteRuleTokenStream(adaptor, "token d", d); + RewriteRuleTokenStream stream_f = new RewriteRuleTokenStream(adaptor, "token f", f); + RewriteRuleSubtreeStream stream_retval = new RewriteRuleSubtreeStream(adaptor, "token retval", + retval != null ? retval.tree : null); + + root_0 = (Object) adaptor.nil(); + // 261:78: -> ^( DATE_LITERAL $d ( $f)? ) + { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:81: + // ^( DATE_LITERAL $d ( $f)? ) + { + Object root_1 = (Object) adaptor.nil(); + root_1 = (Object) adaptor.becomeRoot(adaptor.create(DATE_LITERAL, "DATE_LITERAL"), root_1); + + adaptor.addChild(root_1, stream_d.next()); + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:261:99: + // ( $f)? + if (stream_f.hasNext()) { + adaptor.addChild(root_1, stream_f.next()); + + } + stream_f.reset(); + + adaptor.addChild(root_0, root_1); + } + + } + + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end dateLiteral + + public static class relationalOperator_return extends ParserRuleReturnScope { + Object tree; + + public Object getTree() { + return tree; + } + }; + + // $ANTLR start relationalOperator + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:268:1: + // relationalOperator : ( EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL + // | IN | IS | BETWEEN | LIKE | MATCHES | SOUNDSLIKE | DISTANCETO ); + public final relationalOperator_return relationalOperator() throws RecognitionException { + relationalOperator_return retval = new relationalOperator_return(); + retval.start = input.LT(1); + + Object root_0 = null; + + Token set175 = null; + + Object set175_tree = null; + + try { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:269:5: + // ( EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL | IN | IS | + // BETWEEN | LIKE | MATCHES | SOUNDSLIKE | DISTANCETO ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g: + { + root_0 = (Object) adaptor.nil(); + + set175 = (Token) input.LT(1); + if ((input.LA(1) >= EQUAL && input.LA(1) <= DISTANCETO)) { + input.consume(); + if (backtracking == 0) + adaptor.addChild(root_0, adaptor.create(set175)); + errorRecovery = false; + failed = false; + } else { + if (backtracking > 0) { + failed = true; + return retval; + } + MismatchedSetException mse = new MismatchedSetException(null, input); + recoverFromMismatchedSet(input, mse, FOLLOW_set_in_relationalOperator0); + throw mse; + } + + } + + retval.stop = input.LT(-1); + + if (backtracking == 0) { + retval.tree = (Object) adaptor.rulePostProcessing(root_0); + adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop); + } + } + + catch (RecognitionException e) { + // reportError(e); + throw e; + } finally { + } + return retval; + } + + // $ANTLR end relationalOperator + + // $ANTLR start synpred1 + public final void synpred1_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:104:5: + // ( LPAREN expression SEMI ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:104:6: + // LPAREN expression SEMI + { + match(input, LPAREN, FOLLOW_LPAREN_in_synpred1545); + if (failed) + return; + pushFollow(FOLLOW_expression_in_synpred1547); + expression(); + _fsp--; + if (failed) + return; + match(input, SEMI, FOLLOW_SEMI_in_synpred1549); + if (failed) + return; + + } + } + + // $ANTLR end synpred1 + + // $ANTLR start synpred2 + public final void synpred2_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:138:7: + // ( POUND ID LPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:138:8: + // POUND ID LPAREN + { + match(input, POUND, FOLLOW_POUND_in_synpred2797); + if (failed) + return; + match(input, ID, FOLLOW_ID_in_synpred2799); + if (failed) + return; + match(input, LPAREN, FOLLOW_LPAREN_in_synpred2801); + if (failed) + return; + + } + } + + // $ANTLR end synpred2 + + // $ANTLR start synpred3 + public final void synpred3_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:147:4: + // ( DOLLAR ID LPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:147:5: + // DOLLAR ID LPAREN + { + match(input, DOLLAR, FOLLOW_DOLLAR_in_synpred3880); + if (failed) + return; + match(input, ID, FOLLOW_ID_in_synpred3882); + if (failed) + return; + match(input, LPAREN, FOLLOW_LPAREN_in_synpred3884); + if (failed) + return; + + } + } + + // $ANTLR end synpred3 + + // $ANTLR start synpred4 + public final void synpred4_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:155:4: + // ( ID LPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:155:5: + // ID LPAREN + { + match(input, ID, FOLLOW_ID_in_synpred4946); + if (failed) + return; + match(input, LPAREN, FOLLOW_LPAREN_in_synpred4948); + if (failed) + return; + + } + } + + // $ANTLR end synpred4 + + // $ANTLR start synpred5 + public final void synpred5_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:210:4: + // ( 'new' qualifiedId LPAREN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:210:5: + // 'new' qualifiedId LPAREN + { + match(input, 94, FOLLOW_94_in_synpred51295); + if (failed) + return; + pushFollow(FOLLOW_qualifiedId_in_synpred51297); + qualifiedId(); + _fsp--; + if (failed) + return; + match(input, LPAREN, FOLLOW_LPAREN_in_synpred51299); + if (failed) + return; + + } + } + + // $ANTLR end synpred5 + + // $ANTLR start synpred6 + public final void synpred6_fragment() throws RecognitionException { + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:240:7: + // ( ID ASSIGN ) + // /Users/aclement/spring-pieces/spring-el/trunk/org.springframework.el/src/main/java/org/springframework/el/generated/SpringExpressions.g:240:8: + // ID ASSIGN + { + match(input, ID, FOLLOW_ID_in_synpred61551); + if (failed) + return; + match(input, ASSIGN, FOLLOW_ASSIGN_in_synpred61553); + if (failed) + return; + + } + } + + // $ANTLR end synpred6 + + public final boolean synpred4() { + backtracking++; + int start = input.mark(); + try { + synpred4_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public final boolean synpred2() { + backtracking++; + int start = input.mark(); + try { + synpred2_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public final boolean synpred3() { + backtracking++; + int start = input.mark(); + try { + synpred3_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public final boolean synpred1() { + backtracking++; + int start = input.mark(); + try { + synpred1_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public final boolean synpred5() { + backtracking++; + int start = input.mark(); + try { + synpred5_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public final boolean synpred6() { + backtracking++; + int start = input.mark(); + try { + synpred6_fragment(); // can never throw exception + } catch (RecognitionException re) { + System.err.println("impossible: " + re); + } + boolean success = !failed; + input.rewind(start); + backtracking--; + failed = false; + return success; + } + + public static final BitSet FOLLOW_expression_in_expr173 = new BitSet(new long[] { 0x0000000000000000L }); + public static final BitSet FOLLOW_EOF_in_expr175 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LPAREN_in_exprList188 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_exprList190 = new BitSet(new long[] { 0x0000000080000000L }); + public static final BitSet FOLLOW_SEMI_in_exprList193 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_exprList195 = new BitSet(new long[] { 0x0000000380000000L }); + public static final BitSet FOLLOW_SEMIRPAREN_in_exprList200 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_RPAREN_in_exprList204 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_logicalOrExpression_in_expression248 = new BitSet( + new long[] { 0x0000001C00000002L }); + public static final BitSet FOLLOW_ASSIGN_in_expression257 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_logicalOrExpression_in_expression260 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_DEFAULT_in_expression270 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_logicalOrExpression_in_expression273 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_QMARK_in_expression283 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_expression286 = new BitSet(new long[] { 0x0000002000000000L }); + public static final BitSet FOLLOW_COLON_in_expression288 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_expression291 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LPAREN_in_parenExpr302 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_parenExpr305 = new BitSet(new long[] { 0x0000000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_parenExpr307 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_logicalAndExpression_in_logicalOrExpression318 = new BitSet( + new long[] { 0x0000004000000002L }); + public static final BitSet FOLLOW_OR_in_logicalOrExpression321 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_logicalAndExpression_in_logicalOrExpression324 = new BitSet( + new long[] { 0x0000004000000002L }); + public static final BitSet FOLLOW_relationalExpression_in_logicalAndExpression358 = new BitSet( + new long[] { 0x0000008000000002L }); + public static final BitSet FOLLOW_AND_in_logicalAndExpression361 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_relationalExpression_in_logicalAndExpression364 = new BitSet( + new long[] { 0x0000008000000002L }); + public static final BitSet FOLLOW_sumExpression_in_relationalExpression375 = new BitSet(new long[] { + 0x0000000000000002L, 0x00000000007FFC00L }); + public static final BitSet FOLLOW_relationalOperator_in_relationalExpression378 = new BitSet(new long[] { + 0xBEB7430040000020L, 0x00000000C000007FL }); + public static final BitSet FOLLOW_sumExpression_in_relationalExpression381 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_productExpression_in_sumExpression392 = new BitSet( + new long[] { 0x0000030000000002L }); + public static final BitSet FOLLOW_PLUS_in_sumExpression397 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_MINUS_in_sumExpression402 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_productExpression_in_sumExpression406 = new BitSet( + new long[] { 0x0000030000000002L }); + public static final BitSet FOLLOW_powerExpr_in_productExpression421 = new BitSet(new long[] { 0x00001C0000000002L }); + public static final BitSet FOLLOW_STAR_in_productExpression425 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_DIV_in_productExpression430 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_MOD_in_productExpression434 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_powerExpr_in_productExpression438 = new BitSet(new long[] { 0x00001C0000000002L }); + public static final BitSet FOLLOW_unaryExpression_in_powerExpr454 = new BitSet(new long[] { 0x0000200000000002L }); + public static final BitSet FOLLOW_POWER_in_powerExpr457 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_unaryExpression_in_powerExpr460 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_PLUS_in_unaryExpression474 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_MINUS_in_unaryExpression479 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_BANG_in_unaryExpression484 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_unaryExpression_in_unaryExpression488 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_primaryExpression_in_unaryExpression494 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_startNode_in_primaryExpression508 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_node_in_primaryExpression511 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_exprList_in_startNode554 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_parenExpr_in_startNode563 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_methodOrProperty_in_startNode571 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_functionOrVar_in_startNode580 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_localFunctionOrVar_in_startNode588 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_reference_in_startNode596 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_indexer_in_startNode604 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_literal_in_startNode612 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_type_in_startNode620 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_constructor_in_startNode628 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_projection_in_startNode636 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_selection_in_startNode645 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_firstSelection_in_startNode654 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_lastSelection_in_startNode662 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_listInitializer_in_startNode670 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_mapInitializer_in_startNode678 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_lambda_in_startNode686 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_methodOrProperty_in_node707 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_functionOrVar_in_node713 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_indexer_in_node721 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_projection_in_node729 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_selection_in_node738 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_firstSelection_in_node747 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_lastSelection_in_node756 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_exprList_in_node765 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_DOT_in_node773 = new BitSet(new long[] { 0x0EA3800040000002L }); + public static final BitSet FOLLOW_function_in_functionOrVar806 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_var_in_functionOrVar814 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_POUND_in_function831 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_function835 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_methodArgs_in_function837 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_POUND_in_var858 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_var862 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_localFunction_in_localFunctionOrVar889 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_localVar_in_localFunctionOrVar894 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_DOLLAR_in_localFunction904 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_localFunction908 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_methodArgs_in_localFunction910 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_DOLLAR_in_localVar925 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_localVar929 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_methodOrProperty955 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_methodArgs_in_methodOrProperty957 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_property_in_methodOrProperty971 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LPAREN_in_methodArgs986 = new BitSet(new long[] { 0xBEB7430240000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_argument_in_methodArgs990 = new BitSet(new long[] { 0x0008000200000000L }); + public static final BitSet FOLLOW_COMMA_in_methodArgs993 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_argument_in_methodArgs996 = new BitSet(new long[] { 0x0008000200000000L }); + public static final BitSet FOLLOW_COMMA_in_methodArgs1001 = new BitSet(new long[] { 0x0000000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_methodArgs1008 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_property1021 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_AT_in_reference1043 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_reference1047 = new BitSet(new long[] { 0x0002000200000000L }); + public static final BitSet FOLLOW_contextName_in_reference1052 = new BitSet(new long[] { 0x0000002000000000L }); + public static final BitSet FOLLOW_COLON_in_reference1054 = new BitSet(new long[] { 0x0002000200000000L }); + public static final BitSet FOLLOW_qualifiedId_in_reference1061 = new BitSet(new long[] { 0x0000000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_reference1065 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LBRACKET_in_indexer1100 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_argument_in_indexer1104 = new BitSet(new long[] { 0x0048000000000000L }); + public static final BitSet FOLLOW_COMMA_in_indexer1107 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_argument_in_indexer1111 = new BitSet(new long[] { 0x0048000000000000L }); + public static final BitSet FOLLOW_RBRACKET_in_indexer1115 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_PROJECT_in_projection1142 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_projection1145 = new BitSet(new long[] { 0x0100000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_projection1147 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_SELECT_in_selection1155 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_selection1158 = new BitSet(new long[] { 0x0100000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_selection1160 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_SELECT_FIRST_in_firstSelection1168 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_firstSelection1171 = new BitSet(new long[] { 0x0100000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_firstSelection1173 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_SELECT_LAST_in_lastSelection1181 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_lastSelection1184 = new BitSet(new long[] { 0x0100000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_lastSelection1186 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_TYPE_in_type1195 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_qualifiedId_in_type1197 = new BitSet(new long[] { 0x0000000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_type1199 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LAMBDA_in_lambda1226 = new BitSet(new long[] { 0x4002000000000000L }); + public static final BitSet FOLLOW_argList_in_lambda1229 = new BitSet(new long[] { 0x4000000000000000L }); + public static final BitSet FOLLOW_PIPE_in_lambda1233 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_lambda1235 = new BitSet(new long[] { 0x0100000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_lambda1237 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_argList1261 = new BitSet(new long[] { 0x0008000000000002L }); + public static final BitSet FOLLOW_COMMA_in_argList1264 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_argList1268 = new BitSet(new long[] { 0x0008000000000002L }); + public static final BitSet FOLLOW_94_in_constructor1304 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_qualifiedId_in_constructor1306 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_ctorArgs_in_constructor1308 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_arrayConstructor_in_constructor1325 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_94_in_arrayConstructor1336 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_qualifiedId_in_arrayConstructor1338 = new BitSet( + new long[] { 0x0020000000000000L }); + public static final BitSet FOLLOW_arrayRank_in_arrayConstructor1340 = new BitSet(new long[] { 0x8000000000000002L }); + public static final BitSet FOLLOW_listInitializer_in_arrayConstructor1343 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LBRACKET_in_arrayRank1378 = new BitSet(new long[] { 0xBEF7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_arrayRank1381 = new BitSet(new long[] { 0x0048000000000000L }); + public static final BitSet FOLLOW_COMMA_in_arrayRank1384 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_arrayRank1386 = new BitSet(new long[] { 0x0048000000000000L }); + public static final BitSet FOLLOW_RBRACKET_in_arrayRank1392 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LCURLY_in_listInitializer1417 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_listInitializer1419 = new BitSet(new long[] { 0x0108000000000000L }); + public static final BitSet FOLLOW_COMMA_in_listInitializer1422 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_listInitializer1424 = new BitSet(new long[] { 0x0108000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_listInitializer1428 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_POUND_in_mapInitializer1456 = new BitSet(new long[] { 0x8000000000000000L }); + public static final BitSet FOLLOW_LCURLY_in_mapInitializer1458 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_mapEntry_in_mapInitializer1460 = new BitSet(new long[] { 0x0108000000000000L }); + public static final BitSet FOLLOW_COMMA_in_mapInitializer1463 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_mapEntry_in_mapInitializer1465 = new BitSet(new long[] { 0x0108000000000000L }); + public static final BitSet FOLLOW_RCURLY_in_mapInitializer1469 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_expression_in_mapEntry1490 = new BitSet(new long[] { 0x0000002000000000L }); + public static final BitSet FOLLOW_COLON_in_mapEntry1492 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_mapEntry1494 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LPAREN_in_ctorArgs1512 = new BitSet(new long[] { 0xBEB7430240000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_namedArgument_in_ctorArgs1516 = new BitSet(new long[] { 0x0008000200000000L }); + public static final BitSet FOLLOW_COMMA_in_ctorArgs1519 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_namedArgument_in_ctorArgs1522 = new BitSet(new long[] { 0x0008000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_ctorArgs1528 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_expression_in_argument1537 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_namedArgument1560 = new BitSet(new long[] { 0x0000000400000000L }); + public static final BitSet FOLLOW_ASSIGN_in_namedArgument1562 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_namedArgument1564 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_argument_in_namedArgument1600 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_qualifiedId1612 = new BitSet(new long[] { 0x0000800000000002L }); + public static final BitSet FOLLOW_DOT_in_qualifiedId1615 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_qualifiedId1617 = new BitSet(new long[] { 0x0000800000000002L }); + public static final BitSet FOLLOW_ID_in_contextName1636 = new BitSet(new long[] { 0x0000080000000002L }); + public static final BitSet FOLLOW_DIV_in_contextName1639 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_contextName1641 = new BitSet(new long[] { 0x0000080000000002L }); + public static final BitSet FOLLOW_INTEGER_LITERAL_in_literal1662 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_STRING_LITERAL_in_literal1668 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_DQ_STRING_LITERAL_in_literal1673 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_boolLiteral_in_literal1678 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_NULL_LITERAL_in_literal1683 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_HEXADECIMAL_INTEGER_LITERAL_in_literal1688 = new BitSet( + new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_REAL_LITERAL_in_literal1694 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_dateLiteral_in_literal1699 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_set_in_boolLiteral0 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_95_in_dateLiteral1720 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_dateLiteral1722 = new BitSet(new long[] { 0x0000000000000000L, + 0x0000000000000001L }); + public static final BitSet FOLLOW_STRING_LITERAL_in_dateLiteral1726 = new BitSet(new long[] { 0x0008000200000000L }); + public static final BitSet FOLLOW_COMMA_in_dateLiteral1729 = new BitSet(new long[] { 0x0000000000000000L, + 0x0000000000000001L }); + public static final BitSet FOLLOW_STRING_LITERAL_in_dateLiteral1733 = new BitSet(new long[] { 0x0000000200000000L }); + public static final BitSet FOLLOW_RPAREN_in_dateLiteral1737 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_set_in_relationalOperator0 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_LPAREN_in_synpred1545 = new BitSet(new long[] { 0xBEB7430040000020L, + 0x00000000C000007FL }); + public static final BitSet FOLLOW_expression_in_synpred1547 = new BitSet(new long[] { 0x0000000080000000L }); + public static final BitSet FOLLOW_SEMI_in_synpred1549 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_POUND_in_synpred2797 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_synpred2799 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_synpred2801 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_DOLLAR_in_synpred3880 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_ID_in_synpred3882 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_synpred3884 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_synpred4946 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_synpred4948 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_94_in_synpred51295 = new BitSet(new long[] { 0x0002000000000000L }); + public static final BitSet FOLLOW_qualifiedId_in_synpred51297 = new BitSet(new long[] { 0x0000000040000000L }); + public static final BitSet FOLLOW_LPAREN_in_synpred51299 = new BitSet(new long[] { 0x0000000000000002L }); + public static final BitSet FOLLOW_ID_in_synpred61551 = new BitSet(new long[] { 0x0000000400000000L }); + public static final BitSet FOLLOW_ASSIGN_in_synpred61553 = new BitSet(new long[] { 0x0000000000000002L }); + +} \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions__.g b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions__.g new file mode 100644 index 00000000000..e53f23fe7e0 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions__.g @@ -0,0 +1,174 @@ +lexer grammar SpringExpressions; +options { + language=Java; + +} +@header {package org.springframework.expression.spel.generated;} + +T94 : 'new' ; +T95 : 'date' ; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 62 +SEMIRPAREN : ';)'; // recoveryrelated: allows us to cope with a rogue superfluous semicolon before the rparen in an expression list + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 263 +INTEGER_LITERAL + : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 266 +HEXADECIMAL_INTEGER_LITERAL : '0x' (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 284 +ASSIGN: '='; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 285 +EQUAL: '=='; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 286 +NOT_EQUAL: '!='; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 287 +LESS_THAN: '<'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 288 +LESS_THAN_OR_EQUAL: '<='; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 289 +GREATER_THAN: '>'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 290 +GREATER_THAN_OR_EQUAL: '>='; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 291 +SOUNDSLIKE + : 'soundslike'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 293 +DISTANCETO + : 'distanceto'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 295 +IN: 'in'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 296 +IS: 'is'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 297 +BETWEEN:'between'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 298 +LIKE: 'like'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 299 +MATCHES:'matches'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 300 +NULL_LITERAL: 'null'; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 302 +SEMI: ';'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 303 +DOT: '.'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 304 +COMMA: ','; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 305 +LPAREN: '('; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 306 +RPAREN: ')'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 307 +LCURLY: '{'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 308 +RCURLY: '}'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 309 +LBRACKET: '['; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 310 +RBRACKET: ']'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 311 +PIPE: '|'; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 313 +AND: 'and'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 314 +OR: 'or'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 315 +FALSE: 'false'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 316 +TRUE: 'true'; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 318 +PLUS: '+'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 319 +MINUS: '-'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 320 +DIV: '/'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 321 +STAR: '*'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 322 +MOD: '%'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 323 +POWER: '^'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 324 +BANG: '!'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 325 +POUND: '#'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 326 +QMARK: '?'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 327 +DEFAULT: '??'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 328 +LAMBDA: '{|'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 329 +PROJECT: '!{'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 330 +SELECT: '?{'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 331 +SELECT_FIRST: '^{'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 332 +SELECT_LAST: '${'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 333 +TYPE: 'T('; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 335 +STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 336 +DQ_STRING_LITERAL: '"'! (~'"')* '"'!; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 337 +ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 338 +DOT_ESCAPED: '\\.'; +//DOUBLE_DOT: ':'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 340 +WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 341 +DOLLAR: '$'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 342 +AT: '@'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 343 +UPTO: '..'; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 344 +COLON: ':'; + + /* + // real - use syntactic predicates (guess mode) + : ('.' DECIMAL_DIGIT) => + in= '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ '.' DECIMAL_DIGIT) => + in=(DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ (EXPONENT_PART)) => + in= (DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)? + + | ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)) => + in= (DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX) +*/ + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 361 +REAL_LITERAL : + ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 367 +fragment APOS : '\''! '\''; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 368 +fragment DECIMAL_DIGIT : '0'..'9' ; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 369 +fragment INTEGER_TYPE_SUFFIX : ( 'UL' | 'LU' | 'ul' | 'lu' | 'uL' | 'lU' | 'U' | 'L' | 'u' | 'l' ); +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 370 +fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; + +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 372 +fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 373 +fragment SIGN : '+' | '-' ; +// TODO what is M or m? +// $ANTLR src "/Users/aclement/el/spring3/spring-framework/trunk/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g" 375 +fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd' | 'M' | 'm' ; diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/EmptySpelNode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/EmptySpelNode.java new file mode 100644 index 00000000000..b1f81300121 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/EmptySpelNode.java @@ -0,0 +1,39 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.antlr.runtime.Token; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.ast.SpelNode; + +public class EmptySpelNode extends SpelNode { + + public EmptySpelNode(Token payload) { + super(payload); + } + + @Override + public Object getValue(ExpressionState state) throws SpelException { + throw new RuntimeException("?"); + } + + @Override + public String toStringAST() { + return ""; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/InternalELException.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/InternalELException.java new file mode 100644 index 00000000000..267271ebcd9 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/InternalELException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.springframework.expression.spel.SpelException; + +/** + * Wraps an ELException and can pass up through Antlr since it is unchecked, where it can then be unwrapped. + * + * @author Andy Clement + */ +public class InternalELException extends RuntimeException { + + InternalELException(SpelException e) { + super(e); + } + + @Override + public SpelException getCause() { + return (SpelException) super.getCause(); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/KeyValuePair.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/KeyValuePair.java new file mode 100644 index 00000000000..ee15d037c83 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/KeyValuePair.java @@ -0,0 +1,33 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +/** + * Special object that is used to wrap a map entry/value when iterating over a map. Providing a direct way for the + * expression to refer to either the key or value. + * + * @author Andy Clement + */ +public class KeyValuePair { + public Object key; + public Object value; + + public KeyValuePair(Object k, Object v) { + this.key = k; + this.value = v; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpelTreeAdaptor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpelTreeAdaptor.java new file mode 100644 index 00000000000..a7714fe6489 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpelTreeAdaptor.java @@ -0,0 +1,220 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.antlr.runtime.Token; +import org.antlr.runtime.tree.CommonTreeAdaptor; +import org.springframework.expression.spel.ast.ArgList; +import org.springframework.expression.spel.ast.Assign; +import org.springframework.expression.spel.ast.BooleanLiteral; +import org.springframework.expression.spel.ast.CompoundExpression; +import org.springframework.expression.spel.ast.ConstructorReference; +import org.springframework.expression.spel.ast.DateLiteral; +import org.springframework.expression.spel.ast.Dot; +import org.springframework.expression.spel.ast.ExpressionListNode; +import org.springframework.expression.spel.ast.FunctionReference; +import org.springframework.expression.spel.ast.Identifier; +import org.springframework.expression.spel.ast.Indexer; +import org.springframework.expression.spel.ast.IntLiteral; +import org.springframework.expression.spel.ast.Lambda; +import org.springframework.expression.spel.ast.ListInitializer; +import org.springframework.expression.spel.ast.LocalFunctionReference; +import org.springframework.expression.spel.ast.LocalVariableReference; +import org.springframework.expression.spel.ast.MapEntry; +import org.springframework.expression.spel.ast.MapInitializer; +import org.springframework.expression.spel.ast.MethodReference; +import org.springframework.expression.spel.ast.NullLiteral; +import org.springframework.expression.spel.ast.OperatorAnd; +import org.springframework.expression.spel.ast.OperatorBetween; +import org.springframework.expression.spel.ast.OperatorDistanceTo; +import org.springframework.expression.spel.ast.OperatorDivide; +import org.springframework.expression.spel.ast.OperatorEquality; +import org.springframework.expression.spel.ast.OperatorGreaterThan; +import org.springframework.expression.spel.ast.OperatorGreaterThanOrEqual; +import org.springframework.expression.spel.ast.OperatorIn; +import org.springframework.expression.spel.ast.OperatorInequality; +import org.springframework.expression.spel.ast.OperatorIs; +import org.springframework.expression.spel.ast.OperatorLessThan; +import org.springframework.expression.spel.ast.OperatorLessThanOrEqual; +import org.springframework.expression.spel.ast.OperatorLike; +import org.springframework.expression.spel.ast.OperatorMatches; +import org.springframework.expression.spel.ast.OperatorMinus; +import org.springframework.expression.spel.ast.OperatorModulus; +import org.springframework.expression.spel.ast.OperatorMultiply; +import org.springframework.expression.spel.ast.OperatorNot; +import org.springframework.expression.spel.ast.OperatorOr; +import org.springframework.expression.spel.ast.OperatorPlus; +import org.springframework.expression.spel.ast.OperatorSoundsLike; +import org.springframework.expression.spel.ast.Placeholder; +import org.springframework.expression.spel.ast.Projection; +import org.springframework.expression.spel.ast.PropertyOrFieldReference; +import org.springframework.expression.spel.ast.QualifiedIdentifier; +import org.springframework.expression.spel.ast.RealLiteral; +import org.springframework.expression.spel.ast.Reference; +import org.springframework.expression.spel.ast.Selection; +import org.springframework.expression.spel.ast.StringLiteral; +import org.springframework.expression.spel.ast.Ternary; +import org.springframework.expression.spel.ast.TypeReference; +import org.springframework.expression.spel.ast.VariableReference; +import org.springframework.expression.spel.generated.SpringExpressionsLexer; + +public class SpelTreeAdaptor extends CommonTreeAdaptor { + @Override + public Object create(Token payload) { + if (payload != null) { + switch (payload.getType()) { + case SpringExpressionsLexer.EXPRESSIONLIST: + return new ExpressionListNode(payload); + + case SpringExpressionsLexer.TRUE: + return new BooleanLiteral(payload, true); + case SpringExpressionsLexer.FALSE: + return new BooleanLiteral(payload, false); + + case SpringExpressionsLexer.OR: + return new OperatorOr(payload); + case SpringExpressionsLexer.AND: + return new OperatorAnd(payload); + case SpringExpressionsLexer.BANG: + return new OperatorNot(payload); + + case SpringExpressionsLexer.REAL_LITERAL: + return new RealLiteral(payload); + case SpringExpressionsLexer.INTEGER_LITERAL: + return new IntLiteral(payload); + case SpringExpressionsLexer.HEXADECIMAL_INTEGER_LITERAL: + return new IntLiteral(payload, 16/* HEX */); + + case SpringExpressionsLexer.NOT_EQUAL: + return new OperatorInequality(payload); + case SpringExpressionsLexer.EQUAL: + return new OperatorEquality(payload); + case SpringExpressionsLexer.GREATER_THAN: + return new OperatorGreaterThan(payload); + case SpringExpressionsLexer.LESS_THAN: + return new OperatorLessThan(payload); + case SpringExpressionsLexer.LESS_THAN_OR_EQUAL: + return new OperatorLessThanOrEqual(payload); + case SpringExpressionsLexer.GREATER_THAN_OR_EQUAL: + return new OperatorGreaterThanOrEqual(payload); + case SpringExpressionsLexer.SOUNDSLIKE: + return new OperatorSoundsLike(payload); + case SpringExpressionsLexer.DISTANCETO: + return new OperatorDistanceTo(payload); + case SpringExpressionsLexer.PLUS: + return new OperatorPlus(payload); + case SpringExpressionsLexer.MINUS: + return new OperatorMinus(payload); + case SpringExpressionsLexer.STAR/* MULTIPLY */: + return new OperatorMultiply(payload); + case SpringExpressionsLexer.DIV/* DIVIDE */: + return new OperatorDivide(payload); + case SpringExpressionsLexer.MOD: + return new OperatorModulus(payload); + + case SpringExpressionsLexer.STRING_LITERAL: + case SpringExpressionsLexer.DQ_STRING_LITERAL: + return new StringLiteral(payload); + case SpringExpressionsLexer.NULL_LITERAL: + return new NullLiteral(payload); + case SpringExpressionsLexer.DATE_LITERAL: + return new DateLiteral(payload); + + case SpringExpressionsLexer.ID: + return new Identifier(payload); + case SpringExpressionsLexer.PROPERTY_OR_FIELD: + return new PropertyOrFieldReference(payload); + case SpringExpressionsLexer.METHOD: + return new MethodReference(payload); + case SpringExpressionsLexer.QUALIFIED_IDENTIFIER: + return new QualifiedIdentifier(payload); + case SpringExpressionsLexer.REFERENCE: + return new Reference(payload); + case SpringExpressionsLexer.TYPEREF: + return new TypeReference(payload); + + case SpringExpressionsLexer.EXPRESSION: + return new CompoundExpression(payload); + + case SpringExpressionsLexer.LIST_INITIALIZER: + return new ListInitializer(payload); + case SpringExpressionsLexer.MAP_ENTRY: + return new MapEntry(payload); + case SpringExpressionsLexer.MAP_INITIALIZER: + return new MapInitializer(payload); + + case SpringExpressionsLexer.CONSTRUCTOR: + return new ConstructorReference(payload, false); + case SpringExpressionsLexer.CONSTRUCTOR_ARRAY: + return new ConstructorReference(payload, true); + case SpringExpressionsLexer.LOCALFUNC: + return new LocalFunctionReference(payload); + case SpringExpressionsLexer.LOCALVAR: + return new LocalVariableReference(payload); + case SpringExpressionsLexer.VARIABLEREF: + return new VariableReference(payload); + case SpringExpressionsLexer.FUNCTIONREF: + return new FunctionReference(payload); + case SpringExpressionsLexer.PROJECT: + return new Projection(payload); + case SpringExpressionsLexer.SELECT: + return new Selection(payload, Selection.ALL); + case SpringExpressionsLexer.SELECT_FIRST: + return new Selection(payload, Selection.FIRST); + case SpringExpressionsLexer.SELECT_LAST: + return new Selection(payload, Selection.LAST); + + case SpringExpressionsLexer.ASSIGN: + return new Assign(payload); + case SpringExpressionsLexer.QMARK: + return new Ternary(payload); + case SpringExpressionsLexer.INDEXER: + return new Indexer(payload); + // case SpringExpressionsLexer.UPTO: return new Range(payload); + + case SpringExpressionsLexer.IN: + return new OperatorIn(payload); + case SpringExpressionsLexer.LIKE: + return new OperatorLike(payload); + case SpringExpressionsLexer.BETWEEN: + return new OperatorBetween(payload); + case SpringExpressionsLexer.MATCHES: + return new OperatorMatches(payload); + case SpringExpressionsLexer.IS: + return new OperatorIs(payload); + + case SpringExpressionsLexer.ARGLIST: + return new ArgList(payload); + case SpringExpressionsLexer.LAMBDA: + return new Lambda(payload); + + case SpringExpressionsLexer.RPAREN: + return new Placeholder(payload); + case SpringExpressionsLexer.COLON: + return new Placeholder(payload); + + // case SpringExpressionsLexer.EOF: return new ErrorNode(payload); + case SpringExpressionsLexer.DOT: + return new Dot(payload); + + default: + throw new RuntimeException("Not implemented for '" + payload + "' " + getToken(payload) + "' " + + payload.getType()); + } + } + return new EmptySpelNode(payload); + } +} \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsLexerExtender.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsLexerExtender.java new file mode 100644 index 00000000000..3ab74b61cb0 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsLexerExtender.java @@ -0,0 +1,81 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.antlr.runtime.RecognitionException; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.generated.SpringExpressionsLexer; + +public class SpringExpressionsLexerExtender extends SpringExpressionsLexer { + + public SpringExpressionsLexerExtender() { + super(); + } + + /** + * recover() attempts to provide better error messages once something has gone wrong. It then throws a + * InternalELException (has to be this unchecked exception as the exception must flow through Antlr lexer methods + * that do not have declared exceptions). The InternalELException will be caught at the top level and altered to + * include context (line,column) information before being rethrown.
+ * + * This error analysis code is in recover() rather than reportError() because reportError() isn't always called by + * the lexer and there is no way to add the calls to it by editing the .g file. + */ + @Override + public void recover(RecognitionException re) { + // TODO recovery needs an overhaul once the expression language syntax is agreed + + // List rules = getRuleInvocationStack(re, SpringExpressionsLexer.class.getName()); + // String failedRule = (String) rules.get(rules.size() - 1); + // System.out.println("DBG: lexer rule " + failedRule); + // need a concrete example of error recovery in here please! then i can delete the below + // if (re instanceof NoViableAltException) { + // NoViableAltException nvae = (NoViableAltException) re; + // // example error data: { "abc": def } + // if (failedRule.equals("mTokens") && Character.isLetter((char) (nvae.getUnexpectedType()))) { + // logger.error(ParserMessage.ERROR_STRINGS_MUST_BE_QUOTED, re.line, re.charPositionInLine); + // } + // + // } else if (re instanceof MismatchedRangeException) { + // // MismatchedRangeException mre = (MismatchedRangeException) re; + // // example error data: [ 123e ] + // if (failedRule.equals("mDIGIT") && rules.size() > 3 && ((String) rules.get(rules.size() - + // 3)).equals("mExponent")) { + // logger.error(ParserMessage.ERROR_INVALID_EXPONENT, re.line, re.charPositionInLine); + // } + // } else if (re instanceof MismatchedTokenException) { + // MismatchedTokenException mte = (MismatchedTokenException) re; + // logger.error(ParserMessage.ERROR_MISMATCHED_CHARACTER, mte.charPositionInLine, mte.charPositionInLine, + // getCharErrorDisplay(mte.expecting), getCharErrorDisplay(mte.c)); + // } + SpelException realException = new SpelException(re, SpelMessages.RECOGNITION_ERROR, re.toString()); + throw new InternalELException(realException); + } + + @Override + public void reportError(RecognitionException re) { + // Do not report anything. If better messages could be reported they will have been reported + // by the recover() method above. + } + + private String getTokenForId(int id) { + if (id == -1) + return "EOF"; + return getTokenNames()[id]; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsParserExtender.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsParserExtender.java new file mode 100644 index 00000000000..d7d0d9455f3 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/SpringExpressionsParserExtender.java @@ -0,0 +1,78 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.antlr.runtime.BitSet; +import org.antlr.runtime.CommonTokenStream; +import org.antlr.runtime.IntStream; +import org.antlr.runtime.RecognitionException; +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenStream; +import org.springframework.expression.spel.generated.SpringExpressionsParser; + +public class SpringExpressionsParserExtender extends SpringExpressionsParser { + + public SpringExpressionsParserExtender(TokenStream input) { + super(input); + } + + /** + * This method does not actually recover but can attempt to produce better error messages than a generic Antlr + * parser because it knows about grammar specifics. would do + */ + @Override + public void recoverFromMismatchedToken(IntStream input, RecognitionException re, int ttype, BitSet follow) + throws RecognitionException { + CommonTokenStream tokStream = (CommonTokenStream) input; + int prevToken = tokStream.LA(-1); + int nextToken = tokStream.LA(1); + String prevTokenText = tokStream.LT(-1).getText(); + String expectedToken = getTokenForId(ttype); + // Use token knowledge to log a more appropriate error: + // logger.error(ParserMessage.ERROR_NO_LEADING_ZERO, re.line, re.charPositionInLine); + throw re; + } + + // + // /** + // * Similar to the BaseRecognizer getErrorMessage() but uses the ParserMessages class to get the text of the + // message + // */ + // public void logError(RecognitionException re, String[] tokenNames) { + // logger.error(ELMessages.RECOGNITION_ERROR, re.line, re.charPositionInLine, re); + // } + + @Override + public void recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) + throws RecognitionException { + throw e; + } + + @Override + public String getTokenErrorDisplay(Token t) { + if (t == null) { + return ""; + } + return super.getTokenErrorDisplay(t); + } + + private String getTokenForId(int id) { + if (id == -1) + return "EOF"; + return getTokenNames()[id]; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/TypeCode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/TypeCode.java new file mode 100644 index 00000000000..0333b5cc899 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/TypeCode.java @@ -0,0 +1,103 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +public enum TypeCode { + + OBJECT(0, Object.class), BOOLEAN(1, Boolean.TYPE), BYTE(1, Byte.TYPE), CHAR(1, Character.TYPE), SHORT(2, Short.TYPE), INT( + 3, Integer.TYPE), LONG(4, Long.TYPE), FLOAT(5, Float.TYPE), DOUBLE(6, Double.TYPE); + + private int code; + private Class type; + + TypeCode(int code, Class type) { + this.code = code; + this.type = type; + } + + public Class getType() { + return type; + } + + public static TypeCode forClass(Class c) { + TypeCode[] allValues = TypeCode.values(); + for (int i = 0; i < allValues.length; i++) { + TypeCode typeCode = allValues[i]; + if (c == typeCode.getType()) { + return typeCode; + } + } + return OBJECT; + } + + /** + * For a primitive name this will determine the typecode value - supports + * int,byte,char,short,long,double,float,boolean + */ + public static TypeCode forName(String name) { + if (name.equals("int")) + return TypeCode.INT; + else if (name.equals("boolean")) + return TypeCode.BOOLEAN; + else if (name.equals("char")) + return TypeCode.CHAR; + else if (name.equals("long")) + return TypeCode.LONG; + else if (name.equals("float")) + return TypeCode.FLOAT; + else if (name.equals("double")) + return TypeCode.DOUBLE; + else if (name.equals("short")) + return TypeCode.SHORT; + else if (name.equals("byte")) + return TypeCode.BYTE; + return TypeCode.OBJECT; + } + + public int getCode() { + return code; + } + + public Object coerce(TypeCode fromTypeCode, Object fromObject) { + if (this == TypeCode.INT) { + switch (fromTypeCode) { + case BOOLEAN: + return ((Boolean) fromObject).booleanValue() ? 1 : 0; + } + } + // + // return Integer.valueOf + // } else if (this==TypeCode.BOOLEAN) { + // return new Boolean(left).intValue(); + return null; + } + + public static TypeCode forValue(Number op1) { + return forClass(op1.getClass()); + } + + public boolean isDouble() { + return this == DOUBLE; + } + + public boolean isFloat() { + return this == FLOAT; + } + + public boolean isLong() { + return this == LONG; + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/Utils.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/Utils.java new file mode 100644 index 00000000000..3df8695398c --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/Utils.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +/** + * Utility methods (formatters, etc) used during parsing and evaluation. + * + * @author Andy Clement + */ +public class Utils { + + /** + * Produce a nice string for a given method name with specified arguments. + * + * @param name the name of the method + * @param argumentTypes the types of the arguments to the method + * @return nicely formatted string, eg. foo(String,int) + */ + public static String formatMethodForMessage(String name, Class... argumentTypes) { + StringBuilder sb = new StringBuilder(); + sb.append(name); + sb.append("("); + if (argumentTypes != null) { + for (int i = 0; i < argumentTypes.length; i++) { + if (i > 0) + sb.append(","); + sb.append(argumentTypes[i].getName()); + } + } + sb.append(")"); + return sb.toString(); + } + + /** + * Produce a nice string for a given class object. For example a string array will have the formatted name + * "java.lang.String[]". + * + * @param clazz The class whose name is to be formatted + * @return a formatted string suitable for message inclusion + */ + public static String formatClassnameForMessage(Class clazz) { + if (clazz==null) { + return "null"; + } + StringBuilder fmtd = new StringBuilder(); + if (clazz.isArray()) { + int dims = 1; + Class baseClass = clazz.getComponentType(); + while (baseClass.isArray()) { + baseClass = baseClass.getComponentType(); + dims++; + } + fmtd.append(baseClass.getName()); + for (int i = 0; i < dims; i++) { + fmtd.append("[]"); + } + } else { + fmtd.append(clazz.getName()); + } + return fmtd.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/VariableScope.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/VariableScope.java new file mode 100644 index 00000000000..957f2b30c00 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/VariableScope.java @@ -0,0 +1,57 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import java.util.HashMap; +import java.util.Map; + +/** + * A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names + * of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst + * the function is executing. When the function returns the scope is exited. + * + * @author Andy Clement + * + */ +public class VariableScope { + + private final Map vars = new HashMap(); + + public VariableScope() { } + + public VariableScope(Map arguments) { + if (arguments!=null) { + vars.putAll(arguments); + } + } + + public VariableScope(String name,Object value) { + vars.put(name,value); + } + + public Object lookupVariable(String name) { + return vars.get(name); + } + + public void setVariable(String name, Object value) { + vars.put(name,value); + } + + public boolean definesVariable(String name) { + return vars.containsKey(name); + } + +} \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/WrappedExpressionException.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/WrappedExpressionException.java new file mode 100644 index 00000000000..6f0dac55b17 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/internal/WrappedExpressionException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.internal; + +import org.springframework.expression.spel.SpelException; + +/** + * Wraps an ELException and can pass up through Antlr since it is unchecked, where it can then be unwrapped. + * + * @author Andy Clement + */ +public class WrappedExpressionException extends RuntimeException { + + WrappedExpressionException(SpelException e) { + super(e); + } + + @Override + public SpelException getCause() { + return (SpelException) super.getCause(); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/AverageProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/AverageProcessor.java new file mode 100644 index 00000000000..3a4009cc5da --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/AverageProcessor.java @@ -0,0 +1,57 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.Collection; + +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +// TODO 3 does it return an element consistent with input? (an int if input is ints, even though the average may be +// X.Y?) yes, for now +/** + * The AverageProcessor operates upon an input collection and computes the average value of the elements within it. It + * will currently only operate upon Numbers and its return value type is an Integer if the input values were integers, + * otherwise it is a double. + */ +public class AverageProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws SpelException { + // TypeUtilities typeUtilities = state.getTypeUtilities(); + boolean allIntegerObjects = true; + int total = 0; + int numberOfElements = 0; + for (Object element : input) { + if (element != null) { + if (element instanceof Number) { + allIntegerObjects = allIntegerObjects + && (element.getClass() == Integer.class || element.getClass() == Integer.TYPE); + total = total + ((Number) element).intValue(); + numberOfElements++; + } else { + throw new SpelException(SpelMessages.TYPE_NOT_SUPPORTED_BY_PROCESSOR, "average", element.getClass()); + } + } + } + int result = total / numberOfElements; + // if (allIntegerObjects) { + // return new Integer(((Number) result).intValue()); + // } else { + return result; + // } + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CountProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CountProcessor.java new file mode 100644 index 00000000000..c8cf2b39ab3 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CountProcessor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.Collection; + +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * The count processor returns an Integer value representing the number of elements in the collection. + * + * @author Andy Clement + * + */ +public class CountProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws SpelException { + return input.size(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CutProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CutProcessor.java new file mode 100644 index 00000000000..9fb96373f78 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/CutProcessor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; +import org.springframework.expression.spel.ExpressionState; + +public class CutProcessor implements DataProcessor { + + /** Cut a piece out of a collection - the arguments are from (inclusive) to (exclusive) */ + public Object process(Collection input, Object[] arguments, ExpressionState state) throws SpelException { + if (!(arguments[0] instanceof Integer && arguments[1] instanceof Integer)) { + throw new SpelException(SpelMessages.CUT_ARGUMENTS_MUST_BE_INTS, arguments[0].getClass().getName(), + arguments[1].getClass().getName()); + } + int first = ((Integer) arguments[0]).intValue(); + int last = ((Integer) arguments[1]).intValue(); + List result = new ArrayList(); + int pos = 0; + if (first < last) { + for (Object o : input) { + if (pos >= first && pos <= last) + result.add(o); + pos++; + } + } else { + for (Object o : input) { + if (pos >= last && pos <= first) + result.add(0, o); + pos++; + } + } + return result; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DataProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DataProcessor.java new file mode 100644 index 00000000000..e4380cdfa87 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DataProcessor.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.Collection; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.ExpressionState; + +/** + * A Data processor takes as input: a collection, an optional set of arguments that configure its behaviour, an + * evaluation context. It returns the result of processing the collection which might be as simple as adding up its + * elements or returning a subset of the non null elements. + * + * @author Andy Clement + * + */ +public interface DataProcessor { + + Object process(Collection input, Object[] arguments, ExpressionState state) throws EvaluationException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DistinctProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DistinctProcessor.java new file mode 100644 index 00000000000..46a961f6a72 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/DistinctProcessor.java @@ -0,0 +1,43 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * The DistinctProcessor returns a new collection containing that is similar to the input collection but with all + * duplicate entries removed. + * + * @author Andy Clement + * + */ +public class DistinctProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws SpelException { + List result = new ArrayList(); + for (Object o : input) { + if (!result.contains(o)) + result.add(o); + } + return result; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MaxProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MaxProcessor.java new file mode 100644 index 00000000000..7ef8e040361 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MaxProcessor.java @@ -0,0 +1,47 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.Collection; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.spel.ExpressionState; + +/** + * The Max Processor returns the maximum element in the input collection, the maximum is determined using the comparator + * accessible in the evaluation context. + * + * @author Andy Clement + * + */ +public class MaxProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws EvaluationException { + Object max = null; + TypeComparator comparator = state.getTypeComparator(); + for (Object element : input) { + if (max == null) { + max = element; + } else { + if (comparator.compare(element, max) > 0) + max = element; + } + } + return max; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MinProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MinProcessor.java new file mode 100644 index 00000000000..a95319d4d79 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/MinProcessor.java @@ -0,0 +1,47 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.Collection; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.spel.ExpressionState; + +/** + * The Min Processor returns the minimum element in the input collection, the minimum is determined using the comparator + * accessible in the evaluation context. + * + * @author Andy Clement + * + */ +public class MinProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws EvaluationException { + Object minimum = null; + TypeComparator elementComparator = state.getTypeComparator(); + for (Object element : input) { + if (minimum == null) { + minimum = element; + } else { + if (elementComparator.compare(element, minimum) < 0) + minimum = element; + } + } + return minimum; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/NonNullProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/NonNullProcessor.java new file mode 100644 index 00000000000..c3a1c951d0b --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/NonNullProcessor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.ExpressionState; + +/** + * The NonNull Processor returns a new collection containing all non-null entries from the input collection. + * + * @author Andy Clement + * + */ +public class NonNullProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws SpelException { + List l = new ArrayList(); + for (Object o : input) { + if (o != null) + l.add(o); + } + return l; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/SortProcessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/SortProcessor.java new file mode 100644 index 00000000000..e572de1470e --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/SortProcessor.java @@ -0,0 +1,66 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.processors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.spel.ExpressionState; + +/** + * The Sort Processor will sort an input collection, comparing elements using the comparator accessible in the + * evaluation context. + * + * @author Andy Clement + * + */ +@SuppressWarnings("unchecked") +public class SortProcessor implements DataProcessor { + + public Object process(Collection input, Object[] arguments, ExpressionState state) throws EvaluationException { + List sortedCollection = new ArrayList(); + sortedCollection.addAll(input); + LocalComparator comparator = new LocalComparator(state.getTypeComparator()); + Collections.sort(sortedCollection, comparator); + if (comparator.exceptionOccurred != null) + throw comparator.exceptionOccurred; + return sortedCollection; + } + + private static class LocalComparator implements java.util.Comparator { + TypeComparator comparator; + EvaluationException exceptionOccurred; + + public LocalComparator(TypeComparator comparator) { + this.comparator = comparator; + } + + public int compare(Object o1, Object o2) { + try { + return comparator.compare(o1, o2); + } catch (EvaluationException e) { + exceptionOccurred = e; + return 0; + } + } + + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/package.html b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/package.html new file mode 100644 index 00000000000..4a5cdfae083 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/processors/package.html @@ -0,0 +1,14 @@ + + +

+Contains the registered collection processors available 'out of the box' with Spring +Expression Language. They are:

    +
  • sort() - sorts a collection +
  • nonnull() - returns a new collection containing the non-null elements from the input collection +
  • count() - returns the number of elements in the collection +
  • min() - returns the minimum element from the input collection +
  • max() - returns the maximum element from the input collection +
  • distinct() - returns a new collection where duplicates from the input collection have been removed +

    + + \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorExecutor.java new file mode 100644 index 00000000000..b84ce01f49f --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorExecutor.java @@ -0,0 +1,68 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import org.springframework.expression.AccessException; +import org.springframework.expression.ConstructorExecutor; +import org.springframework.expression.EvaluationContext; + +/** + * A simple CommandExecutor implementation that runs a constructor using reflective invocation. + * + * @author Andy Clement + */ +public class ReflectionConstructorExecutor implements ConstructorExecutor { + + private final Constructor c; + + // When the constructor was found, we will have determined if arguments need to be converted for it + // to be invoked. Conversion won't be cheap so let's only do it if necessary. + private final Integer[] argsRequiringConversion; + + public ReflectionConstructorExecutor(Constructor constructor, Integer[] argsRequiringConversion) { + this.c = constructor; + this.argsRequiringConversion = argsRequiringConversion; + } + + /** + * Invoke a constructor via reflection. + */ + public Object execute(EvaluationContext context, Object... arguments) throws AccessException { + if (argsRequiringConversion != null && arguments != null) { + ReflectionUtils.convertArguments(c.getParameterTypes(), c.isVarArgs(), context.getTypeUtils().getTypeConverter(), argsRequiringConversion, arguments); + } + if (c.isVarArgs()) { + arguments = ReflectionUtils.setupArgumentsForVarargsInvocation(c.getParameterTypes(),arguments); + } + try { + if (!c.isAccessible()) { + c.setAccessible(true); + } + return c.newInstance(arguments); + } catch (IllegalArgumentException e) { + throw new AccessException("Problem invoking constructor on '" + c + "' : " + e.getMessage(), e); + } catch (InstantiationException e) { + throw new AccessException("Problem invoking constructor on '" + c + "' : " + e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new AccessException("Problem invoking constructor on '" + c + "' : " + e.getMessage(), e); + } catch (InvocationTargetException e) { + throw new AccessException("Problem invoking constructor on '" + c + "' : " + e.getMessage(), e); + } + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorResolver.java new file mode 100644 index 00000000000..c96b4a4eeb9 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionConstructorResolver.java @@ -0,0 +1,66 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import org.springframework.expression.AccessException; +import org.springframework.expression.ConstructorExecutor; +import org.springframework.expression.ConstructorResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.reflection.ReflectionUtils.DiscoveredConstructor; + +/** + * A constructor resolver that uses reflection to locate the constructor that should be invoked + * + * @author Andy Clement + */ +public class ReflectionConstructorResolver implements ConstructorResolver { + + /* + * Indicates if this resolve will allow matches to be found that require some of the input arguments to be + * transformed by the conversion service. + */ + private boolean allowMatchesRequiringArgumentConversion = true; + + public ReflectionConstructorResolver() { + } + + public ReflectionConstructorResolver(boolean allowMatchesRequiringArgumentConversion) { + this.allowMatchesRequiringArgumentConversion = allowMatchesRequiringArgumentConversion; + } + + public void setAllowMatchRequiringArgumentConversion(boolean allow) { + this.allowMatchesRequiringArgumentConversion = allow; + } + + /** + * Locate a matching constructor or return null if non can be found. + */ + public ConstructorExecutor resolve(EvaluationContext context, String typename, Class[] argumentTypes) + throws AccessException { + try { + Class c = context.getTypeUtils().getTypeLocator().findType(typename); + DiscoveredConstructor dCtor = ReflectionUtils.findConstructor(context.getTypeUtils().getTypeConverter(), c, + argumentTypes, allowMatchesRequiringArgumentConversion); + if (dCtor == null) { + return null; + } + return new ReflectionConstructorExecutor(dCtor.theConstructor, dCtor.argumentsRequiringConversion); + } catch (EvaluationException e) { + throw new AccessException(null,e); + } + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodExecutor.java new file mode 100644 index 00000000000..39c7a3c970a --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodExecutor.java @@ -0,0 +1,64 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.MethodExecutor; + +public class ReflectionMethodExecutor implements MethodExecutor { + + private final Method m; + + // When the method was found, we will have determined if arguments need to be converted for it + // to be invoked. Conversion won't be cheap so let's only do it if necessary. + private final Integer[] argsRequiringConversion; + + public ReflectionMethodExecutor(Method theMethod, Integer[] argumentsRequiringConversion) { + this.m = theMethod; + this.argsRequiringConversion = argumentsRequiringConversion; + } + + + public Object execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { + if (argsRequiringConversion != null && arguments != null) { + ReflectionUtils.convertArguments(m.getParameterTypes(),m.isVarArgs(),context.getTypeUtils().getTypeConverter(), argsRequiringConversion, arguments); + } + if (m.isVarArgs()) { + arguments = ReflectionUtils.setupArgumentsForVarargsInvocation(m.getParameterTypes(),arguments); + } + try { + if (!m.isAccessible()) { + m.setAccessible(true); + } + return m.invoke(target, arguments); + } catch (IllegalArgumentException e) { + throw new AccessException("Problem invoking method '" + m.getName() + "' on '" + target.getClass() + "': " + + e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new AccessException("Problem invoking method '" + m.getName() + "' on '" + target.getClass() + "': " + + e.getMessage(), e); + } catch (InvocationTargetException e) { + e.getCause().printStackTrace(); + throw new AccessException("Problem invoking method '" + m.getName() + "' on '" + target.getClass() + "': " + + e.getMessage(), e); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodResolver.java new file mode 100644 index 00000000000..572a1b97e02 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionMethodResolver.java @@ -0,0 +1,63 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.MethodExecutor; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.spel.reflection.ReflectionUtils.DiscoveredMethod; + +/** + * A method resolver that uses reflection to locate the method that should be invoked + * + * @author Andy Clement + */ +public class ReflectionMethodResolver implements MethodResolver { + + /* + * Indicates if this resolve will allow matches to be found that require some of the input arguments to be + * transformed by the conversion service. + */ + private boolean allowMatchesRequiringArgumentConversion = true; + + public ReflectionMethodResolver() { + } + + public ReflectionMethodResolver(boolean allowMatchesRequiringArgumentConversion) { + this.allowMatchesRequiringArgumentConversion = allowMatchesRequiringArgumentConversion; + } + + public void setAllowMatchRequiringArgumentConversion(boolean allow) { + this.allowMatchesRequiringArgumentConversion = allow; + } + + public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, Class[] argumentTypes) throws AccessException { + try { + Class relevantClass = (targetObject instanceof Class ? (Class) targetObject : targetObject.getClass()); + DiscoveredMethod dMethod = ReflectionUtils.findMethod(context.getTypeUtils().getTypeConverter(), name, + argumentTypes, relevantClass, allowMatchesRequiringArgumentConversion); + if (dMethod == null) { + return null; + } + return new ReflectionMethodExecutor(dMethod.theMethod, dMethod.argumentsRequiringConversion); + } catch (EvaluationException e) { + throw new AccessException(null,e); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutor.java new file mode 100644 index 00000000000..efc3519a05a --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutor.java @@ -0,0 +1,56 @@ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyReaderExecutor; + +public class ReflectionPropertyReaderExecutor implements PropertyReaderExecutor { + + private Method methodToAccessProperty; + private Field fieldToAccessProperty; + private String propertyName; + + public ReflectionPropertyReaderExecutor(String propertyName, Method method) { + this.propertyName = propertyName; + this.methodToAccessProperty = method; + } + + public ReflectionPropertyReaderExecutor(String propertyName, Field field) { + this.propertyName = propertyName; + this.fieldToAccessProperty = field; + } + + public Object execute(EvaluationContext context, Object target) throws AccessException { + if (fieldToAccessProperty != null) { + try { + if (!fieldToAccessProperty.isAccessible()) { + fieldToAccessProperty.setAccessible(true); + } + return fieldToAccessProperty.get(target); + } catch (IllegalArgumentException e) { + throw new AccessException("Unable to access field: " + propertyName, e); + } catch (IllegalAccessException e) { + throw new AccessException("Unable to access field: " + propertyName, e); + } + } + if (methodToAccessProperty != null) { + try { + if (!methodToAccessProperty.isAccessible()) + methodToAccessProperty.setAccessible(true); + return methodToAccessProperty.invoke(target); + } catch (IllegalArgumentException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through getter", e); + } catch (IllegalAccessException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through getter", e); + } catch (InvocationTargetException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through getter", e); + } + } + throw new AccessException("No method or field accessor found for property '" + propertyName + "'"); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutorForArrayLength.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutorForArrayLength.java new file mode 100644 index 00000000000..ade80cc4058 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyReaderExecutorForArrayLength.java @@ -0,0 +1,21 @@ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Array; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyReaderExecutor; + +public class ReflectionPropertyReaderExecutorForArrayLength implements PropertyReaderExecutor { + + public ReflectionPropertyReaderExecutorForArrayLength() { + } + + public Object execute(EvaluationContext context, Object target) throws AccessException { + if (target.getClass().isArray()) { + return Array.getLength(target); + } + throw new AccessException("Cannot determine length of a non-array type '" + target.getClass() + "'"); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyResolver.java new file mode 100644 index 00000000000..8ab657694e8 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyResolver.java @@ -0,0 +1,202 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.springframework.expression.CacheablePropertyAccessor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyReaderExecutor; +import org.springframework.expression.PropertyWriterExecutor; + +/** + * Simple PropertyResolver that uses reflection to access properties for reading and writing. A property can be accessed + * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). + * + * @author Andy Clement + */ +public class ReflectionPropertyResolver extends CacheablePropertyAccessor { + + public static boolean useResolverExecutorModel = true; + + public boolean supportsResolverExecutorModel() { + return useResolverExecutorModel; + } + + public PropertyReaderExecutor getReaderAccessor(EvaluationContext relatedContext, Object target, Object name) { + if (target==null) { + return null; + } + Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); + if (!(name instanceof String)) { + return null; // TODO should raise an exception when the property-name is not a String? + } + String propertyName = (String) name; + if (relevantClass.isArray() && propertyName.equals("length")) { + return new ReflectionPropertyReaderExecutorForArrayLength(); + } + Field field = ReflectionUtils.findField(propertyName, relevantClass); + if (field != null) { + return new ReflectionPropertyReaderExecutor(propertyName, field); + } + Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass); + if (m != null) { + return new ReflectionPropertyReaderExecutor(propertyName, m); + } + return null; + } + + public PropertyWriterExecutor getWriterAccessor(EvaluationContext context, Object target, Object name) { + if (target==null) { + return null; + } + Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); + if (!(name instanceof String)) { + return null; + } + Field field = ReflectionUtils.findField((String) name, relevantClass); + if (field != null) { + return new ReflectionPropertyWriterExecutor((String) name, field); + } + Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass); + if (m != null) { + return new ReflectionPropertyWriterExecutor((String) name, m); + } + return null; + } + + /** + * Return true if the resolver is able to read the specified property from the specified target. + */ +// public boolean canRead(EvaluationContext relatedContext, Object target, Object name) throws AccessException { +// if (target==null) { +// return false; +// } +// Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); +// if (!(name instanceof String)) { +// return false; // TODO should raise an exception when the property-name is not a String? +// } +// String propertyName = (String) name; +// Field field = ReflectionUtils.findField(propertyName, relevantClass); +// if (field != null) { +// return true; +// } +// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass); +// if (m != null) { +// return true; +// } +// return false; +// } + + /** + * Read the specified property from the specified target. +// */ +// public Object read(EvaluationContext context, Object target, Object name) throws AccessException { +// if (target==null) { +// return null; +// } +// Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); +// if (!(name instanceof String)) { +// return null; // TODO should raise an exception if the property cannot be found? +// } +// String propertyName = (String) name; +// Field field = ReflectionUtils.findField(propertyName, relevantClass); +// if (field != null) { +// try { +// if (!field.isAccessible()) { +// field.setAccessible(true); +// } +// return field.get(target); +// } catch (IllegalArgumentException e) { +// throw new AccessException("Unable to access field: " + name, e); +// } catch (IllegalAccessException e) { +// throw new AccessException("Unable to access field: " + name, e); +// } +// } +// Method m = ReflectionUtils.findGetterForProperty(propertyName, relevantClass); +// if (m != null) { +// try { +// if (!m.isAccessible()) +// m.setAccessible(true); +// return m.invoke(target); +// } catch (IllegalArgumentException e) { +// throw new AccessException("Unable to access property '" + name + "' through getter", e); +// } catch (IllegalAccessException e) { +// throw new AccessException("Unable to access property '" + name + "' through getter", e); +// } catch (InvocationTargetException e) { +// throw new AccessException("Unable to access property '" + name + "' through getter", e); +// } +// } +// return null; +// } + +// public void write(EvaluationContext context, Object target, Object name, Object newValue) throws AccessException { +// if (target==null) { +// return; +// } +// Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); +// if (!(name instanceof String)) +// return; +// Field field = ReflectionUtils.findField((String) name, relevantClass); +// if (field != null) { +// try { +// if (!field.isAccessible()) +// field.setAccessible(true); +// field.set(target, newValue); +// } catch (IllegalArgumentException e) { +// throw new AccessException("Unable to write to property '" + name + "'", e); +// } catch (IllegalAccessException e) { +// throw new AccessException("Unable to write to property '" + name + "'", e); +// } +// } +// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass); +// if (m != null) { +// try { +// if (!m.isAccessible()) +// m.setAccessible(true); +// m.invoke(target, newValue); +// } catch (IllegalArgumentException e) { +// throw new AccessException("Unable to access property '" + name + "' through setter", e); +// } catch (IllegalAccessException e) { +// throw new AccessException("Unable to access property '" + name + "' through setter", e); +// } catch (InvocationTargetException e) { +// throw new AccessException("Unable to access property '" + name + "' through setter", e); +// } +// } +// } + + public Class[] getSpecificTargetClasses() { + return null; // this is a general purpose resolver that will try to access properties on any type! + } + +// public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException { +// if (target==null) { +// return false; +// } +// Class relevantClass = (target instanceof Class ? (Class) target : target.getClass()); +// if (!(name instanceof String)) +// return false; +// Field field = ReflectionUtils.findField((String) name, relevantClass); +// if (field != null) +// return true; +// Method m = ReflectionUtils.findSetterForProperty((String) name, relevantClass); +// if (m != null) +// return true; +// return false; +// } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyWriterExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyWriterExecutor.java new file mode 100644 index 00000000000..81fb014a40b --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionPropertyWriterExecutor.java @@ -0,0 +1,58 @@ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyWriterExecutor; + +public class ReflectionPropertyWriterExecutor implements PropertyWriterExecutor { + + private Method methodToAccessProperty; + private Field fieldToAccessProperty; + private String propertyName; + + public ReflectionPropertyWriterExecutor(String propertyName, Method method) { + this.propertyName = propertyName; + this.methodToAccessProperty = method; + } + + public ReflectionPropertyWriterExecutor(String propertyName, Field field) { + this.propertyName = propertyName; + this.fieldToAccessProperty = field; + } + + // public Object execute(EvaluationContext context, Object target) throws AccessException { + public void execute(EvaluationContext evaluationContext, Object target, Object newValue) throws AccessException { + if (fieldToAccessProperty != null) { + try { + if (!fieldToAccessProperty.isAccessible()) { + fieldToAccessProperty.setAccessible(true); + } + fieldToAccessProperty.set(target, newValue); + return; + } catch (IllegalArgumentException e) { + throw new AccessException("Unable to access field: " + propertyName, e); + } catch (IllegalAccessException e) { + throw new AccessException("Unable to access field: " + propertyName, e); + } + } + if (methodToAccessProperty != null) { + try { + if (!methodToAccessProperty.isAccessible()) + methodToAccessProperty.setAccessible(true); + methodToAccessProperty.invoke(target, newValue); + return; + } catch (IllegalArgumentException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through setter", e); + } catch (IllegalAccessException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through setter", e); + } catch (InvocationTargetException e) { + throw new AccessException("Unable to access property '" + propertyName + "' through setter", e); + } + } + throw new AccessException("No method or field accessor found for property '" + propertyName + "'"); + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionUtils.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionUtils.java new file mode 100644 index 00000000000..1304f94c6cf --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/reflection/ReflectionUtils.java @@ -0,0 +1,612 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.reflection; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; + +/** + * Utility methods used by the reflection resolver code to discover the correct methods/constructors and fields that + * should be used in expressions. + * + * @author Andy Clement + * + */ +@SuppressWarnings("unchecked") +public class ReflectionUtils { + + /** + * Locate a constructor on a type. There are three kinds of match that might occur: + *
      + *
    1. An exact match where the types of the arguments match the types of the constructor + *
    2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor + *
    3. A match where we are able to convert the arguments into those expected by the constructor, according to the + * registered type converter. + *
    + * + * @param typeConverter a converter that can be used to determine if the supplied arguments can be converted to + * expected arguments + * @param type the type being searched for a valid constructor + * @param argumentTypes the types of the arguments we want the constructor to have + * @return a DiscoveredConstructor object or null if non found + * @throws SpelException + */ + public static DiscoveredMethod findMethod(TypeConverter typeConverter, String name, Class[] argumentTypes, + Class type, boolean conversionAllowed) throws SpelException { + Method[] methods = type.getMethods(); + Method closeMatch = null; + Integer[] argsToConvert = null; + boolean multipleOptions = false; + Method matchRequiringConversion = null; + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + if (method.isBridge()) { + continue; + } + if (method.getName().equals(name)) { + ArgumentsMatchInfo matchInfo = null; + if (method.isVarArgs() && argumentTypes.length>=(method.getParameterTypes().length-1)) { + // *sigh* complicated + matchInfo = compareArgumentsVarargs(method.getParameterTypes(), argumentTypes, typeConverter, conversionAllowed); + } else if (method.getParameterTypes().length == argumentTypes.length) { + // name and parameter number match, check the arguments + matchInfo = compareArguments(method.getParameterTypes(), argumentTypes, typeConverter, conversionAllowed); + } + if (matchInfo != null) { + if (matchInfo.kind == ArgsMatchKind.EXACT) { + return new DiscoveredMethod(method, null); + } else if (matchInfo.kind == ArgsMatchKind.CLOSE) { + if (matchRequiringConversion!=null) { + int stop = 1; + } + closeMatch = method; + } else if (matchInfo.kind == ArgsMatchKind.REQUIRES_CONVERSION) { + if (matchRequiringConversion!=null) { + multipleOptions = true; + } + argsToConvert = matchInfo.argsRequiringConversion; + matchRequiringConversion = method; + } + } + } + } + if (closeMatch != null) { + return new DiscoveredMethod(closeMatch, null); + } else if (matchRequiringConversion != null) { + if (multipleOptions) { + throw new SpelException(SpelMessages.MULTIPLE_POSSIBLE_METHODS,name); + } + return new DiscoveredMethod(matchRequiringConversion, argsToConvert); + } else { + return null; + } + } + + /** + * Locate a constructor on the type. There are three kinds of match that might occur: + *
      + *
    1. An exact match where the types of the arguments match the types of the constructor + *
    2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor + *
    3. A match where we are able to convert the arguments into those expected by the constructor, according to the + * registered type converter. + *
    + * + * @param typeConverter a converter that can be used to determine if the supplied arguments can be converted to + * expected arguments + * @param type the type being searched for a valid constructor + * @param argumentTypes the types of the arguments we want the constructor to have + * @return a DiscoveredConstructor object or null if non found + */ + public static DiscoveredConstructor findConstructor(TypeConverter typeConverter, Class type, + Class[] argumentTypes, boolean conversionAllowed) { + Constructor[] ctors = type.getConstructors(); + Constructor closeMatch = null; + Integer[] argsToConvert = null; + Constructor matchRequiringConversion = null; + for (int i = 0; i < ctors.length; i++) { + Constructor ctor = ctors[i]; + if (ctor.isVarArgs() && argumentTypes.length>=(ctor.getParameterTypes().length-1)) { + // *sigh* complicated + // Basically.. we have to have all parameters match up until the varargs one, then the rest of what is being provided should be + // the same type whilst the final argument to the method must be an array of that (oh, how easy...not) - or the final parameter + // we are supplied does match exactly (it is an array already). + ArgumentsMatchInfo matchInfo = compareArgumentsVarargs(ctor.getParameterTypes(), argumentTypes, typeConverter, conversionAllowed); + if (matchInfo != null) { + if (matchInfo.kind == ArgsMatchKind.EXACT) { + return new DiscoveredConstructor(ctor, null); + } else if (matchInfo.kind == ArgsMatchKind.CLOSE) { + closeMatch = ctor; + } else if (matchInfo.kind == ArgsMatchKind.REQUIRES_CONVERSION) { + argsToConvert = matchInfo.argsRequiringConversion; + matchRequiringConversion = ctor; + } + } + + } else if (ctor.getParameterTypes().length == argumentTypes.length) { + // worth a closer look + ArgumentsMatchInfo matchInfo = compareArguments(ctor.getParameterTypes(), argumentTypes, typeConverter, + conversionAllowed); + if (matchInfo != null) { + if (matchInfo.kind == ArgsMatchKind.EXACT) { + return new DiscoveredConstructor(ctor, null); + } else if (matchInfo.kind == ArgsMatchKind.CLOSE) { + closeMatch = ctor; + } else if (matchInfo.kind == ArgsMatchKind.REQUIRES_CONVERSION) { + argsToConvert = matchInfo.argsRequiringConversion; + matchRequiringConversion = ctor; + } + } + } + } + if (closeMatch != null) { + return new DiscoveredConstructor(closeMatch, null); + } else if (matchRequiringConversion != null) { + return new DiscoveredConstructor(matchRequiringConversion, argsToConvert); + } else { + return null; + } + } + + /** + * Compare argument arrays and return information about whether they match. A supplied type converter and + * conversionAllowed flag allow for matches to take into account that a type may be transformed into a different + * type by the converter. + * + * @param expectedArgTypes the array of types the method/constructor is expecting + * @param suppliedArgTypes the array of types that are being supplied at the point of invocation + * @param typeConverter a registered type converter + * @param conversionAllowed if true then allow for what the type converter can do when seeing if a supplied type can + * match an expected type + * @return a MatchInfo object indicating what kind of match it was or null if it was not a match + */ + @SuppressWarnings("unchecked") + private static ArgumentsMatchInfo compareArguments(Class[] expectedArgTypes, Class[] suppliedArgTypes, + TypeConverter typeConverter, boolean conversionAllowed) { + ArgsMatchKind match = ArgsMatchKind.EXACT; + List argsRequiringConversion = null; + for (int i = 0; i < expectedArgTypes.length && match != null; i++) { + Class suppliedArg = suppliedArgTypes[i]; + Class expectedArg = expectedArgTypes[i]; + if (expectedArg != suppliedArg) { + if (expectedArg.isAssignableFrom(suppliedArg) || areBoxingCompatible(expectedArg, suppliedArg) + /* || isWidenableTo(expectedArg, suppliedArg) */) { + if (match != ArgsMatchKind.REQUIRES_CONVERSION) { + match = ArgsMatchKind.CLOSE; + } + } else if (typeConverter.canConvert(suppliedArg, expectedArg)) { + if (argsRequiringConversion == null) { + argsRequiringConversion = new ArrayList(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } else { + match = null; + } + } + } + if (match == null) { + return null; + } else { + if (match == ArgsMatchKind.REQUIRES_CONVERSION) { + return new ArgumentsMatchInfo(match, argsRequiringConversion.toArray(new Integer[] {})); + } else { + return new ArgumentsMatchInfo(match); + } + } + } + + /** + * Compare argument arrays and return information about whether they match. A supplied type converter and + * conversionAllowed flag allow for matches to take into account that a type may be transformed into a different + * type by the converter. This variant of compareArguments allows for a varargs match. + * + * @param expectedArgTypes the array of types the method/constructor is expecting + * @param suppliedArgTypes the array of types that are being supplied at the point of invocation + * @param typeConverter a registered type converter + * @param conversionAllowed if true then allow for what the type converter can do when seeing if a supplied type can + * match an expected type + * @return a MatchInfo object indicating what kind of match it was or null if it was not a match + */ + @SuppressWarnings("unchecked") + private static ArgumentsMatchInfo compareArgumentsVarargs(Class[] expectedArgTypes, Class[] suppliedArgTypes, TypeConverter typeConverter, boolean conversionAllowed) { + ArgsMatchKind match = ArgsMatchKind.EXACT; + List argsRequiringConversion = null; + + // Check up until the varargs argument: + + // Deal with the arguments up to 'expected number' - 1 + for (int i = 0; i < expectedArgTypes.length - 1 && match != null; i++) { + Class suppliedArg = suppliedArgTypes[i]; + Class expectedArg = expectedArgTypes[i]; + if (expectedArg != suppliedArg) { + if (expectedArg.isAssignableFrom(suppliedArg) || areBoxingCompatible(expectedArg, suppliedArg) + /* || isWidenableTo(expectedArg, suppliedArg) */) { + if (match != ArgsMatchKind.REQUIRES_CONVERSION) { + match = ArgsMatchKind.CLOSE; + } + } else if (typeConverter.canConvert(suppliedArg, expectedArg)) { + if (argsRequiringConversion == null) { + argsRequiringConversion = new ArrayList(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } else { + match = null; + } + } + } + // Already does not match + if (match == null) { + return null; + } + + // Special case: there is one parameter left and it is an array and it matches the varargs expected argument - that is a match, the caller has already built the array + if (suppliedArgTypes.length==expectedArgTypes.length && expectedArgTypes[expectedArgTypes.length-1]==suppliedArgTypes[suppliedArgTypes.length-1]) { + + } else { + + + // Now... we have the final argument in the method we are checking as a match and we have 0 or more other arguments left to pass to it. + Class varargsParameterType = expectedArgTypes[expectedArgTypes.length-1].getComponentType(); + + // All remaining parameters must be of this type or convertable to this type + for (int i=expectedArgTypes.length-1;i(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } else { + match = null; + } + } + } + } + + if (match == null) { + return null; + } else { + if (match == ArgsMatchKind.REQUIRES_CONVERSION) { + return new ArgumentsMatchInfo(match, argsRequiringConversion.toArray(new Integer[] {})); + } else { + return new ArgumentsMatchInfo(match); + } + } + } + + private static boolean isDouble(Class c) { + return c == Double.class || c == Double.TYPE; + } + + private static boolean isFloat(Class c) { + return c == Float.class || c == Float.TYPE; + } + + private static boolean isLong(Class c) { + return c == Long.class || c == Long.TYPE; + } + + private static boolean isInt(Class c) { + return c == Integer.class || c == Integer.TYPE; + } + + private static boolean isChar(Class c) { + return c == Character.class || c == Character.TYPE; + } + + private static boolean isShort(Class c) { + return c == Short.class || c == Short.TYPE; + } + + private static boolean isByte(Class c) { + return c == Byte.class || c == Byte.TYPE; + } + + /** + * Returns true if the input-type can be 'widened' to the target-type, according to the following allowed widenings: + * + * byte to short, int, long, float, or double
    + * short to int, long, float, or double
    + * char to int, long, float, or double
    + * int to long, float, or double
    + * long to float or double
    + * float to double + */ + private static boolean isWidenableTo(Class targetType, Class inputType) { + if (inputType.isPrimitive()) { + if (inputType == Double.TYPE) { + return (isDouble(targetType)); + } else if (inputType == Long.TYPE) { + return (isDouble(targetType) || isFloat(targetType)); + } else if (inputType == Integer.TYPE) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType); + } else if (inputType == Character.TYPE) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType); + } else if (inputType == Short.TYPE) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType); + } else if (inputType == Byte.TYPE) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType) + || isShort(targetType); + } + } else { + if (inputType == Double.class) { + return (isDouble(targetType)); + } else if (inputType == Long.class) { + return (isDouble(targetType) || isFloat(targetType)); + } else if (inputType == Integer.class) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType); + } else if (inputType == Character.class) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType); + } else if (inputType == Short.class) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType); + } else if (inputType == Byte.class) { + return isDouble(targetType) || isFloat(targetType) || isLong(targetType) || isInt(targetType) + || isShort(targetType); + } + } + return false; + } + + // TODO optimize impl + private static boolean areBoxingCompatible(Class class1, Class class2) { + if (class1 == Integer.class && class2 == Integer.TYPE) + return true; + if (class1 == Float.class && class2 == Float.TYPE) + return true; + if (class1 == Double.class && class2 == Double.TYPE) + return true; + if (class1 == Short.class && class2 == Short.TYPE) + return true; + if (class1 == Long.class && class2 == Long.TYPE) + return true; + if (class1 == Boolean.class && class2 == Boolean.TYPE) + return true; + if (class1 == Character.class && class2 == Character.TYPE) + return true; + if (class1 == Byte.class && class2 == Byte.TYPE) + return true; + if (class2 == Integer.class && class1 == Integer.TYPE) + return true; + if (class2 == Float.class && class1 == Float.TYPE) + return true; + if (class2 == Double.class && class1 == Double.TYPE) + return true; + if (class2 == Short.class && class1 == Short.TYPE) + return true; + if (class2 == Long.class && class1 == Long.TYPE) + return true; + if (class2 == Boolean.class && class1 == Boolean.TYPE) + return true; + if (class2 == Character.class && class1 == Character.TYPE) + return true; + if (class2 == Byte.class && class1 == Byte.TYPE) + return true; + return false; + } + + /** + * Find a field of a certain name on a specified class + */ + public final static Field findField(String name, Class clazz) { + Field[] fields = clazz.getFields(); // TODO what about inherited fields? try getFields() too? + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.getName().equals(name)) { + return field; + } + } + return null; + } + + /** + * Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix + * 'get' and the rest of the name is the same as the property name (with the first character uppercased). + */ + public static Method findGetterForProperty(String propertyName, Class clazz) { + Method[] ms = clazz.getMethods(); + StringBuilder sb = new StringBuilder(); + sb.append("get").append(propertyName.substring(0, 1).toUpperCase()).append(propertyName.substring(1)); + String expectedGetterName = sb.toString(); + for (int i = 0; i < ms.length; i++) { + Method method = ms[i]; + if (method.getParameterTypes().length == 0 && method.getName().equals(expectedGetterName)) { + return method; + } + } + return null; + } + + /** + * Find a setter method for the specified property + */ + public static Method findSetterForProperty(String propertyName, Class clazz) { + Method[] ms = clazz.getMethods(); + StringBuilder sb = new StringBuilder(); + sb.append("set").append(propertyName.substring(0, 1).toUpperCase()).append(propertyName.substring(1)); + String setterName = sb.toString(); + for (int i = 0; i < ms.length; i++) { + Method method = ms[i]; + if (method.getParameterTypes().length == 1 && method.getName().equals(setterName)) { + return method; + } + } + return null; + } + + /** + * An instance of MatchInfo describes what kind of match was achieved between two sets of arguments - the set that a + * method/constructor is expecting and the set that are being supplied at the point of invocation. If the kind + * indicates that conversion is required for some of the arguments then the arguments that require conversion are + * listed in the argsRequiringConversion array. + * + */ + private static class ArgumentsMatchInfo { + ArgsMatchKind kind; + Integer[] argsRequiringConversion; + + ArgumentsMatchInfo(ArgsMatchKind kind, Integer[] integers) { + this.kind = kind; + this.argsRequiringConversion = integers; + } + + ArgumentsMatchInfo(ArgsMatchKind kind) { + this.kind = kind; + } + } + + private static enum ArgsMatchKind { + EXACT, CLOSE, REQUIRES_CONVERSION; + } + + /** + * When a match is found searching for a particular constructor, this object captures the constructor object and + * details of which arguments require conversion for the call to be allowed. + */ + public static class DiscoveredConstructor { + public Constructor theConstructor; + public Integer[] argumentsRequiringConversion; + + public DiscoveredConstructor(Constructor theConstructor, Integer[] argsToConvert) { + this.theConstructor = theConstructor; + this.argumentsRequiringConversion = argsToConvert; + } + } + + /** + * When a match is found searching for a particular method, this object captures the method object and details of + * which arguments require conversion for the call to be allowed. + */ + public static class DiscoveredMethod { + public Method theMethod; + public Integer[] argumentsRequiringConversion; + + public DiscoveredMethod(Method theMethod, Integer[] argsToConvert) { + this.theMethod = theMethod; + this.argumentsRequiringConversion = argsToConvert; + } + } + + static void convertArguments(Class[] parameterTypes,boolean isVarargs, TypeConverter converter ,Integer[] argsRequiringConversion, Object... arguments) throws AccessException { + Class varargsType = null; + if (isVarargs) { + varargsType = parameterTypes[parameterTypes.length-1].getComponentType(); + } + for (int i = 0; i < argsRequiringConversion.length; i++) { + int argPosition = argsRequiringConversion[i]; + Class targetType = null; + if (isVarargs && argPosition>=(parameterTypes.length-1)) { + targetType = varargsType; + } else { + targetType = parameterTypes[argPosition]; + } + try { + arguments[argPosition] = converter.convertValue(arguments[argPosition],targetType); + } catch (EvaluationException e) { + throw new AccessException("Converter failed to convert '" + arguments[argPosition] + " to type '" + + targetType + "'", e); + } + } + } + + static void convertArguments(Class[] parameterTypes,boolean isVarargs, TypeConverter converter , Object... arguments) throws AccessException { + Class varargsType = null; + if (isVarargs) { + varargsType = parameterTypes[parameterTypes.length-1].getComponentType(); + } + for (int i = 0; i < arguments.length; i++) { + Class targetType = null; + if (isVarargs && i>=(parameterTypes.length-1)) { + targetType = varargsType; + } else { + targetType = parameterTypes[i]; + } + try { + if (arguments[i]!=null && arguments[i].getClass()!=targetType) { + arguments[i] = converter.convertValue(arguments[i],targetType); + } + } catch (EvaluationException e) { + throw new AccessException("Converter failed to convert '" + arguments[i] + " to type '" + + targetType + "'", e); + } + } + } + + /** + * Package up the arguments so that they correctly match what is expected in parameterTypes. For example, if parameterTypes is (int, String[]) + * because the second parameter was declared String... then if arguments is [1,"a","b"] then it must be repackaged as [1,new String[]{"a","b"}] + * in order to match the expected parameterTypes. + * + * @param parameterTypes the types of the parameters for the invocation + * @param arguments the arguments to be setup ready for the invocation + * @return a repackaged array of arguments where any varargs setup has been done + */ + static Object[] setupArgumentsForVarargsInvocation(Class[] parameterTypes, Object... arguments) { + // Check if array already built for final argument + int nParams = parameterTypes.length; + int nArgs = arguments.length; + + // Check if repackaging is needed: + if (nParams!=arguments.length || parameterTypes[nParams-1]!=(arguments[nArgs-1]==null?null:arguments[nArgs-1].getClass())) { + int arraySize = 0; // zero size array if nothing to pass as the varargs parameter + if (arguments!=null && nArgs>=nParams) { + arraySize = nArgs-(nParams-1); + } + Object[] repackagedArguments = (Object[])Array.newInstance(parameterTypes[nParams-1].getComponentType(),arraySize); + + // Copy all but the varargs arguments + for (int i=0;i + * To resolved properties/methods/fields this context uses a reflection mechanism. + * + * @author Andy Clement + * + */ +public class StandardEvaluationContext implements EvaluationContext { + + private Object rootObject; + private StandardTypeUtilities typeUtils; + private final Map variables = new HashMap(); + private final List methodResolvers = new ArrayList(); + private final List constructorResolvers = new ArrayList(); + private final List propertyResolvers = new ArrayList(); + private final Map> simpleReferencesMap = new HashMap>(); + + public StandardEvaluationContext() { + typeUtils = new StandardTypeUtilities(); + addMethodResolver(new ReflectionMethodResolver()); + addConstructorResolver(new ReflectionConstructorResolver()); + addPropertyAccessor(new ReflectionPropertyResolver()); + } + + public StandardEvaluationContext(Object rootContextObject) { + this(); + this.rootObject = rootContextObject; + } + + public void setClassLoader(ClassLoader loader) { + TypeLocator tLocator = typeUtils.getTypeLocator(); + if (tLocator instanceof StandardTypeLocator) { + ((StandardTypeLocator) tLocator).setClassLoader(loader); + } + } + + public void registerImport(String importPrefix) { + TypeLocator tLocator = typeUtils.getTypeLocator(); + if (tLocator instanceof StandardTypeLocator) { + ((StandardTypeLocator) tLocator).registerImport(importPrefix); + } + } + + public void setClasspath(String classpath) { + StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator); + List urls = new ArrayList(); + while (st.hasMoreTokens()) { + String element = st.nextToken(); + try { + urls.add(new File(element).toURL()); + } catch (MalformedURLException e) { + throw new RuntimeException("Invalid element in classpath " + element); + } + } + ClassLoader cl = new URLClassLoader(urls.toArray(new URL[] {}), Thread.currentThread().getContextClassLoader()); + TypeLocator tLocator = typeUtils.getTypeLocator(); + if (tLocator instanceof StandardTypeLocator) { + ((StandardTypeLocator) tLocator).setClassLoader(cl); + } + } + + public Object lookupVariable(String name) { + return variables.get(name); + } + + public TypeUtils getTypeUtils() { + return typeUtils; + } + + public Object getRootContextObject() { + return rootObject; + } + + public Object lookupReference(Object contextName, Object objectName) { + String contextToLookup = (contextName == null ? "root" : (String) contextName); + // if (contextName==null) return simpleReferencesMap; + Map contextMap = simpleReferencesMap.get(contextToLookup); + if (contextMap == null) + return null; + if (objectName == null) + return contextMap; + return contextMap.get(objectName); + } + + public List getPropertyAccessors() { + return propertyResolvers; + } + + public void addPropertyAccessor(PropertyAccessor accessor) { + propertyResolvers.add(accessor); + } + + public void removePropertyAccessor(PropertyAccessor accessor) { + propertyResolvers.remove(accessor); + } + + public void insertPropertyAccessor(int position,PropertyAccessor accessor) { + propertyResolvers.add(position,accessor); + } + + + public List getMethodResolvers() { + return methodResolvers; + } + + public List getConstructorResolvers() { + return constructorResolvers; + } + + public void setVariable(String name, Object value) { + variables.put(name, value); + } + + public void registerFunction(String name, Method m) { + variables.put(name, m); + } + + public void setRootObject(Object o) { + this.rootObject = o; + } + + // TODO 3 have a variant that adds at position (same for ctor/propOrField) + public void addMethodResolver(MethodResolver resolver) { + methodResolvers.add(resolver); + } + + public void removeMethodResolver(MethodResolver resolver) { + methodResolvers.remove(resolver); + } + + public void insertMethodResolver(int pos, MethodResolver resolver) { + methodResolvers.add(pos, resolver); + } + + + public void addConstructorResolver(ConstructorResolver resolver) { + constructorResolvers.add(resolver); + } + + + public void addReference(String contextName, String objectName, Object value) { + Map contextMap = simpleReferencesMap.get(contextName); + if (contextMap == null) { + contextMap = new HashMap(); + simpleReferencesMap.put(contextName, contextMap); + } + contextMap.put(objectName, value); + } + + public void addTypeConverter(StandardIndividualTypeConverter newConverter) { + ((StandardTypeConverter)typeUtils.getTypeConverter()).registerConverter(newConverter); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardIndividualTypeConverter.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardIndividualTypeConverter.java new file mode 100644 index 00000000000..640411624e4 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardIndividualTypeConverter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2004-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.standard; + +import org.springframework.expression.EvaluationException; + +/** + * Implementations of this interface are able to convert from some set of types to another type. For + * example they might be able to convert some set of number types (Integer.class, Double.class) to + * a string (String.class). Once created they are registered with the {@link StandardEvaluationContext} or + * {@link StandardTypeConverter}. + * + * @author Andy Clement + */ +public interface StandardIndividualTypeConverter { + + /** + * @return return the set of classes which this converter can convert from. + */ + Class[] getFrom(); + + /** + * @return the class which this converter can convert to. + */ + Class getTo(); + + /** + * Return a value converted to the type that {@link #getTo()} specified. + * + * @param value the object to convert + * @return the converted value + * @throws EvaluationException if there is a problem during conversion + */ + Object convert(Object value) throws EvaluationException; +} \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeConverter.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeConverter.java new file mode 100644 index 00000000000..b371d9a3656 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeConverter.java @@ -0,0 +1,283 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.standard; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; + +public class StandardTypeConverter implements TypeConverter { + + public Map, Map, StandardIndividualTypeConverter>> converters = new HashMap, Map, StandardIndividualTypeConverter>>(); + + StandardTypeConverter() { + registerConverter(new ToBooleanConverter()); + registerConverter(new ToCharacterConverter()); + registerConverter(new ToShortConverter()); + registerConverter(new ToLongConverter()); + registerConverter(new ToDoubleConverter()); + registerConverter(new ToFloatConverter()); + registerConverter(new ToStringConverter()); + registerConverter(new ToIntegerConverter()); + registerConverter(new ToByteConverter()); + } + + public boolean canConvert(Class sourceType, Class targetType) { + Map, StandardIndividualTypeConverter> possibleConvertersToTheTargetType = converters.get(targetType); + if (possibleConvertersToTheTargetType == null && targetType.isPrimitive()) { + if (targetType == Integer.TYPE) + possibleConvertersToTheTargetType = converters.get(Integer.class); + else if (targetType == Boolean.TYPE) + possibleConvertersToTheTargetType = converters.get(Boolean.class); + else if (targetType == Short.TYPE) + possibleConvertersToTheTargetType = converters.get(Short.class); + else if (targetType == Long.TYPE) + possibleConvertersToTheTargetType = converters.get(Long.class); + else if (targetType == Character.TYPE) + possibleConvertersToTheTargetType = converters.get(Character.class); + else if (targetType == Double.TYPE) + possibleConvertersToTheTargetType = converters.get(Double.class); + else if (targetType == Float.TYPE) + possibleConvertersToTheTargetType = converters.get(Float.class); + else if (targetType == Byte.TYPE) + possibleConvertersToTheTargetType = converters.get(Byte.class); + } + if (possibleConvertersToTheTargetType != null) { + StandardIndividualTypeConverter aConverter = possibleConvertersToTheTargetType.get(sourceType); + if (aConverter != null) { + return true; + } + } + return false; + } + + // TODO 3 Q In case of a loss in information with coercion to a narrower type, should we throw an exception? + public Object convertValue(Object value, Class targetType) throws SpelException { + if (value==null || value.getClass()==targetType) return value; + Map, StandardIndividualTypeConverter> possibleConvertersToTheTargetType = converters.get(targetType); + if (possibleConvertersToTheTargetType == null && targetType.isPrimitive()) { + if (targetType == Integer.TYPE) + possibleConvertersToTheTargetType = converters.get(Integer.class); + else if (targetType == Boolean.TYPE) + possibleConvertersToTheTargetType = converters.get(Boolean.class); + else if (targetType == Short.TYPE) + possibleConvertersToTheTargetType = converters.get(Short.class); + else if (targetType == Long.TYPE) + possibleConvertersToTheTargetType = converters.get(Long.class); + else if (targetType == Character.TYPE) + possibleConvertersToTheTargetType = converters.get(Character.class); + else if (targetType == Double.TYPE) + possibleConvertersToTheTargetType = converters.get(Double.class); + else if (targetType == Float.TYPE) + possibleConvertersToTheTargetType = converters.get(Float.class); + else if (targetType == Byte.TYPE) + possibleConvertersToTheTargetType = converters.get(Byte.class); + } + Object result = null; + if (possibleConvertersToTheTargetType != null) { + StandardIndividualTypeConverter aConverter = possibleConvertersToTheTargetType.get(value.getClass()); + if (aConverter != null) { + try { + result = aConverter.convert(value); + } catch (EvaluationException ee) { + if (ee instanceof SpelException) { + throw (SpelException)ee; + } else { + throw new SpelException(SpelMessages.PROBLEM_DURING_TYPE_CONVERSION,ee.getMessage()); + } + } + } + } + if (result != null) + return result; + throw new SpelException(SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), targetType); + } + + public void registerConverter(StandardIndividualTypeConverter aConverter) { + Class toType = aConverter.getTo(); + Map, StandardIndividualTypeConverter> convertersResultingInSameType = converters.get(toType); + if (convertersResultingInSameType == null) { + convertersResultingInSameType = new HashMap, StandardIndividualTypeConverter>(); + } + Class[] fromTypes = aConverter.getFrom(); + for (int i = 0; i < fromTypes.length; i++) { + convertersResultingInSameType.put(fromTypes[i], aConverter); + } + converters.put(aConverter.getTo(), convertersResultingInSameType); + } + + private static class ToBooleanConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + return ((Boolean) value).booleanValue(); + } + + public Class[] getFrom() { + return new Class[] { Boolean.class }; + } + + public Class getTo() { + return Boolean.TYPE; + } + } + + private static class ToDoubleConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + if (value instanceof Double) { + return ((Double) value).doubleValue(); + } else if (value instanceof String) { + try { + Double.parseDouble((String) value); + } catch (NumberFormatException nfe) { + // TODO 3 Q throw something or leave the caller to throw a conversion exception? + } + } else if (value instanceof Integer) { + return new Double(((Integer) value).intValue()); + } + return null; + } + + public Class[] getFrom() { + return new Class[] { Double.class, String.class, Integer.class }; + } + + public Class getTo() { + return Double.class; + } + } + + private static class ToFloatConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + return ((Double) value).floatValue(); + } + + public Class[] getFrom() { + return new Class[] { Double.class }; + } + + public Class getTo() { + return Float.class; + } + } + + private static class ToByteConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + return ((Integer) value).byteValue(); + } + + public Class[] getFrom() { + return new Class[] { Integer.class }; + } + + public Class getTo() { + return Byte.class; + } + } + + private static class ToLongConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + if (value instanceof Integer) + return ((Integer) value).longValue(); + else if (value instanceof Short) + return ((Short) value).longValue(); + else if (value instanceof Byte) + return ((Byte) value).longValue(); + return null; + } + + public Class[] getFrom() { + return new Class[] { Integer.class, Short.class, Byte.class }; + } + + public Class getTo() { + return Long.class; + } + } + + private static class ToCharacterConverter implements StandardIndividualTypeConverter { + public Character convert(Object value) throws SpelException { + if (value instanceof Integer) + return ((char) ((Integer) value).intValue()); + if (value instanceof String) { + String s = (String) value; + if (s.length() == 1) + return s.charAt(0); + } + return null; + } + + public Class[] getFrom() { + return new Class[] { Integer.class, String.class }; + } + + public Class getTo() { + return Character.class; + } + } + + private static class ToShortConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + if (value instanceof Integer) + return ((short) ((Integer) value).shortValue()); + return null; + } + + public Class[] getFrom() { + return new Class[] { Integer.class }; + } + + public Class getTo() { + return Short.class; + } + } + + private static class ToStringConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + return value.toString(); + } + + public Class[] getFrom() { + return new Class[] { Integer.class, Double.class }; + } + + public Class getTo() { + return String.class; + } + } + + private static class ToIntegerConverter implements StandardIndividualTypeConverter { + public Object convert(Object value) throws SpelException { + if (value instanceof Integer) + return ((Integer) value).intValue(); + else if (value instanceof Long) + return ((Long) value).intValue(); + else + return null; + } + + public Class[] getFrom() { + return new Class[] { Integer.class, Long.class }; + } + + public Class getTo() { + return Integer.TYPE; + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeLocator.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeLocator.java new file mode 100644 index 00000000000..9ac0ab9d4c1 --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeLocator.java @@ -0,0 +1,81 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.standard; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeLocator; +import org.springframework.expression.spel.SpelException; +import org.springframework.expression.spel.SpelMessages; + +// TODO 3 promote import prefix support and classloader setting to the interface? +public class StandardTypeLocator implements TypeLocator { + + private ClassLoader loader; + private final List knownPackagePrefixes = new ArrayList(); + + public StandardTypeLocator() { + loader = Thread.currentThread().getContextClassLoader(); + registerImport("java.lang"); + registerImport("java.util"); + registerImport("java.awt"); + } + + // OPTIMIZE I'm sure this *could* be more inefficient if I tried really hard... + public Class findType(String type) throws EvaluationException { + String nameToLookup = type; + try { + Class c = loader.loadClass(nameToLookup); + return c; + } catch (ClassNotFoundException e) { + // might need a prefix... + } + // try prefixes + for (String prefix : knownPackagePrefixes) { + try { + nameToLookup = new StringBuilder().append(prefix).append(".").append(type).toString(); + Class c = loader.loadClass(nameToLookup); + return c; + } catch (ClassNotFoundException e) { + } + } + // TODO should some of these common messages be promoted to top level exception types? + throw new SpelException(SpelMessages.TYPE_NOT_FOUND, type); + } + + /** + * Register a new import prefix that will be used when searching for unqualified types. Expected format is something + * like "java.lang" + */ + public void registerImport(String prefix) { + knownPackagePrefixes.add(prefix); + } + + public void unregisterImport(String prefix) { + knownPackagePrefixes.add(prefix); + } + + public List getImports() { + return knownPackagePrefixes; + } + + public void setClassLoader(ClassLoader loader) { + this.loader = loader; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeUtilities.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeUtilities.java new file mode 100644 index 00000000000..34012d3cffd --- /dev/null +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/StandardTypeUtilities.java @@ -0,0 +1,102 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.standard; + +import org.springframework.expression.OperatorOverloader; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.TypeLocator; +import org.springframework.expression.TypeUtils; + +/** + * The StandardTypeUtilities implementation pulls together the standard implementations of the TypeComparator, + * TypeLocator and TypeConverter interfaces. Each of these can be replaced so if only wishing to replace one of those + * type facilities. + * + * @author Andy Clement + * + */ +public class StandardTypeUtilities implements TypeUtils { + + private TypeComparator typeComparator; + private TypeLocator typeLocator; + private TypeConverter typeConverter; + private OperatorOverloader operatorOverloader; + + public StandardTypeUtilities() { + typeComparator = new StandardComparator(); + typeLocator = new StandardTypeLocator(); + typeConverter = new StandardTypeConverter(); + operatorOverloader = null; // this means operations between basic types are supported (eg. numbers) + } + + public TypeLocator getTypeLocator() { + return typeLocator; + } + + /** + * Set the type locator for the StandardTypeUtilities object, allows a user to replace parts of the standard + * TypeUtilities implementation if they wish. + * + * @param typeLocator the TypeLocator to use from now on + */ + public void setTypeLocator(TypeLocator typeLocator) { + this.typeLocator = typeLocator; + } + + public TypeConverter getTypeConverter() { + return typeConverter; + } + + /** + * Set the type converter for the StandardTypeUtilities object, allows a user to replace parts of the standard + * TypeUtilities implementation if they wish. + * + * @param typeConverter the TypeConverter to use from now on + */ + public void setTypeConverter(TypeConverter typeConverter) { + this.typeConverter = typeConverter; + } + + public TypeComparator getTypeComparator() { + return typeComparator; + } + + /** + * Set the type comparator for the StandardTypeUtilities object, allows a user to replace parts of the standard + * TypeUtilities implementation if they wish. + * + * @param typeComparator the TypeComparator to use from now on + */ + public void setTypeComparator(TypeComparator typeComparator) { + this.typeComparator = typeComparator; + } + + public OperatorOverloader getOperatorOverloader() { + return operatorOverloader; + } + + /** + * Set the operator overloader for the StandardTypeUtilities object, allows a user to overload the mathematical + * operators to support them between non-standard types. + * + * @param operatorOverloader the OperatorOverloader to use from now on + */ + public void setOperatorOverloader(OperatorOverloader operatorOverloader) { + this.operatorOverloader = operatorOverloader; + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/AllTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/AllTests.java new file mode 100644 index 00000000000..78089bb8fbb --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/AllTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Pulls together all the tests for Spring EL into a single suite. + * + * @author Andy Clement + * + */ +public class AllTests { + + public static Test suite() { + TestSuite suite = new TestSuite("Spring Expression Language tests"); + // $JUnit-BEGIN$ + suite.addTestSuite(BooleanExpressionTests.class); + suite.addTestSuite(ParsingTests.class); + suite.addTestSuite(EvaluationTests.class); + suite.addTestSuite(OperatorTests.class); + suite.addTestSuite(ConstructorInvocationTests.class); + suite.addTestSuite(MethodInvocationTests.class); + suite.addTestSuite(PropertyAccessTests.class); + suite.addTestSuite(TypeReferencing.class); + suite.addTestSuite(PerformanceTests.class); + suite.addTestSuite(DefaultComparatorUnitTests.class); + suite.addTestSuite(TemplateExpressionParsing.class); + suite.addTestSuite(ExpressionLanguageScenarioTests.class); + suite.addTestSuite(ScenariosForSpringSecurity.class); + // $JUnit-END$ + return suite; + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/BooleanExpressionTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/BooleanExpressionTests.java new file mode 100644 index 00000000000..88b5ec2de9b --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/BooleanExpressionTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +/** + * Tests the evaluation of real boolean expressions, these use AND, OR, NOT, TRUE, FALSE + * + * @author Andy Clement + */ +public class BooleanExpressionTests extends ExpressionTestCase { + + public void testBooleanTrue() { + evaluate("true", Boolean.TRUE, Boolean.class); + } + + public void testBooleanFalse() { + evaluate("false", Boolean.FALSE, Boolean.class); + } + + public void testOr() { + evaluate("false or false", Boolean.FALSE, Boolean.class); + evaluate("false or true", Boolean.TRUE, Boolean.class); + evaluate("true or false", Boolean.TRUE, Boolean.class); + evaluate("true or true", Boolean.TRUE, Boolean.class); + } + + public void testAnd() { + evaluate("false and false", Boolean.FALSE, Boolean.class); + evaluate("false and true", Boolean.FALSE, Boolean.class); + evaluate("true and false", Boolean.FALSE, Boolean.class); + evaluate("true and true", Boolean.TRUE, Boolean.class); + } + + public void testNot() { + evaluate("!false", Boolean.TRUE, Boolean.class); + evaluate("!true", Boolean.FALSE, Boolean.class); + } + + public void testCombinations01() { + evaluate("false and false or true", Boolean.TRUE, Boolean.class); + evaluate("true and false or true", Boolean.TRUE, Boolean.class); + evaluate("true and false or false", Boolean.FALSE, Boolean.class); + } +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ConstructorInvocationTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ConstructorInvocationTests.java new file mode 100644 index 00000000000..c9824f58942 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ConstructorInvocationTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.spel.standard.StandardEvaluationContext; + +/** + * Tests invocation of constructors. + * + * @author Andy Clement + */ +public class ConstructorInvocationTests extends ExpressionTestCase { + + public void testPrimitiveTypeArrayConstructors() { + evaluate("new int[]{1,2,3,4}.count()", 4, Integer.class); + evaluate("new boolean[]{true,false,true}.count()", 3, Integer.class); + evaluate("new char[]{'a','b','c'}.count()", 3, Integer.class); + evaluate("new long[]{1,2,3,4,5}.count()", 5, Integer.class); + evaluate("new short[]{2,3,4,5,6}.count()", 5, Integer.class); + evaluate("new double[]{1d,2d,3d,4d}.count()", 4, Integer.class); + evaluate("new float[]{1f,2f,3f,4f}.count()", 4, Integer.class); + evaluate("new byte[]{1,2,3,4}.count()", 4, Integer.class); + } + + public void testPrimitiveTypeArrayConstructorsElements() { + evaluate("new int[]{1,2,3,4}[0]", 1, Integer.class); + evaluate("new boolean[]{true,false,true}[0]", true, Boolean.class); + evaluate("new char[]{'a','b','c'}[0]", 'a', Character.class); + evaluate("new long[]{1,2,3,4,5}[0]", 1L, Long.class); + evaluate("new short[]{2,3,4,5,6}[0]", (short) 2, Short.class); + evaluate("new double[]{1d,2d,3d,4d}[0]", (double) 1, Double.class); + evaluate("new float[]{1f,2f,3f,4f}[0]", (float) 1, Float.class); + evaluate("new byte[]{1,2,3,4}[0]", (byte) 1, Byte.class); + } + + public void testTypeConstructors() { + evaluate("new String('hello world')", "hello world", String.class); + evaluate("new String(new char[]{'h','e','l','l','o'})", "hello", String.class); + } + + public void testErrorCases() { + evaluateAndCheckError("new char[7]{'a','c','d','e'}", SpelMessages.INITIALIZER_LENGTH_INCORRECT); + evaluateAndCheckError("new char[3]{'a','c','d','e'}", SpelMessages.INITIALIZER_LENGTH_INCORRECT); + evaluateAndCheckError("new char[2]{'hello','world'}", SpelMessages.TYPE_CONVERSION_ERROR); + evaluateAndCheckError("new String('a','c','d')", SpelMessages.CONSTRUCTOR_NOT_FOUND); + } + + public void testTypeArrayConstructors() { + evaluate("new String[]{'a','b','c','d'}[1]", "b", String.class); + evaluateAndCheckError("new String[]{'a','b','c','d'}.size()", SpelMessages.METHOD_NOT_FOUND, 30, "size()", "java.lang.String[]"); + evaluateAndCheckError("new String[]{'a','b','c','d'}.juggernaut", SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, 30, "juggernaut", "java.lang.String[]"); + evaluate("new String[]{'a','b','c','d'}.length", 4, Integer.class); + } + + public void testMultiDimensionalArrays() { + evaluate("new String[3,4]","[Ljava.lang.String;[3]{java.lang.String[4]{null,null,null,null},java.lang.String[4]{null,null,null,null},java.lang.String[4]{null,null,null,null}}",new String[3][4].getClass()); + } + + /* + * These tests are attempting to call constructors where we need to widen or convert the argument in order to + * satisfy a suitable constructor. + */ + public void testWidening01() { + // widening of int 3 to double 3 is OK + evaluate("new Double(3)", 3.0d, Double.class); + // widening of int 3 to long 3 is OK + evaluate("new Long(3)", 3L, Long.class); + } + + public void testArgumentConversion01() { + // Closest ctor will be new String(String) and converter supports Double>String + evaluate("new String(3.0d)", "3.0", String.class); + } + + public void testVarargsInvocation01() throws Exception { + // Calling 'public TestCode(String... strings)' + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext ctx = new StandardEvaluationContext(); + ctx.setClasspath("target/test-classes/testcode.jar"); + + @SuppressWarnings("unused") + Object v = parser.parseExpression("new TestType('a','b','c')").getValue(ctx); + v = parser.parseExpression("new TestType('a')").getValue(ctx); + v = parser.parseExpression("new TestType()").getValue(ctx); + v = parser.parseExpression("new TestType(1,2,3)").getValue(ctx); + v = parser.parseExpression("new TestType(1)").getValue(ctx); + v = parser.parseExpression("new TestType(1,'a',3.0d)").getValue(ctx); + v = parser.parseExpression("new TestType(new String[]{'a','b','c'})").getValue(ctx); + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/DefaultComparatorUnitTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/DefaultComparatorUnitTests.java new file mode 100644 index 00000000000..72cc40fc5f5 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/DefaultComparatorUnitTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import junit.framework.TestCase; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.spel.standard.StandardComparator; + +/** + * Unit tests for type comparison + * + * @author Andy Clement + */ +public class DefaultComparatorUnitTests extends TestCase { + + public void testPrimitives() throws EvaluationException { + TypeComparator comparator = new StandardComparator(); + // primitive int + assertTrue(comparator.compare(1, 2) < 0); + assertTrue(comparator.compare(1, 1) == 0); + assertTrue(comparator.compare(2, 1) > 0); + + assertTrue(comparator.compare(1.0d, 2) < 0); + assertTrue(comparator.compare(1.0d, 1) == 0); + assertTrue(comparator.compare(2.0d, 1) > 0); + + assertTrue(comparator.compare(1.0f, 2) < 0); + assertTrue(comparator.compare(1.0f, 1) == 0); + assertTrue(comparator.compare(2.0f, 1) > 0); + + } +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java new file mode 100644 index 00000000000..3904a2cb6b9 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java @@ -0,0 +1,650 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.springframework.expression.spel.ast.Lambda; + +/** + * Tests the evaluation of real expressions in a real context. + * + * @author Andy Clement + */ +public class EvaluationTests extends ExpressionTestCase { + + // literals: boolean, integer, string, hex, real, null, date + public void testLiteralBoolean01() { + evaluate("false", "false", Boolean.class); + } + + public void testLiteralBoolean02() { + evaluate("true", "true", Boolean.class); + } + + public void testLiteralInteger01() { + evaluate("1", "1", Integer.class); + } + + public void testLiteralInteger02() { + evaluate("1415", "1415", Integer.class); + } + + public void testLiteralString01() { + evaluate("'Hello World'", "Hello World", String.class); + } + + public void testLiteralString02() { + evaluate("'joe bloggs'", "joe bloggs", String.class); + } + + public void testLiteralString03() { + evaluate("'hello'", "hello", String.class); + } + + public void testLiteralString04() { + evaluate("'Tony''s Pizza'", "Tony's Pizza", String.class); + } + + public void testLiteralString05() { + evaluate("\"Hello World\"", "Hello World", String.class); + } + + public void testLiteralString06() { + evaluate("\"Hello ' World\"", "Hello ' World", String.class); + } + + public void testLiteralHex01() { + evaluate("0x7FFFFFFF", "2147483647", Integer.class); + } + + public void testLiteralReal01() { + evaluate("6.0221415E+23", "6.0221415E23", Double.class); + } + + public void testLiteralNull01() { + evaluate("null", null, null); + } + + // TODO 3 'default' format for date varies too much, we need to standardize on a format for EL + // public void testLiteralDate01() { + // eval("date('3-Feb-2008 4:50:20 PM').getTime()>0", "true", Boolean.class); + // } + + public void testLiteralDate02() { + evaluate("date('19740824131030','yyyyMMddHHmmss').getHours()", "13", Integer.class); + } + + // boolean operators: and or not + public void testBooleanOperators01() { + evaluate("false or false", "false", Boolean.class); + } + + public void testBooleanOperators02() { + evaluate("false or true", "true", Boolean.class); + } + + public void testBooleanOperators03() { + evaluate("true or false", "true", Boolean.class); + } + + public void testBooleanOperators04() { + evaluate("true or true", "true", Boolean.class); + } + + public void testBooleanOperators05() { + evaluate("false or true and false", "false", Boolean.class); + } + + public void testBooleanErrors01() { + evaluateAndCheckError("1 or false", SpelMessages.TYPE_CONVERSION_ERROR, 0); + evaluateAndCheckError("false or 39", SpelMessages.TYPE_CONVERSION_ERROR, 9); + evaluateAndCheckError("true and 'hello'", SpelMessages.TYPE_CONVERSION_ERROR, 9); + evaluateAndCheckError(" 'hello' and 'goodbye'", SpelMessages.TYPE_CONVERSION_ERROR, 1); + evaluateAndCheckError("!35", SpelMessages.TYPE_CONVERSION_ERROR, 1); + evaluateAndCheckError("! 'foob'", SpelMessages.TYPE_CONVERSION_ERROR, 2); + } + + // relational operators: lt, le, gt, ge, eq, ne + public void testRelOperatorGT01() { + evaluate("3 > 6", "false", Boolean.class); + } + + public void testRelOperatorLT01() { + evaluate("3 < 6", "true", Boolean.class); + } + + public void testRelOperatorLE01() { + evaluate("3 <= 6", "true", Boolean.class); + } + + public void testRelOperatorGE01() { + evaluate("3 >= 6", "false", Boolean.class); + } + + public void testRelOperatorGE02() { + evaluate("3 >= 3", "true", Boolean.class); + } + + public void testRelOperatorsIn01() { + evaluate("3 in {1,2,3,4,5}", "true", Boolean.class); + } + + public void testRelOperatorsIn02() { + evaluate("name in {null, \"Nikola Tesla\"}", "true", Boolean.class); + evaluate("name in {null, \"Anonymous\"}", "false", Boolean.class); + } + + public void testRelOperatorsLike01() { + evaluate("'Abc' like '[A-Z]b.*'", "true", Boolean.class); + } // not the same as CSharp thing which matched '[A-Z]b*' + + public void testRelOperatorsLike02() { + evaluate("'Abc' like '..'", "false", Boolean.class); + } // was '?' + + public void testRelOperatorsLike03() { + evaluateAndCheckError("7 like '.'", SpelMessages.INVALID_FIRST_OPERAND_FOR_LIKE_OPERATOR); + } + + public void testRelOperatorsLike04() { + evaluateAndCheckError("'abc' like 2.0", SpelMessages.INVALID_SECOND_OPERAND_FOR_LIKE_OPERATOR); + } + + public void testRelOperatorsBetween01() { + evaluate("1 between {1, 5}", "true", Boolean.class); + } + + public void testRelOperatorsBetween02() { + evaluate("'efg' between {'abc', 'xyz'}", "true", Boolean.class); + } + + public void testRelOperatorsBetweenErrors01() { + evaluateAndCheckError("1 between T(String)", SpelMessages.BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST, 12); + } + + public void testRelOperatorsBetweenErrors02() { + evaluateAndCheckError("'abc' between {5,7}", SpelMessages.NOT_COMPARABLE, 6); + } + + public void testRelOperatorsIs01() { + evaluate("'xyz' is T(int)", "false", Boolean.class); + } + + public void testRelOperatorsIs02() { + evaluate("{1, 2, 3, 4, 5} is T(List)", "true", Boolean.class); + } + + public void testRelOperatorsIs03() { + evaluate("{1, 2, 3, 4, 5} is T(List)", "true", Boolean.class); + } + + public void testRelOperatorsMatches01() { + evaluate("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "false", Boolean.class); + } + + public void testRelOperatorsMatches02() { + evaluate("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "true", Boolean.class); + } + + // mathematical operators + public void testMathOperatorAdd01() { + evaluate("2 + 4", "6", Integer.class); + } + + public void testMathOperatorAdd02() { + evaluate("'hello' + ' ' + 'world'", "hello world", String.class); + } + + public void testMathOperatorSubtract01() { + evaluate("5 - 4", "1", Integer.class); + } + + public void testMathOperatorMultiply01() { + evaluate("7 * 4", "28", Integer.class); + } + + public void testMathOperatorDivide01() { + evaluate("8 / 4", "2", Integer.class); + } + + public void testMathOperatorDivide02() { + evaluate("8.4 / 4", "2.1", Double.class); + } + + public void testMathOperatorDivide03() { + evaluateAndAskForReturnType("8/4", new Double(2.0), Double.class); + } + + // TODO decide about a conversion like this, should we support it and coerce silently? + // public void testMathOperatorDivide04() { + // evaluateAndAskForReturnType("8.4 / 4", "2", Integer.class); + // } + + public void testMathOperatorModulus01() { + evaluate("7 % 4", "3", Integer.class); + } + + // mixing operators + public void testMixingOperators01() { + evaluate("true and 5>3", "true", Boolean.class); + } + + // property access + public void testPropertyField01() { + eval("name", "Nikola Tesla", String.class, false); // not writable because (1) name is private (2) there is no setter, only a getter + evaluateAndCheckError("madeup", SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, 0, "madeup", + "org.springframework.expression.spel.testresources.Inventor"); + } + + // nested properties + public void testPropertiesNested01() { + eval("placeOfBirth.city", "SmilJan", String.class, true); + } + + public void testPropertiesNested02() { + evaluate("placeOfBirth.doubleIt(12)", "24", Integer.class); + } + + // methods + public void testMethods01() { + evaluate("echo(12)", "12", String.class); + } + + public void testMethods02() { + evaluate("echo(name)", "Nikola Tesla", String.class); + } + + // inline list creation + public void testInlineListCreation01() { + evaluate("{1, 2, 3, 4, 5}", "[1, 2, 3, 4, 5]", ArrayList.class); + } + + public void testInlineListCreation02() { + evaluate("{'abc', 'xyz'}", "[abc, xyz]", ArrayList.class); + } + + // inline map creation + public void testInlineMapCreation01() { + evaluate("#{'key1':'Value 1', 'today':'Monday'}", "{key1=Value 1, today=Monday}", HashMap.class); + } + + public void testInlineMapCreation02() { + evaluate("#{1:'January', 2:'February', 3:'March'}", "{2=February, 1=January, 3=March}", HashMap.class); + } + + public void testInlineMapCreation03() { + evaluate("#{'key1':'Value 1', 'today':'Monday'}['key1']", "Value 1", String.class); + } + + public void testInlineMapCreation04() { + evaluate("#{1:'January', 2:'February', 3:'March'}[3]", "March", String.class); + } + + public void testInlineMapCreation05() { + evaluate("#{1:'January', 2:'February', 3:'March'}.get(2)", "February", String.class); + } + + public void testInlineMapCreation06() { + evaluate("(#pos=3;#{1:'January', 2:'February', 3:'March'}[#pos])", "March", String.class); + } + + // set construction + public void testSetConstruction01() { + evaluate("new HashSet().addAll({'a','b','c'})", "true", Boolean.class); + } + + public void testSets01() { + evaluate("(#var=new HashSet();#var.addAll({'a','b','c'});#var[1])", "c", String.class); + } + + // constructors + public void testConstructorInvocation01() { + evaluate("new String('hello')", "hello", String.class); + } + + public void testConstructorInvocation02() { + evaluate("new String[3]", "java.lang.String[3]{null,null,null}", String[].class); + } + + public void testConstructorInvocation03() { + evaluateAndCheckError("new String[]", SpelMessages.NO_SIZE_OR_INITIALIZER_FOR_ARRAY_CONSTRUCTION, 4); + } + + public void testConstructorInvocation04() { + evaluateAndCheckError("new String[3]{'abc',3,'def'}", SpelMessages.INCORRECT_ELEMENT_TYPE_FOR_ARRAY, 4); + } + + public void testConstructorInvocation05() { + evaluate("new java.lang.String('foobar')", "foobar", String.class); + } + + // array construction + public void testArrayConstruction01() { + evaluate("new int[] {1, 2, 3, 4, 5}", "int[5]{1,2,3,4,5}", int[].class); + } + + public void testArrayConstruction02() { + evaluate("new String[] {'abc', 'xyz'}", "java.lang.String[2]{abc,xyz}", String[].class); + } + + // unary expressions + public void testUnaryMinus01() { + evaluate("-5", "-5", Integer.class); + } + + public void testUnaryPlus01() { + evaluate("+5", "5", Integer.class); + } + + public void testUnaryNot01() { + evaluate("!true", "false", Boolean.class); + } + + // collection processors + // from spring.net: count,sum,max,min,average,sort,orderBy,distinct,nonNull + public void testProcessorsCount01() { + evaluate("new String[] {'abc','def','xyz'}.count()", "3", Integer.class); + } + + public void testProcessorsCount02() { + evaluate("new int[] {1,2,3}.count()", "3", Integer.class); + } + + public void testProcessorsMax01() { + evaluate("new int[] {1,2,3}.max()", "3", Integer.class); + } + + public void testProcessorsMin01() { + evaluate("new int[] {1,2,3}.min()", "1", Integer.class); + } + + public void testProcessorsKeys01() { + evaluate("#{1:'January', 2:'February', 3:'March'}.keySet().sort()", "[1, 2, 3]", ArrayList.class); + } + + public void testProcessorsValues01() { + evaluate("#{1:'January', 2:'February', 3:'March'}.values().sort()", "[February, January, March]", + ArrayList.class); + } + + public void testProcessorsAverage01() { + evaluate("new int[] {1,2,3}.average()", "2", Integer.class); + } + + public void testProcessorsSort01() { + evaluate("new int[] {3,2,1}.sort()", "int[3]{1,2,3}", int[].class); + } + + public void testCollectionProcessorsNonNull01() { + evaluate("{'a','b',null,'d',null}.nonnull()", "[a, b, d]", ArrayList.class); + } + + public void testCollectionProcessorsDistinct01() { + evaluate("{'a','b','a','d','e'}.distinct()", "[a, b, d, e]", ArrayList.class); + } + + // projection and selection + public void testProjection01() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#isEven(#this)}", "[n, y, n, y, n, y, n, y, n, y]", ArrayList.class); + } + + public void testProjection02() { + evaluate("#{'a':'y','b':'n','c':'y'}.!{value=='y'?key:null}.nonnull().sort()", "[a, c]", ArrayList.class); + } + + public void testProjection03() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.!{#this>5}", + "[false, false, false, false, false, true, true, true, true, true]", ArrayList.class); + } + + public void testProjection04() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.!{$index>5?'y':'n'}", "[n, n, n, n, n, n, y, y, y, y]", ArrayList.class); + } + + public void testSelection01() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}", "[2, 4, 6, 8, 10]", ArrayList.class); + } + + public void testSelectionError_NonBooleanSelectionCriteria() { + evaluateAndCheckError("{1,2,3,4,5,6,7,8,9,10}.?{'nonboolean'}", + SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN); + } + + // TODO 3 Q Is $index within projection/selection useful or just cute? + public void testSelectionUsingIndex() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.?{$index > 5 }", "[7, 8, 9, 10]", ArrayList.class); + } + + public void testSelectionFirst01() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}", "2", Integer.class); + } + + public void testSelectionLast01() { + evaluate("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}", "10", Integer.class); + } + + // assignment + public void testAssignmentToVariables01() { + evaluate("#var1='value1'", "value1", String.class); + } + + public void testAssignmentToVariables02() { + eval("(#var1='value1';#var1)", "value1", String.class, true); + } + + // Property setting + public void testAssignmentToProperty01() { + evaluate("placeOfBirth.city='SmilJan'", "SmilJan", String.class); + evaluate( + "(#oldPOB = placeOfBirth.city;placeOfBirth.city='FairOak';'From ' + #oldPOB + ' to ' + placeOfBirth.city)", + "From SmilJan to FairOak", String.class); + evaluate("placeOfBirth.city='SmilJan'", "SmilJan", String.class); + } + + // Ternary operator + public void testTernaryOperator01() { + evaluate("{1}.#isEven(#this[0]) == 'y'?'it is even':'it is odd'", "it is odd", String.class); + } + + public void testTernaryOperator02() { + evaluate("{2}.#isEven(#this[0]) == 'y'?'it is even':'it is odd'", "it is even", String.class); + } + + // Indexer + public void testCutProcessor01() { + evaluate("{1,2,3,4,5}.cut(1,3)", "[2, 3, 4]", ArrayList.class); + } + + public void testCutProcessor02() { + evaluate("{1,2,3,4,5}.cut(3,1)", "[4, 3, 2]", ArrayList.class); + } + + public void testIndexer03() { + evaluate("'christian'[8]", "n", String.class); + } + + // Bean references + public void testReferences01() { + eval("@(apple).name", "Apple", String.class, true); + } + + public void testReferences02() { + eval("@(fruits:banana).name", "Banana", String.class, true); + } + + public void testReferences03() { + evaluate("@(a.b.c)", null, null); + } // null - no context, a.b.c treated as name + + public void testReferences05() { + eval("@(a/b/c:orange).name", "Orange", String.class, true); + } + + // TODO 4 automatic/default imports for next line? + public void testReferences06() { + evaluate("@(apple).color.getRGB() == T(Color).green.getRGB()", "true", Boolean.class); + } + + public void testReferences06b() { + evaluate("(#t='Color';@(apple).color.getRGB() == T(java.awt.Color).green.getRGB())", "true", Boolean.class); + } + + public void testReferences07() { + evaluate("@(apple).color.getRGB().equals(T(java.awt.Color).green.getRGB())", "true", Boolean.class); + } + +// value is not public, it is accessed through getRGB() +// public void testStaticRef01() { +// evaluate("T(Color).green.value!=0", "true", Boolean.class); +// } + + public void testStaticRef02() { + evaluate("T(Color).green.getRGB()!=0", "true", Boolean.class); + } + + // variables and functions + public void testVariableAccess01() { + eval("#answer", "42", Integer.class, true); + } + + public void testFunctionAccess01() { + evaluate("#reverseInt(1,2,3)", "int[3]{3,2,1}", int[].class); + } + + public void testFunctionAccess02() { + evaluate("#reverseString('hello')", "olleh", String.class); + } + + // lambda + public void testLambdaNoArgs() { + evaluate("{|| true }", "{|| true }", Lambda.class); + } + + public void testLambdaNoArgsReferenced() { + eval("(#fn={|| false };#fn)", "{|| false }", Lambda.class, true); + } + + public void testLambda01() { + evaluate("{|x,y| $x > $y ? $x : $y }", "{|x,y| ($x > $y) ? $x : $y }", + org.springframework.expression.spel.ast.Lambda.class); + } + + public void testLambda02() { + evaluate("(#max={|x,y| $x > $y ? $x : $y };true)", "true", Boolean.class); + } + + public void testLambdaMax() { + evaluate("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", "25", Integer.class); + } + + public void testLambdaFactorial01() { + evaluate("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", "120", Integer.class); + } + + public void testLambdaFactorial02() { + evaluate("(#fact = {|n| $n <= 1 ? 1 : #fact($n-1) * $n }; #fact(5))", "120", Integer.class); + } + + public void testLambdaAlphabet01() { + evaluate("(#alpha = {|l,s| $l>'z'?$s:#alpha($l+1,$s+$l)};#alphabet={||#alpha('a','')}; #alphabet())", + "abcdefghijklmnopqrstuvwxyz", String.class); + } + + public void testLambdaAlphabet02() { + evaluate("(#alphabet = {|l,s| $l>'z'?$s:#alphabet($l+1,$s+$l)};#alphabet('a',''))", + "abcdefghijklmnopqrstuvwxyz", String.class); + } + + public void testLambdaDelegation01() { + evaluate("(#sqrt={|n| T(Math).sqrt($n)};#delegate={|f,n| $f($n)};#delegate(#sqrt,4))", "2.0", Double.class); + } + + // Soundex + public void testSoundex01() { + evaluate("'Rob' soundslike 'Rod'", "false", Boolean.class); + } + + public void testSoundex02() { + evaluate("'Robert' soundslike 'Rupert'", "true", Boolean.class); + } + + public void testSoundex03() { + evaluate("'Andy' soundslike 'Christian'", "false", Boolean.class); + } + + public void testSoundex04() { + evaluate("@(fruits:).values().?{#this.colorName soundslike 'gren'}!=null", "true", Boolean.class); + } + + public void testSoundex05() { + evaluate("@(fruits:).values().?{colorName soundslike 'gren'}!=null", "true", Boolean.class); + } + + public void testSoundex06() { + evaluate("'Adrian' soundslike 'Adrain'", "true", Boolean.class); + } + + // Word distance + public void testDistanceTo01() { + evaluate("'Saturday' distanceto 'Sunday'", "3", Integer.class); + evaluate("'Saturday' distanceto 'Monday'", "5", Integer.class); + evaluate("'Saturday' distanceto 'Saturdaz'", "1", Integer.class); + evaluate("'Saturday' distanceto 'Saturdab'", "1", Integer.class); + } + + public void testDistanceTo02() { + evaluate("'Kitten' distanceto 'Sitting'", "3", Integer.class); + } + + public void testVariableReferences() { + eval("(#answer=42;#answer)", "42", Integer.class, true); + eval("($answer=42;$answer)", "42", Integer.class, true); + } + + // type references + public void testTypeReferences01() { + evaluate("T(java.lang.String)", "class java.lang.String", Class.class); + } + + public void testTypeReferencesPrimitive() { + evaluate("T(int)", "int", Class.class); + evaluate("T(byte)", "byte", Class.class); + evaluate("T(char)", "char", Class.class); + evaluate("T(boolean)", "boolean", Class.class); + evaluate("T(long)", "long", Class.class); + evaluate("T(short)", "short", Class.class); + evaluate("T(double)", "double", Class.class); + evaluate("T(float)", "float", Class.class); + } + + public void testTypeReferences02() { + evaluate("T(String)", "class java.lang.String", Class.class); + } + + public void testStringType() { + evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "SmilJan", String.class); + } + + public void testNumbers01() { + evaluateAndAskForReturnType("3*4+5",17,Integer.class); + evaluateAndAskForReturnType("3*4+5",17L,Long.class); + evaluateAndAskForReturnType("65",'A',Character.class); + evaluateAndAskForReturnType("3*4+5",(short)17,Short.class); + evaluateAndAskForReturnType("3*4+5","17",String.class); + } +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionLanguageScenarioTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionLanguageScenarioTests.java new file mode 100644 index 00000000000..ef14dcd2386 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionLanguageScenarioTests.java @@ -0,0 +1,430 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.expression.AccessException; +import org.springframework.expression.CacheablePropertyAccessor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Expression; +import org.springframework.expression.ParseException; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.PropertyReaderExecutor; +import org.springframework.expression.PropertyWriterExecutor; +import org.springframework.expression.spel.standard.StandardEvaluationContext; +import org.springframework.expression.spel.standard.StandardIndividualTypeConverter; + +/** + * Testcases showing the common scenarios/use-cases for picking up the expression language support. + * The first test shows very basic usage, just drop it in and go. By 'standard infrastructure', it means:
    + *
      + *
    • The context classloader is used (so, the default classpath) + *
    • Some basic type converters are included + *
    • properties/methods/constructors are discovered and invoked using reflection + *
    + * The scenarios after that then how how to plug in extensions:
    + *
      + *
    • Adding entries to the classpath that will be used to load types and define well known 'imports' + *
    • Defining variables that are then accessible in the expression + *
    • Changing the root context object against which non-qualified references are resolved + *
    • Registering java methods as functions callable from the expression + *
    • Adding a basic property resolver + *
    • Adding an advanced (better performing) property resolver + *
    • Adding your own type converter to support conversion between any types you like + *
    + * + * @author Andy Clement + */ +public class ExpressionLanguageScenarioTests extends ExpressionTestCase { + + /** + * Scenario: using the standard infrastructure and running simple expression evaluation. + */ + public void testScenario_UsingStandardInfrastructure() { + try { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Parse an expression + Expression expr = parser.parseExpression("new String('hello world')"); + // Evaluate it using a 'standard' context + Object value = expr.getValue(); + // They are reusable + value = expr.getValue(); + + assertEquals("hello world", value); + assertEquals(String.class, value.getClass()); + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Scenario: using the standard context but adding a jar to the classpath and registering an import. + */ + public void testScenario_LoadingDifferentClassesAndUsingImports() { + try { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + // Set the classpath (creates a new classloader with this classpath and uses it) + ctx.setClasspath("target/test-classes/testcode.jar"); + // Register an import (so types in a.b.c can be referred to by their short name) + ctx.registerImport("a.b.c"); + + // Parse an expression (here, PackagedType is in package a.b.c) + Expression expr = parser.parseExpression("new PackagedType().sayHi('Andy')"); + + // Evaluate the expression in our context + Object value = expr.getValue(ctx); + + assertEquals("Hi! Andy", value); + assertEquals(String.class, value.getClass()); + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Scenario: using the standard context but adding your own variables + */ + public void testScenario_DefiningVariablesThatWillBeAccessibleInExpressions() throws Exception { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + ctx.setVariable("favouriteColour","blue"); + List primes = new ArrayList(); + primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); + ctx.setVariable("primes",primes); + + Expression expr = parser.parseExpression("#favouriteColour"); + Object value = expr.getValue(ctx); + assertEquals("blue", value); + + expr = parser.parseExpression("#primes.get(1)"); + value = expr.getValue(ctx); + assertEquals(3, value); + + // all prime numbers > 10 from the list (using selection ?{...}) + expr = parser.parseExpression("#primes.?{#this>10}"); + value = expr.getValue(ctx); + assertEquals("[11, 13, 17]", value.toString()); + } + + + static class TestClass { + public String str; + private int property; + public int getProperty() { return property; } + public void setProperty(int i) { property = i; } + } + + /** + * Scenario: using your own root context object + */ + public void testScenario_UsingADifferentRootContextObject() throws Exception { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + + TestClass tc = new TestClass(); + tc.setProperty(42); + tc.str = "wibble"; + + ctx.setRootObject(tc); + + // read it, set it, read it again + Expression expr = parser.parseExpression("str"); + Object value = expr.getValue(ctx); + assertEquals("wibble", value); + expr = parser.parseExpression("str"); + expr.setValue(ctx,"wobble"); + expr = parser.parseExpression("str"); + value = expr.getValue(ctx); + assertEquals("wobble", value); + // or using assignment within the expression + expr = parser.parseExpression("str='wabble'"); + value = expr.getValue(ctx); + expr = parser.parseExpression("str"); + value = expr.getValue(ctx); + assertEquals("wabble", value); + + // private property will be accessed through getter() + expr = parser.parseExpression("property"); + value = expr.getValue(ctx); + assertEquals(42, value); + + // ... and set through setter + expr = parser.parseExpression("property=4"); + value = expr.getValue(ctx); + expr = parser.parseExpression("property"); + value = expr.getValue(ctx); + assertEquals(4,value); + } + + public static String repeat(String s) { return s+s; } + + /** + * Scenario: using your own java methods and calling them from the expression + */ + public void testScenario_RegisteringJavaMethodsAsFunctionsAndCallingThem() throws SecurityException, NoSuchMethodException { + try { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + ctx.registerFunction("repeat",ExpressionLanguageScenarioTests.class.getDeclaredMethod("repeat",String.class)); + + Expression expr = parser.parseExpression("#repeat('hello')"); + Object value = expr.getValue(ctx); + assertEquals("hellohello", value); + + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Scenario: add a property resolver that will get called in the resolver chain, this one only supports reading. + */ + public void testScenario_AddingYourOwnPropertyResolvers_1() throws SecurityException, NoSuchMethodException { + try { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + + ctx.addPropertyAccessor(new FruitColourAccessor()); + Expression expr = parser.parseExpression("orange"); + Object value = expr.getValue(ctx); + assertEquals(Color.orange,value); + + try { + expr.setValue(ctx,Color.blue); + fail("Should not be allowed to set oranges to be blue !"); + } catch (EvaluationException ee) { + SpelException ele = (SpelException)ee; + assertEquals(ele.getMessageUnformatted(),SpelMessages.PROPERTY_OR_FIELD_SETTER_NOT_FOUND); + } + + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Regardless of the current context object, or root context object, this resolver can tell you what colour a fruit is ! + * It only supports property reading, not writing. To support writing it would need to override canWrite() and write() + */ + static class FruitColourAccessor implements PropertyAccessor { + + private static Map propertyMap = new HashMap(); + + static { + propertyMap.put("banana",Color.yellow); + propertyMap.put("apple",Color.red); + propertyMap.put("orange",Color.orange); + } + + /** + * Null means you might be able to read any property, if an earlier property resolver hasn't beaten you to it + */ + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, Object name) throws AccessException { + return propertyMap.containsKey(name); + } + + + public Object read(EvaluationContext context, Object target, Object name) throws AccessException { + return propertyMap.get(name); + } + + public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, Object name, Object newValue) + throws AccessException { + } + + } + + + /** + * Scenario: add an optimized property resolver. Property resolution can be thought of it two parts: resolving (finding the property you mean) and accessing (reading or writing that property). + * In some cases the act of discovering which property is meant is expensive - and there is no benefit to rediscovering it every time the expression is evaluated as it will + * always be the same property. For example, with reflection it can be expensive to find out which field on an object maps to the property, but it will always be the same field + * for each evaluation. In these cases we use a Resolver/Executor based property accessor. In this setup the property resolver does not immediately return the value of the property, + * instead it returns an executor object that can be used to read the property. The executor can be cached and reused by SPEL so it does not go back to the resolver every time the + * expression is evaluated. In this testcase we use this different accessor mechanism to return the colours of vegetables. + */ + public void testScenario_AddingYourOwnPropertyResolvers_2() throws SecurityException, NoSuchMethodException { + try { + // Create a parser + SpelExpressionParser parser = new SpelExpressionParser(); + // Use the standard evaluation context + StandardEvaluationContext ctx = new StandardEvaluationContext(); + + ctx.addPropertyAccessor(new VegetableColourAccessor()); + Expression expr = parser.parseExpression("pea"); + Object value = expr.getValue(ctx); + assertEquals(Color.green,value); + + try { + expr.setValue(ctx,Color.blue); + fail("Should not be allowed to set peas to be blue !"); + } catch (EvaluationException ee) { + SpelException ele = (SpelException)ee; + assertEquals(ele.getMessageUnformatted(),SpelMessages.PROPERTY_OR_FIELD_SETTER_NOT_FOUND); + } + + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Regardless of the current context object, or root context object, this resolver can tell you what colour a vegetable is ! + * It only supports property reading, not writing. + */ + static class VegetableColourAccessor extends CacheablePropertyAccessor { + + private static Map propertyMap = new HashMap(); + + static { + propertyMap.put("carrot",Color.orange); + propertyMap.put("pea",Color.green); + } + + /** + * Null means you might be able to read any property, if an earlier property resolver hasn't beaten you to it + */ + public Class[] getSpecificTargetClasses() { + return null; + } + + /** + * Work out if we can resolve the named property and if so return an executor that can be cached and reused to + * discover the value. + */ + public PropertyReaderExecutor getReaderAccessor(EvaluationContext relatedContext, Object target, Object name) { + if (propertyMap.containsKey(name)) { + return new VegetableColourExecutor(propertyMap.get(name)); + } + return null; + } + + public PropertyWriterExecutor getWriterAccessor(EvaluationContext context, Object target, Object name) { + return null; + } + + } + + static class VegetableColourExecutor implements PropertyReaderExecutor { + private Color colour; + + public VegetableColourExecutor(Color colour) { + this.colour = colour; + } + + public Object execute(EvaluationContext context, Object target) throws AccessException { + return colour; + } + + } + + /** + * Scenario: adding your own type converter + */ + public void testScenario_AddingYourOwnTypeConverter() throws SecurityException, NoSuchMethodException { + try { + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext ctx = new StandardEvaluationContext(); + ctx.registerFunction("functionTakesColour",ExpressionLanguageScenarioTests.class.getDeclaredMethod("functionTakesColour",Color.class)); + + Expression expr = parser.parseExpression("#functionTakesColour('orange')"); + try { + Object value = expr.getValue(ctx); + fail("Should have failed, no type converter registered"); + } catch (EvaluationException ee) {} + + ctx.addTypeConverter(new StringToColorConverter()); + Object value = expr.getValue(ctx); + + assertEquals(Color.orange,value); + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + public static Color functionTakesColour(Color c) {return c;} + + static class StringToColorConverter implements StandardIndividualTypeConverter { + + public Object convert(Object value) throws EvaluationException { + String colourName = (String)value; + if (colourName.equals("orange")) return Color.orange; + else if (colourName.equals("red")) return Color.red; + else return Color.blue; // hmm, quite a simplification here + } + + public Class[] getFrom() { + return new Class[]{String.class}; + } + + public Class getTo() { + return Color.class; + } + + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestCase.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestCase.java new file mode 100644 index 00000000000..93387c6ee26 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestCase.java @@ -0,0 +1,298 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import java.util.Arrays; +import java.util.List; + +import junit.framework.TestCase; + +import org.springframework.expression.Expression; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.ParseException; +import org.springframework.expression.spel.standard.StandardEvaluationContext; + +/** + * Common superclass for expression tests. + * + * @author Andy Clement + */ +public abstract class ExpressionTestCase extends TestCase { + + private final static boolean DEBUG = false; + + protected static SpelExpressionParser parser = new SpelExpressionParser(); + protected static StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); + + /** + * Evaluate an expression and check that the actual result matches the expectedValue and the class of the result + * matches the expectedClassOfResult. + * @param expression The expression to evaluate + * @param expectedValue the expected result for evaluating the expression + * @param expectedResultType the expected class of the evaluation result + */ + public void evaluate(String expression, Object expectedValue, Class expectedResultType) { + try { + SpelExpression expr = parser.parseExpression(expression); + if (expr == null) { + fail("Parser returned null for expression"); + } + if (DEBUG) { + SpelUtilities.printAbstractSyntaxTree(System.out, expr); + } + // Class expressionType = expr.getValueType(); + // assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is + // '"+expressionType+"'", + // expectedResultType,expressionType); + + Object value = expr.getValue(eContext); + + // Check the return value + if (value == null) { + if (expectedValue == null) { + return; // no point doing other checks + } + assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, + null); + } + + Class resultType = value.getClass(); + assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType + + "' but result was of type '" + resultType + "'", expectedResultType, resultType); + // .equals/* isAssignableFrom */(resultType), truers); + + // TODO isAssignableFrom would allow some room for compatibility + // in the above expression... + + if (expectedValue instanceof String) { + assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, + ExpressionTestCase.stringValueOf(value)); + } else { + assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value); + } + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + public void evaluateAndAskForReturnType(String expression, Object expectedValue, Class expectedResultType) { + try { + SpelExpression expr = (SpelExpression) parser.parseExpression(expression); + if (expr == null) { + fail("Parser returned null for expression"); + } + if (DEBUG) { + SpelUtilities.printAbstractSyntaxTree(System.out, expr); + } + // Class expressionType = expr.getValueType(); + // assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is + // '"+expressionType+"'", + // expectedResultType,expressionType); + + Object value = expr.getValue(eContext, expectedResultType); + if (value == null) { + if (expectedValue == null) + return; // no point doing other checks + assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, + null); + } + + Class resultType = value.getClass(); + assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType + + "' but result was of type '" + resultType + "'", expectedResultType, resultType); + // .equals/* isAssignableFrom */(resultType), truers); + assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value); + // isAssignableFrom would allow some room for compatibility + // in the above expression... + } catch (EvaluationException ee) { + SpelException ex = (SpelException) ee; + ex.printStackTrace(); + fail("Unexpected EvaluationException: " + ex.getMessage()); + } catch (ParseException pe) { + fail("Unexpected ParseException: " + pe.getMessage()); + } + } + + /** + * Evaluate an expression and check that the actual result matches the expectedValue and the class of the result + * matches the expectedClassOfResult. This method can also check if the expression is writable (for example, it is a + * variable or property reference). + * + * @param expression The expression to evaluate + * @param expectedValue the expected result for evaluating the expression + * @param expectedClassOfResult the expected class of the evaluation result + * @param shouldBeWritable should the parsed expression be writable? + */ + public void eval(String expression, Object expectedValue, Class expectedClassOfResult, boolean shouldBeWritable) { + try { + SpelExpression e = (SpelExpression) parser.parseExpression(expression); + if (e == null) { + fail("Parser returned null for expression"); + } + if (DEBUG) { + SpelUtilities.printAbstractSyntaxTree(System.out, e); + } + Object value = e.getValue(eContext); + if (value == null) { + if (expectedValue == null) + return; // no point doing other + // checks + assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, + null); + } + Class resultType = value.getClass(); + assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, + ExpressionTestCase.stringValueOf(value)); + assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult + + "' but result was of type '" + resultType + "'", expectedClassOfResult + .equals/* isAssignableFrom */(resultType), true); + // TODO 4 isAssignableFrom would allow some room for compatibility + // in the above expression... + + boolean isWritable = e.isWritable(eContext); + if (isWritable != shouldBeWritable) { + if (shouldBeWritable) + fail("Expected the expression to be writable but it is not"); + else + fail("Expected the expression to be readonly but it is not"); + } + } catch (EvaluationException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + /** + * Evaluate the specified expression and ensure the expected message comes out. The message may have inserts and + * they will be checked if otherProperties is specified. The first entry in otherProperties should always be the + * position. + * @param expression The expression to evaluate + * @param expectedMessage The expected message + * @param otherProperties The expected inserts within the message + */ + protected void evaluateAndCheckError(String expression, SpelMessages expectedMessage, Object... otherProperties) { + try { + Expression expr = (Expression) parser.parseExpression(expression); + if (expr == null) { + fail("Parser returned null for expression"); + } + @SuppressWarnings("unused") + Object value = expr.getValue(eContext); + fail("Should have failed with message " + expectedMessage); + } catch (EvaluationException ee) { + SpelException ex = (SpelException) ee; + if (ex.getMessageUnformatted() != expectedMessage) { + System.out.println(ex.getMessage()); + ex.printStackTrace(); + assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted()); + } + if (otherProperties != null && otherProperties.length != 0) { + // first one is expected position of the error within the string + int pos = ((Integer) otherProperties[0]).intValue(); + assertEquals("Did not get correct position reported in error ", pos, ex.getPosition()); + if (otherProperties.length > 1) { + // Check inserts match + Object[] inserts = ex.getInserts(); + if (inserts == null) { + inserts = new Object[0]; + } + if (inserts.length < otherProperties.length - 1) { + ex.printStackTrace(); + fail("Cannot check " + (otherProperties.length - 1) + + " properties of the exception, it only has " + inserts.length + " inserts"); + } + for (int i = 1; i < otherProperties.length; i++) { + if (!inserts[i - 1].equals(otherProperties[i])) { + ex.printStackTrace(); + fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '" + + inserts[i - 1] + "'"); + } + } + } + } + } catch (ParseException pe) { + pe.printStackTrace(); + fail("Unexpected Exception: " + pe.getMessage()); + } + } + + public static String stringValueOf(Object value) { + // do something nice for arrays + if (value==null) return "null"; + if (value.getClass().isArray()) { + StringBuilder sb = new StringBuilder(); + if (value.getClass().getComponentType().isPrimitive()) { + // TODO 4 ought to support other primitives! + int[] l = (int[]) value; + sb.append("int[").append(l.length).append("]{"); + for (int j = 0; j < l.length; j++) { + if (j > 0) + sb.append(","); + sb.append(stringValueOf(l[j])); + } + sb.append("}"); + } else { + List l = Arrays.asList((Object[]) value); + sb.append(value.getClass().getComponentType().getName()).append("[").append(l.size()).append("]{"); + int i = 0; + for (Object object : l) { + if (i > 0) { + sb.append(","); + } + i++; + sb.append(stringValueOf(object)); + } + sb.append("}"); + } + return sb.toString(); + } else { + return value.toString(); + } + } + + // protected void evaluateAndCheckError(String string, ELMessages expectedMessage, Object... otherProperties) { + // try { + // SpelExpression expr = (SpelExpression) parser.parseExpression(string); + // if (expr == null) + // fail("Parser returned null for expression"); + // // expr.printAST(System.out); + // @SuppressWarnings("unused") + // Object value = expr.getValue(eContext); + // fail("Should have failed with message " + expectedMessage); + // } catch (ExpressionException ee) { + // ELException ex = (ELException) ee; + // if (expectedMessage != ex.getMessageUnformatted()) { + // System.out.println(ex.getMessage()); + // ex.printStackTrace(); + // assertEquals("Failed to get expected message", expectedMessage, ex.getMessageUnformatted()); + // } + // if (otherProperties != null && otherProperties.length != 0) { + // // first one is expected position of the error within the string + // int pos = ((Integer) otherProperties[0]).intValue(); + // assertEquals("Did not get correct position reported in error ", pos, ex.getPosition()); + // } + // } + // + // } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java new file mode 100644 index 00000000000..1f683e623b0 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/MethodInvocationTests.java @@ -0,0 +1,113 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.spel.standard.StandardEvaluationContext; + +/** + * Tests invocation of methods. + * + * @author Andy Clement + */ +@SuppressWarnings("unused") +public class MethodInvocationTests extends ExpressionTestCase { + + public void testSimpleAccess01() { + evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class); + } + + public void testBuiltInProcessors() { + evaluate("new int[]{1,2,3,4}.count()", 4, Integer.class); + evaluate("new int[]{4,3,2,1}.sort()[3]", 4, Integer.class); + evaluate("new int[]{4,3,2,1}.average()", 2, Integer.class); + evaluate("new int[]{4,3,2,1}.max()", 4, Integer.class); + evaluate("new int[]{4,3,2,1}.min()", 1, Integer.class); + evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class); + evaluate("{1,2,3,null}.nonnull().count()", 3, Integer.class); + evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class); + } + + public void testStringClass() { + evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class); + // TODO 3 hmmm, have to do the second charAt() because all '' are strings, never chars and cannot do cast + evaluate("new java.lang.String('hello').charAt(2).equals('l'.charAt(0))", true, Boolean.class); + evaluate("'HELLO'.toLowerCase()", "hello", String.class); + evaluate("' abcba '.trim()", "abcba", String.class); + } + + public void testNonExistentMethods() { + // name is ok but madeup() does not exist + evaluateAndCheckError("name.madeup()", SpelMessages.METHOD_NOT_FOUND, 5); + } + + public void testWidening01() { + // widening of int 3 to double 3 is OK + evaluate("new Double(3.0d).compareTo(8)", -1, Integer.class); + evaluate("new Double(3.0d).compareTo(3)", 0, Integer.class); + evaluate("new Double(3.0d).compareTo(2)", 1, Integer.class); + } + + public void testArgumentConversion01() { + // Rely on Double>String conversion for calling startsWith() + evaluate("new String('hello 2.0 to you').startsWith(7.0d)", false, Boolean.class); + evaluate("new String('7.0 foobar').startsWith(7.0d)", true, Boolean.class); + } + + public void testVarargsInvocation01() { + // Calling 'public int aVarargsMethod(String... strings)' + evaluate("aVarargsMethod('a','b','c')",3,Integer.class); + evaluate("aVarargsMethod('a')",1,Integer.class); + evaluate("aVarargsMethod()",0,Integer.class); + evaluate("aVarargsMethod(1,2,3)",3,Integer.class); // all need converting to strings + evaluate("aVarargsMethod(1)",1,Integer.class); // needs string conversion + evaluate("aVarargsMethod(1,'a',3.0d)",3,Integer.class); // first and last need conversion + evaluate("aVarargsMethod(new String[]{'a','b','c'})",3,Integer.class); + } + + public void testVarargsInvocation02() { + // Calling 'public int aVarargsMethod2(int i, String... strings)' - returns int+length_of_strings + evaluate("aVarargsMethod2(5,'a','b','c')",8,Integer.class); + evaluate("aVarargsMethod2(2,'a')",3,Integer.class); + evaluate("aVarargsMethod2(4)",4,Integer.class); + evaluate("aVarargsMethod2(8,2,3)",10,Integer.class); + evaluate("aVarargsMethod2(9)",9,Integer.class); + evaluate("aVarargsMethod2(2,'a',3.0d)",4,Integer.class); + evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})",11,Integer.class); + } + + // Due to conversion there are two possible methods to call ... + public void testVarargsInvocation03() throws Exception { + // Calling 'm(String... strings)' and 'm(int i,String... strings)' + try { + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext ctx = new StandardEvaluationContext(); + ctx.setClasspath("target/test-classes/testcode.jar"); + + Object v = null; + v = parser.parseExpression("new TestType().m(1,2,3)").getValue(ctx); +// v = parser.parseExpression("new TestType().m('a','b','c')").getValue(ctx); +// v = parser.parseExpression("new TestType().m(5,'a','b','c')").getValue(ctx); +// v = parser.parseExpression("new TestType().m()").getValue(ctx); +// v = parser.parseExpression("new TestType().m(1)").getValue(ctx); +// v = parser.parseExpression("new TestType().m(1,'a',3.0d)").getValue(ctx); +// v = parser.parseExpression("new TestType().m(new String[]{'a','b','c'})").getValue(ctx); + fail("Should have detected ambiguity, there are two possible matches"); + } catch (EvaluationException ee) { + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/OperatorTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/OperatorTests.java new file mode 100644 index 00000000000..a9931a5cb51 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/OperatorTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +/** + * Tests the evaluation of expressions using relational operators. + * + * @author Andy Clement + */ +public class OperatorTests extends ExpressionTestCase { + + public void testIntegerLiteral() { + evaluate("3", 3, Integer.class); + } + + public void testRealLiteral() { + evaluate("3.5", 3.5d, Double.class); + } + + public void testLessThan() { + evaluate("3 < 5", true, Boolean.class); + evaluate("5 < 3", false, Boolean.class); + } + + public void testLessThanOrEqual() { + evaluate("3 <= 5", true, Boolean.class); + evaluate("5 <= 3", false, Boolean.class); + evaluate("6 <= 6", true, Boolean.class); + } + + public void testEqual() { + evaluate("3 == 5", false, Boolean.class); + evaluate("5 == 3", false, Boolean.class); + evaluate("6 == 6", true, Boolean.class); + } + + public void testGreaterThanOrEqual() { + evaluate("3 >= 5", false, Boolean.class); + evaluate("5 >= 3", true, Boolean.class); + evaluate("6 >= 6", true, Boolean.class); + } + + public void testGreaterThan() { + evaluate("3 > 5", false, Boolean.class); + evaluate("5 > 3", true, Boolean.class); + } + + public void testMultiplyStringInt() { + evaluate("'a' * 5", "aaaaa", String.class); + } + + public void testMultiplyIntInt() { + evaluate("3 * 5", 15, Integer.class); + } + + public void testMultiplyDoubleDoubleGivesDouble() { + evaluate("3.0d * 5.0d", 15.0d, Double.class); + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ParsingTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ParsingTests.java new file mode 100644 index 00000000000..37bcc84d636 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ParsingTests.java @@ -0,0 +1,463 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import junit.framework.TestCase; + +import org.springframework.expression.ParseException; + +/** + * Parse some expressions and check we get the AST we expect. Rather than inspecting each node in the AST, we ask it to + * write itself to a string form and check that is as expected. + * + * @author Andy Clement + */ +public class ParsingTests extends TestCase { + + private SpelExpressionParser parser; + + public void setUp() { + parser = new SpelExpressionParser(); + } + + // literals + public void testLiteralBoolean01() { + parseCheck("false"); + } + + public void testLiteralLong01() { + parseCheck("37L","37"); + } + + public void testLiteralBoolean02() { + parseCheck("true"); + } + + public void testLiteralInteger01() { + parseCheck("1"); + } + + public void testLiteralInteger02() { + parseCheck("1415"); + } + + public void testLiteralString01() { + parseCheck("'hello'"); + } + + public void testLiteralString02() { + parseCheck("'joe bloggs'"); + } + + public void testLiteralString03() { + parseCheck("'Tony''s Pizza'", "'Tony's Pizza'"); + } + + public void testLiteralReal01() { + parseCheck("6.0221415E+23", "6.0221415E23"); + } + + public void testLiteralHex01() { + parseCheck("0x7FFFFFFF", "2147483647"); + } + + public void testLiteralDate01() { + parseCheck("date('1974/08/24')"); + } + + public void testLiteralDate02() { + parseCheck("date('19740824T131030','yyyyMMddTHHmmss')"); + } + + public void testLiteralNull01() { + parseCheck("null"); + } + + // boolean operators + public void testBooleanOperatorsOr01() { + parseCheck("false or false", "(false or false)"); + } + + public void testBooleanOperatorsOr02() { + parseCheck("false or true", "(false or true)"); + } + + public void testBooleanOperatorsOr03() { + parseCheck("true or false", "(true or false)"); + } + + public void testBooleanOperatorsOr04() { + parseCheck("true or false", "(true or false)"); + } + + public void testBooleanOperatorsMix01() { + parseCheck("false or true and false", "(false or (true and false))"); + } + + // relational operators + public void testRelOperatorsGT01() { + parseCheck("3>6", "(3 > 6)"); + } + + public void testRelOperatorsLT01() { + parseCheck("3<6", "(3 < 6)"); + } + + public void testRelOperatorsLE01() { + parseCheck("3<=6", "(3 <= 6)"); + } + + public void testRelOperatorsGE01() { + parseCheck("3>=6", "(3 >= 6)"); + } + + public void testRelOperatorsGE02() { + parseCheck("3>=3", "(3 >= 3)"); + } + + public void testRelOperatorsIn01() { + parseCheck("3 in {1,2,3,4,5}", "(3 in {1,2,3,4,5})"); + } + + public void testRelOperatorsLike01() { + parseCheck("'Abc' like '[A-Z]b*'", "('Abc' like '[A-Z]b*')"); + } + + public void testRelOperatorsLike02() { + parseCheck("'Abc' like '?'", "('Abc' like '?')"); + } + + public void testRelOperatorsBetween01() { + parseCheck("1 between {1, 5}", "(1 between {1,5})"); + } + + public void testRelOperatorsBetween02() { + parseCheck("'efg' between {'abc', 'xyz'}", "('efg' between {'abc','xyz'})"); + }// true + + public void testRelOperatorsIs01() { + parseCheck("'xyz' is int", "('xyz' is int)"); + }// false + + public void testRelOperatorsIs02() { + parseCheck("{1, 2, 3, 4, 5} is List", "({1,2,3,4,5} is List)"); + }// true + + public void testRelOperatorsMatches01() { + parseCheck("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "('5.0067' matches '^-?\\d+(\\.\\d{2})?$')"); + }// false + + public void testRelOperatorsMatches02() { + parseCheck("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "('5.00' matches '^-?\\d+(\\.\\d{2})?$')"); + }// true + + // mathematical operators + public void testMathOperatorsAdd01() { + parseCheck("2+4", "(2 + 4)"); + } + + public void testMathOperatorsAdd02() { + parseCheck("'a'+'b'", "('a' + 'b')"); + } + + public void testMathOperatorsAdd03() { + parseCheck("'hello'+' '+'world'", "(('hello' + ' ') + 'world')"); + } + + public void testMathOperatorsSubtract01() { + parseCheck("5-4", "(5 - 4)"); + } + + public void testMathOperatorsMultiply01() { + parseCheck("7*4", "(7 * 4)"); + } + + public void testMathOperatorsDivide01() { + parseCheck("8/4", "(8 / 4)"); + } + + public void testMathOperatorModulus01() { + parseCheck("7 % 4", "(7 % 4)"); + } + + // mixed operators + public void testMixedOperators01() { + parseCheck("true and 5>3", "(true and (5 > 3))"); + } + + // collection processors + public void testCollectionProcessorsCount01() { + parseCheck("new String[] {'abc','def','xyz'}.count()"); + } + + public void testCollectionProcessorsCount02() { + parseCheck("new int[] {1,2,3}.count()"); + } + + public void testCollectionProcessorsMax01() { + parseCheck("new int[] {1,2,3}.max()"); + } + + public void testCollectionProcessorsMin01() { + parseCheck("new int[] {1,2,3}.min()"); + } + + public void testCollectionProcessorsAverage01() { + parseCheck("new int[] {1,2,3}.average()"); + } + + public void testCollectionProcessorsSort01() { + parseCheck("new int[] {3,2,1}.sort()"); + } + + public void testCollectionProcessorsNonNull01() { + parseCheck("{'a','b',null,'d',null}.nonNull()"); + } + + public void testCollectionProcessorsDistinct01() { + parseCheck("{'a','b','a','d','e'}.distinct()"); + } + + // references + public void testReferences01() { + parseCheck("@(foo)"); + } + + public void testReferences02() { + parseCheck("@(p:foo)"); + } + + public void testReferences04() { + parseCheck("@(a/b/c:foo)", "@(a.b.c:foo)"); + }// normalized to '.' for separator in QualifiedIdentifier + + // properties + public void testProperties01() { + parseCheck("name"); + } + + public void testProperties02() { + parseCheck("placeofbirth.CitY"); + } + + public void testProperties03() { + parseCheck("a.b.c.d.e"); + } + + // inline list creation + public void testInlineListCreation01() { + parseCheck("{1, 2, 3, 4, 5}", "{1,2,3,4,5}"); + } + + public void testInlineListCreation02() { + parseCheck("{'abc','xyz'}", "{'abc','xyz'}"); + } + + // inline map creation + public void testInlineMapCreation01() { + parseCheck("#{'key1':'Value 1', 'today':DateTime.Today}"); + } + + public void testInlineMapCreation02() { + parseCheck("#{1:'January', 2:'February', 3:'March'}"); + } + + public void testInlineMapCreation03() { + parseCheck("#{'key1':'Value 1', 'today':'Monday'}['key1']"); + } + + public void testInlineMapCreation04() { + parseCheck("#{1:'January', 2:'February', 3:'March'}[3]"); + } + + // methods + public void testMethods01() { + parseCheck("echo(12)"); + } + + public void testMethods02() { + parseCheck("echo(name)"); + } + + public void testMethods03() { + parseCheck("age.doubleItAndAdd(12)"); + } + + // constructors + public void testConstructors01() { + parseCheck("new String('hello')"); + } + + public void testConstructors02() { + parseCheck("new String[3]"); + } + + // array construction + public void testArrayConstruction01() { + parseCheck("new int[] {1, 2, 3, 4, 5}", "new int[] {1,2,3,4,5}"); + } + + public void testArrayConstruction02() { + parseCheck("new String[] {'abc','xyz'}", "new String[] {'abc','xyz'}"); + } + + // variables and functions + public void testVariables01() { + parseCheck("#foo"); + } + + public void testFunctions01() { + parseCheck("#fn(1,2,3)"); + } + + public void testFunctions02() { + parseCheck("#fn('hello')"); + } + + // projections and selections + public void testProjections01() { + parseCheck("{1,2,3,4,5,6,7,8,9,10}.!{#isEven()}"); + } + + public void testSelections01() { + parseCheck("{1,2,3,4,5,6,7,8,9,10}.?{#isEven(#this) == 'y'}", + "{1,2,3,4,5,6,7,8,9,10}.?{(#isEven(#this) == 'y')}"); + } + + public void testSelectionsFirst01() { + parseCheck("{1,2,3,4,5,6,7,8,9,10}.^{#isEven(#this) == 'y'}", + "{1,2,3,4,5,6,7,8,9,10}.^{(#isEven(#this) == 'y')}"); + } + + public void testSelectionsLast01() { + parseCheck("{1,2,3,4,5,6,7,8,9,10}.${#isEven(#this) == 'y'}", + "{1,2,3,4,5,6,7,8,9,10}.${(#isEven(#this) == 'y')}"); + } + + // assignment + public void testAssignmentToVariables01() { + parseCheck("#var1='value1'"); + } + + // ternary operator + public void testTernaryOperator01() { + parseCheck("{1}.#isEven(#this) == 'y'?'it is even':'it is odd'", + "({1}.#isEven(#this) == 'y') ? 'it is even' : 'it is odd'"); + } + + // lambda + public void testLambda01() { + parseCheck("{|x,y| $x > $y ? $x : $y }", "{|x,y| ($x > $y) ? $x : $y }"); + } + + public void testLambdaMax() { + parseCheck("(#max = {|x,y| $x > $y ? $x : $y }; #max(5,25))", "(#max={|x,y| ($x > $y) ? $x : $y };#max(5,25))"); + } + + public void testLambdaFactorial() { + parseCheck("(#fact = {|n| $n <= 1 ? 1 : $n * #fact($n-1) }; #fact(5))", + "(#fact={|n| ($n <= 1) ? 1 : ($n * #fact(($n - 1))) };#fact(5))"); + } // 120 + + // Type references + public void testTypeReferences01() { + parseCheck("T(java.lang.String)"); + } + + public void testTypeReferences02() { + parseCheck("T(String)"); + } + + // Nesting expressions and expression lists + public void testExpressionLists01() { + parseCheck("(3;4;5)"); + } + + public void testExpressionLists02() { + parseCheck("( (3;4);5)", "((3;4);5)"); + } + + // TODO 4 parser recovery for this next one: missing semi + // public void testExpressionLists02a() { parseCheck("( (3;4)5)","((3;4);5)");} + // // badly formed, missing a semi + public void testExpressionLists03() { + parseCheck("(3;(4;5))"); + } + + public void testExpressionLists04() { + parseCheck("((3;4;5))", "(3;4;5)"); + } + + public void testExpressionLists05() { + parseCheck("((3;4)+(5;6))", "((3;4) + (5;6))"); + } + + public void testExpressionLists06() { + parseCheck("((3;4;)+(5;6))", "((3;4) + (5;6))"); + } + + public void testExpressionLists07() { + parseCheck("((3;4;)+(5;6;))", "((3;4) + (5;6))"); + } + + // TODO 3 too many close brackets - parser recover + // public void testExpressionLists07a() { parseCheck("((3;4;)+(5;6;)))","((3;4) + // + (5;6))");} + + + // parser warnings/errors +// public void testBrokenExpression01() { +// parseCheck("1 + "); +// +// } + + + // --- + + /** + * Parse the supplied expression and then create a string representation of the resultant AST, it should be the same + * as the original expression. + * + * @param expression the expression to parse *and* the expected value of the string form of the resultant AST + */ + public void parseCheck(String expression) { + parseCheck(expression, expression); + } + + /** + * Parse the supplied expression and then create a string representation of the resultant AST, it should be the + * expected value. + * + * @param expression the expression to parse + * @param expectedStringFormOfAST the expected string form of the AST + */ + public void parseCheck(String expression, String expectedStringFormOfAST) { + try { + SpelExpression e = parser.parseExpression(expression); + if (e != null && !e.toStringAST().equals(expectedStringFormOfAST)) { + SpelUtilities.printAbstractSyntaxTree(System.err, e); + } + if (e == null) { + fail("Parsed exception was null"); + } + assertEquals("String form of AST does not match expected output", expectedStringFormOfAST, e.toStringAST()); + } catch (ParseException ee) { + ee.printStackTrace(); + fail("Unexpected Exception: " + ee.getMessage()); + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/PerformanceTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/PerformanceTests.java new file mode 100644 index 00000000000..32551d41943 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/PerformanceTests.java @@ -0,0 +1,296 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import junit.framework.TestCase; + +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.ast.ConstructorReference; +import org.springframework.expression.spel.ast.PropertyOrFieldReference; + +/** + * Tests the evaluation of real expressions in a real context. + * + * @author Andy Clement + */ +@SuppressWarnings("unused") +public class PerformanceTests extends TestCase { + + public static final int ITERATIONS = 1000; + public static final boolean report = true; + + private static SpelExpressionParser parser = new SpelExpressionParser(); + private static EvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();; + + public void testPerformanceOfSimpleAccess() throws Exception { + long starttime = 0; + long endtime = 0; + + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("getPlaceOfBirth().getCity()"); + if (expr == null) + fail("Parser returned null for expression"); + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long freshParseTime = endtime - starttime; + + Expression expr = (Expression) parser.parseExpression("getPlaceOfBirth().getCity()"); + if (expr == null) + fail("Parser returned null for expression"); + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long reuseTime = endtime - starttime; + if (reuseTime > freshParseTime) { + System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms"); + System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms"); + fail("Should have been quicker to reuse!"); + } + } + + /** + * Testing that using a resolver/executor split for constructor invocation (ie. just doing the reflection once to + * find the constructor then executing it over and over) is faster than redoing the reflection and execution every + * time. + * + * MacBook speeds: 4-Aug-08
    + * Fresh parse every time, ITERATIONS iterations = 373ms
    + * Reuse SpelExpression, ITERATIONS iterations = 1ms
    + * Reuse SpelExpression (caching off), ITERATIONS iterations = 188ms
    + */ + public void testConstructorResolverExecutorBenefit01() throws Exception { + long starttime = 0; + long endtime = 0; + + // warmup + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("new Integer(5)"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + + // ITERATIONS calls, parsing fresh each time + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("new Integer(5)"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long freshParseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + Expression expr = (Expression) parser.parseExpression("new Integer(5)"); + if (expr == null) { + fail("Parser returned null for expression"); + } + try { + ConstructorReference.useCaching = false; + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + } finally { + ConstructorReference.useCaching = true; + } + endtime = System.currentTimeMillis(); + long cachingOffReuseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + expr = (Expression) parser.parseExpression("new Integer(5)"); + if (expr == null) { + fail("Parser returned null for expression"); + } + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long reuseTime = endtime - starttime; + + if (report) { + System.out.println("Timings for constructor execution 'new Integer(5)'"); + System.out.println("Fresh parse every time, " + ITERATIONS + " iterations = " + freshParseTime + "ms"); + System.out.println("Reuse SpelExpression (caching off), " + ITERATIONS + " iterations = " + + cachingOffReuseTime + "ms"); + System.out.println("Reuse SpelExpression, " + ITERATIONS + " iterations = " + reuseTime + "ms"); + } + if (reuseTime > freshParseTime) { + fail("Should have been quicker to reuse a parsed expression!"); + } + if (reuseTime > cachingOffReuseTime) { + fail("Should have been quicker to reuse cached!"); + } + } + + /** + * Testing that using a resolver/executor split for property access is faster than redoing the reflection and + * execution every time. + * + * MacBook speeds:
    + */ + public void testPropertyResolverExecutorBenefit_Reading() throws Exception { + long starttime = 0; + long endtime = 0; + + // warmup + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("getPlaceOfBirth().city"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + + // ITERATIONS calls, parsing fresh each time + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("getPlaceOfBirth().city"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long freshParseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + Expression expr = (Expression) parser.parseExpression("getPlaceOfBirth().city"); + if (expr == null) { + fail("Parser returned null for expression"); + } + try { + PropertyOrFieldReference.useCaching = false; + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + } finally { + PropertyOrFieldReference.useCaching = true; + } + endtime = System.currentTimeMillis(); + long cachingOffReuseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + expr = (Expression) parser.parseExpression("getPlaceOfBirth().city"); + if (expr == null) { + fail("Parser returned null for expression"); + } + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long reuseTime = endtime - starttime; + if (report) { + System.out.println("Timings for property reader execution 'getPlaceOfBirth().city'"); + System.out.println("Fresh parse every time, " + ITERATIONS + " iterations = " + freshParseTime + "ms"); + System.out.println("Reuse SpelExpression (caching off), " + ITERATIONS + " iterations = " + + cachingOffReuseTime + "ms"); + System.out.println("Reuse SpelExpression, " + ITERATIONS + " iterations = " + reuseTime + "ms"); + } + if (reuseTime > freshParseTime) { + fail("Should have been quicker to reuse a parsed expression!"); + } + if (reuseTime > cachingOffReuseTime) { + fail("Should have been quicker to reuse cached!"); + } + } + + /** + * Testing that using a resolver/executor split for property writing is faster than redoing the reflection and + * execution every time. + * + * MacBook speeds:
    + */ + public void testPropertyResolverExecutorBenefit_Writing() throws Exception { + long starttime = 0; + long endtime = 0; + + // warmup + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("randomField='Andy'"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + + // ITERATIONS calls, parsing fresh each time + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Expression expr = (Expression) parser.parseExpression("randomField='Andy'"); + if (expr == null) { + fail("Parser returned null for expression"); + } + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long freshParseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + Expression expr = (Expression) parser.parseExpression("randomField='Andy'"); + if (expr == null) { + fail("Parser returned null for expression"); + } + try { + PropertyOrFieldReference.useCaching = false; + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + } finally { + PropertyOrFieldReference.useCaching = true; + } + endtime = System.currentTimeMillis(); + long cachingOffReuseTime = endtime - starttime; + + // ITERATIONS calls, parsing once and using cached executor + expr = (Expression) parser.parseExpression("randomField='Andy'"); + if (expr == null) { + fail("Parser returned null for expression"); + } + starttime = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + Object value = expr.getValue(eContext); + } + endtime = System.currentTimeMillis(); + long reuseTime = endtime - starttime; + if (report) { + System.out.println("Timings for property writing execution 'randomField='Andy''"); + System.out.println("Fresh parse every time, " + ITERATIONS + " iterations = " + freshParseTime + "ms"); + System.out.println("Reuse SpelExpression (caching off), " + ITERATIONS + " iterations = " + + cachingOffReuseTime + "ms"); + System.out.println("Reuse SpelExpression, " + ITERATIONS + " iterations = " + reuseTime + "ms"); + } + if (reuseTime > freshParseTime) { + fail("Should have been quicker to reuse a parsed expression!"); + } + if (reuseTime > cachingOffReuseTime) { + fail("Should have been quicker to reuse cached!"); + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java new file mode 100644 index 00000000000..ac72c9a6327 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/PropertyAccessTests.java @@ -0,0 +1,138 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.spel.reflection.ReflectionPropertyResolver; +import org.springframework.expression.spel.standard.StandardEvaluationContext; + +/** + * Tests accessing of properties. + * + * @author Andy Clement + */ +public class PropertyAccessTests extends ExpressionTestCase { + + public void testSimpleAccess01() { + evaluate("name", "Nikola Tesla", String.class); + } + + public void testSimpleAccess02() { + evaluate("placeOfBirth.city", "SmilJan", String.class); + } + + public void testSimpleAccess03() { + try { + ReflectionPropertyResolver.useResolverExecutorModel = false; + evaluate("name", "Nikola Tesla", String.class); + } finally { + ReflectionPropertyResolver.useResolverExecutorModel = true; + } + } + + public void testSimpleAccess04() { + try { + ReflectionPropertyResolver.useResolverExecutorModel = false; + evaluate("placeOfBirth.city", "SmilJan", String.class); + } finally { + ReflectionPropertyResolver.useResolverExecutorModel = true; + } + } + + public void testNonExistentPropertiesAndMethods() { + // madeup does not exist as a property + evaluateAndCheckError("madeup", SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, 0); + + // name is ok but foobar does not exist: + evaluateAndCheckError("name.foobar", SpelMessages.PROPERTY_OR_FIELD_NOT_FOUND, 5); + } + + // This can resolve the property 'flibbles' on any String (very useful...) + static class StringyPropertyAccessor implements PropertyAccessor { + + int flibbles = 7; + + public Class[] getSpecificTargetClasses() { + return new Class[]{String.class}; + } + + public boolean canRead(EvaluationContext context, Object target, Object name) throws AccessException { + if (!(target instanceof String)) throw new RuntimeException("Assertion Failed! target should be String"); + return (name.equals("flibbles")); + } + + public boolean canWrite(EvaluationContext context, Object target, Object name) throws AccessException { + if (!(target instanceof String)) throw new RuntimeException("Assertion Failed! target should be String"); + return (name.equals("flibbles")); + } + + + public Object read(EvaluationContext context, Object target, Object name) throws AccessException { + if (!name.equals("flibbles") ) throw new RuntimeException("Assertion Failed! name should be flibbles"); + return flibbles; + } + + public void write(EvaluationContext context, Object target, Object name, Object newValue) + throws AccessException { + if (!name.equals("flibbles") ) throw new RuntimeException("Assertion Failed! name should be flibbles"); + try { + flibbles = (Integer)context.getTypeUtils().getTypeConverter().convertValue(newValue, Integer.class); + } catch (EvaluationException e) { + throw new AccessException("Cannot set flibbles to an object of type '"+newValue.getClass()+"'"); + } + } + + } + + // Adding a new property accessor just for a particular type + public void testAddingSpecificPropertyAccessor() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext ctx = new StandardEvaluationContext(); + + // Even though this property accessor is added after the reflection one, it specifically + // names the String class as the type it is interested in so is chosen in preference to + // any 'default' ones + ctx.addPropertyAccessor(new StringyPropertyAccessor()); + Expression expr = parser.parseExpression("new String('hello').flibbles"); + Integer i = (Integer)expr.getValue(ctx,Integer.class); + assertEquals((int)i,7); + + // The reflection one will be used for other properties... + expr = parser.parseExpression("new String('hello').CASE_INSENSITIVE_ORDER"); + Object o = expr.getValue(ctx); + assertNotNull(o); + + expr = parser.parseExpression("new String('hello').flibbles"); + expr.setValue(ctx,99); + i = (Integer)expr.getValue(ctx,Integer.class); + assertEquals((int)i,99); + + + // Cannot set it to a string value + try { + expr.setValue(ctx,"not allowed"); + fail("Should not have been allowed"); + } catch (EvaluationException e) { + // success - message will be: EL1063E:(pos 20): A problem occurred whilst attempting to set the property 'flibbles': 'Cannot set flibbles to an object of type 'class java.lang.String'' + System.out.println(e.getMessage()); + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ScenariosForSpringSecurity.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ScenariosForSpringSecurity.java new file mode 100644 index 00000000000..9c432f57d33 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ScenariosForSpringSecurity.java @@ -0,0 +1,292 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import java.lang.reflect.Method; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.MethodExecutor; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.reflection.ReflectionUtils; +import org.springframework.expression.spel.standard.StandardEvaluationContext; + + +/** + * Spring Security scenarios from https://wiki.springsource.com/display/SECURITY/Spring+Security+Expression-based+Authorization + * + * @author Andy Clement + */ +public class ScenariosForSpringSecurity extends ExpressionTestCase { + + // Helper classes for the scenario: + static class Person { + + private String n; + + Person(String n) { this.n = n; } + + public String[] getRoles() { return new String[]{"NONE"}; } + + public boolean hasAnyRole(String... roles) { + if (roles==null) return true; + String[] myRoles = getRoles(); + for (int i=0;i[] arguments) + throws AccessException { + if (name.equals("hasRole")) { + return new HasRoleExecutor(context.getTypeUtils().getTypeConverter()); + } + return null; + } + + } + + // Here i'm going to change which hasRole() executes and make it one of my own Java methods + public void testScenario04_ControllingWhichMethodsRun() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext ctx = new StandardEvaluationContext(); + + ctx.insertMethodResolver(0, new MyMethodResolver()); // NEEDS TO OVERRIDE THE REFLECTION ONE - SHOW REORDERING MECHANISM + // Might be better with a as a variable although it would work as a property too... + // Variable references using a '#' +// SpelExpression expr = parser.parseExpression("(hasRole('SUPERVISOR') or (#a < 1.042)) and hasIpAddress('10.10.0.0/16')"); + Expression expr = parser.parseExpression("(hasRole(3) or (#a < 1.042)) and hasIpAddress('10.10.0.0/16')"); + + Boolean value = null; + + ctx.setVariable("a",1.0d); // referenced as #a in the expression + ctx.setRootObject(new Supervisor("Ben")); // so non-qualified references 'hasRole()' 'hasIpAddress()' are invoked against it + value = (Boolean)expr.getValue(ctx,Boolean.class); + assertTrue(value); + +// ctx.setRootObject(new Manager("Luke")); +// ctx.setVariable("a",1.043d); +// value = (Boolean)expr.getValue(ctx,Boolean.class); +// assertFalse(value); + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsing.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsing.java new file mode 100644 index 00000000000..57f24aa0269 --- /dev/null +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsing.java @@ -0,0 +1,61 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.Expression; +import org.springframework.expression.common.DefaultTemplateParserContext; + +/** + * Test parsing of template expressions + * + * @author Andy Clement + */ +public class TemplateExpressionParsing extends ExpressionTestCase { + + public void testParsingSimpleTemplateExpression01() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + Expression expr = parser.parseExpression("hello ${'world'}",DefaultTemplateParserContext.INSTANCE); + Object o = expr.getValue(); + System.out.println(o); + assertEquals("hello world",o.toString()); + } + + public void testParsingSimpleTemplateExpression02() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + Expression expr = parser.parseExpression("hello ${'to'} you",DefaultTemplateParserContext.INSTANCE); + Object o = expr.getValue(); + System.out.println(o); + assertEquals("hello to you",o.toString()); + } + + public void testParsingSimpleTemplateExpression03() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + Expression expr = parser.parseExpression("The quick ${'brown'} fox jumped over the ${'lazy'} dog",DefaultTemplateParserContext.INSTANCE); + Object o = expr.getValue(); + System.out.println(o); + assertEquals("The quick brown fox jumped over the lazy dog",o.toString()); + } + + // TODO need to support this case but what is the neatest way? Escapet the clasing delimiters in the expression string? +// public void testParsingTemplateExpressionThatEmbedsTheDelimiters() throws Exception { +// SpelExpressionParser parser = new SpelExpressionParser(); +// Expression expr = parser.parseExpression("The quick ${{'green','brown'}.${true}} fox jumped over the ${'lazy'} dog",DefaultTemplateParserContext.INSTANCE); +// Object o = expr.getValue(); +// System.out.println(o); +// assertEquals("The quick brown fox jumped over the lazy dog",o.toString()); +// } + +}