fix for ternary or elvis using a full expression for their result components. parser polishing

This commit is contained in:
Andy Clement 2009-05-27 19:16:45 +00:00
parent 1a7ec7daf2
commit e5fea54aea
12 changed files with 172 additions and 192 deletions

View File

@ -28,9 +28,9 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("and", pos, operands);
} }

View File

@ -28,9 +28,9 @@ import org.springframework.expression.spel.ExpressionState;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("/", pos, operands);
} }

View File

@ -36,9 +36,9 @@ import org.springframework.expression.spel.ExpressionState;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("-", pos, operands);
} }

View File

@ -27,9 +27,9 @@ import org.springframework.expression.spel.ExpressionState;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("%", pos, operands);
} }

View File

@ -36,10 +36,10 @@ import org.springframework.expression.spel.ExpressionState;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("*", pos, operands);
} }

View File

@ -27,9 +27,9 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("or", pos, operands);
} }

View File

@ -35,9 +35,9 @@ import org.springframework.expression.spel.ExpressionState;
* @author Andy Clement * @author Andy Clement
* @since 3.0 * @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); super("+", pos, operands);
} }

View File

@ -37,22 +37,22 @@ import org.springframework.expression.spel.ast.Indexer;
import org.springframework.expression.spel.ast.Literal; import org.springframework.expression.spel.ast.Literal;
import org.springframework.expression.spel.ast.MethodReference; import org.springframework.expression.spel.ast.MethodReference;
import org.springframework.expression.spel.ast.NullLiteral; 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.OpEQ;
import org.springframework.expression.spel.ast.OpGE; import org.springframework.expression.spel.ast.OpGE;
import org.springframework.expression.spel.ast.OpGT; import org.springframework.expression.spel.ast.OpGT;
import org.springframework.expression.spel.ast.OpLE; import org.springframework.expression.spel.ast.OpLE;
import org.springframework.expression.spel.ast.OpLT; 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.OpNE;
import org.springframework.expression.spel.ast.OperatorAnd; import org.springframework.expression.spel.ast.OpOr;
import org.springframework.expression.spel.ast.OperatorDivide; import org.springframework.expression.spel.ast.OpPlus;
import org.springframework.expression.spel.ast.OperatorInstanceof; import org.springframework.expression.spel.ast.OperatorInstanceof;
import org.springframework.expression.spel.ast.OperatorMatches; 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.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.OperatorPower;
import org.springframework.expression.spel.ast.Projection; import org.springframework.expression.spel.ast.Projection;
import org.springframework.expression.spel.ast.PropertyOrFieldReference; 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 { protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
try { try {
this.expressionString = expressionString;
Tokenizer tokenizer = new Tokenizer(expressionString); Tokenizer tokenizer = new Tokenizer(expressionString);
tokenizer.process(); tokenizer.process();
this.expressionString = expressionString;
tokenStream = tokenizer.getTokens(); tokenStream = tokenizer.getTokens();
tokenStreamLength = tokenStream.size(); tokenStreamLength = tokenStream.size();
tokenStreamPointer = 0; 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 // expression
// : logicalOrExpression // : logicalOrExpression
// ( (ASSIGN^ logicalOrExpression) // ( (ASSIGN^ logicalOrExpression)
// | (DEFAULT^ logicalOrExpression) // | (DEFAULT^ logicalOrExpression)
// | (QMARK^ expression COLON! expression))?; // | (QMARK^ expression COLON! expression)
// | (ELVIS^ expression))?;
private SpelNodeImpl eatExpression() { private SpelNodeImpl eatExpression() {
SpelNodeImpl expr = eatLogicalOrExpression(); SpelNodeImpl expr = eatLogicalOrExpression();
if (moreTokens()) { if (moreTokens()) {
@ -138,13 +131,13 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
return new Assign(toPos(t),expr,assignedValue); return new Assign(toPos(t),expr,assignedValue);
} else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b) } else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b)
nextToken(); // elvis has left the building nextToken(); // elvis has left the building
SpelNodeImpl valueIfNull = eatLogicalOrExpression(); SpelNodeImpl valueIfNull = eatExpression();
return new Elvis(toPos(t),expr,valueIfNull); return new Elvis(toPos(t),expr,valueIfNull);
} else if (t.kind==TokenKind.QMARK) { // a?b:c } else if (t.kind==TokenKind.QMARK) { // a?b:c
nextToken(); nextToken();
SpelNodeImpl ifTrueExprValue = eatLogicalOrExpression(); SpelNodeImpl ifTrueExprValue = eatExpression();
eatToken(TokenKind.COLON); eatToken(TokenKind.COLON);
SpelNodeImpl ifFalseExprValue = eatLogicalOrExpression(); SpelNodeImpl ifFalseExprValue = eatExpression();
return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue); return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue);
} }
} }
@ -155,63 +148,59 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
private SpelNodeImpl eatLogicalOrExpression() { private SpelNodeImpl eatLogicalOrExpression() {
SpelNodeImpl expr = eatLogicalAndExpression(); SpelNodeImpl expr = eatLogicalAndExpression();
while (peekIdentifierToken("or")) { while (peekIdentifierToken("or")) {
Token t = nextToken();//consume OR Token t = nextToken(); //consume OR
SpelNodeImpl expr2 = eatLogicalAndExpression(); SpelNodeImpl rhExpr = eatLogicalAndExpression();
checkRightOperand(t,expr2); checkRightOperand(t,rhExpr);
expr = new OperatorOr(toPos(t),expr,expr2); expr = new OpOr(toPos(t),expr,rhExpr);
} }
return expr; 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() { private SpelNodeImpl eatLogicalAndExpression() {
SpelNodeImpl expr = eatRelationalExpression(); SpelNodeImpl expr = eatRelationalExpression();
while (peekIdentifierToken("and")) { while (peekIdentifierToken("and")) {
Token t = nextToken();// consume 'AND' Token t = nextToken();// consume 'AND'
SpelNodeImpl rightExpr = eatRelationalExpression(); SpelNodeImpl rhExpr = eatRelationalExpression();
checkRightOperand(t,rightExpr); checkRightOperand(t,rhExpr);
expr = new OperatorAnd(toPos(t),expr,rightExpr); expr = new OpAnd(toPos(t),expr,rhExpr);
} }
return expr; return expr;
} }
//relationalExpression : sumExpression (relationalOperator^ sumExpression)?; // relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
private SpelNodeImpl eatRelationalExpression() { private SpelNodeImpl eatRelationalExpression() {
SpelNodeImpl expr = eatSumExpression(); SpelNodeImpl expr = eatSumExpression();
Token relationalOperatorToken = maybeEatRelationalOperator(); Token relationalOperatorToken = maybeEatRelationalOperator();
if (relationalOperatorToken!=null) { if (relationalOperatorToken!=null) {
Token t = nextToken();//consume relational operator token Token t = nextToken(); //consume relational operator token
SpelNodeImpl expr2 = eatSumExpression(); SpelNodeImpl rhExpr = eatSumExpression();
checkRightOperand(t,expr2); checkRightOperand(t,rhExpr);
TokenKind tk = relationalOperatorToken.kind;
if (relationalOperatorToken.isNumericRelationalOperator()) { if (relationalOperatorToken.isNumericRelationalOperator()) {
if (relationalOperatorToken.isGreaterThan()) { int pos = toPos(t);
return new OpGT(toPos(t),expr,expr2); if (tk==TokenKind.GT) {
} else if (relationalOperatorToken.isLessThan()) { return new OpGT(pos,expr,rhExpr);
return new OpLT(toPos(t),expr,expr2); } else if (tk==TokenKind.LT) {
} else if (relationalOperatorToken.isLessThanOrEqual()) { return new OpLT(pos,expr,rhExpr);
return new OpLE(toPos(t),expr,expr2); } else if (tk==TokenKind.LE) {
} else if (relationalOperatorToken.isGreaterThanOrEqual()) { return new OpLE(pos,expr,rhExpr);
return new OpGE(toPos(t),expr,expr2); } else if (tk==TokenKind.GE) {
} else if (relationalOperatorToken.isEquality()) { return new OpGE(pos,expr,rhExpr);
return new OpEQ(toPos(t),expr,expr2); } else if (tk==TokenKind.EQ) {
return new OpEQ(pos,expr,rhExpr);
} else { } else {
assert relationalOperatorToken.kind==TokenKind.NE; assert tk==TokenKind.NE;
return new OpNE(toPos(t),expr,expr2); return new OpNE(pos,expr,rhExpr);
} }
} }
if (relationalOperatorToken.kind==TokenKind.INSTANCEOF) { if (tk==TokenKind.INSTANCEOF) {
return new OperatorInstanceof(toPos(t),expr,expr2); return new OperatorInstanceof(toPos(t),expr,rhExpr);
} else if (relationalOperatorToken.kind==TokenKind.MATCHES) { } else if (tk==TokenKind.MATCHES) {
return new OperatorMatches(toPos(t),expr,expr2); return new OperatorMatches(toPos(t),expr,rhExpr);
} else { } else {
assert relationalOperatorToken.kind==TokenKind.BETWEEN; assert tk==TokenKind.BETWEEN;
return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,expr2); return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,rhExpr);
} }
} }
return expr; return expr;
@ -222,69 +211,71 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
SpelNodeImpl expr = eatProductExpression(); SpelNodeImpl expr = eatProductExpression();
while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) { while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) {
Token t = nextToken();//consume PLUS or MINUS Token t = nextToken();//consume PLUS or MINUS
SpelNodeImpl rhOperand = eatProductExpression(); SpelNodeImpl rhExpr = eatProductExpression();
checkRightOperand(t,rhOperand); checkRightOperand(t,rhExpr);
if (t.getKind()==TokenKind.PLUS) { if (t.kind==TokenKind.PLUS) {
expr = new OperatorPlus(toPos(t),expr,rhOperand); expr = new OpPlus(toPos(t),expr,rhExpr);
} else { } else {
expr = new OperatorMinus(toPos(t),expr,rhOperand); assert t.kind==TokenKind.MINUS;
expr = new OpMinus(toPos(t),expr,rhExpr);
} }
} }
return expr; return expr;
} }
//productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; // productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
private SpelNodeImpl eatProductExpression() { private SpelNodeImpl eatProductExpression() {
SpelNodeImpl expr = eatPowerExpression(); SpelNodeImpl expr = eatPowerExpression();
while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) { while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) {
Token t = nextToken(); // consume STAR/DIV/MOD Token t = nextToken(); // consume STAR/DIV/MOD
SpelNodeImpl expr2 = eatPowerExpression(); SpelNodeImpl rhExpr = eatPowerExpression();
checkRightOperand(t,expr2); checkRightOperand(t,rhExpr);
if (t.getKind()==TokenKind.STAR) { if (t.kind==TokenKind.STAR) {
expr = new OperatorMultiply(toPos(t),expr,expr2); expr = new OpMultiply(toPos(t),expr,rhExpr);
} else if (t.getKind()==TokenKind.DIV) { } else if (t.kind==TokenKind.DIV) {
expr = new OperatorDivide(toPos(t),expr,expr2); expr = new OpDivide(toPos(t),expr,rhExpr);
} else { } else {
expr = new OperatorModulus(toPos(t),expr,expr2); assert t.kind==TokenKind.MOD;
expr = new OpModulus(toPos(t),expr,rhExpr);
} }
} }
return expr; return expr;
} }
//powerExpr : unaryExpression (POWER^ unaryExpression)? ; // powerExpr : unaryExpression (POWER^ unaryExpression)? ;
private SpelNodeImpl eatPowerExpression() { private SpelNodeImpl eatPowerExpression() {
SpelNodeImpl expr = eatUnaryExpression(); SpelNodeImpl expr = eatUnaryExpression();
if (peekToken(TokenKind.POWER)) { if (peekToken(TokenKind.POWER)) {
Token t = nextToken();//consume POWER Token t = nextToken();//consume POWER
SpelNodeImpl expr2 = eatUnaryExpression(); SpelNodeImpl rhExpr = eatUnaryExpression();
checkRightOperand(t,expr2); checkRightOperand(t,rhExpr);
return new OperatorPower(toPos(t),expr, expr2); return new OperatorPower(toPos(t),expr, rhExpr);
} }
return expr; return expr;
} }
//unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ; // unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ;
private SpelNodeImpl eatUnaryExpression() { private SpelNodeImpl eatUnaryExpression() {
if (peekToken(TokenKind.PLUS) || peekToken(TokenKind.MINUS) || peekToken(TokenKind.BANG)) { if (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.BANG)) {
Token t = nextToken(); Token t = nextToken();
SpelNodeImpl expr = eatUnaryExpression(); SpelNodeImpl expr = eatUnaryExpression();
if (t.kind==TokenKind.BANG) { if (t.kind==TokenKind.BANG) {
return new OperatorNot(toPos(t),expr); return new OperatorNot(toPos(t),expr);
} else if (t.kind==TokenKind.PLUS) { } else if (t.kind==TokenKind.PLUS) {
return new OperatorPlus(toPos(t),expr); return new OpPlus(toPos(t),expr);
} else { } else {
assert t.kind==TokenKind.MINUS; assert t.kind==TokenKind.MINUS;
return new OperatorMinus(toPos(t),expr); return new OpMinus(toPos(t),expr);
} }
} else { } else {
return eatPrimaryExpression(); return eatPrimaryExpression();
} }
} }
//primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?); // primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?);
private SpelNodeImpl eatPrimaryExpression() { private SpelNodeImpl eatPrimaryExpression() {
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>(); List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
SpelNodeImpl start = eatStartNode(); SpelNodeImpl start = eatStartNode(); // always a start node
nodes.add(start); nodes.add(start);
while (maybeEatNode()) { while (maybeEatNode()) {
nodes.add(pop()); nodes.add(pop());
@ -296,15 +287,10 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
} }
} }
private int toPos(int start,int end) { // node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+;
return (start<<16)+end;
}
//node : ((DOT dottedNode) | nonDottedNode)+;
private boolean maybeEatNode() { private boolean maybeEatNode() {
Token t = peekToken();
SpelNodeImpl expr = null; SpelNodeImpl expr = null;
if (t!=null && peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) { if (peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) {
expr = eatDottedNode(); expr = eatDottedNode();
} else { } else {
expr = maybeEatNonDottedNode(); expr = maybeEatNonDottedNode();
@ -317,7 +303,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
} }
} }
//nonDottedNode: indexer; // nonDottedNode: indexer;
private SpelNodeImpl maybeEatNonDottedNode() { private SpelNodeImpl maybeEatNonDottedNode() {
if (peekToken(TokenKind.LSQUARE)) { if (peekToken(TokenKind.LSQUARE)) {
if (maybeEatIndexer()) { if (maybeEatIndexer()) {
@ -338,23 +324,20 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
// ; // ;
private SpelNodeImpl eatDottedNode() { private SpelNodeImpl eatDottedNode() {
Token t = nextToken();// it was a '.' or a '?.' Token t = nextToken();// it was a '.' or a '?.'
//eatToken(TokenKind.DOT);
boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI; boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI;
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) { if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
return pop(); 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 // functionOrVar
// : (POUND ID LPAREN) => function // : (POUND ID LPAREN) => function
// | var // | var
// ; //
// // function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs);
//function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); // var : POUND id=ID -> ^(VARIABLEREF[$id]);
//
//var : POUND id=ID -> ^(VARIABLEREF[$id]);
private boolean maybeEatFunctionOrVar() { private boolean maybeEatFunctionOrVar() {
if (!peekToken(TokenKind.HASH)) { if (!peekToken(TokenKind.HASH)) {
return false; 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() { private SpelNodeImpl[] maybeEatMethodArgs() {
if (!peekToken(TokenKind.LPAREN)) { if (!peekToken(TokenKind.LPAREN)) {
return null; return null;
@ -484,22 +466,20 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
//projection: PROJECT^ expression RCURLY!; //projection: PROJECT^ expression RCURLY!;
private boolean maybeEatProjection(boolean nullSafeNavigation) { private boolean maybeEatProjection(boolean nullSafeNavigation) {
Token t = peekToken(); Token t = peekToken();
if (!peekToken(TokenKind.PROJECT)) { if (!peekToken(TokenKind.PROJECT,true)) {
return false; return false;
} }
nextToken();
SpelNodeImpl expr = eatExpression(); SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RSQUARE); eatToken(TokenKind.RSQUARE);
constructedNodes.push(new Projection(nullSafeNavigation, toPos(t),expr)); constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr));
return true; return true;
} }
private boolean maybeEatIndexer() { private boolean maybeEatIndexer() {
Token t = peekToken(); Token t = peekToken();
if (!peekToken(TokenKind.LSQUARE)) { if (!peekToken(TokenKind.LSQUARE,true)) {
return false; return false;
} }
nextToken();
SpelNodeImpl expr = eatExpression(); SpelNodeImpl expr = eatExpression();
eatToken(TokenKind.RSQUARE); eatToken(TokenKind.RSQUARE);
constructedNodes.push(new Indexer(toPos(t),expr)); constructedNodes.push(new Indexer(toPos(t),expr));
@ -528,8 +508,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>(); List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>();
Token startnode = eatToken(TokenKind.IDENTIFIER); Token startnode = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode))); qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode)));
while (peekToken(TokenKind.DOT)) { while (peekToken(TokenKind.DOT,true)) {
nextToken();
Token node = eatToken(TokenKind.IDENTIFIER); Token node = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node))); qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
} }
@ -555,8 +534,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
} }
//constructor //constructor
// : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) //: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs)
// ;
private boolean maybeEatConstructorReference() { private boolean maybeEatConstructorReference() {
if (peekIdentifierToken("new")) { if (peekIdentifierToken("new")) {
Token newToken = nextToken(); Token newToken = nextToken();
@ -579,63 +557,42 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
return constructedNodes.pop(); return constructedNodes.pop();
} }
// literal: // literal
// INTEGER_LITERAL // : INTEGER_LITERAL
// | boolLiteral // | boolLiteral
// | STRING_LITERAL // | STRING_LITERAL
// | HEXADECIMAL_INTEGER_LITERAL
// | HEXADECIMAL_INTEGER_LITERAL // | REAL_LITERAL
// | REAL_LITERAL // | DQ_STRING_LITERAL
// | DQ_STRING_LITERAL // | NULL_LITERAL
// | NULL_LITERAL
// ;
private boolean maybeEatLiteral() { private boolean maybeEatLiteral() {
Token t = peekToken(); Token t = peekToken();
if (t==null) { if (t==null) {
return false; return false;
} }
if (t.kind==TokenKind.LITERAL_INT) { if (t.kind==TokenKind.LITERAL_INT) {
nextToken();
push(Literal.getIntLiteral(t.data, toPos(t), 10)); push(Literal.getIntLiteral(t.data, toPos(t), 10));
return true;
} else if (t.kind==TokenKind.LITERAL_LONG) { } else if (t.kind==TokenKind.LITERAL_LONG) {
nextToken();
push(Literal.getLongLiteral(t.data, toPos(t), 10)); push(Literal.getLongLiteral(t.data, toPos(t), 10));
return true;
} else if (t.kind==TokenKind.LITERAL_HEXINT) { } else if (t.kind==TokenKind.LITERAL_HEXINT) {
nextToken();
push(Literal.getIntLiteral(t.data, toPos(t), 16)); push(Literal.getIntLiteral(t.data, toPos(t), 16));
return true;
} else if (t.kind==TokenKind.LITERAL_HEXLONG) { } else if (t.kind==TokenKind.LITERAL_HEXLONG) {
nextToken();
push(Literal.getLongLiteral(t.data, toPos(t), 16)); push(Literal.getLongLiteral(t.data, toPos(t), 16));
return true;
} else if (t.kind==TokenKind.LITERAL_REAL) { } else if (t.kind==TokenKind.LITERAL_REAL) {
nextToken();
push(Literal.getRealLiteral(t.data, toPos(t),false)); push(Literal.getRealLiteral(t.data, toPos(t),false));
return true;
} else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) { } else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) {
nextToken();
push(Literal.getRealLiteral(t.data, toPos(t), true)); push(Literal.getRealLiteral(t.data, toPos(t), true));
return true;
} else if (peekIdentifierToken("true")) { } else if (peekIdentifierToken("true")) {
nextToken();
push(new BooleanLiteral(t.data,toPos(t),true)); push(new BooleanLiteral(t.data,toPos(t),true));
return true;
} else if (peekIdentifierToken("false")) { } else if (peekIdentifierToken("false")) {
nextToken();
push(new BooleanLiteral(t.data,toPos(t),false)); push(new BooleanLiteral(t.data,toPos(t),false));
return true;
} else if (t.kind==TokenKind.LITERAL_STRING) { } else if (t.kind==TokenKind.LITERAL_STRING) {
nextToken();
push(new StringLiteral(t.data,toPos(t),t.data)); push(new StringLiteral(t.data,toPos(t),t.data));
return true; } else {
return false;
} }
return false; nextToken();
} return true;
private int toPos(Token t) {
return (t.startpos<<16)+t.endpos;
} }
//parenExpr : LPAREN! expression RPAREN!; //parenExpr : LPAREN! expression RPAREN!;
@ -650,11 +607,10 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
return false; return false;
} }
} }
// relationalOperator // relationalOperator
// : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN | GREATER_THAN_OR_EQUAL | INSTANCEOF // : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN
// | BETWEEN | MATCHES // | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES
private Token maybeEatRelationalOperator() { private Token maybeEatRelationalOperator() {
Token t = peekToken(); Token t = peekToken();
if (t==null) { if (t==null) {
@ -689,9 +645,22 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
} }
private boolean peekToken(TokenKind desiredTokenKind) { 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(); 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) { private boolean peekToken(TokenKind possible1,TokenKind possible2) {
@ -707,7 +676,9 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
} }
private boolean peekIdentifierToken(String identifierString) { private boolean peekIdentifierToken(String identifierString) {
if (!moreTokens()) return false; if (!moreTokens()) {
return false;
}
Token t = peekToken(); Token t = peekToken();
return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString); return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString);
} }
@ -722,7 +693,6 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
private boolean moreTokens() { private boolean moreTokens() {
return tokenStreamPointer<tokenStream.size(); return tokenStreamPointer<tokenStream.size();
} }
private Token nextToken() { private Token nextToken() {
if (tokenStreamPointer>=tokenStreamLength) { if (tokenStreamPointer>=tokenStreamLength) {
@ -741,5 +711,30 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
private void raiseInternalException(int pos, SpelMessages message,Object... inserts) { private void raiseInternalException(int pos, SpelMessages message,Object... inserts) {
throw new InternalParseException(new SpelParseException(expressionString,pos,message,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;
}
} }

View File

@ -64,30 +64,6 @@ class Token {
return kind==TokenKind.IDENTIFIER; 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() { public boolean isNumericRelationalOperator() {
return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE; return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE;
} }

View File

@ -217,6 +217,7 @@ public class EvaluationTests extends ExpressionTestCase {
evaluate("2>4?1:2",2,Integer.class); evaluate("2>4?1:2",2,Integer.class);
} }
@Test @Test
public void testTernaryOperator02() { public void testTernaryOperator02() {
evaluate("'abc'=='abc'?1:2",1,Integer.class); evaluate("'abc'=='abc'?1:2",1,Integer.class);
@ -233,6 +234,14 @@ public class EvaluationTests extends ExpressionTestCase {
Assert.assertFalse(expr.isWritable(eContext)); 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 @Test
public void testIndexer03() { public void testIndexer03() {
evaluate("'christian'[8]", "n", String.class); evaluate("'christian'[8]", "n", String.class);

View File

@ -85,7 +85,7 @@ public class HelperTests extends ExpressionTestCase {
// IntLiteral value:2 // IntLiteral value:2
// ===> Expression '3+4+5+6+7-2' - AST end // ===> 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("===> 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 @Test

View File

@ -24,8 +24,8 @@ import org.springframework.expression.spel.SpelExpression;
import org.springframework.expression.spel.SpelMessages; import org.springframework.expression.spel.SpelMessages;
import org.springframework.expression.spel.SpelNode; import org.springframework.expression.spel.SpelNode;
import org.springframework.expression.spel.SpelParseException; import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.ast.OperatorAnd; import org.springframework.expression.spel.ast.OpAnd;
import org.springframework.expression.spel.ast.OperatorOr; import org.springframework.expression.spel.ast.OpOr;
public class SpelParserTests { public class SpelParserTests {
@ -228,8 +228,8 @@ public class SpelParserTests {
public void testPositionalInformation() throws EvaluationException, ParseException { public void testPositionalInformation() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parse("true and true or false"); SpelExpression expr = new SpelExpressionParser().parse("true and true or false");
SpelNode rootAst = expr.getAST(); SpelNode rootAst = expr.getAST();
OperatorOr operatorOr = (OperatorOr)rootAst; OpOr operatorOr = (OpOr)rootAst;
OperatorAnd operatorAnd = (OperatorAnd)operatorOr.getLeftOperand(); OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand();
SpelNode rightOrOperand = operatorOr.getRightOperand(); SpelNode rightOrOperand = operatorOr.getRightOperand();
// check position for final 'false' // check position for final 'false'