Browse Source

Merge pull request #115 from aclement/SPR-9614

* SPR-9614:
  Support symbolic boolean operators for OR and AND
pull/115/merge
Sam Brannen 12 years ago
parent
commit
0d963a690b
  1. 8
      spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
  2. 4
      spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java
  3. 12
      spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java
  4. 20
      spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java
  5. 3
      src/dist/changelog.txt

8
spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java

@ -169,7 +169,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
//logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*; //logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*;
private SpelNodeImpl eatLogicalOrExpression() { private SpelNodeImpl eatLogicalOrExpression() {
SpelNodeImpl expr = eatLogicalAndExpression(); SpelNodeImpl expr = eatLogicalAndExpression();
while (peekIdentifierToken("or")) { while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
Token t = nextToken(); //consume OR Token t = nextToken(); //consume OR
SpelNodeImpl rhExpr = eatLogicalAndExpression(); SpelNodeImpl rhExpr = eatLogicalAndExpression();
checkRightOperand(t,rhExpr); checkRightOperand(t,rhExpr);
@ -181,7 +181,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
// 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") || peekToken(TokenKind.SYMBOLIC_AND)) {
Token t = nextToken();// consume 'AND' Token t = nextToken();// consume 'AND'
SpelNodeImpl rhExpr = eatRelationalExpression(); SpelNodeImpl rhExpr = eatRelationalExpression();
checkRightOperand(t,rhExpr); checkRightOperand(t,rhExpr);
@ -432,7 +432,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
} }
} }
//startNode //startNode
// : parenExpr | literal // : parenExpr | literal
// | type // | type
@ -513,7 +512,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatNullReference() { private boolean maybeEatNullReference() {
if (peekToken(TokenKind.IDENTIFIER)) { if (peekToken(TokenKind.IDENTIFIER)) {
Token nullToken = peekToken(); Token nullToken = peekToken();
if (!nullToken.stringValue().toLowerCase().equals("null")) { if (!nullToken.stringValue().equalsIgnoreCase("null")) {
return false; return false;
} }
nextToken(); nextToken();
@ -805,7 +804,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST; return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST;
} }
private boolean moreTokens() { private boolean moreTokens() {
return tokenStreamPointer<tokenStream.size(); return tokenStreamPointer<tokenStream.size();
} }

4
spring-expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2012 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -29,7 +29,7 @@ enum TokenKind {
DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="), DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="),
MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"), MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
SELECT("?["), POWER("^"), SELECT("?["), POWER("^"),
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@") ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@"), SYMBOLIC_OR("||"), SYMBOLIC_AND("&&")
; ;
char[] tokenChars; char[] tokenChars;

12
spring-expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java

@ -128,6 +128,16 @@ class Tokenizer {
pushCharToken(TokenKind.ASSIGN); pushCharToken(TokenKind.ASSIGN);
} }
break; break;
case '&':
if (isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
pushPairToken(TokenKind.SYMBOLIC_AND);
}
break;
case '|':
if (isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
pushPairToken(TokenKind.SYMBOLIC_OR);
}
break;
case '?': case '?':
if (isTwoCharToken(TokenKind.SELECT)) { if (isTwoCharToken(TokenKind.SELECT)) {
pushPairToken(TokenKind.SELECT); pushPairToken(TokenKind.SELECT);
@ -200,7 +210,6 @@ class Tokenizer {
return tokens; return tokens;
} }
// STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; // STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
private void lexQuotedStringLiteral() { private void lexQuotedStringLiteral() {
int start = pos; int start = pos;
@ -242,7 +251,6 @@ class Tokenizer {
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos)); tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
} }
// REAL_LITERAL : // REAL_LITERAL :
// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | // ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | // ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |

20
spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java

@ -70,7 +70,7 @@ public class SpelParserTests {
assertEquals(5, expr.getValue()); assertEquals(5, expr.getValue());
expr = parser.parseRaw("2 + 3"); expr = parser.parseRaw("2 + 3");
assertEquals(5, expr.getValue()); assertEquals(5, expr.getValue());
expr = parser.parseRaw("2\n+ 3"); expr = parser.parseRaw("2\n+\t3");
assertEquals(5, expr.getValue()); assertEquals(5, expr.getValue());
expr = parser.parseRaw("2\r\n+\t3"); expr = parser.parseRaw("2\r\n+\t3");
assertEquals(5, expr.getValue()); assertEquals(5, expr.getValue());
@ -229,6 +229,24 @@ public class SpelParserTests {
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class)); assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
} }
@Test
public void booleanOperators_symbolic_spr9614() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("false && false");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true && (true || false)");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("true && true || false");
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!true");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
expr = new SpelExpressionParser().parseRaw("!(false || true)");
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
}
@Test @Test
public void stringLiterals() throws EvaluationException, ParseException { public void stringLiterals() throws EvaluationException, ParseException {
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'"); SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");

3
src/dist/changelog.txt vendored

@ -8,7 +8,8 @@ Changes in version 3.2 M2 (2012-08-xx)
* spring-test module now depends on junit:junit-dep (SPR-6966) * spring-test module now depends on junit:junit-dep (SPR-6966)
* now inferring return type of generic factory methods (SPR-9493) * now inferring return type of generic factory methods (SPR-9493)
* SpEL Tokenizer now supports methods on integers (SPR-9612) * SpEL now supports method invocations on integers (SPR-9612)
* SpEL now supports symbolic boolean operators for OR and AND (SPR-9614)
* introduced support for case-insensitive null literals in SpEL expressions (SPR-9613) * introduced support for case-insensitive null literals in SpEL expressions (SPR-9613)
* now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528) * now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528)
* introduced "repeatCount" property in Quartz SimpleTriggerFactoryBean (SPR-9521) * introduced "repeatCount" property in Quartz SimpleTriggerFactoryBean (SPR-9521)

Loading…
Cancel
Save