@Override protected Object eval(RowContext ctx) {
return ctx.getThisColumnValue();
}
+ @Override protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append("<THIS_COL>");
+ }
};
private static final Expr NULL_VALUE = new Expr() {
@Override protected Object eval(RowContext ctx) {
return null;
}
+ @Override protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append("Null");
+ }
};
private static final Expr TRUE_VALUE = new Expr() {
@Override protected Object eval(RowContext ctx) {
return Boolean.TRUE;
}
+ @Override protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append("True");
+ }
};
private static final Expr FALSE_VALUE = new Expr() {
@Override protected Object eval(RowContext ctx) {
return Boolean.FALSE;
}
+ @Override protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append("False");
+ }
};
private Expressionator()
return null;
}
- TokBuf buf = new TokBuf(exprType, tokens);
- parseExpression(buf, false);
-
- // FIXME
- return null;
+ return parseExpression(new TokBuf(exprType, tokens), false);
}
private static List<Token> trimSpaces(List<Token> tokens) {
}
public void setPendingExpr(Expr expr) {
- if(_pendingExpr == null) {
+ if(_pendingExpr != null) {
throw new IllegalArgumentException(
"Found multiple expressions with no operator " + this);
}
}
private static boolean isHigherPrecendence(String op1, String op2) {
- int prec1 = PRECENDENCE.get(op1);
- int prec2 = PRECENDENCE.get(op2);
+ int prec1 = PRECENDENCE.get(op1.toLowerCase());
+ int prec2 = PRECENDENCE.get(op2.toLowerCase());
// higher preceendence ops have lower numbers
return (prec1 < prec2);
return val.equals(ctx.getThisColumnValue());
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb, false);
+ return sb.toString();
+ }
+
+ public String toDebugString() {
+ StringBuilder sb = new StringBuilder();
+ toString(sb, true);
+ return sb.toString();
+ }
+
+ protected void toString(StringBuilder sb, boolean isDebug) {
+ if(isDebug) {
+ sb.append("<").append(getClass().getSimpleName()).append(">{");
+ }
+ toExprString(sb, isDebug);
+ if(isDebug) {
+ sb.append("}");
+ }
+ }
+
protected abstract Object eval(RowContext ctx);
+
+ protected abstract void toExprString(StringBuilder sb, boolean isDebug);
}
public interface RowContext
public Object eval(RowContext ctx) {
return _value;
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ // FIXME, stronger typing?
+ if(_value instanceof String) {
+ sb.append("\"").append(_value).append("\"");
+ } else if(_value instanceof Date) {
+ // FIXME Date,Time,DateTime formatting?
+ sb.append("#").append(_value).append("#");
+ } else {
+ sb.append(_value);
+ }
+ }
}
private static final class EObjValue extends Expr
public Object eval(RowContext ctx) {
return ctx.getRowValue(_collectionName, _objName, _fieldName);
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ if(_collectionName != null) {
+ sb.append("[").append(_collectionName).append("].");
+ }
+ if(_objName != null) {
+ sb.append("[").append(_objName).append("].");
+ }
+ sb.append("[").append(_fieldName).append("]");
+ }
}
private static abstract class EOp
protected Object eval(RowContext ctx) {
return _expr.eval(ctx);
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append("(");
+ _expr.toString(sb, isDebug);
+ sb.append(")");
+ }
}
private static class EFunc extends Expr
return false;
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append(_name).append("(");
+
+ if(!_params.isEmpty()) {
+ Iterator<Expr> iter = _params.iterator();
+ iter.next().toString(sb, isDebug);
+ while(iter.hasNext()) {
+ sb.append(",");
+ iter.next().toString(sb, isDebug);
+ }
+ }
+
+ sb.append(")");
+ }
}
private static abstract class EBaseBinaryOp extends Expr
// as all other precedence has been resolved in previous parsing
// rounds.
if((leftOp._right == this) && isHigherPrecendence(leftOp._op, _op)) {
+
+ // FIXME, need to move up if precedecne is the same!
// doh, "this" is lower precedence, restore the original order of
// things
return outerExpr;
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ _left.toString(sb, isDebug);
+ sb.append(" ").append(_op).append(" ");
+ _right.toString(sb, isDebug);
+ }
}
private static class EBinaryOp extends EBaseBinaryOp
private static class EUnaryOp extends Expr
{
private final String _op;
- private final Expr _val;
+ private final Expr _expr;
- private EUnaryOp(String op, Expr val) {
+ private EUnaryOp(String op, Expr expr) {
_op = op;
- _val = val;
+ _expr = expr;
}
@Override
return null;
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ sb.append(" ").append(_op).append(" ");
+ _expr.toString(sb, isDebug);
+ }
}
private static class ECompOp extends EBaseBinaryOp
_op = op;
_expr = expr;
}
+
+ @Override
+ protected void toExprString(StringBuilder sb, boolean isDebug) {
+ // FIXME
+ throw new UnsupportedOperationException("FIXME");
+ // _expr.toString(sb, isDebug);
+ // sb.append(" ").append(_op);
+ }
}
private static class ENullOp extends ESpecOp
--- /dev/null
+/*
+Copyright (c) 2016 James Ahlborn
+
+Licensed 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 com.healthmarketscience.jackcess.util;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author James Ahlborn
+ */
+public class ExpressionatorTest extends TestCase
+{
+
+ public ExpressionatorTest(String name) {
+ super(name);
+ }
+
+ public void testOrderOfOperations() throws Exception
+ {
+ Expressionator.Expr expr = Expressionator.parse(
+ Expressionator.Type.FIELD_VALIDATOR, "\"A\" Eqv \"B\"", null);
+ assertEquals("<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELiteralValue>{\"B\"}}",
+ expr.toDebugString());
+
+ expr = Expressionator.parse(
+ Expressionator.Type.FIELD_VALIDATOR, "\"A\" Eqv \"B\" Xor \"C\"", null);
+ assertEquals("<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELiteralValue>{\"C\"}}}",
+ expr.toDebugString());
+
+ expr = Expressionator.parse(
+ Expressionator.Type.FIELD_VALIDATOR, "\"A\" Eqv \"B\" Xor \"C\" Or \"D\"", null);
+ assertEquals("<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELogicalOp>{<ELiteralValue>{\"C\"} Or <ELiteralValue>{\"D\"}}}}",
+ expr.toDebugString());
+
+ expr = Expressionator.parse(
+ Expressionator.Type.FIELD_VALIDATOR, "\"A\" Eqv \"B\" Xor \"C\" Or \"D\" And \"E\"", null);
+ assertEquals("<ELogicalOp>{<ELiteralValue>{\"A\"} Eqv <ELogicalOp>{<ELiteralValue>{\"B\"} Xor <ELogicalOp>{<ELiteralValue>{\"C\"} Or <ELogicalOp>{<ELiteralValue>{\"D\"} And <ELiteralValue>{\"E\"}}}}}",
+ expr.toDebugString());
+ }
+}