You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/01/12 14:08:14 UTC
[13/30] olingo-odata4 git commit: [OLINGO-834] ExpressionParser uses
UriTokenizer
[OLINGO-834] ExpressionParser uses UriTokenizer
Signed-off-by: Christian Amend <ch...@sap.com>
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/2f3bc286
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/2f3bc286
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/2f3bc286
Branch: refs/heads/master
Commit: 2f3bc2866befb2f8f75a81ecb4952950dc3913df
Parents: 208f26c
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Dec 11 16:48:38 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Mon Dec 14 10:12:22 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/ExpressionParser.java | 499 +++++++------------
.../olingo/server/core/uri/parser/Parser.java | 8 +
.../server/core/uri/parser/ParserHelper.java | 65 +++
.../core/uri/parser/ResourcePathParser.java | 130 +++--
.../server/core/uri/parser/SelectParser.java | 15 +-
.../server/core/uri/parser/UriTokenizer.java | 291 ++++++++++-
.../uri/queryoption/expression/UnaryImpl.java | 2 +-
.../core/uri/parser/ExpressionParserTest.java | 174 +++----
.../core/uri/parser/UriTokenizerTest.java | 313 +++++++-----
9 files changed, 841 insertions(+), 656 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
index 854536d..3b04089 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpressionParser.java
@@ -32,6 +32,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.Method;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.apache.olingo.server.core.uri.queryoption.expression.AliasImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl;
@@ -39,75 +40,73 @@ import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
import org.apache.olingo.server.core.uri.queryoption.expression.UnaryImpl;
public class ExpressionParser {
- private Tokenizer tokenizer;
-
private static final Map<TokenKind, BinaryOperatorKind> tokenToBinaryOperator;
static {
- Map<TokenKind, BinaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, BinaryOperatorKind>();
- temp.put(TokenKind.OR_OP, BinaryOperatorKind.OR);
- temp.put(TokenKind.AND_OP, BinaryOperatorKind.AND);
+ Map<TokenKind, BinaryOperatorKind> temp = new HashMap<TokenKind, BinaryOperatorKind>();
+ temp.put(TokenKind.OrOperator, BinaryOperatorKind.OR);
+ temp.put(TokenKind.AndOperator, BinaryOperatorKind.AND);
- temp.put(TokenKind.EQ_OP, BinaryOperatorKind.EQ);
- temp.put(TokenKind.NE_OP, BinaryOperatorKind.NE);
+ temp.put(TokenKind.EqualsOperator, BinaryOperatorKind.EQ);
+ temp.put(TokenKind.NotEqualsOperator, BinaryOperatorKind.NE);
- temp.put(TokenKind.GT_OP, BinaryOperatorKind.GT);
- temp.put(TokenKind.GE_OP, BinaryOperatorKind.GE);
- temp.put(TokenKind.LT_OP, BinaryOperatorKind.LT);
- temp.put(TokenKind.LE_OP, BinaryOperatorKind.LE);
+ temp.put(TokenKind.GreaterThanOperator, BinaryOperatorKind.GT);
+ temp.put(TokenKind.GreaterThanOrEqualsOperator, BinaryOperatorKind.GE);
+ temp.put(TokenKind.LessThanOperator, BinaryOperatorKind.LT);
+ temp.put(TokenKind.LessThanOrEqualsOperator, BinaryOperatorKind.LE);
- temp.put(TokenKind.ADD_OP, BinaryOperatorKind.ADD);
- temp.put(TokenKind.SUB_OP, BinaryOperatorKind.SUB);
+ temp.put(TokenKind.AddOperator, BinaryOperatorKind.ADD);
+ temp.put(TokenKind.SubOperator, BinaryOperatorKind.SUB);
- temp.put(TokenKind.MUL_OP, BinaryOperatorKind.MUL);
- temp.put(TokenKind.DIV_OP, BinaryOperatorKind.DIV);
- temp.put(TokenKind.MOD_OP, BinaryOperatorKind.MOD);
+ temp.put(TokenKind.MulOperator, BinaryOperatorKind.MUL);
+ temp.put(TokenKind.DivOperator, BinaryOperatorKind.DIV);
+ temp.put(TokenKind.ModOperator, BinaryOperatorKind.MOD);
tokenToBinaryOperator = Collections.unmodifiableMap(temp);
}
private static final Map<TokenKind, UnaryOperatorKind> tokenToUnaryOperator;
static {
- Map<TokenKind, UnaryOperatorKind> temp = new HashMap<ExpressionParser.TokenKind, UnaryOperatorKind>();
+ Map<TokenKind, UnaryOperatorKind> temp = new HashMap<TokenKind, UnaryOperatorKind>();
temp.put(TokenKind.MINUS, UnaryOperatorKind.MINUS);
- temp.put(TokenKind.NOT, UnaryOperatorKind.NOT);
+ temp.put(TokenKind.NotOperator, UnaryOperatorKind.NOT);
tokenToUnaryOperator = Collections.unmodifiableMap(temp);
}
private static final Map<TokenKind, MethodKind> tokenToMethod;
static {
- Map<TokenKind, MethodKind> temp = new HashMap<ExpressionParser.TokenKind, MethodKind>();
- temp.put(TokenKind.Cast, MethodKind.CAST);
- temp.put(TokenKind.Ceiling, MethodKind.CEILING);
- temp.put(TokenKind.Concat, MethodKind.CONCAT);
- temp.put(TokenKind.Contains, MethodKind.CONTAINS);
- temp.put(TokenKind.Date, MethodKind.DATE);
- temp.put(TokenKind.Day, MethodKind.DAY);
- temp.put(TokenKind.Endswith, MethodKind.ENDSWITH);
- temp.put(TokenKind.Floor, MethodKind.FLOOR);
- temp.put(TokenKind.Fractionalseconds, MethodKind.FRACTIONALSECONDS);
- temp.put(TokenKind.GeoDistance, MethodKind.GEODISTANCE);
- temp.put(TokenKind.GeoIntersects, MethodKind.GEOINTERSECTS);
- temp.put(TokenKind.GeoLength, MethodKind.GEOLENGTH);
- temp.put(TokenKind.Hour, MethodKind.HOUR);
- temp.put(TokenKind.Indexof, MethodKind.INDEXOF);
- temp.put(TokenKind.Isof, MethodKind.ISOF);
- temp.put(TokenKind.Length, MethodKind.LENGTH);
- temp.put(TokenKind.Maxdatetime, MethodKind.MAXDATETIME);
- temp.put(TokenKind.Mindatetime, MethodKind.MINDATETIME);
- temp.put(TokenKind.Minute, MethodKind.MINUTE);
- temp.put(TokenKind.Month, MethodKind.MONTH);
- temp.put(TokenKind.Now, MethodKind.NOW);
- temp.put(TokenKind.Round, MethodKind.ROUND);
- temp.put(TokenKind.Second, MethodKind.SECOND);
- temp.put(TokenKind.Startswith, MethodKind.STARTSWITH);
- temp.put(TokenKind.Substring, MethodKind.SUBSTRING);
- temp.put(TokenKind.Time, MethodKind.TIME);
- temp.put(TokenKind.Tolower, MethodKind.TOLOWER);
- temp.put(TokenKind.Totaloffsetminutes, MethodKind.TOTALOFFSETMINUTES);
- temp.put(TokenKind.Totalseconds, MethodKind.TOTALSECONDS);
- temp.put(TokenKind.Toupper, MethodKind.TOUPPER);
- temp.put(TokenKind.Trim, MethodKind.TRIM);
- temp.put(TokenKind.Year, MethodKind.YEAR);
+ Map<TokenKind, MethodKind> temp = new HashMap<TokenKind, MethodKind>();
+ temp.put(TokenKind.CastMethod, MethodKind.CAST);
+ temp.put(TokenKind.CeilingMethod, MethodKind.CEILING);
+ temp.put(TokenKind.ConcatMethod, MethodKind.CONCAT);
+ temp.put(TokenKind.ContainsMethod, MethodKind.CONTAINS);
+ temp.put(TokenKind.DateMethod, MethodKind.DATE);
+ temp.put(TokenKind.DayMethod, MethodKind.DAY);
+ temp.put(TokenKind.EndswithMethod, MethodKind.ENDSWITH);
+ temp.put(TokenKind.FloorMethod, MethodKind.FLOOR);
+ temp.put(TokenKind.FractionalsecondsMethod, MethodKind.FRACTIONALSECONDS);
+ temp.put(TokenKind.GeoDistanceMethod, MethodKind.GEODISTANCE);
+ temp.put(TokenKind.GeoIntersectsMethod, MethodKind.GEOINTERSECTS);
+ temp.put(TokenKind.GeoLengthMethod, MethodKind.GEOLENGTH);
+ temp.put(TokenKind.HourMethod, MethodKind.HOUR);
+ temp.put(TokenKind.IndexofMethod, MethodKind.INDEXOF);
+ temp.put(TokenKind.IsofMethod, MethodKind.ISOF);
+ temp.put(TokenKind.LengthMethod, MethodKind.LENGTH);
+ temp.put(TokenKind.MaxdatetimeMethod, MethodKind.MAXDATETIME);
+ temp.put(TokenKind.MindatetimeMethod, MethodKind.MINDATETIME);
+ temp.put(TokenKind.MinuteMethod, MethodKind.MINUTE);
+ temp.put(TokenKind.MonthMethod, MethodKind.MONTH);
+ temp.put(TokenKind.NowMethod, MethodKind.NOW);
+ temp.put(TokenKind.RoundMethod, MethodKind.ROUND);
+ temp.put(TokenKind.SecondMethod, MethodKind.SECOND);
+ temp.put(TokenKind.StartswithMethod, MethodKind.STARTSWITH);
+ temp.put(TokenKind.SubstringMethod, MethodKind.SUBSTRING);
+ temp.put(TokenKind.TimeMethod, MethodKind.TIME);
+ temp.put(TokenKind.TolowerMethod, MethodKind.TOLOWER);
+ temp.put(TokenKind.TotaloffsetminutesMethod, MethodKind.TOTALOFFSETMINUTES);
+ temp.put(TokenKind.TotalsecondsMethod, MethodKind.TOTALSECONDS);
+ temp.put(TokenKind.ToupperMethod, MethodKind.TOUPPER);
+ temp.put(TokenKind.TrimMethod, MethodKind.TRIM);
+ temp.put(TokenKind.YearMethod, MethodKind.YEAR);
tokenToMethod = Collections.unmodifiableMap(temp);
}
@@ -115,24 +114,26 @@ public class ExpressionParser {
private static final Map<TokenKind, EdmPrimitiveTypeKind> tokenToPrimitiveType;
static {
/* Enum and null are not present in the map. These have to be handled differently */
- Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<ExpressionParser.TokenKind, EdmPrimitiveTypeKind>();
- temp.put(TokenKind.PrimitiveBooleanValue, EdmPrimitiveTypeKind.Boolean);
- temp.put(TokenKind.PrimitiveStringValue, EdmPrimitiveTypeKind.String);
+ Map<TokenKind, EdmPrimitiveTypeKind> temp = new HashMap<TokenKind, EdmPrimitiveTypeKind>();
+ temp.put(TokenKind.BooleanValue, EdmPrimitiveTypeKind.Boolean);
+ temp.put(TokenKind.StringValue, EdmPrimitiveTypeKind.String);
// TODO:Check if int64 is correct here or if it has to be single instead
- temp.put(TokenKind.PrimitiveIntegerValue, EdmPrimitiveTypeKind.Int64);
- temp.put(TokenKind.PrimitiveGuidValue, EdmPrimitiveTypeKind.Guid);
- temp.put(TokenKind.PrimitiveDateValue, EdmPrimitiveTypeKind.Date);
- temp.put(TokenKind.PrimitiveDateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
- temp.put(TokenKind.PrimitiveTimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
- temp.put(TokenKind.PrimitiveDecimalValue, EdmPrimitiveTypeKind.Decimal);
- temp.put(TokenKind.PrimitiveDoubleValue, EdmPrimitiveTypeKind.Double);
- temp.put(TokenKind.PrimitiveDurationValue, EdmPrimitiveTypeKind.Duration);
- temp.put(TokenKind.PrimitiveBinaryValue, EdmPrimitiveTypeKind.Binary);
+ temp.put(TokenKind.IntegerValue, EdmPrimitiveTypeKind.Int64);
+ temp.put(TokenKind.GuidValue, EdmPrimitiveTypeKind.Guid);
+ temp.put(TokenKind.DateValue, EdmPrimitiveTypeKind.Date);
+ temp.put(TokenKind.DateTimeOffsetValue, EdmPrimitiveTypeKind.DateTimeOffset);
+ temp.put(TokenKind.TimeOfDayValue, EdmPrimitiveTypeKind.TimeOfDay);
+ temp.put(TokenKind.DecimalValue, EdmPrimitiveTypeKind.Decimal);
+ temp.put(TokenKind.DoubleValue, EdmPrimitiveTypeKind.Double);
+ temp.put(TokenKind.DurationValue, EdmPrimitiveTypeKind.Duration);
+ temp.put(TokenKind.BinaryValue, EdmPrimitiveTypeKind.Binary);
tokenToPrimitiveType = Collections.unmodifiableMap(temp);
}
- public Expression parse(Tokenizer tokenizer) throws UriParserException {
+ private UriTokenizer tokenizer;
+
+ public Expression parse(UriTokenizer tokenizer) throws UriParserException {
// Initialize tokenizer.
this.tokenizer = tokenizer;
@@ -141,23 +142,17 @@ public class ExpressionParser {
private Expression parseExpression() throws UriParserException {
Expression left = parseAnd();
-
- while (is(TokenKind.OR_OP) != null) {
- tokenizer.getText();
-
- Expression right = parseAnd();
+ while (tokenizer.next(TokenKind.OrOperator)) {
+ final Expression right = parseAnd();
left = new BinaryImpl(left, BinaryOperatorKind.OR, right);
}
-
return left;
}
private Expression parseAnd() throws UriParserException {
Expression left = parseExprEquality();
- while (is(TokenKind.AND_OP) != null) {
- tokenizer.getText();
-
- Expression right = parseExprEquality();
+ while (tokenizer.next(TokenKind.AndOperator)) {
+ final Expression right = parseExprEquality();
left = new BinaryImpl(left, BinaryOperatorKind.AND, right);
}
return left;
@@ -165,110 +160,107 @@ public class ExpressionParser {
private Expression parseExprEquality() throws UriParserException {
Expression left = parseExprRel();
-
- TokenKind nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+ TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
// Null for everything other than EQ or NE
- while (nextTokenKind != null) {
- tokenizer.getText();
-
- Expression right = parseExprEquality();
- left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
- nextTokenKind = is(TokenKind.EQ_OP, TokenKind.NE_OP);
+ while (operatorTokenKind != null) {
+ final Expression right = parseExprEquality();
+ left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+ operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.EqualsOperator, TokenKind.NotEqualsOperator);
}
-
return left;
}
private Expression parseExprRel() throws UriParserException {
Expression left = parseExprAdd();
-
- TokenKind nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+ TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
+ TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
+ TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
// Null for everything other than GT or GE or LT or LE
- while (nextTokenKind != null) {
- tokenizer.getText();
-
- Expression right = parseExprAdd();
- left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
- nextTokenKind = is(TokenKind.GT_OP, TokenKind.GE_OP, TokenKind.LT_OP, TokenKind.LE_OP);
+ while (operatorTokenKind != null) {
+ final Expression right = parseExprAdd();
+ left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+ operatorTokenKind = ParserHelper.next(tokenizer,
+ TokenKind.GreaterThanOperator, TokenKind.GreaterThanOrEqualsOperator,
+ TokenKind.LessThanOperator, TokenKind.LessThanOrEqualsOperator);
}
-
return left;
}
private Expression parseExprAdd() throws UriParserException {
Expression left = parseExprMul();
-
- TokenKind nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+ TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
// Null for everything other than ADD or SUB
- while (nextTokenKind != null) {
- tokenizer.getText();
-
- Expression right = parseExprMul();
- left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
- nextTokenKind = is(TokenKind.ADD_OP, TokenKind.SUB_OP);
+ while (operatorTokenKind != null) {
+ final Expression right = parseExprMul();
+ left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+ operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.AddOperator, TokenKind.SubOperator);
}
-
return left;
}
private Expression parseExprMul() throws UriParserException {
Expression left = parseExprUnary();
-
- TokenKind nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+ TokenKind operatorTokenKind = ParserHelper.next(tokenizer,
+ TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
// Null for everything other than MUL or DIV or MOD
- while (nextTokenKind != null) {
- tokenizer.getText();
-
- Expression right = parseExprUnary();
- left = new BinaryImpl(left, tokenToBinaryOperator.get(nextTokenKind), right);
- nextTokenKind = is(TokenKind.MUL_OP, TokenKind.DIV_OP, TokenKind.MOD_OP);
+ while (operatorTokenKind != null) {
+ final Expression right = parseExprUnary();
+ left = new BinaryImpl(left, tokenToBinaryOperator.get(operatorTokenKind), right);
+ operatorTokenKind = ParserHelper.next(tokenizer,
+ TokenKind.MulOperator, TokenKind.DivOperator, TokenKind.ModOperator);
}
-
return left;
}
private Expression parseExprUnary() throws UriParserException {
Expression left = null;
- TokenKind nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+ TokenKind operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
// Null for everything other than - or NOT
- while (nextTokenKind != null) {
- tokenizer.getText();
-
- Expression exp = parseExprValue();
- left = new UnaryImpl(tokenToUnaryOperator.get(nextTokenKind), exp);
- nextTokenKind = is(TokenKind.MINUS, TokenKind.NOT);
+ while (operatorTokenKind != null) {
+ final Expression expression = parseExprValue();
+ left = new UnaryImpl(tokenToUnaryOperator.get(operatorTokenKind), expression);
+ operatorTokenKind = ParserHelper.next(tokenizer, TokenKind.MINUS, TokenKind.NotOperator);
}
-
if (left == null) {
left = parseExprValue();
}
-
return left;
}
private Expression parseExprValue() throws UriParserException {
- if (is(TokenKind.OPEN) != null) {
- tokenizer.getText();
- Expression exp = parseExpression();
- require(TokenKind.CLOSE);
- return exp;
+ if (tokenizer.next(TokenKind.OPEN)) {
+ final Expression expression = parseExpression();
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+ return expression;
}
- if (is(TokenKind.ParameterAlias) != null) {
+ if (tokenizer.next(TokenKind.ParameterAliasName)) {
return new AliasImpl(tokenizer.getText());
}
- if (is(TokenKind.RootExpr) != null) {
- tokenizer.getText();
- // TODO: Consume $root Expression.
+ if (tokenizer.next(TokenKind.jsonArrayOrObject)) {
+ // TODO: Can the type be determined?
+ return new LiteralImpl(tokenizer.getText(), null);
}
- TokenKind nextPrimitive = isPrimitive();
+ if (tokenizer.next(TokenKind.ROOT)) {
+ // TODO: Consume $root expression.
+ }
+
+ if (tokenizer.next(TokenKind.IT)) {
+ // TODO: Consume $it expression.
+ }
+
+ if (tokenizer.next(TokenKind.QualifiedName)) {
+ // TODO: Consume typecast or bound-function expression.
+ }
+
+ TokenKind nextPrimitive = ParserHelper.nextPrimitive(tokenizer);
if (nextPrimitive != null) {
- EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
+ final EdmPrimitiveTypeKind primitiveTypeKind = tokenToPrimitiveType.get(nextPrimitive);
EdmPrimitiveType type;
if (primitiveTypeKind == null) {
- if (nextPrimitive == TokenKind.PrimitiveEnumValue) {
+ if (nextPrimitive == TokenKind.EnumValue) {
// TODO: Get enum type.
type = null;
} else {
@@ -281,22 +273,16 @@ public class ExpressionParser {
return new LiteralImpl(tokenizer.getText(), type);
}
- TokenKind nextMethod = isMethod();
+ TokenKind nextMethod = nextMethod();
if (nextMethod != null) {
MethodKind methodKind = tokenToMethod.get(nextMethod);
List<Expression> parameters = new ArrayList<Expression>();
- // Consume Method name.
- tokenizer.getText();
- if (is(TokenKind.CLOSE) != null) {
- // Consume closing parenthesis.
- tokenizer.getText();
- } else {
- parameters.add(parseExpression());
- while (is(TokenKind.COMMA) != null) {
- tokenizer.getText();
+ // The method token text includes the opening parenthesis!
+ if (!tokenizer.next(TokenKind.CLOSE)) {
+ do {
parameters.add(parseExpression());
- }
- require(TokenKind.CLOSE);
+ } while (tokenizer.next(TokenKind.COMMA));
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
}
MethodImpl methodImpl = new MethodImpl(methodKind, parameters);
@@ -305,6 +291,10 @@ public class ExpressionParser {
return methodImpl;
}
+ if (tokenizer.next(TokenKind.ODataIdentifier)) {
+ // TODO: Consume property-path or lambda-variable expression.
+ }
+
throw new UriParserSyntaxException("Unexpected token", UriParserSyntaxException.MessageKeys.SYNTAX);
}
@@ -356,7 +346,7 @@ public class ExpressionParser {
case NOW:
case MAXDATETIME:
case MINDATETIME:
- if (size != 0) {
+ if (size > 0) {
throw new UriParserSemanticException("The method '" + method.getMethod() + "' must have no parameters.",
null); // TODO: message key
}
@@ -384,192 +374,39 @@ public class ExpressionParser {
}
}
- private String require(TokenKind required) throws UriParserException {
- if (is(required) == null) {
- throw new UriParserSyntaxException("Required token: " + required,
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- return tokenizer.getText();
- }
-
- private TokenKind is(TokenKind... kind) {
- for (int i = 0; i < kind.length; i++) {
- if (tokenizer.next(kind[i])) {
- return kind[i];
- }
- }
- return null;
- }
-
- private TokenKind isMethod() {
- return is(TokenKind.Cast,
- TokenKind.Ceiling,
- TokenKind.Concat,
- TokenKind.Contains,
- TokenKind.Date,
- TokenKind.Day,
- TokenKind.Endswith,
- TokenKind.Floor,
- TokenKind.Fractionalseconds,
- TokenKind.GeoDistance,
- TokenKind.GeoIntersects,
- TokenKind.GeoLength,
- TokenKind.Hour,
- TokenKind.Indexof,
- TokenKind.Isof,
- TokenKind.Length,
- TokenKind.Maxdatetime,
- TokenKind.Mindatetime,
- TokenKind.Minute,
- TokenKind.Month,
- TokenKind.Now,
- TokenKind.Round,
- TokenKind.Second,
- TokenKind.Startswith,
- TokenKind.Substring,
- TokenKind.Time,
- TokenKind.Tolower,
- TokenKind.Totaloffsetminutes,
- TokenKind.Totalseconds,
- TokenKind.Toupper,
- TokenKind.Trim,
- TokenKind.Year);
- }
-
- private TokenKind isPrimitive() {
- return is(TokenKind.PrimitiveNullValue,
- TokenKind.PrimitiveBooleanValue,
- TokenKind.PrimitiveStringValue,
-
- // The order of the next seven expressions is important in order to avoid
- // finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
- TokenKind.PrimitiveDoubleValue,
- TokenKind.PrimitiveDecimalValue,
- TokenKind.PrimitiveGuidValue,
- TokenKind.PrimitiveDateTimeOffsetValue,
- TokenKind.PrimitiveDateValue,
- TokenKind.PrimitiveTimeOfDayValue,
- TokenKind.PrimitiveIntegerValue,
- TokenKind.PrimitiveDurationValue,
- TokenKind.PrimitiveBinaryValue,
- TokenKind.PrimitiveEnumValue);
- }
-
- public enum TokenKind {
- // BINARY
- OR_OP,
- AND_OP,
-
- EQ_OP,
- NE_OP,
-
- GT_OP,
- GE_OP,
- LT_OP,
- LE_OP,
-
- ADD_OP,
- SUB_OP,
-
- MUL_OP,
- DIV_OP,
- MOD_OP,
-
- MINUS,
- NOT,
-
- // Grouping
- OPEN,
- CLOSE,
-
- // PrimitiveValues
- PrimitiveNullValue,
- PrimitiveBooleanValue,
-
- PrimitiveStringValue,
- PrimitiveIntegerValue,
- PrimitiveGuidValue,
- PrimitiveDateValue,
- PrimitiveDateTimeOffsetValue,
- PrimitiveTimeOfDayValue,
- PrimitiveDecimalValue,
- PrimitiveDoubleValue,
- PrimitiveDurationValue,
- PrimitiveBinaryValue,
- PrimitiveEnumValue,
-
- // ExpressionValues
- ParameterAlias,
- ArrayOrObject,
- RootExpr,
- IT,
-
- // BuiltInMethods
- Cast,
- Ceiling,
- Concat,
- Contains,
- Date,
- Day,
- Endswith,
- Floor,
- Fractionalseconds,
- GeoDistance,
- GeoIntersects,
- GeoLength,
- Hour,
- Indexof,
- Isof,
- Length,
- Maxdatetime,
- Mindatetime,
- Minute,
- Month,
- Now,
- Round,
- Second,
- Startswith,
- Substring,
- Time,
- Tolower,
- Totaloffsetminutes,
- Totalseconds,
- Toupper,
- Trim,
- Year,
- COMMA
- }
-
- public static class Token {
- TokenKind kind;
- String text;
-
- public Token(TokenKind kind, String text) {
- this.kind = kind;
- this.text = text;
- }
- }
-
- public static class Tokenizer {
- private List<Token> tokens;
- int counter = 0;
-
- public Tokenizer(List<Token> tokens) {
- this.tokens = tokens;
- }
-
- public boolean next(TokenKind expectedKind) {
- if (counter < tokens.size() && expectedKind == tokens.get(counter).kind) {
- return true;
- }
- return false;
- }
-
- public String getText() {
- String text = tokens.get(counter).text;
- counter++;
- return text;
- }
+ private TokenKind nextMethod() {
+ return ParserHelper.next(tokenizer,
+ TokenKind.CastMethod,
+ TokenKind.CeilingMethod,
+ TokenKind.ConcatMethod,
+ TokenKind.ContainsMethod,
+ TokenKind.DateMethod,
+ TokenKind.DayMethod,
+ TokenKind.EndswithMethod,
+ TokenKind.FloorMethod,
+ TokenKind.FractionalsecondsMethod,
+ TokenKind.GeoDistanceMethod,
+ TokenKind.GeoIntersectsMethod,
+ TokenKind.GeoLengthMethod,
+ TokenKind.HourMethod,
+ TokenKind.IndexofMethod,
+ TokenKind.IsofMethod,
+ TokenKind.LengthMethod,
+ TokenKind.MaxdatetimeMethod,
+ TokenKind.MindatetimeMethod,
+ TokenKind.MinuteMethod,
+ TokenKind.MonthMethod,
+ TokenKind.NowMethod,
+ TokenKind.RoundMethod,
+ TokenKind.SecondMethod,
+ TokenKind.StartswithMethod,
+ TokenKind.SubstringMethod,
+ TokenKind.TimeMethod,
+ TokenKind.TolowerMethod,
+ TokenKind.TotaloffsetminutesMethod,
+ TokenKind.TotalsecondsMethod,
+ TokenKind.ToupperMethod,
+ TokenKind.TrimMethod,
+ TokenKind.YearMethod);
}
-
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 0b53e69..2a994d3 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -208,6 +208,14 @@ public class Parser {
(UriParserException) e.getCause() :
new UriParserSyntaxException("Syntax error", e, UriParserSyntaxException.MessageKeys.SYNTAX);
}
+// UriTokenizer filterTokenizer = new UriTokenizer(optionValue);
+// systemOption = new FilterOptionImpl().setExpression(
+// new ExpressionParser().parse(filterTokenizer));
+// if (!filterTokenizer.next(TokenKind.EOF)) {
+// throw new UriParserSyntaxException("Illegal value of $filter option!",
+// UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION,
+// optionName, optionValue);
+// }
} else if (optionName.equals(SystemQueryOptionKind.FORMAT.toString())) {
FormatOptionImpl formatOption = new FormatOptionImpl();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
new file mode 100644
index 0000000..e811575
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ParserHelper.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.olingo.server.core.uri.parser;
+
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
+
+public class ParserHelper {
+
+ public static void requireNext(UriTokenizer tokenizer, final TokenKind required) throws UriParserException {
+ if (!tokenizer.next(required)) {
+ throw new UriParserSyntaxException("Expected token '" + required.toString() + "' not found.",
+ UriParserSyntaxException.MessageKeys.SYNTAX);
+ }
+ }
+
+ public static void requireTokenEnd(UriTokenizer tokenizer) throws UriParserException {
+ requireNext(tokenizer, TokenKind.EOF);
+ }
+
+ public static TokenKind next(UriTokenizer tokenizer, final TokenKind... kind) {
+ for (int i = 0; i < kind.length; i++) {
+ if (tokenizer.next(kind[i])) {
+ return kind[i];
+ }
+ }
+ return null;
+ }
+
+ public static TokenKind nextPrimitive(UriTokenizer tokenizer) {
+ return next(tokenizer,
+ TokenKind.NULL,
+ TokenKind.BooleanValue,
+ TokenKind.StringValue,
+
+ // The order of the next seven expressions is important in order to avoid
+ // finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
+ TokenKind.DoubleValue,
+ TokenKind.DecimalValue,
+ TokenKind.GuidValue,
+ TokenKind.DateTimeOffsetValue,
+ TokenKind.DateValue,
+ TokenKind.TimeOfDayValue,
+ TokenKind.IntegerValue,
+
+ TokenKind.DurationValue,
+ TokenKind.BinaryValue,
+ TokenKind.EnumValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
index 9852011..5d2fbde 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ResourcePathParser.java
@@ -115,9 +115,9 @@ public class ResourcePathParser {
public UriInfoImpl parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
tokenizer = new UriTokenizer(pathSegment);
- requireNext(TokenKind.QualifiedName);
+ ParserHelper.requireNext(tokenizer, TokenKind.QualifiedName);
final String name = tokenizer.getText();
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
final EdmEntityType type = edm.getEntityType(new FullQualifiedName(name));
if (type == null) {
throw new UriParserSemanticException("Type '" + name + "' not found.",
@@ -131,11 +131,11 @@ public class ResourcePathParser {
public UriInfoImpl parseCrossjoinSegment(final String pathSegment) throws UriParserException {
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
tokenizer = new UriTokenizer(pathSegment);
- requireNext(TokenKind.CROSSJOIN);
- requireNext(TokenKind.OPEN);
+ ParserHelper.requireNext(tokenizer, TokenKind.CROSSJOIN);
+ ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
// At least one entity-set name is mandatory. Try to fetch all.
do {
- requireNext(TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(name);
if (edmEntitySet == null) {
@@ -145,13 +145,13 @@ public class ResourcePathParser {
uriInfo.addEntitySetName(name);
}
} while (tokenizer.next(TokenKind.COMMA));
- requireNext(TokenKind.CLOSE);
- requireTokenEnd();
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
+ ParserHelper.requireTokenEnd(tokenizer);
return uriInfo;
}
private UriResource ref(final UriResource previous) throws UriParserException {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
requireTyped(previous, "$ref");
if (((UriResourcePartTyped) previous).getType() instanceof EdmEntityType) {
return new UriResourceRefImpl();
@@ -162,7 +162,7 @@ public class ResourcePathParser {
}
private UriResource value(final UriResource previous) throws UriParserException {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
requireTyped(previous, "$value");
if (!((UriResourcePartTyped) previous).isCollection()) {
return new UriResourceValueImpl();
@@ -173,7 +173,7 @@ public class ResourcePathParser {
}
private UriResource count(final UriResource previous) throws UriParserException {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
requireTyped(previous, "$count");
if (((UriResourcePartTyped) previous).isCollection()) {
return new UriResourceCountImpl();
@@ -195,19 +195,19 @@ public class ResourcePathParser {
entitySetResource.setKeyPredicates(keyPredicates);
}
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return entitySetResource;
}
final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
if (edmSingleton != null) {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceSingletonImpl().setSingleton(edmSingleton);
}
final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
if (edmActionImport != null) {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceActionImpl().setActionImport(edmActionImport);
}
@@ -271,7 +271,7 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
}
}
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceNavigationPropertyImpl()
.setNavigationProperty(navigationProperty)
.setKeyPredicates(keyPredicate);
@@ -288,7 +288,7 @@ public class ResourcePathParser {
previousType.getFullQualifiedName(),
previousTyped.isCollection());
if (boundAction != null) {
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return new UriResourceActionImpl().setAction(boundAction);
}
EdmStructuredType type = edm.getEntityType(name);
@@ -386,7 +386,7 @@ public class ResourcePathParser {
edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
edmProperty == null ? false : edmProperty.isNullable())) {
final String literalValue = tokenizer.getText();
- requireNext(TokenKind.CLOSE);
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
} else {
throw new UriParserSemanticException("The key value is not valid.",
@@ -424,10 +424,10 @@ public class ResourcePathParser {
parameterNames.add(keyPredicateName);
hasComma = tokenizer.next(TokenKind.COMMA);
if (hasComma) {
- requireNext(TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
}
} while (hasComma);
- requireNext(TokenKind.CLOSE);
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
@@ -440,7 +440,7 @@ public class ResourcePathParser {
throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
}
- requireNext(TokenKind.EQ);
+ ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
@@ -512,7 +512,7 @@ public class ResourcePathParser {
}
((UriResourceTypedImpl) previousTyped).setTypeFilter(type);
}
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return null;
} else {
throw new UriParserSemanticException(
@@ -572,53 +572,42 @@ public class ResourcePathParser {
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
}
}
- requireTokenEnd();
+ ParserHelper.requireTokenEnd(tokenizer);
return resource;
}
private List<UriParameter> functionParameters() throws UriParserException {
List<UriParameter> parameters = new ArrayList<UriParameter>();
- requireNext(TokenKind.OPEN);
+ ParserHelper.requireNext(tokenizer, TokenKind.OPEN);
if (tokenizer.next(TokenKind.CLOSE)) {
return parameters;
}
do {
- requireNext(TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
final String name = tokenizer.getText();
if (parameters.contains(name)) {
throw new UriParserSemanticException("Duplicated function parameter " + name,
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
}
- requireNext(TokenKind.EQ);
+ ParserHelper.requireNext(tokenizer, TokenKind.EQ);
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
}
- if (nextPrimitiveValue()) {
+ if (tokenizer.next(TokenKind.ParameterAliasName)) {
+ parameters.add(new UriParameterImpl().setName(name).setAlias(tokenizer.getText()));
+ } else if (nextPrimitiveValue()) {
final String literalValue = tokenizer.getText();
- UriParameterImpl parameter = new UriParameterImpl().setName(name);
- parameters.add(literalValue.startsWith("@") ?
- parameter.setAlias(literalValue) :
- parameter.setText("null".equals(literalValue) ? null : literalValue));
+ parameters.add(new UriParameterImpl().setName(name)
+ .setText("null".equals(literalValue) ? null : literalValue));
} else {
throw new UriParserSemanticException("Wrong parameter value.",
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
}
} while (tokenizer.next(TokenKind.COMMA));
- requireNext(TokenKind.CLOSE);
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
return parameters;
}
- private void requireNext(final TokenKind kind) throws UriParserException {
- if (!tokenizer.next(kind)) {
- throw new UriParserSyntaxException("Expected token '" + kind.toString() + "' not found.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- }
-
- private void requireTokenEnd() throws UriParserException {
- requireNext(TokenKind.EOF);
- }
-
private boolean nextPrimitiveTypeValue(final EdmPrimitiveType primitiveType, final boolean nullable) {
final EdmPrimitiveType type = primitiveType instanceof EdmTypeDefinition ?
((EdmTypeDefinition) primitiveType).getUnderlyingType() :
@@ -629,64 +618,63 @@ public class ResourcePathParser {
return true;
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveBooleanValue);
+ return tokenizer.next(TokenKind.BooleanValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveStringValue);
+ return tokenizer.next(TokenKind.StringValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32).equals(type)
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveIntegerValue);
+ return tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveGuidValue);
+ return tokenizer.next(TokenKind.GuidValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveDateValue);
+ return tokenizer.next(TokenKind.DateValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue);
+ return tokenizer.next(TokenKind.DateTimeOffsetValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveTimeOfDayValue);
+ return tokenizer.next(TokenKind.TimeOfDayValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal).equals(type)) {
// The order is important.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
- return tokenizer.next(TokenKind.PrimitiveDecimalValue)
- || tokenizer.next(TokenKind.PrimitiveIntegerValue);
+ return tokenizer.next(TokenKind.DecimalValue)
+ || tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double).equals(type)) {
// The order is important.
// A floating-point value should not be parsed as decimal and let the tokenizer stop at 'E'.
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
- return tokenizer.next(TokenKind.PrimitiveDoubleValue)
- || tokenizer.next(TokenKind.PrimitiveDecimalValue)
- || tokenizer.next(TokenKind.PrimitiveIntegerValue);
+ return tokenizer.next(TokenKind.DoubleValue)
+ || tokenizer.next(TokenKind.DecimalValue)
+ || tokenizer.next(TokenKind.IntegerValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveDurationValue);
+ return tokenizer.next(TokenKind.DurationValue);
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
- return tokenizer.next(TokenKind.PrimitiveBinaryValue);
+ return tokenizer.next(TokenKind.BinaryValue);
} else if (type.getKind() == EdmTypeKind.ENUM) {
- return tokenizer.next(TokenKind.PrimitiveEnumValue);
+ return tokenizer.next(TokenKind.EnumValue);
} else {
return false;
}
}
private boolean nextPrimitiveValue() {
- return tokenizer.next(TokenKind.ParameterAliasName)
- || tokenizer.next(TokenKind.NULL)
- || tokenizer.next(TokenKind.PrimitiveBooleanValue)
- || tokenizer.next(TokenKind.PrimitiveStringValue)
+ return tokenizer.next(TokenKind.NULL)
+ || tokenizer.next(TokenKind.BooleanValue)
+ || tokenizer.next(TokenKind.StringValue)
// The order of the next seven expressions is important in order to avoid
// finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
- || tokenizer.next(TokenKind.PrimitiveDoubleValue)
- || tokenizer.next(TokenKind.PrimitiveDecimalValue)
- || tokenizer.next(TokenKind.PrimitiveGuidValue)
- || tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue)
- || tokenizer.next(TokenKind.PrimitiveDateValue)
- || tokenizer.next(TokenKind.PrimitiveTimeOfDayValue)
- || tokenizer.next(TokenKind.PrimitiveIntegerValue)
-
- || tokenizer.next(TokenKind.PrimitiveDurationValue)
- || tokenizer.next(TokenKind.PrimitiveBinaryValue)
- || tokenizer.next(TokenKind.PrimitiveEnumValue);
+ || tokenizer.next(TokenKind.DoubleValue)
+ || tokenizer.next(TokenKind.DecimalValue)
+ || tokenizer.next(TokenKind.GuidValue)
+ || tokenizer.next(TokenKind.DateTimeOffsetValue)
+ || tokenizer.next(TokenKind.DateValue)
+ || tokenizer.next(TokenKind.TimeOfDayValue)
+ || tokenizer.next(TokenKind.IntegerValue)
+
+ || tokenizer.next(TokenKind.DurationValue)
+ || tokenizer.next(TokenKind.BinaryValue)
+ || tokenizer.next(TokenKind.EnumValue);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
index 3d933d2..b257e68 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/SelectParser.java
@@ -92,7 +92,7 @@ public class SelectParser {
if (type.compatibleTo(referencedType)) {
item.setTypeFilter(type);
if (tokenizer.next(TokenKind.SLASH)) {
- requireNext(tokenizer, TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
UriInfoImpl resource = new UriInfoImpl().setKind(UriInfoKind.resource);
addSelectPath(tokenizer, type, resource);
item.setResourcePath(resource);
@@ -105,7 +105,7 @@ public class SelectParser {
}
} else {
- requireNext(tokenizer, TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
// The namespace or its alias could be a single OData identifier.
final FullQualifiedName allOperationsInSchema = parseAllOperationsInSchema(tokenizer);
if (allOperationsInSchema != null) {
@@ -167,10 +167,10 @@ public class SelectParser {
List<String> names = new ArrayList<String>();
if (tokenizer.next(TokenKind.OPEN)) {
do {
- requireNext(tokenizer, TokenKind.ODataIdentifier);
+ ParserHelper.requireNext(tokenizer, TokenKind.ODataIdentifier);
names.add(tokenizer.getText());
} while (tokenizer.next(TokenKind.COMMA));
- requireNext(tokenizer, TokenKind.CLOSE);
+ ParserHelper.requireNext(tokenizer, TokenKind.CLOSE);
}
return names;
}
@@ -231,11 +231,4 @@ public class SelectParser {
}
}
}
-
- private void requireNext(UriTokenizer tokenizer, final TokenKind kind) throws UriParserSyntaxException {
- if (!tokenizer.next(kind)) {
- throw new UriParserSyntaxException("Illegal $select expression.",
- UriParserSyntaxException.MessageKeys.SYNTAX);
- }
- }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
index 8051573..a40f4ec 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriTokenizer.java
@@ -24,6 +24,8 @@ package org.apache.olingo.server.core.uri.parser;
* Since only the index is "moved", backing out while parsing a token is easy and used throughout.
* There is intentionally no method to push back tokens (although it would be easy to add such a method)
* because this tokenizer should behave like a classical token-consuming tokenizer.</p>
+ * <p>Whitespace is not an extra token but consumed with the tokens that require whitespace.
+ * Optional whitespace is not supported.</p>
*/
public class UriTokenizer {
@@ -35,6 +37,9 @@ public class UriTokenizer {
VALUE,
COUNT,
CROSSJOIN,
+ ROOT,
+ IT,
+
OPEN,
CLOSE,
COMMA,
@@ -44,6 +49,7 @@ public class UriTokenizer {
EQ,
STAR,
PLUS,
+ MINUS,
NULL,
// variable-value tokens (convention: mixed case)
@@ -51,20 +57,68 @@ public class UriTokenizer {
QualifiedName,
ParameterAliasName,
- PrimitiveBooleanValue,
- PrimitiveStringValue,
- PrimitiveIntegerValue,
- PrimitiveGuidValue,
- PrimitiveDateValue,
- PrimitiveDateTimeOffsetValue,
- PrimitiveTimeOfDayValue,
- PrimitiveDecimalValue,
- PrimitiveDoubleValue,
- PrimitiveDurationValue,
- PrimitiveBinaryValue,
- PrimitiveEnumValue,
-
- jsonArrayOrObject
+ BooleanValue,
+ StringValue,
+ IntegerValue,
+ GuidValue,
+ DateValue,
+ DateTimeOffsetValue,
+ TimeOfDayValue,
+ DecimalValue,
+ DoubleValue,
+ DurationValue,
+ BinaryValue,
+ EnumValue,
+
+ jsonArrayOrObject,
+
+ OrOperator,
+ AndOperator,
+ EqualsOperator,
+ NotEqualsOperator,
+ GreaterThanOperator,
+ GreaterThanOrEqualsOperator,
+ LessThanOperator,
+ LessThanOrEqualsOperator,
+ AddOperator,
+ SubOperator,
+ MulOperator,
+ DivOperator,
+ ModOperator,
+ NotOperator,
+
+ CastMethod,
+ CeilingMethod,
+ ConcatMethod,
+ ContainsMethod,
+ DateMethod,
+ DayMethod,
+ EndswithMethod,
+ FloorMethod,
+ FractionalsecondsMethod,
+ GeoDistanceMethod,
+ GeoIntersectsMethod,
+ GeoLengthMethod,
+ HourMethod,
+ IndexofMethod,
+ IsofMethod,
+ LengthMethod,
+ MaxdatetimeMethod,
+ MindatetimeMethod,
+ MinuteMethod,
+ MonthMethod,
+ NowMethod,
+ RoundMethod,
+ SecondMethod,
+ StartswithMethod,
+ SubstringMethod,
+ TimeMethod,
+ TolowerMethod,
+ TotaloffsetminutesMethod,
+ TotalsecondsMethod,
+ ToupperMethod,
+ TrimMethod,
+ YearMethod
}
private final String parseString;
@@ -111,6 +165,13 @@ public class UriTokenizer {
case CROSSJOIN:
found = nextConstant("$crossjoin");
break;
+ case ROOT:
+ found = nextConstant("$root");
+ break;
+ case IT:
+ found = nextConstant("$it");
+ break;
+
case OPEN:
found = nextCharacter('(');
break;
@@ -138,6 +199,9 @@ public class UriTokenizer {
case PLUS:
found = nextCharacter('+');
break;
+ case MINUS:
+ found = nextCharacter('-');
+ break;
case NULL:
found = nextConstant("null");
break;
@@ -157,47 +221,189 @@ public class UriTokenizer {
break;
// Primitive Values
- case PrimitiveBooleanValue:
+ case BooleanValue:
found = nextBooleanValue();
break;
- case PrimitiveStringValue:
+ case StringValue:
found = nextStringValue();
break;
- case PrimitiveIntegerValue:
+ case IntegerValue:
found = nextIntegerValue(true);
break;
- case PrimitiveGuidValue:
+ case GuidValue:
found = nextGuidValue();
break;
- case PrimitiveDateValue:
+ case DateValue:
found = nextDateValue();
break;
- case PrimitiveDateTimeOffsetValue:
+ case DateTimeOffsetValue:
found = nextDateTimeOffsetValue();
break;
- case PrimitiveTimeOfDayValue:
+ case TimeOfDayValue:
found = nextTimeOfDayValue();
break;
- case PrimitiveDecimalValue:
+ case DecimalValue:
found = nextDecimalValue();
break;
- case PrimitiveDoubleValue:
+ case DoubleValue:
found = nextDoubleValue();
break;
- case PrimitiveDurationValue:
+ case DurationValue:
found = nextDurationValue();
break;
- case PrimitiveBinaryValue:
+ case BinaryValue:
found = nextBinaryValue();
break;
- case PrimitiveEnumValue:
+ case EnumValue:
found = nextEnumValue();
break;
- // Primitive Values
+ // Complex or Collection Value
case jsonArrayOrObject:
found = nextJsonArrayOrObject();
break;
+
+ // Operators
+ case OrOperator:
+ found = nextBinaryOperator("or");
+ break;
+ case AndOperator:
+ found = nextBinaryOperator("and");
+ break;
+ case EqualsOperator:
+ found = nextBinaryOperator("eq");
+ break;
+ case NotEqualsOperator:
+ found = nextBinaryOperator("ne");
+ break;
+ case GreaterThanOperator:
+ found = nextBinaryOperator("gt");
+ break;
+ case GreaterThanOrEqualsOperator:
+ found = nextBinaryOperator("ge");
+ break;
+ case LessThanOperator:
+ found = nextBinaryOperator("lt");
+ break;
+ case LessThanOrEqualsOperator:
+ found = nextBinaryOperator("le");
+ break;
+ case AddOperator:
+ found = nextBinaryOperator("add");
+ break;
+ case SubOperator:
+ found = nextBinaryOperator("sub");
+ break;
+ case MulOperator:
+ found = nextBinaryOperator("mul");
+ break;
+ case DivOperator:
+ found = nextBinaryOperator("div");
+ break;
+ case ModOperator:
+ found = nextBinaryOperator("mod");
+ break;
+ case NotOperator:
+ found = nextConstant("not") && nextWhitespace();
+ break;
+
+ // Methods
+ case CastMethod:
+ found = nextMethod("cast");
+ break;
+ case CeilingMethod:
+ found = nextMethod("ceiling");
+ break;
+ case ConcatMethod:
+ found = nextMethod("concat");
+ break;
+ case ContainsMethod:
+ found = nextMethod("contains");
+ break;
+ case DateMethod:
+ found = nextMethod("date");
+ break;
+ case DayMethod:
+ found = nextMethod("day");
+ break;
+ case EndswithMethod:
+ found = nextMethod("endswith");
+ break;
+ case FloorMethod:
+ found = nextMethod("floor");
+ break;
+ case FractionalsecondsMethod:
+ found = nextMethod("fractionalseconds");
+ break;
+ case GeoDistanceMethod:
+ found = nextMethod("geo.distance");
+ break;
+ case GeoIntersectsMethod:
+ found = nextMethod("geo.intersects");
+ break;
+ case GeoLengthMethod:
+ found = nextMethod("geo.length");
+ break;
+ case HourMethod:
+ found = nextMethod("hour");
+ break;
+ case IndexofMethod:
+ found = nextMethod("indexof");
+ break;
+ case IsofMethod:
+ found = nextMethod("isof");
+ break;
+ case LengthMethod:
+ found = nextMethod("length");
+ break;
+ case MaxdatetimeMethod:
+ found = nextMethod("maxdatetime");
+ break;
+ case MindatetimeMethod:
+ found = nextMethod("mindatetime");
+ break;
+ case MinuteMethod:
+ found = nextMethod("minute");
+ break;
+ case MonthMethod:
+ found = nextMethod("month");
+ break;
+ case NowMethod:
+ found = nextMethod("now");
+ break;
+ case RoundMethod:
+ found = nextMethod("round");
+ break;
+ case SecondMethod:
+ found = nextMethod("second");
+ break;
+ case StartswithMethod:
+ found = nextMethod("startswith");
+ break;
+ case SubstringMethod:
+ found = nextMethod("substring");
+ break;
+ case TimeMethod:
+ found = nextMethod("time");
+ break;
+ case TolowerMethod:
+ found = nextMethod("tolower");
+ break;
+ case TotaloffsetminutesMethod:
+ found = nextMethod("totaloffsetminutes");
+ break;
+ case TotalsecondsMethod:
+ found = nextMethod("totalseconds");
+ break;
+ case ToupperMethod:
+ found = nextMethod("toupper");
+ break;
+ case TrimMethod:
+ found = nextMethod("trim");
+ break;
+ case YearMethod:
+ found = nextMethod("year");
+ break;
}
if (found) {
@@ -301,6 +507,37 @@ public class UriTokenizer {
}
/**
+ * Moves past whitespace (space or horizontal tabulator) characters if found;
+ * otherwise leaves the index unchanged.
+ * @return whether whitespace characters have been found at the current index
+ */
+ private boolean nextWhitespace() {
+ int count = 0;
+ while (nextCharacter(' ') || nextCharacter('\t')) {
+ count++;
+ }
+ return count > 0;
+ }
+
+ /**
+ * Moves past the given whitespace-surrounded operator constant if found;
+ * otherwise leaves the index unchanged.
+ * @return whether the operator has been found at the current index
+ */
+ private boolean nextBinaryOperator(final String operator) {
+ return nextWhitespace() && nextConstant(operator) && nextWhitespace();
+ }
+
+ /**
+ * Moves past the given method name and its immediately following opening parenthesis if found;
+ * otherwise leaves the index unchanged.
+ * @return whether the method has been found at the current index
+ */
+ private boolean nextMethod(final String methodName) {
+ return nextConstant(methodName) && nextCharacter('(');
+ }
+
+ /**
* Moves past an OData identifier if found; otherwise leaves the index unchanged.
* @return whether an OData identifier has been found at the current index
*/
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
index 2438d27..910997e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/UnaryImpl.java
@@ -53,6 +53,6 @@ public class UnaryImpl implements Unary {
@Override
public String toString() {
- return "{" + operator + " " + expression + '}';
+ return "{" + operator.name() + " " + expression + '}';
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2f3bc286/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
index 7da823e..58f2a1f 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/ExpressionParserTest.java
@@ -20,191 +20,157 @@ package org.apache.olingo.server.core.uri.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
-import java.util.ArrayList;
+import java.util.Locale;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.Token;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.TokenKind;
-import org.apache.olingo.server.core.uri.parser.ExpressionParser.Tokenizer;
+import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
import org.junit.Test;
public class ExpressionParserTest {
@Test
public void equality() throws Exception {
- Expression expression = parseExpression(TokenKind.EQ_OP);
+ Expression expression = parseExpression("5 eq 5");
assertEquals("{5 EQ 5}", expression.toString());
- expression = parseExpression(TokenKind.NE_OP);
+ expression = parseExpression("5 ne 5");
assertEquals("{5 NE 5}", expression.toString());
}
@Test
public void relational() throws Exception {
- Expression expression = parseExpression(TokenKind.GT_OP);
+ Expression expression = parseExpression("5 gt 5");
assertEquals("{5 GT 5}", expression.toString());
- expression = parseExpression(TokenKind.GE_OP);
+ expression = parseExpression("5 ge 5");
assertEquals("{5 GE 5}", expression.toString());
- expression = parseExpression(TokenKind.LT_OP);
+ expression = parseExpression("5 lt 5");
assertEquals("{5 LT 5}", expression.toString());
- expression = parseExpression(TokenKind.LE_OP);
+ expression = parseExpression("5 le 5");
assertEquals("{5 LE 5}", expression.toString());
}
@Test
public void additive() throws Exception {
- Expression expression = parseExpression(TokenKind.ADD_OP);
+ Expression expression = parseExpression("5 add 5");
assertEquals("{5 ADD 5}", expression.toString());
- expression = parseExpression(TokenKind.SUB_OP);
+ expression = parseExpression("5 sub 5");
assertEquals("{5 SUB 5}", expression.toString());
}
@Test
public void multiplicative() throws Exception {
- Expression expression = parseExpression(TokenKind.MUL_OP);
+ Expression expression = parseExpression("5 mul 5");
assertEquals("{5 MUL 5}", expression.toString());
- expression = parseExpression(TokenKind.DIV_OP);
+ expression = parseExpression("5 div 5");
assertEquals("{5 DIV 5}", expression.toString());
- expression = parseExpression(TokenKind.MOD_OP);
+ expression = parseExpression("5 mod 5");
assertEquals("{5 MOD 5}", expression.toString());
}
@Test
public void unary() throws Exception {
- ArrayList<Token> tokens = new ArrayList<Token>();
- tokens.add(new Token(TokenKind.MINUS, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- Tokenizer tokenizer = new Tokenizer(tokens);
- Expression expression = new ExpressionParser().parse(tokenizer);
- assertEquals("{- 5}", expression.toString());
-
- tokens = new ArrayList<Token>();
- tokens.add(new Token(TokenKind.NOT, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- tokenizer = new Tokenizer(tokens);
- expression = new ExpressionParser().parse(tokenizer);
- assertEquals("{not 5}", expression.toString());
+ Expression expression = parseExpression("-5");
+ assertEquals("{MINUS 5}", expression.toString());
+
+ assertEquals("{MINUS -1}", parseExpression("--1").toString());
+
+ expression = parseExpression("not 5");
+ assertEquals("{NOT 5}", expression.toString());
}
@Test
public void grouping() throws Exception {
- ArrayList<Token> tokens = new ArrayList<Token>();
- tokens.add(new Token(TokenKind.MINUS, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- tokens.add(new Token(TokenKind.ADD_OP, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- Tokenizer tokenizer = new Tokenizer(tokens);
- Expression expression = new ExpressionParser().parse(tokenizer);
- assertEquals("{{- 5} ADD 5}", expression.toString());
-
- tokens = new ArrayList<Token>();
- tokens.add(new Token(TokenKind.MINUS, ""));
- tokens.add(new Token(TokenKind.OPEN, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- tokens.add(new Token(TokenKind.ADD_OP, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- tokens.add(new Token(TokenKind.CLOSE, ""));
- tokenizer = new Tokenizer(tokens);
- expression = new ExpressionParser().parse(tokenizer);
- assertEquals("{- {5 ADD 5}}", expression.toString());
+ Expression expression = parseExpression("-5 add 5");
+ assertEquals("{{MINUS 5} ADD 5}", expression.toString());
+
+ expression = parseExpression("-(5 add 5)");
+ assertEquals("{MINUS {5 ADD 5}}", expression.toString());
+ }
+
+ @Test
+ public void precedence() throws Exception {
+ assertEquals("{{MINUS 1} ADD {2 DIV 3}}", parseExpression("-1 add 2 div 3").toString());
+ assertEquals("{true OR {{NOT false} AND true}}", parseExpression("true or not false and true").toString());
}
@Test
public void noParameterMethods() throws Exception {
- Expression expression = parseMethod(TokenKind.Now);
+ Expression expression = parseMethod(TokenKind.NowMethod);
assertEquals("{now []}", expression.toString());
- expression = parseMethod(TokenKind.Maxdatetime);
+ expression = parseMethod(TokenKind.MaxdatetimeMethod);
assertEquals("{maxdatetime []}", expression.toString());
- expression = parseMethod(TokenKind.Mindatetime);
+ expression = parseMethod(TokenKind.MindatetimeMethod);
assertEquals("{mindatetime []}", expression.toString());
}
@Test
public void oneParameterMethods() throws Exception {
- Expression expression = parseMethod(TokenKind.Length, TokenKind.PrimitiveStringValue);
- assertEquals("{length [String1]}", expression.toString());
-
- expression = parseMethod(TokenKind.Tolower, TokenKind.PrimitiveStringValue);
- assertEquals("{tolower [String1]}", expression.toString());
+ final String stringValue = "'abc'";
+ final String dateValue = "1234-12-25";
+ final String dateTimeOffsetValue = "1234-12-25T11:12:13.456Z";
- expression = parseMethod(TokenKind.Toupper, TokenKind.PrimitiveStringValue);
- assertEquals("{toupper [String1]}", expression.toString());
+ Expression expression = parseMethod(TokenKind.LengthMethod, stringValue);
+ assertEquals("{length [" + stringValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Trim, TokenKind.PrimitiveStringValue);
- assertEquals("{trim [String1]}", expression.toString());
+ expression = parseMethod(TokenKind.TolowerMethod, stringValue);
+ assertEquals("{tolower [" + stringValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Year, TokenKind.PrimitiveDateValue);
- assertEquals("{year [Date1]}", expression.toString());
+ expression = parseMethod(TokenKind.ToupperMethod, stringValue);
+ assertEquals("{toupper [" + stringValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Month, TokenKind.PrimitiveDateValue);
- assertEquals("{month [Date1]}", expression.toString());
+ expression = parseMethod(TokenKind.TrimMethod, stringValue);
+ assertEquals("{trim [" + stringValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Day, TokenKind.PrimitiveDateValue);
- assertEquals("{day [Date1]}", expression.toString());
+ expression = parseMethod(TokenKind.YearMethod, dateValue);
+ assertEquals("{year [" + dateValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Hour, TokenKind.PrimitiveDateTimeOffsetValue);
- assertEquals("{hour [DateTimeOffset1]}", expression.toString());
+ expression = parseMethod(TokenKind.MonthMethod, dateValue);
+ assertEquals("{month [" + dateValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Minute, TokenKind.PrimitiveDateTimeOffsetValue);
- assertEquals("{minute [DateTimeOffset1]}", expression.toString());
+ expression = parseMethod(TokenKind.DayMethod, dateValue);
+ assertEquals("{day [" + dateValue + "]}", expression.toString());
- expression = parseMethod(TokenKind.Second, TokenKind.PrimitiveDateTimeOffsetValue);
- assertEquals("{second [DateTimeOffset1]}", expression.toString());
- }
+ expression = parseMethod(TokenKind.HourMethod, dateTimeOffsetValue);
+ assertEquals("{hour [" + dateTimeOffsetValue + "]}", expression.toString());
- @Test
- public void twoParameterMethods() {
+ expression = parseMethod(TokenKind.MinuteMethod, dateTimeOffsetValue);
+ assertEquals("{minute [" + dateTimeOffsetValue + "]}", expression.toString());
+ expression = parseMethod(TokenKind.SecondMethod, dateTimeOffsetValue);
+ assertEquals("{second [" + dateTimeOffsetValue + "]}", expression.toString());
}
- private Expression parseMethod(TokenKind... kind) throws UriParserException {
- ArrayList<Token> tokens = new ArrayList<Token>();
- tokens.add(new Token(kind[0], ""));
-
- for (int i = 1; i < kind.length; i++) {
- String text = null;
- switch (kind[i]) {
- case PrimitiveStringValue:
- text = "String" + i;
- break;
- case PrimitiveDateValue:
- text = "Date" + i;
- break;
- case PrimitiveDateTimeOffsetValue:
- text = "DateTimeOffset" + i;
- break;
- default:
- text = "" + i;
- break;
+ private Expression parseMethod(TokenKind kind, String... parameters) throws UriParserException {
+ String expressionString = kind.name().substring(0, kind.name().indexOf("Method"))
+ .toLowerCase(Locale.ROOT).replace("geo", "geo.") + '(';
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ expressionString += ',';
}
- tokens.add(new Token(kind[i], text));
+ expressionString += parameters[i];
}
+ expressionString += ')';
- tokens.add(new Token(TokenKind.CLOSE, ""));
- Tokenizer tokenizer = new Tokenizer(tokens);
- Expression expression = new ExpressionParser().parse(tokenizer);
+ Expression expression = parseExpression(expressionString);
assertNotNull(expression);
return expression;
}
- private Expression parseExpression(TokenKind operator) throws UriParserException {
- ArrayList<Token> tokens = new ArrayList<Token>();
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- tokens.add(new Token(operator, ""));
- tokens.add(new Token(TokenKind.PrimitiveIntegerValue, "5"));
- Tokenizer tokenizer = new Tokenizer(tokens);
-
+ private Expression parseExpression(final String expressionString) throws UriParserException {
+ UriTokenizer tokenizer = new UriTokenizer(expressionString);
Expression expression = new ExpressionParser().parse(tokenizer);
assertNotNull(expression);
+ assertTrue(tokenizer.next(TokenKind.EOF));
return expression;
}
}