aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2017-10-14 14:38:17 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2017-10-14 14:38:17 +0000
commit389a37297d6a75052c8852002ba6288c3b02f26c (patch)
treeeee058b12945dd375c3dc282ef7a9a1d40f01601
parent774d505946db6b249aad04d8ecac506600731c93 (diff)
downloadjackcess-389a37297d6a75052c8852002ba6288c3b02f26c.tar.gz
jackcess-389a37297d6a75052c8852002ba6288c3b02f26c.zip
handle plus as a unary number modifier; handle precedence of plus/minus in more confusing math expressions
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/exprs@1127 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java7
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java55
-rw-r--r--src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java17
3 files changed, 67 insertions, 12 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java
index 0efd21a..0535332 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/ExpressionTokenizer.java
@@ -107,13 +107,6 @@ class ExpressionTokenizer
switch(charFlag) {
case IS_OP_FLAG:
- // special case '-' for negative number
- Token numLit = maybeParseNumberLiteral(c, buf);
- if(numLit != null) {
- tokens.add(numLit);
- continue;
- }
-
// all simple operator chars are single character operators
tokens.add(new Token(TokenType.OP, String.valueOf(c)));
break;
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java b/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
index 9e65c5e..b8681c6 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java
@@ -111,11 +111,36 @@ public class Expressionator
@Override public Value eval(EvalContext ctx, Value param1) {
return BuiltinOperators.negate(ctx, param1);
}
+ @Override public UnaryOp getUnaryNumOp() {
+ return UnaryOp.NEG_NUM;
+ }
+ },
+ POS("+", false) {
+ @Override public Value eval(EvalContext ctx, Value param1) {
+ // basically a no-op
+ return param1;
+ }
+ @Override public UnaryOp getUnaryNumOp() {
+ return UnaryOp.POS_NUM;
+ }
},
NOT("Not", true) {
@Override public Value eval(EvalContext ctx, Value param1) {
return BuiltinOperators.not(param1);
}
+ },
+ // when a '-' immediately precedes a number, it needs "highest" precedence
+ NEG_NUM("-", false) {
+ @Override public Value eval(EvalContext ctx, Value param1) {
+ return BuiltinOperators.negate(ctx, param1);
+ }
+ },
+ // when a '+' immediately precedes a number, it needs "highest" precedence
+ POS_NUM("+", false) {
+ @Override public Value eval(EvalContext ctx, Value param1) {
+ // basically a no-op
+ return param1;
+ }
};
private final String _str;
@@ -135,6 +160,10 @@ public class Expressionator
return _str;
}
+ public UnaryOp getUnaryNumOp() {
+ return null;
+ }
+
public abstract Value eval(EvalContext ctx, Value param1);
}
@@ -341,8 +370,9 @@ public class Expressionator
private static final Map<OpType, Integer> PRECENDENCE =
buildPrecedenceMap(
+ new OpType[]{UnaryOp.NEG_NUM, UnaryOp.POS_NUM},
new OpType[]{BinaryOp.EXP},
- new OpType[]{UnaryOp.NEG},
+ new OpType[]{UnaryOp.NEG, UnaryOp.POS},
new OpType[]{BinaryOp.MULT, BinaryOp.DIV},
new OpType[]{BinaryOp.INT_DIV},
new OpType[]{BinaryOp.MOD},
@@ -714,10 +744,11 @@ public class Expressionator
private static void parseOperatorExpression(Token t, TokBuf buf) {
- // most ops are two argument except that '-' could be negation
+ // most ops are two argument except that '-' could be negation, "+" could
+ // be pos-ation
if(buf.hasPendingExpr()) {
parseBinaryOpExpression(t, buf);
- } else if(isOp(t, "-")) {
+ } else if(isEitherOp(t, "-", "+")) {
parseUnaryOpExpression(t, buf);
} else {
throw new IllegalArgumentException(
@@ -736,6 +767,18 @@ public class Expressionator
private static void parseUnaryOpExpression(Token firstTok, TokBuf buf) {
UnaryOp op = getOpType(firstTok, UnaryOp.class);
+
+ UnaryOp numOp = op.getUnaryNumOp();
+ if(numOp != null) {
+ // if this operator is immediately preceding a number, it has a higher
+ // precedence
+ Token nextTok = buf.peekNext();
+ if((nextTok != null) && (nextTok.getType() == TokenType.LITERAL) &&
+ nextTok.getValueType().isNumeric()) {
+ op = numOp;
+ }
+ }
+
Expr val = parseExpression(buf, true);
buf.setPendingExpr(new EUnaryOp(op, val));
@@ -935,6 +978,12 @@ public class Expressionator
opStr.equalsIgnoreCase(t.getValueStr()));
}
+ private static boolean isEitherOp(Token t, String opStr1, String opStr2) {
+ return ((t != null) && (t.getType() == TokenType.OP) &&
+ (opStr1.equalsIgnoreCase(t.getValueStr()) ||
+ opStr2.equalsIgnoreCase(t.getValueStr())));
+ }
+
private static boolean isDelim(Token t, String opStr) {
return ((t != null) && (t.getType() == TokenType.DELIM) &&
opStr.equalsIgnoreCase(t.getValueStr()));
diff --git a/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java b/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
index f0e5397..6463106 100644
--- a/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
+++ b/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java
@@ -52,7 +52,9 @@ public class ExpressionatorTest extends TestCase
validateExpr("13", "<ELiteralValue>{13}");
- validateExpr("-42", "<ELiteralValue>{-42}");
+ validateExpr("-42", "<EUnaryOp>{- <ELiteralValue>{42}}");
+
+ validateExpr("(+37)", "<EParen>{(<EUnaryOp>{+ <ELiteralValue>{37}})}");
doTestSimpleBinOp("EBinaryOp", "+", "-", "*", "/", "\\", "^", "&", "Mod");
doTestSimpleBinOp("ECompOp", "<", "<=", ">", ">=", "=", "<>");
@@ -136,10 +138,18 @@ public class ExpressionatorTest extends TestCase
assertEquals(-i, eval("=-(" + i + ")"));
}
+ for(int i = -10; i <= 10; ++i) {
+ assertEquals(i, eval("=+(" + i + ")"));
+ }
+
for(double i : DBLS) {
assertEquals(-i, eval("=-(" + i + ")"));
}
+ for(double i : DBLS) {
+ assertEquals(i, eval("=+(" + i + ")"));
+ }
+
for(int i = -10; i <= 10; ++i) {
for(int j = -10; j <= 10; ++j) {
assertEquals((i + j), eval("=" + i + " + " + j));
@@ -254,7 +264,10 @@ public class ExpressionatorTest extends TestCase
}
}
-
+ assertEquals(37, eval("=30+7"));
+ assertEquals(23, eval("=30+-7"));
+ assertEquals(23, eval("=30-+7"));
+ assertEquals(23, eval("=30-7"));
}
public void testTypeCoercion() throws Exception