From e5fea54aea4d9b874242c993d8fd3210c02d69dc Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Wed, 27 May 2009 19:16:45 +0000 Subject: [PATCH] fix for ternary or elvis using a full expression for their result components. parser polishing --- .../spel/ast/{OperatorAnd.java => OpAnd.java} | 4 +- .../{OperatorDivide.java => OpDivide.java} | 4 +- .../ast/{OperatorMinus.java => OpMinus.java} | 4 +- .../{OperatorModulus.java => OpModulus.java} | 4 +- ...{OperatorMultiply.java => OpMultiply.java} | 4 +- .../spel/ast/{OperatorOr.java => OpOr.java} | 4 +- .../ast/{OperatorPlus.java => OpPlus.java} | 4 +- .../spel/standard/SpelExpressionParser.java | 293 +++++++++--------- .../expression/spel/standard/Token.java | 24 -- .../expression/spel/EvaluationTests.java | 9 + .../expression/spel/HelperTests.java | 2 +- .../spel/standard/SpelParserTests.java | 8 +- 12 files changed, 172 insertions(+), 192 deletions(-) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorAnd.java => OpAnd.java} (94%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorDivide.java => OpDivide.java} (95%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorMinus.java => OpMinus.java} (97%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorModulus.java => OpModulus.java} (94%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorMultiply.java => OpMultiply.java} (96%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorOr.java => OpOr.java} (95%) rename org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/{OperatorPlus.java => OpPlus.java} (97%) 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/OpAnd.java similarity index 94% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorAnd.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpAnd.java index 2dffb11a9e8..916245612d6 100644 --- 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/OpAnd.java @@ -28,9 +28,9 @@ import org.springframework.expression.spel.support.BooleanTypedValue; * @author Andy Clement * @since 3.0 */ -public class OperatorAnd extends Operator { +public class OpAnd extends Operator { - public OperatorAnd(int pos, SpelNodeImpl... operands) { + public OpAnd(int pos, SpelNodeImpl... operands) { super("and", pos, operands); } 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/OpDivide.java similarity index 95% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorDivide.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java index 503b3acd89a..edd96e29515 100644 --- 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/OpDivide.java @@ -28,9 +28,9 @@ import org.springframework.expression.spel.ExpressionState; * @author Andy Clement * @since 3.0 */ -public class OperatorDivide extends Operator { +public class OpDivide extends Operator { - public OperatorDivide(int pos, SpelNodeImpl... operands) { + public OpDivide(int pos, SpelNodeImpl... operands) { super("/", pos, operands); } 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/OpMinus.java similarity index 97% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMinus.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpMinus.java index db7dcbe5257..67dd05cd3cb 100644 --- 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/OpMinus.java @@ -36,9 +36,9 @@ import org.springframework.expression.spel.ExpressionState; * @author Andy Clement * @since 3.0 */ -public class OperatorMinus extends Operator { +public class OpMinus extends Operator { - public OperatorMinus(int pos, SpelNodeImpl... operands) { + public OpMinus(int pos, SpelNodeImpl... operands) { super("-", pos, operands); } 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/OpModulus.java similarity index 94% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorModulus.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpModulus.java index 08504b55e2a..c60ff662223 100644 --- 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/OpModulus.java @@ -27,9 +27,9 @@ import org.springframework.expression.spel.ExpressionState; * @author Andy Clement * @since 3.0 */ -public class OperatorModulus extends Operator { +public class OpModulus extends Operator { - public OperatorModulus(int pos, SpelNodeImpl... operands) { + public OpModulus(int pos, SpelNodeImpl... operands) { super("%", pos, operands); } 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/OpMultiply.java similarity index 96% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorMultiply.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java index 80561ce3cc1..148d318b93a 100644 --- 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/OpMultiply.java @@ -36,10 +36,10 @@ import org.springframework.expression.spel.ExpressionState; * @author Andy Clement * @since 3.0 */ -public class OperatorMultiply extends Operator { +public class OpMultiply extends Operator { - public OperatorMultiply(int pos, SpelNodeImpl... operands) { + public OpMultiply(int pos, SpelNodeImpl... operands) { super("*", pos, operands); } 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/OpOr.java similarity index 95% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorOr.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpOr.java index 4df05be373e..a798f0d0e09 100644 --- 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/OpOr.java @@ -27,9 +27,9 @@ import org.springframework.expression.spel.support.BooleanTypedValue; * @author Andy Clement * @since 3.0 */ -public class OperatorOr extends Operator { +public class OpOr extends Operator { - public OperatorOr(int pos, SpelNodeImpl... operands) { + public OpOr(int pos, SpelNodeImpl... operands) { super("or", pos, operands); } 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/OpPlus.java similarity index 97% rename from org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OperatorPlus.java rename to org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index 85fbc178130..c6d5c190314 100644 --- 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/OpPlus.java @@ -35,9 +35,9 @@ import org.springframework.expression.spel.ExpressionState; * @author Andy Clement * @since 3.0 */ -public class OperatorPlus extends Operator { +public class OpPlus extends Operator { - public OperatorPlus(int pos, SpelNodeImpl... operands) { + public OpPlus(int pos, SpelNodeImpl... operands) { super("+", pos, operands); } diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java index f2846c15345..50893d28cfd 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -37,22 +37,22 @@ import org.springframework.expression.spel.ast.Indexer; import org.springframework.expression.spel.ast.Literal; import org.springframework.expression.spel.ast.MethodReference; import org.springframework.expression.spel.ast.NullLiteral; +import org.springframework.expression.spel.ast.OpAnd; +import org.springframework.expression.spel.ast.OpDivide; import org.springframework.expression.spel.ast.OpEQ; import org.springframework.expression.spel.ast.OpGE; import org.springframework.expression.spel.ast.OpGT; import org.springframework.expression.spel.ast.OpLE; import org.springframework.expression.spel.ast.OpLT; +import org.springframework.expression.spel.ast.OpMinus; +import org.springframework.expression.spel.ast.OpModulus; +import org.springframework.expression.spel.ast.OpMultiply; import org.springframework.expression.spel.ast.OpNE; -import org.springframework.expression.spel.ast.OperatorAnd; -import org.springframework.expression.spel.ast.OperatorDivide; +import org.springframework.expression.spel.ast.OpOr; +import org.springframework.expression.spel.ast.OpPlus; import org.springframework.expression.spel.ast.OperatorInstanceof; 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.OperatorPower; import org.springframework.expression.spel.ast.Projection; import org.springframework.expression.spel.ast.PropertyOrFieldReference; @@ -97,9 +97,9 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { try { + this.expressionString = expressionString; Tokenizer tokenizer = new Tokenizer(expressionString); tokenizer.process(); - this.expressionString = expressionString; tokenStream = tokenizer.getTokens(); tokenStreamLength = tokenStream.size(); tokenStreamPointer = 0; @@ -115,19 +115,12 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } } - public String toString(Token t) { - if (t.getKind().hasPayload()) { - return t.stringValue(); - } else { - return t.kind.toString().toLowerCase(); - } - } - // expression // : logicalOrExpression // ( (ASSIGN^ logicalOrExpression) // | (DEFAULT^ logicalOrExpression) - // | (QMARK^ expression COLON! expression))?; + // | (QMARK^ expression COLON! expression) + // | (ELVIS^ expression))?; private SpelNodeImpl eatExpression() { SpelNodeImpl expr = eatLogicalOrExpression(); if (moreTokens()) { @@ -138,13 +131,13 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { return new Assign(toPos(t),expr,assignedValue); } else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b) nextToken(); // elvis has left the building - SpelNodeImpl valueIfNull = eatLogicalOrExpression(); + SpelNodeImpl valueIfNull = eatExpression(); return new Elvis(toPos(t),expr,valueIfNull); } else if (t.kind==TokenKind.QMARK) { // a?b:c nextToken(); - SpelNodeImpl ifTrueExprValue = eatLogicalOrExpression(); + SpelNodeImpl ifTrueExprValue = eatExpression(); eatToken(TokenKind.COLON); - SpelNodeImpl ifFalseExprValue = eatLogicalOrExpression(); + SpelNodeImpl ifFalseExprValue = eatExpression(); return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue); } } @@ -155,63 +148,59 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { private SpelNodeImpl eatLogicalOrExpression() { SpelNodeImpl expr = eatLogicalAndExpression(); while (peekIdentifierToken("or")) { - Token t = nextToken();//consume OR - SpelNodeImpl expr2 = eatLogicalAndExpression(); - checkRightOperand(t,expr2); - expr = new OperatorOr(toPos(t),expr,expr2); + Token t = nextToken(); //consume OR + SpelNodeImpl rhExpr = eatLogicalAndExpression(); + checkRightOperand(t,rhExpr); + expr = new OpOr(toPos(t),expr,rhExpr); } return expr; } - - private void checkRightOperand(Token token, SpelNodeImpl operandExpression) { - if (operandExpression==null) { - throw new InternalParseException(new SpelParseException(token.startpos,SpelMessages.RIGHT_OPERAND_PROBLEM)); - } - } - //logicalAndExpression : relationalExpression (AND^ relationalExpression)*; + // logicalAndExpression : relationalExpression (AND^ relationalExpression)*; private SpelNodeImpl eatLogicalAndExpression() { SpelNodeImpl expr = eatRelationalExpression(); while (peekIdentifierToken("and")) { Token t = nextToken();// consume 'AND' - SpelNodeImpl rightExpr = eatRelationalExpression(); - checkRightOperand(t,rightExpr); - expr = new OperatorAnd(toPos(t),expr,rightExpr); + SpelNodeImpl rhExpr = eatRelationalExpression(); + checkRightOperand(t,rhExpr); + expr = new OpAnd(toPos(t),expr,rhExpr); } return expr; } - //relationalExpression : sumExpression (relationalOperator^ sumExpression)?; + // relationalExpression : sumExpression (relationalOperator^ sumExpression)?; private SpelNodeImpl eatRelationalExpression() { SpelNodeImpl expr = eatSumExpression(); Token relationalOperatorToken = maybeEatRelationalOperator(); if (relationalOperatorToken!=null) { - Token t = nextToken();//consume relational operator token - SpelNodeImpl expr2 = eatSumExpression(); - checkRightOperand(t,expr2); + Token t = nextToken(); //consume relational operator token + SpelNodeImpl rhExpr = eatSumExpression(); + checkRightOperand(t,rhExpr); + TokenKind tk = relationalOperatorToken.kind; if (relationalOperatorToken.isNumericRelationalOperator()) { - if (relationalOperatorToken.isGreaterThan()) { - return new OpGT(toPos(t),expr,expr2); - } else if (relationalOperatorToken.isLessThan()) { - return new OpLT(toPos(t),expr,expr2); - } else if (relationalOperatorToken.isLessThanOrEqual()) { - return new OpLE(toPos(t),expr,expr2); - } else if (relationalOperatorToken.isGreaterThanOrEqual()) { - return new OpGE(toPos(t),expr,expr2); - } else if (relationalOperatorToken.isEquality()) { - return new OpEQ(toPos(t),expr,expr2); + int pos = toPos(t); + if (tk==TokenKind.GT) { + return new OpGT(pos,expr,rhExpr); + } else if (tk==TokenKind.LT) { + return new OpLT(pos,expr,rhExpr); + } else if (tk==TokenKind.LE) { + return new OpLE(pos,expr,rhExpr); + } else if (tk==TokenKind.GE) { + return new OpGE(pos,expr,rhExpr); + } else if (tk==TokenKind.EQ) { + return new OpEQ(pos,expr,rhExpr); } else { - assert relationalOperatorToken.kind==TokenKind.NE; - return new OpNE(toPos(t),expr,expr2); + assert tk==TokenKind.NE; + return new OpNE(pos,expr,rhExpr); } } - if (relationalOperatorToken.kind==TokenKind.INSTANCEOF) { - return new OperatorInstanceof(toPos(t),expr,expr2); - } else if (relationalOperatorToken.kind==TokenKind.MATCHES) { - return new OperatorMatches(toPos(t),expr,expr2); + if (tk==TokenKind.INSTANCEOF) { + return new OperatorInstanceof(toPos(t),expr,rhExpr); + } else if (tk==TokenKind.MATCHES) { + return new OperatorMatches(toPos(t),expr,rhExpr); } else { - assert relationalOperatorToken.kind==TokenKind.BETWEEN; - return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,expr2); + assert tk==TokenKind.BETWEEN; + return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,rhExpr); } } return expr; @@ -222,69 +211,71 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { SpelNodeImpl expr = eatProductExpression(); while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) { Token t = nextToken();//consume PLUS or MINUS - SpelNodeImpl rhOperand = eatProductExpression(); - checkRightOperand(t,rhOperand); - if (t.getKind()==TokenKind.PLUS) { - expr = new OperatorPlus(toPos(t),expr,rhOperand); + SpelNodeImpl rhExpr = eatProductExpression(); + checkRightOperand(t,rhExpr); + if (t.kind==TokenKind.PLUS) { + expr = new OpPlus(toPos(t),expr,rhExpr); } else { - expr = new OperatorMinus(toPos(t),expr,rhOperand); + assert t.kind==TokenKind.MINUS; + expr = new OpMinus(toPos(t),expr,rhExpr); } } return expr; } - //productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; + // productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; private SpelNodeImpl eatProductExpression() { SpelNodeImpl expr = eatPowerExpression(); while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) { Token t = nextToken(); // consume STAR/DIV/MOD - SpelNodeImpl expr2 = eatPowerExpression(); - checkRightOperand(t,expr2); - if (t.getKind()==TokenKind.STAR) { - expr = new OperatorMultiply(toPos(t),expr,expr2); - } else if (t.getKind()==TokenKind.DIV) { - expr = new OperatorDivide(toPos(t),expr,expr2); + SpelNodeImpl rhExpr = eatPowerExpression(); + checkRightOperand(t,rhExpr); + if (t.kind==TokenKind.STAR) { + expr = new OpMultiply(toPos(t),expr,rhExpr); + } else if (t.kind==TokenKind.DIV) { + expr = new OpDivide(toPos(t),expr,rhExpr); } else { - expr = new OperatorModulus(toPos(t),expr,expr2); + assert t.kind==TokenKind.MOD; + expr = new OpModulus(toPos(t),expr,rhExpr); } } return expr; } - //powerExpr : unaryExpression (POWER^ unaryExpression)? ; + // powerExpr : unaryExpression (POWER^ unaryExpression)? ; private SpelNodeImpl eatPowerExpression() { SpelNodeImpl expr = eatUnaryExpression(); if (peekToken(TokenKind.POWER)) { Token t = nextToken();//consume POWER - SpelNodeImpl expr2 = eatUnaryExpression(); - checkRightOperand(t,expr2); - return new OperatorPower(toPos(t),expr, expr2); + SpelNodeImpl rhExpr = eatUnaryExpression(); + checkRightOperand(t,rhExpr); + return new OperatorPower(toPos(t),expr, rhExpr); } return expr; } - //unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ; + // unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ; private SpelNodeImpl eatUnaryExpression() { - if (peekToken(TokenKind.PLUS) || peekToken(TokenKind.MINUS) || peekToken(TokenKind.BANG)) { + if (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.BANG)) { Token t = nextToken(); SpelNodeImpl expr = eatUnaryExpression(); if (t.kind==TokenKind.BANG) { return new OperatorNot(toPos(t),expr); } else if (t.kind==TokenKind.PLUS) { - return new OperatorPlus(toPos(t),expr); + return new OpPlus(toPos(t),expr); } else { assert t.kind==TokenKind.MINUS; - return new OperatorMinus(toPos(t),expr); + return new OpMinus(toPos(t),expr); } } else { return eatPrimaryExpression(); } } - //primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?); + // primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?); private SpelNodeImpl eatPrimaryExpression() { List nodes = new ArrayList(); - SpelNodeImpl start = eatStartNode(); + SpelNodeImpl start = eatStartNode(); // always a start node nodes.add(start); while (maybeEatNode()) { nodes.add(pop()); @@ -296,15 +287,10 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } } - private int toPos(int start,int end) { - return (start<<16)+end; - } - - //node : ((DOT dottedNode) | nonDottedNode)+; + // node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+; private boolean maybeEatNode() { - Token t = peekToken(); SpelNodeImpl expr = null; - if (t!=null && peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) { + if (peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) { expr = eatDottedNode(); } else { expr = maybeEatNonDottedNode(); @@ -317,7 +303,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } } - //nonDottedNode: indexer; + // nonDottedNode: indexer; private SpelNodeImpl maybeEatNonDottedNode() { if (peekToken(TokenKind.LSQUARE)) { if (maybeEatIndexer()) { @@ -338,23 +324,20 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { // ; private SpelNodeImpl eatDottedNode() { Token t = nextToken();// it was a '.' or a '?.' - //eatToken(TokenKind.DOT); boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI; if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) { return pop(); } - throw new InternalParseException(new SpelParseException(expressionString,t.startpos,SpelMessages.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken()))); + raiseInternalException(t.startpos,SpelMessages.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken())); + return null; } -// functionOrVar -// : (POUND ID LPAREN) => function -// | var -// ; -// -//function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); -// -//var : POUND id=ID -> ^(VARIABLEREF[$id]); - + // functionOrVar + // : (POUND ID LPAREN) => function + // | var + // + // function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); + // var : POUND id=ID -> ^(VARIABLEREF[$id]); private boolean maybeEatFunctionOrVar() { if (!peekToken(TokenKind.HASH)) { return false; @@ -371,8 +354,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } } - - //methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; + // methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; private SpelNodeImpl[] maybeEatMethodArgs() { if (!peekToken(TokenKind.LPAREN)) { return null; @@ -484,22 +466,20 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { //projection: PROJECT^ expression RCURLY!; private boolean maybeEatProjection(boolean nullSafeNavigation) { Token t = peekToken(); - if (!peekToken(TokenKind.PROJECT)) { + if (!peekToken(TokenKind.PROJECT,true)) { return false; } - nextToken(); SpelNodeImpl expr = eatExpression(); eatToken(TokenKind.RSQUARE); - constructedNodes.push(new Projection(nullSafeNavigation, toPos(t),expr)); + constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr)); return true; } private boolean maybeEatIndexer() { Token t = peekToken(); - if (!peekToken(TokenKind.LSQUARE)) { + if (!peekToken(TokenKind.LSQUARE,true)) { return false; } - nextToken(); SpelNodeImpl expr = eatExpression(); eatToken(TokenKind.RSQUARE); constructedNodes.push(new Indexer(toPos(t),expr)); @@ -528,8 +508,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { List qualifiedIdPieces = new ArrayList(); Token startnode = eatToken(TokenKind.IDENTIFIER); qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode))); - while (peekToken(TokenKind.DOT)) { - nextToken(); + while (peekToken(TokenKind.DOT,true)) { Token node = eatToken(TokenKind.IDENTIFIER); qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node))); } @@ -555,8 +534,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } //constructor -// : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) -// ; + //: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) private boolean maybeEatConstructorReference() { if (peekIdentifierToken("new")) { Token newToken = nextToken(); @@ -579,63 +557,42 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { return constructedNodes.pop(); } -// literal: -// INTEGER_LITERAL -// | boolLiteral -// | STRING_LITERAL - -// | HEXADECIMAL_INTEGER_LITERAL -// | REAL_LITERAL -// | DQ_STRING_LITERAL -// | NULL_LITERAL -// ; + // literal + // : INTEGER_LITERAL + // | boolLiteral + // | STRING_LITERAL + // | HEXADECIMAL_INTEGER_LITERAL + // | REAL_LITERAL + // | DQ_STRING_LITERAL + // | NULL_LITERAL private boolean maybeEatLiteral() { Token t = peekToken(); if (t==null) { return false; } if (t.kind==TokenKind.LITERAL_INT) { - nextToken(); push(Literal.getIntLiteral(t.data, toPos(t), 10)); - return true; } else if (t.kind==TokenKind.LITERAL_LONG) { - nextToken(); push(Literal.getLongLiteral(t.data, toPos(t), 10)); - return true; } else if (t.kind==TokenKind.LITERAL_HEXINT) { - nextToken(); push(Literal.getIntLiteral(t.data, toPos(t), 16)); - return true; } else if (t.kind==TokenKind.LITERAL_HEXLONG) { - nextToken(); push(Literal.getLongLiteral(t.data, toPos(t), 16)); - return true; } else if (t.kind==TokenKind.LITERAL_REAL) { - nextToken(); push(Literal.getRealLiteral(t.data, toPos(t),false)); - return true; } else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) { - nextToken(); push(Literal.getRealLiteral(t.data, toPos(t), true)); - return true; } else if (peekIdentifierToken("true")) { - nextToken(); push(new BooleanLiteral(t.data,toPos(t),true)); - return true; } else if (peekIdentifierToken("false")) { - nextToken(); push(new BooleanLiteral(t.data,toPos(t),false)); - return true; } else if (t.kind==TokenKind.LITERAL_STRING) { - nextToken(); push(new StringLiteral(t.data,toPos(t),t.data)); - return true; + } else { + return false; } - return false; - } - - private int toPos(Token t) { - return (t.startpos<<16)+t.endpos; + nextToken(); + return true; } //parenExpr : LPAREN! expression RPAREN!; @@ -650,11 +607,10 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { return false; } } - // relationalOperator - // : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL | INSTANCEOF - // | BETWEEN | MATCHES + // : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN + // | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES private Token maybeEatRelationalOperator() { Token t = peekToken(); if (t==null) { @@ -689,9 +645,22 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } private boolean peekToken(TokenKind desiredTokenKind) { - if (!moreTokens()) return false; + return peekToken(desiredTokenKind,false); + } + + private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) { + if (!moreTokens()) { + return false; + } Token t = peekToken(); - return t.kind==desiredTokenKind; + if (t.kind==desiredTokenKind) { + if (consumeIfMatched) { + tokenStreamPointer++; + } + return true; + } else { + return false; + } } private boolean peekToken(TokenKind possible1,TokenKind possible2) { @@ -707,7 +676,9 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { } private boolean peekIdentifierToken(String identifierString) { - if (!moreTokens()) return false; + if (!moreTokens()) { + return false; + } Token t = peekToken(); return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString); } @@ -722,7 +693,6 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { private boolean moreTokens() { return tokenStreamPointer=tokenStreamLength) { @@ -741,5 +711,30 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { private void raiseInternalException(int pos, SpelMessages message,Object... inserts) { throw new InternalParseException(new SpelParseException(expressionString,pos,message,inserts)); } + + public String toString(Token t) { + if (t.getKind().hasPayload()) { + return t.stringValue(); + } else { + return t.kind.toString().toLowerCase(); + } + } + + private void checkRightOperand(Token token, SpelNodeImpl operandExpression) { + if (operandExpression==null) { + raiseInternalException(token.startpos,SpelMessages.RIGHT_OPERAND_PROBLEM); + } + } + /** + * Compress the start and end of a token into a single int + */ + private int toPos(Token t) { + return (t.startpos<<16)+t.endpos; + } + + private int toPos(int start,int end) { + return (start<<16)+end; + } + } diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java index 3b89cabac1e..09cd24ee92c 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java @@ -64,30 +64,6 @@ class Token { return kind==TokenKind.IDENTIFIER; } - public boolean isGreaterThan() { - return kind==TokenKind.GT; - } - - public boolean isLessThan() { - return kind==TokenKind.LT; - } - - public boolean isGreaterThanOrEqual() { - return kind==TokenKind.GE; - } - - public boolean isEquality() { - return kind==TokenKind.EQ; - } - - public boolean isLessThanOrEqual() { - return kind==TokenKind.LE; - } - - public boolean isInstanceOf() { - return kind==TokenKind.INSTANCEOF; - } - public boolean isNumericRelationalOperator() { return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE; } 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 index 325c3a9134e..bb1b60ed563 100644 --- 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 @@ -217,6 +217,7 @@ public class EvaluationTests extends ExpressionTestCase { evaluate("2>4?1:2",2,Integer.class); } + @Test public void testTernaryOperator02() { evaluate("'abc'=='abc'?1:2",1,Integer.class); @@ -233,6 +234,14 @@ public class EvaluationTests extends ExpressionTestCase { Assert.assertFalse(expr.isWritable(eContext)); } + @Test + public void testTernaryOperator05() { + evaluate("1>2?#var=4:#var=5",5,Integer.class); + evaluate("3?:#var=5",3,Integer.class); + evaluate("null?:#var=5",5,Integer.class); + evaluate("2>4?(3>2?true:false):(5<3?true:false)",false,Boolean.class); + } + @Test public void testIndexer03() { evaluate("'christian'[8]", "n", String.class); diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/HelperTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/HelperTests.java index 7b295b09bec..fd411f75772 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/HelperTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/HelperTests.java @@ -85,7 +85,7 @@ public class HelperTests extends ExpressionTestCase { // IntLiteral value:2 // ===> Expression '3+4+5+6+7-2' - AST end Assert.assertTrue(s.indexOf("===> Expression '3+4+5+6+7-2' - AST start")!=-1); - Assert.assertTrue(s.indexOf(" OperatorPlus value:((((3 + 4) + 5) + 6) + 7) #children:2")!=-1); + Assert.assertTrue(s.indexOf(" OpPlus value:((((3 + 4) + 5) + 6) + 7) #children:2")!=-1); } @Test diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java index 1f926f891ce..bfb8de13d54 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java @@ -24,8 +24,8 @@ import org.springframework.expression.spel.SpelExpression; import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelNode; import org.springframework.expression.spel.SpelParseException; -import org.springframework.expression.spel.ast.OperatorAnd; -import org.springframework.expression.spel.ast.OperatorOr; +import org.springframework.expression.spel.ast.OpAnd; +import org.springframework.expression.spel.ast.OpOr; public class SpelParserTests { @@ -228,8 +228,8 @@ public class SpelParserTests { public void testPositionalInformation() throws EvaluationException, ParseException { SpelExpression expr = new SpelExpressionParser().parse("true and true or false"); SpelNode rootAst = expr.getAST(); - OperatorOr operatorOr = (OperatorOr)rootAst; - OperatorAnd operatorAnd = (OperatorAnd)operatorOr.getLeftOperand(); + OpOr operatorOr = (OpOr)rootAst; + OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand(); SpelNode rightOrOperand = operatorOr.getRightOperand(); // check position for final 'false'