git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1181 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-2.2.0
@@ -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); |
@@ -195,6 +195,10 @@ public abstract class BaseEvalContext implements EvalContext | |||
return "<raw>{" + _exprStr + "}"; | |||
} | |||
public String toRawString() { | |||
return _exprStr; | |||
} | |||
public boolean isConstant() { | |||
return getExpr().isConstant(); | |||
} |
@@ -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 |
@@ -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\")")); |
@@ -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) { |