提交 95892dc9 编写于 作者: A Andy Clement

removed lambda functions, local function and local variable references

上级 efee3b34
/*
* 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<String> getArgumentNames() {
if (getChildCount() == 0)
return Collections.emptyList();
List<String> result = new ArrayList<String>();
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);
}
}
......@@ -18,9 +18,6 @@ package org.springframework.expression.spel.ast;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.antlr.runtime.Token;
import org.springframework.expression.EvaluationContext;
......@@ -35,7 +32,7 @@ import org.springframework.expression.spel.reflection.ReflectionUtils;
* 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 may also be static java methods, registered in the context prior to invocation of the
* "#isEven(37)". Functions may also be static java methods, registered in the context prior to invocation of the
* expression.
*
* Functions are very simplistic, the arguments are not part of the definition (right now), so the names must be unique.
......@@ -57,17 +54,13 @@ public class FunctionReference extends SpelNode {
if (o == null) {
throw new SpelException(SpelMessages.FUNCTION_NOT_DEFINED, name);
}
// Two possibilities: a lambda function or a Java static method registered as a function
if (!(o instanceof Lambda || o instanceof Method)) {
if (!(o instanceof Method)) {
throw new SpelException(SpelMessages.FUNCTION_REFERENCE_CANNOT_BE_INVOKED, name, o.getClass());
}
if (o instanceof Lambda) {
return executeLambdaFunction(state, (Lambda) o);
} else { // o instanceof Method
return executeFunctionJLRMethod(state, (Method) o);
}
return executeFunctionJLRMethod(state, (Method) o);
}
/**
......@@ -80,20 +73,23 @@ public class FunctionReference extends SpelNode {
*/
private Object executeFunctionJLRMethod(ExpressionState state, Method m) throws EvaluationException {
Object[] functionArgs = getArguments(state);
if (!m.isVarArgs() && m.getParameterTypes().length != functionArgs.length) {
throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m.getParameterTypes().length);
throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, m
.getParameterTypes().length);
}
// Only static methods can be called in this way
if (!Modifier.isStatic(m.getModifiers())) {
throw new SpelException(getCharPositionInLine(),SpelMessages.FUNCTION_MUST_BE_STATIC,m.getDeclaringClass().getName()+"."+m.getName(),name);
throw new SpelException(getCharPositionInLine(), SpelMessages.FUNCTION_MUST_BE_STATIC, m
.getDeclaringClass().getName()
+ "." + m.getName(), name);
}
// Convert arguments if necessary and remap them for varargs if required
if (functionArgs != null) {
EvaluationContext ctx = state.getEvaluationContext();
TypeConverter converter = null;
if (ctx.getTypeUtils()!=null) {
if (ctx.getTypeUtils() != null) {
converter = ctx.getTypeUtils().getTypeConverter();
}
ReflectionUtils.convertArguments(m.getParameterTypes(), m.isVarArgs(), converter, functionArgs);
......@@ -101,7 +97,7 @@ public class FunctionReference extends SpelNode {
if (m.isVarArgs()) {
functionArgs = ReflectionUtils.setupArgumentsForVarargsInvocation(m.getParameterTypes(), functionArgs);
}
try {
return m.invoke(m.getClass(), functionArgs);
} catch (IllegalArgumentException e) {
......@@ -116,29 +112,6 @@ public class FunctionReference extends SpelNode {
}
}
/*
* Execute a function that was defined as a lambda function.
*/
private Object executeLambdaFunction(ExpressionState state, Lambda lambdaExpression) throws EvaluationException {
Object[] functionArgs = getArguments(state);
List<String> args = lambdaExpression.getArguments();
if (args.size() != functionArgs.length) {
throw new SpelException(SpelMessages.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, functionArgs.length, args
.size());
}
Map<String, Object> argMap = new HashMap<String, Object>();
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);
......
/*
* 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.Collections;
import java.util.List;
import org.antlr.runtime.Token;
import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.ExpressionState;
/**
* Represent a Lambda expression, eg. "{|x,y| $x > $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<String> 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;
}
}
/*
* 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<String> args = lambdaExpression.getArguments();
Map<String, Object> argMap = new HashMap<String, Object>();
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();
}
}
/*
* 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;
}
}
......@@ -16,7 +16,6 @@ tokens {
REFERENCE;
PROPERTY_OR_FIELD;
INDEXER;
ARGLIST;
CONSTRUCTOR;
HOLDER;
CONSTRUCTOR_ARRAY;
......@@ -27,8 +26,6 @@ tokens {
VARIABLEREF;
LIST_INITIALIZER;
MAP_INITIALIZER;
LOCALVAR;
LOCALFUNC;
MAP_ENTRY;
METHOD;
ADD;
......@@ -100,7 +97,6 @@ startNode
parenExpr
| methodOrProperty
| functionOrVar
| localFunctionOrVar
| reference
| indexer
| literal
......@@ -112,7 +108,6 @@ startNode
| lastSelection
| listInitializer
| mapInitializer
| lambda
;
node
......@@ -141,13 +136,6 @@ 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)
......@@ -194,15 +182,6 @@ lastSelection: SELECT_LAST^ expression RCURLY!;
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)
......@@ -312,7 +291,6 @@ BANG: '!';
POUND: '#';
QMARK: '?';
DEFAULT: '??';
LAMBDA: '{|';
PROJECT: '!{';
SELECT: '?{';
SELECT_FIRST: '^{';
......
GREATER_THAN_OR_EQUAL=77
SELECT_FIRST=56
COMMA=49
HOLDER=13
GREATER_THAN=76
TYPE=58
GREATER_THAN_OR_EQUAL=71
SELECT_FIRST=52
COMMA=45
HOLDER=12
GREATER_THAN=70
TYPE=54
EXPRESSIONLIST=4
MINUS=39
MAP_ENTRY=24
SELECT_LAST=57
NUMBER=28
LESS_THAN=74
BANG=44
ARGLIST=11
FALSE=68
METHOD=25
MINUS=36
MAP_ENTRY=21
SELECT_LAST=53
NUMBER=25
LESS_THAN=68
BANG=41
FALSE=62
METHOD=22
PROPERTY_OR_FIELD=9
LBRACKET=51
LBRACKET=47
INDEXER=10
MOD=42
CONSTRUCTOR_ARRAY=14
FUNCTIONREF=16
NULL_LITERAL=64
NAMED_ARGUMENT=15
OR=36
PIPE=60
DOT=45
RCURLY=54
MOD=39
CONSTRUCTOR_ARRAY=13
FUNCTIONREF=15
NULL_LITERAL=58
NAMED_ARGUMENT=14
OR=33
PIPE=77
DOT=42
RCURLY=50
EXPRESSION=6
AND=37
LCURLY=61
REAL_TYPE_SUFFIX=88
STRING_LITERAL=62
SELECT=55
AND=34
LCURLY=55
REAL_TYPE_SUFFIX=84
STRING_LITERAL=56
SELECT=51
QUALIFIED_IDENTIFIER=7
RBRACKET=52
SUBTRACT=27
ASSIGN=30
BETWEEN=80
RPAREN=35
SIGN=89
LPAREN=34
HEX_DIGIT=71
PLUS=38
LIST_INITIALIZER=20
APOS=83
RBRACKET=48
SUBTRACT=24
ASSIGN=27
BETWEEN=74
RPAREN=32
SIGN=85
LPAREN=31
HEX_DIGIT=65
PLUS=35
LIST_INITIALIZER=19
APOS=78
INTEGER_LITERAL=5
AT=50
ID=47
NOT_EQUAL=73
RANGE=18
POWER=43
TYPEREF=17
DECIMAL_DIGIT=69
WS=85
IS=79
DOLLAR=48
LESS_THAN_OR_EQUAL=75
SEMIRPAREN=29
DQ_STRING_LITERAL=63
HEXADECIMAL_INTEGER_LITERAL=65
MAP_INITIALIZER=21
LAMBDA=59
LOCALFUNC=23
IN=78
SEMI=82
CONSTRUCTOR=12
INTEGER_TYPE_SUFFIX=70
EQUAL=72
MATCHES=81
DOT_ESCAPED=84
UPTO=86
QMARK=32
AT=46
ID=44
NOT_EQUAL=67
RANGE=17
POWER=40
TYPEREF=16
DECIMAL_DIGIT=63
WS=80
IS=73
DOLLAR=81
LESS_THAN_OR_EQUAL=69
SEMIRPAREN=26
DQ_STRING_LITERAL=57
HEXADECIMAL_INTEGER_LITERAL=59
MAP_INITIALIZER=20
IN=72
SEMI=76
CONSTRUCTOR=11
INTEGER_TYPE_SUFFIX=64
EQUAL=66
MATCHES=75
DOT_ESCAPED=79
UPTO=82
QMARK=29
REFERENCE=8
PROJECT=53
DEFAULT=31
COLON=33
DIV=41
LOCALVAR=22
STAR=40
REAL_LITERAL=66
VARIABLEREF=19
EXPONENT_PART=87
TRUE=67
ADD=26
POUND=46
'new'=90
PROJECT=49
DEFAULT=28
COLON=30
DIV=38
STAR=37
REAL_LITERAL=60
VARIABLEREF=18
EXPONENT_PART=83
TRUE=61
ADD=23
POUND=43
'new'=86
......@@ -17,7 +17,6 @@ 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;
......@@ -27,11 +26,8 @@ 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.Lambda;
import org.springframework.expression.spel.ast.ListInitializer;
import org.springframework.expression.spel.ast.Literal;
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;
......@@ -150,10 +146,6 @@ public class SpelTreeAdaptor extends CommonTreeAdaptor {
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:
......@@ -184,11 +176,6 @@ public class SpelTreeAdaptor extends CommonTreeAdaptor {
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:
......
......@@ -18,8 +18,6 @@ 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.
*
......@@ -285,9 +283,9 @@ public class EvaluationTests extends ExpressionTestCase {
"[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 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);
......@@ -298,9 +296,9 @@ public class EvaluationTests extends ExpressionTestCase {
SpelMessages.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
}
public void testSelectionUsingIndex() {
evaluate("{1,2,3,4,5,6,7,8,9,10}.?{$index > 5 }", "[7, 8, 9, 10]", ArrayList.class);
}
// 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);
......@@ -394,16 +392,6 @@ public class EvaluationTests extends ExpressionTestCase {
evaluate("#reverseString('hello')", "olleh", String.class);
}
// lambda
public void testLambdaNoArgs() {
evaluate("{|| true }", "{|| true }", Lambda.class);
}
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);
......
......@@ -355,11 +355,6 @@ public class ParsingTests extends TestCase {
"({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))");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册