Author: henrib Date: Tue Sep 13 14:36:46 2011 New Revision: 1170197 URL: http://svn.apache.org/viewvc?rev=1170197&view=rev Log: Moved bitwise operations to JexlArithmetic (so they can be overriden); Fixed small issue in Debugger that was not quoting identifiers that needed it; Fixed issue in Interpreter that was reporting undefined variables when registers used as references contained null
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Debugger.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Debugger.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Debugger.java?rev=1170197&r1=1170196&r2=1170197&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Debugger.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Debugger.java Tue Sep 13 14:36:46 2011 @@ -16,6 +16,7 @@ */ package org.apache.commons.jexl2; +import java.util.regex.Pattern; import org.apache.commons.jexl2.parser.ASTAdditiveNode; import org.apache.commons.jexl2.parser.ASTAdditiveOperator; import org.apache.commons.jexl2.parser.ASTAmbiguous; @@ -401,9 +402,17 @@ final class Debugger implements ParserVi return infixChildren(node, " > ", false, data); } + // check identifiers that contain space, quote, double-quotes or backspace + private static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]"); + /** {@inheritDoc} */ public Object visit(ASTIdentifier node, Object data) { - return check(node, node.image, data); + String image = node.image; + if (QUOTED_IDENTIFIER.matcher(image).find()) { + // quote it + image = "'" + node.image.replace("'", "\\'") + "'"; + } + return check(node, image, data); } /** {@inheritDoc} */ Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=1170197&r1=1170196&r2=1170197&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Tue Sep 13 14:36:46 2011 @@ -251,7 +251,7 @@ public class Interpreter implements Pars * @return the left, right or parent node */ protected JexlNode findNullOperand(RuntimeException xrt, JexlNode node, Object left, Object right) { - if (xrt instanceof NullPointerException + if (xrt instanceof ArithmeticException && (Object) JexlException.NULL_OPERAND == xrt.getMessage()) { if (left == null) { return node.jjtGetChild(0); @@ -377,7 +377,7 @@ public class Interpreter implements Pars throw new UnsupportedOperationException("unknown operator " + which); } throw new IllegalArgumentException("unknown operator " + op); - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "+/- error", xrt); } @@ -407,7 +407,7 @@ public class Interpreter implements Pars if (!rightValue) { return Boolean.FALSE; } - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt); } return Boolean.TRUE; @@ -585,15 +585,10 @@ public class Interpreter implements Pars public Object visit(ASTBitwiseAndNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); - int n = 0; - // coerce these two values longs and 'and'. try { - long l = arithmetic.toLong(left); - n = 1; - long r = arithmetic.toLong(right); - return Long.valueOf(l & r); - } catch (RuntimeException xrt) { - throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt); + return arithmetic.bitwiseAnd(left, right); + } catch (ArithmeticException xrt) { + throw new JexlException(node, "& error", xrt); } } @@ -601,10 +596,9 @@ public class Interpreter implements Pars public Object visit(ASTBitwiseComplNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); try { - long l = arithmetic.toLong(left); - return Long.valueOf(~l); - } catch (RuntimeException xrt) { - throw new JexlException(node.jjtGetChild(0), "long coercion error", xrt); + return arithmetic.bitwiseComplement(left); + } catch (ArithmeticException xrt) { + throw new JexlException(node, "~ error", xrt); } } @@ -612,15 +606,10 @@ public class Interpreter implements Pars public Object visit(ASTBitwiseOrNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); - int n = 0; - // coerce these two values longs and 'or'. try { - long l = arithmetic.toLong(left); - n = 1; - long r = arithmetic.toLong(right); - return Long.valueOf(l | r); - } catch (RuntimeException xrt) { - throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt); + return arithmetic.bitwiseOr(left, right); + } catch (ArithmeticException xrt) { + throw new JexlException(node, "| error", xrt); } } @@ -628,15 +617,10 @@ public class Interpreter implements Pars public Object visit(ASTBitwiseXorNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); - int n = 0; - // coerce these two values longs and 'xor'. try { - long l = arithmetic.toLong(left); - n = 1; - long r = arithmetic.toLong(right); - return Long.valueOf(l ^ r); - } catch (RuntimeException xrt) { - throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt); + return arithmetic.bitwiseXor(left, right); + } catch (ArithmeticException xrt) { + throw new JexlException(node, "^ error", xrt); } } @@ -656,7 +640,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.divide(left, right); - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { if (!strict && xrt instanceof ArithmeticException) { return new Double(0.0); } @@ -693,7 +677,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "== error", xrt); } } @@ -745,7 +729,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.greaterThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, ">= error", xrt); } } @@ -756,7 +740,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.greaterThan(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "> error", xrt); } } @@ -813,7 +797,7 @@ public class Interpreter implements Pars } // defaults to equal return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "=~ error", xrt); } } @@ -870,7 +854,7 @@ public class Interpreter implements Pars return result; } catch (JexlException error) { throw error; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(n), "if error", xrt); } } @@ -900,7 +884,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.lessThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "<= error", xrt); } } @@ -911,7 +895,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.lessThan(left, right) ? Boolean.TRUE : Boolean.FALSE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "< error", xrt); } } @@ -1115,8 +1099,8 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.mod(left, right); - } catch (RuntimeException xrt) { - if (!strict && xrt instanceof ArithmeticException) { + } catch (ArithmeticException xrt) { + if (!strict) { return new Double(0.0); } JexlNode xnode = findNullOperand(xrt, node, left, right); @@ -1130,7 +1114,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.multiply(left, right); - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "* error", xrt); } @@ -1142,7 +1126,7 @@ public class Interpreter implements Pars Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "!= error", xrt); } @@ -1199,7 +1183,7 @@ public class Interpreter implements Pars } // defaults to not equal return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node, "!~ error", xrt); } } @@ -1223,7 +1207,7 @@ public class Interpreter implements Pars if (leftValue) { return Boolean.TRUE; } - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt); } Object right = node.jjtGetChild(1).jjtAccept(this, data); @@ -1232,7 +1216,7 @@ public class Interpreter implements Pars if (rightValue) { return Boolean.TRUE; } - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt); } return Boolean.FALSE; @@ -1243,9 +1227,7 @@ public class Interpreter implements Pars // could be array access, identifier or map literal // followed by zero or more ("." and array access, method, size, // identifier or integer literal) - int numChildren = node.jjtGetNumChildren(); - // pass first piece of data in and loop through children Object result = null; StringBuilder variableName = null; @@ -1277,7 +1259,12 @@ public class Interpreter implements Pars } } if (result == null) { - if (isVariable && !context.has(variableName.toString()) && !isTernaryProtected(node)) { + if (isVariable && !isTernaryProtected(node) + // variable unknow in context and not (from) a register + && !(context.has(variableName.toString()) + || (numChildren == 1 + && node.jjtGetChild(0) instanceof ASTIdentifier + && ((ASTIdentifier) node.jjtGetChild(0)).getRegister() >= 0))) { JexlException xjexl = new JexlException.Variable(node, variableName.toString()); return unknownVariable(xjexl); } @@ -1371,7 +1358,7 @@ public class Interpreter implements Pars number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass()); } return number; - } catch (RuntimeException xrt) { + } catch (ArithmeticException xrt) { throw new JexlException(valNode, "arithmetic error", xrt); } } Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java?rev=1170197&r1=1170196&r2=1170197&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java Tue Sep 13 14:36:46 2011 @@ -40,6 +40,7 @@ import java.math.MathContext; * </li> * </ol> * </p> + * Note that the only exception throw by JexlArithmetic is ArithmeticException. * @since 2.0 */ public class JexlArithmetic { @@ -122,22 +123,22 @@ public class JexlArithmetic { /** * The result of +,/,-,*,% when both operands are null. * @return Integer(0) if lenient - * @throws NullPointerException if strict + * @throws ArithmeticException if strict */ protected Object controlNullNullOperands() { if (!isLenient()) { - throw new NullPointerException(JexlException.NULL_OPERAND); + throw new ArithmeticException(JexlException.NULL_OPERAND); } return Integer.valueOf(0); } /** * Throw a NPE if arithmetic is strict. - * @throws NullPointerException if strict + * @throws ArithmeticException if strict */ protected void controlNullOperand() { if (!isLenient()) { - throw new NullPointerException(JexlException.NULL_OPERAND); + throw new ArithmeticException(JexlException.NULL_OPERAND); } } @@ -591,6 +592,53 @@ public class JexlArithmetic { } /** + * Performs a bitwise and. + * @param left the left operand + * @param right the right operator + * @return left & right + */ + public Object bitwiseAnd(Object left, Object right) { + long l = toLong(left); + long r = toLong(right); + return Long.valueOf(l & r); + } + + /** + * Performs a bitwise or. + * @param left the left operand + * @param right the right operator + * @return left | right + */ + public Object bitwiseOr(Object left, Object right) { + long l = toLong(left); + long r = toLong(right); + return Long.valueOf(l | r); + } + + + /** + * Performs a bitwise xor. + * @param left the left operand + * @param right the right operator + * @return left right + */ + public Object bitwiseXor(Object left, Object right) { + long l = toLong(left); + long r = toLong(right); + return Long.valueOf(l ^ r); + } + + /** + * Performs a bitwise complement. + * @param val the operand + * @return ~val + */ + public Object bitwiseComplement(Object val) { + long l = toLong(val); + return Long.valueOf(~l); + } + + /** * Performs a comparison. * @param left the left operand * @param right the right operator Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java?rev=1170197&r1=1170196&r2=1170197&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java (original) +++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java Tue Sep 13 14:36:46 2011 @@ -717,5 +717,10 @@ public class IssuesTest extends JexlTest s = jexl.createScript("foo.'q u u x'"); result = s.execute(jc); assertEquals("456", result); + + Debugger dbg = new Debugger(); + dbg.debug(((ExpressionImpl) s).script); + String dbgdata = dbg.data(); + assertEquals("foo.'q u u x';", dbgdata); } }