diff options
5 files changed, 62 insertions, 16 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java b/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java index 09fd03b..963af7b 100644 --- a/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java +++ b/src/main/java/com/healthmarketscience/jackcess/expr/Expression.java @@ -22,12 +22,14 @@ import java.util.Collection; * * @author James Ahlborn */ -public interface Expression +public interface Expression { public Object eval(EvalContext ctx); public String toDebugString(); + public String toRawString(); + public boolean isConstant(); public void collectIdentifiers(Collection<Identifier> identifiers); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/BaseEvalContext.java b/src/main/java/com/healthmarketscience/jackcess/impl/BaseEvalContext.java index 640be96..4566225 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/BaseEvalContext.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/BaseEvalContext.java @@ -195,6 +195,10 @@ public abstract class BaseEvalContext implements EvalContext return "<raw>{" + _exprStr + "}"; } + public String toRawString() { + return _exprStr; + } + public boolean isConstant() { return getExpr().isConstant(); } 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 c9af948..04c8aa0 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/expr/Expressionator.java @@ -427,7 +427,7 @@ public class Expressionator // this is handled as a literal string value, not an expression. no // need to memo-ize cause it's a simple literal value - return new ExprWrapper( + return new ExprWrapper(exprStr, new ELiteralValue(Value.Type.STRING, exprStr, null), resultType); } @@ -447,15 +447,15 @@ public class Expressionator return (expr.isConstant() ? // for now, just cache at top-level for speed (could in theory // cache intermediate values?) - new MemoizedExprWrapper(expr, resultType) : - new ExprWrapper(expr, resultType)); + new MemoizedExprWrapper(exprStr, expr, resultType) : + new ExprWrapper(exprStr, expr, resultType)); case FIELD_VALIDATOR: case RECORD_VALIDATOR: return (expr.isConstant() ? // for now, just cache at top-level for speed (could in theory // cache intermediate values?) - new MemoizedCondExprWrapper(expr) : - new CondExprWrapper(expr)); + new MemoizedCondExprWrapper(exprStr, expr) : + new CondExprWrapper(exprStr, expr)); default: throw new ParseException("unexpected expression type " + exprType); } @@ -910,7 +910,7 @@ public class Expressionator t = buf.next(); } if(!isDelim(t, OPEN_PAREN)) { - throw new ParseException("Malformed In expression " + buf); + throw new ParseException("Malformed 'In' expression " + buf); } List<Expr> exprs = findParenExprs(buf, true); @@ -2007,9 +2007,11 @@ public class Expressionator */ private static abstract class BaseExprWrapper implements Expression { + private final String _rawExprStr; private final Expr _expr; - private BaseExprWrapper(Expr expr) { + private BaseExprWrapper(String rawExprStr, Expr expr) { + _rawExprStr = rawExprStr; _expr = expr; } @@ -2017,6 +2019,10 @@ public class Expressionator return _expr.toDebugString(); } + public String toRawString() { + return _rawExprStr; + } + public boolean isConstant() { return _expr.isConstant(); } @@ -2080,8 +2086,8 @@ public class Expressionator { private final Value.Type _resultType; - private ExprWrapper(Expr expr, Value.Type resultType) { - super(expr); + private ExprWrapper(String rawExprStr, Expr expr, Value.Type resultType) { + super(rawExprStr, expr); _resultType = resultType; } @@ -2096,8 +2102,8 @@ public class Expressionator */ private static class CondExprWrapper extends BaseExprWrapper { - private CondExprWrapper(Expr expr) { - super(expr); + private CondExprWrapper(String rawExprStr, Expr expr) { + super(rawExprStr, expr); } public Object eval(EvalContext ctx) { @@ -2113,8 +2119,9 @@ public class Expressionator { private Object _val; - private MemoizedExprWrapper(Expr expr, Value.Type resultType) { - super(expr, resultType); + private MemoizedExprWrapper(String rawExprStr, Expr expr, + Value.Type resultType) { + super(rawExprStr, expr, resultType); } @Override @@ -2134,8 +2141,8 @@ public class Expressionator { private Object _val; - private MemoizedCondExprWrapper(Expr expr) { - super(expr); + private MemoizedCondExprWrapper(String rawExprStr, Expr expr) { + super(rawExprStr, expr); } @Override diff --git a/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java b/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java index 0b02888..c95fbaf 100644 --- a/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java +++ b/src/test/java/com/healthmarketscience/jackcess/impl/expr/DefaultFunctionsTest.java @@ -33,6 +33,8 @@ public class DefaultFunctionsTest extends TestCase super(name); } + // FIXME, test more number/string functions + public void testFuncs() throws Exception { assertEquals("foo", eval("=IIf(10 > 1, \"foo\", \"bar\")")); 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 f491526..6c525cc 100644 --- a/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java +++ b/src/test/java/com/healthmarketscience/jackcess/impl/expr/ExpressionatorTest.java @@ -31,6 +31,7 @@ import com.healthmarketscience.jackcess.expr.EvalContext; import com.healthmarketscience.jackcess.expr.Expression; import com.healthmarketscience.jackcess.expr.FunctionLookup; import com.healthmarketscience.jackcess.expr.Identifier; +import com.healthmarketscience.jackcess.expr.ParseException; import com.healthmarketscience.jackcess.expr.TemporalConfig; import com.healthmarketscience.jackcess.expr.Value; import com.healthmarketscience.jackcess.impl.BaseEvalContext; @@ -462,6 +463,35 @@ public class ExpressionatorTest extends TestCase br.close(); } + public void testInvalidExpressions() throws Exception + { + doTestEvalFail("", "empty"); + doTestEvalFail("=", "found?"); + doTestEvalFail("=(34 + 5", "closing"); + doTestEvalFail("=(34 + )", "found?"); + doTestEvalFail("=(34 + [A].[B].[C].[D])", "object reference"); + doTestEvalFail("=34 + 5,", "delimiter"); + doTestEvalFail("=Foo()", "find function"); + doTestEvalFail("=(/37)", "left expression"); + doTestEvalFail("=(>37)", "left expression"); + doTestEvalFail("=(And 37)", "left expression"); + doTestEvalFail("=37 In 42", "'In' expression"); + doTestEvalFail("=37 Between 42", "'Between' expression"); + doTestEvalFail("=(3 + 5) Rnd()", "multiple expressions"); + // doTestEvalFail("=Blah", ""); + } + + private static void doTestEvalFail(String exprStr, String msgStr) { + try { + eval(exprStr); + fail("ParseException should have been thrown"); + } catch(ParseException pe) { + // success + System.out.println("FOO " + pe); + assertTrue(pe.getMessage().contains(msgStr)); + } + } + private static void validateExpr(String exprStr, String debugStr) { validateExpr(exprStr, debugStr, exprStr); } @@ -479,6 +509,7 @@ public class ExpressionatorTest extends TestCase assertEquals(debugStr, foundDebugStr); } assertEquals(cleanStr, expr.toString()); + assertEquals(exprStr, expr.toRawString()); } static Object eval(String exprStr) { |