This is an automated email from the ASF dual-hosted git repository. henrib pushed a commit to branch JEXL-360 in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
commit 9f768d75c5967e331d2c415e792ac15ef959655d Author: henrib <[email protected]> AuthorDate: Tue Feb 15 16:20:42 2022 +0100 JEXL-360: added operators, syntax, basic tests --- .../org/apache/commons/jexl3/JexlArithmetic.java | 39 ++++++ .../org/apache/commons/jexl3/JexlOperator.java | 45 +++++++ .../apache/commons/jexl3/internal/Debugger.java | 109 +++++------------ .../apache/commons/jexl3/internal/Interpreter.java | 131 ++++++++------------- .../apache/commons/jexl3/internal/Operators.java | 6 + .../commons/jexl3/internal/ScriptVisitor.java | 106 +++++------------ .../org/apache/commons/jexl3/parser/Parser.jjt | 45 +++++-- .../apache/commons/jexl3/parser/ParserVisitor.java | 12 ++ .../org/apache/commons/jexl3/ArithmeticTest.java | 30 +++++ 9 files changed, 280 insertions(+), 243 deletions(-) diff --git a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java index 9c3033a..b34d367 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java +++ b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java @@ -1309,6 +1309,45 @@ public class JexlArithmetic { } /** + * Shifts a bit pattern to the right. + * + * @param left left argument + * @param right right argument + * @return left << right. + */ + public Object shiftLeft(Object left, Object right) { + final long l = toLong(left); + final int r = toInteger(right); + return l << r; + } + + /** + * Shifts a bit pattern to the right. + * + * @param left left argument + * @param right right argument + * @return left >> right. + */ + public Object shiftRight(Object left, Object right) { + final long l = toLong(left); + final long r = toInteger(right); + return l >> r; + } + + /** + * Shifts a bit pattern to the right unsigned. + * + * @param left left argument + * @param right right argument + * @return left >>> right. + */ + public Object shiftRightUnsigned(Object left, Object right) { + final long l = toLong(left); + final long r = toInteger(right); + return l >>> r; + } + + /** * Performs a comparison. * * @param left the left operand diff --git a/src/main/java/org/apache/commons/jexl3/JexlOperator.java b/src/main/java/org/apache/commons/jexl3/JexlOperator.java index 6f21e41..daa68f3 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlOperator.java +++ b/src/main/java/org/apache/commons/jexl3/JexlOperator.java @@ -105,6 +105,30 @@ public enum JexlOperator { XOR("^", "xor", 2), /** + * Bit-pattern right-shift operator. + * <br><strong>Syntax:</strong> <code>x >> y</code> + * <br><strong>Method:</strong> <code>T rightShift(L x, R y);</code>. + * @see JexlArithmetic#shiftRight(Object, Object) + */ + SHIFTRIGHT(">>", "shiftRight", 2), + + /** + * Bit-pattern right-shift unsigned operator. + * <br><strong>Syntax:</strong> <code>x >>> y</code> + * <br><strong>Method:</strong> <code>T rightShiftUnsigned(L x, R y);</code>. + * @see JexlArithmetic#shiftRightUnsigned(Object, Object) + */ + SHIFTRIGHTU(">>>", "shiftRightUnsigned", 2), + + /** + * Bit-pattern left-shift operator. + * <br><strong>Syntax:</strong> <code>x << y</code> + * <br><strong>Method:</strong> <code>T leftShift(L x, R y);</code>. + * @see JexlArithmetic#shiftLeft(Object, Object) + */ + SHIFTLEFT("<<", "shiftLeft", 2), + + /** * Equals operator. * <br><strong>Syntax:</strong> <code>x == y</code> * <br><strong>Method:</strong> <code>boolean equals(L x, R y);</code>. @@ -273,6 +297,27 @@ public enum JexlOperator { SELF_XOR("^=", "selfXor", XOR), /** + * Self-right-shift operator. + * <br><strong>Syntax:</strong> <code>x >>= y</code> + * <br><strong>Method:</strong> <code>T selfShiftRight(L x, R y);</code>. + */ + SELF_SHIFTRIGHT(">>", "selfShiftRight", SHIFTRIGHT), + + /** + * Self-right-shift unsigned operator. + * <br><strong>Syntax:</strong> <code>x >>> y</code> + * <br><strong>Method:</strong> <code>T selfShiftRightUnsigned(L x, R y);</code>. + */ + SELF_SHIFTRIGHTU(">>>=", "selfShiftRightUnsigned", SHIFTRIGHTU), + + /** + * Self-left-shift operator. + * <br><strong>Syntax:</strong> <code>x << y</code> + * <br><strong>Method:</strong> <code>T selfShiftLeft(L x, R y);</code>. + */ + SELF_SHIFTLEFT("<<=", "selfShiftLeft", SHIFTLEFT), + + /** * Marker for side effect. * <br>Returns this from 'self*' overload method to let the engine know the side effect has been performed and * there is no need to assign the result. diff --git a/src/main/java/org/apache/commons/jexl3/internal/Debugger.java b/src/main/java/org/apache/commons/jexl3/internal/Debugger.java index 0f5e577..d3f52a2 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Debugger.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Debugger.java @@ -20,86 +20,9 @@ package org.apache.commons.jexl3.internal; import org.apache.commons.jexl3.JexlExpression; import org.apache.commons.jexl3.JexlInfo; import org.apache.commons.jexl3.JexlScript; -import org.apache.commons.jexl3.parser.ASTAddNode; -import org.apache.commons.jexl3.parser.ASTAndNode; -import org.apache.commons.jexl3.parser.ASTArguments; -import org.apache.commons.jexl3.parser.ASTArrayAccess; -import org.apache.commons.jexl3.parser.ASTArrayLiteral; -import org.apache.commons.jexl3.parser.ASTAssignment; -import org.apache.commons.jexl3.parser.ASTBitwiseAndNode; -import org.apache.commons.jexl3.parser.ASTBitwiseComplNode; -import org.apache.commons.jexl3.parser.ASTBitwiseOrNode; -import org.apache.commons.jexl3.parser.ASTBitwiseXorNode; -import org.apache.commons.jexl3.parser.ASTBlock; -import org.apache.commons.jexl3.parser.ASTBreak; -import org.apache.commons.jexl3.parser.ASTConstructorNode; -import org.apache.commons.jexl3.parser.ASTContinue; -import org.apache.commons.jexl3.parser.ASTDivNode; -import org.apache.commons.jexl3.parser.ASTDoWhileStatement; -import org.apache.commons.jexl3.parser.ASTEQNode; -import org.apache.commons.jexl3.parser.ASTERNode; -import org.apache.commons.jexl3.parser.ASTEWNode; -import org.apache.commons.jexl3.parser.ASTEmptyFunction; -import org.apache.commons.jexl3.parser.ASTExtendedLiteral; -import org.apache.commons.jexl3.parser.ASTFalseNode; -import org.apache.commons.jexl3.parser.ASTForeachStatement; -import org.apache.commons.jexl3.parser.ASTFunctionNode; -import org.apache.commons.jexl3.parser.ASTGENode; -import org.apache.commons.jexl3.parser.ASTGTNode; -import org.apache.commons.jexl3.parser.ASTIdentifier; -import org.apache.commons.jexl3.parser.ASTIdentifierAccess; -import org.apache.commons.jexl3.parser.ASTIfStatement; -import org.apache.commons.jexl3.parser.ASTJexlLambda; -import org.apache.commons.jexl3.parser.ASTJexlScript; -import org.apache.commons.jexl3.parser.ASTJxltLiteral; -import org.apache.commons.jexl3.parser.ASTLENode; -import org.apache.commons.jexl3.parser.ASTLTNode; -import org.apache.commons.jexl3.parser.ASTMapEntry; -import org.apache.commons.jexl3.parser.ASTMapLiteral; -import org.apache.commons.jexl3.parser.ASTMethodNode; -import org.apache.commons.jexl3.parser.ASTModNode; -import org.apache.commons.jexl3.parser.ASTMulNode; -import org.apache.commons.jexl3.parser.ASTNENode; -import org.apache.commons.jexl3.parser.ASTNEWNode; -import org.apache.commons.jexl3.parser.ASTNRNode; -import org.apache.commons.jexl3.parser.ASTNSWNode; -import org.apache.commons.jexl3.parser.ASTNotNode; -import org.apache.commons.jexl3.parser.ASTNullLiteral; -import org.apache.commons.jexl3.parser.ASTNumberLiteral; -import org.apache.commons.jexl3.parser.ASTOrNode; -import org.apache.commons.jexl3.parser.ASTRangeNode; -import org.apache.commons.jexl3.parser.ASTReference; -import org.apache.commons.jexl3.parser.ASTReferenceExpression; -import org.apache.commons.jexl3.parser.ASTRegexLiteral; -import org.apache.commons.jexl3.parser.ASTReturnStatement; -import org.apache.commons.jexl3.parser.ASTSWNode; -import org.apache.commons.jexl3.parser.ASTSetAddNode; -import org.apache.commons.jexl3.parser.ASTSetAndNode; -import org.apache.commons.jexl3.parser.ASTSetDivNode; -import org.apache.commons.jexl3.parser.ASTSetLiteral; -import org.apache.commons.jexl3.parser.ASTSetModNode; -import org.apache.commons.jexl3.parser.ASTSetMultNode; -import org.apache.commons.jexl3.parser.ASTSetOrNode; -import org.apache.commons.jexl3.parser.ASTSetSubNode; -import org.apache.commons.jexl3.parser.ASTSetXorNode; -import org.apache.commons.jexl3.parser.ASTSizeFunction; -import org.apache.commons.jexl3.parser.ASTStringLiteral; -import org.apache.commons.jexl3.parser.ASTSubNode; -import org.apache.commons.jexl3.parser.ASTTernaryNode; -import org.apache.commons.jexl3.parser.ASTTrueNode; -import org.apache.commons.jexl3.parser.ASTUnaryMinusNode; -import org.apache.commons.jexl3.parser.ASTVar; -import org.apache.commons.jexl3.parser.ASTWhileStatement; -import org.apache.commons.jexl3.parser.ASTAnnotatedStatement; -import org.apache.commons.jexl3.parser.ASTAnnotation; -import org.apache.commons.jexl3.parser.ASTNullpNode; - -import org.apache.commons.jexl3.parser.JexlNode; -import org.apache.commons.jexl3.parser.ParserVisitor; +import org.apache.commons.jexl3.parser.*; import java.util.regex.Pattern; -import org.apache.commons.jexl3.parser.ASTUnaryPlusNode; -import org.apache.commons.jexl3.parser.StringParser; /** * Helps pinpoint the cause of problems in expressions that fail during evaluation. @@ -492,6 +415,21 @@ public class Debugger extends ParserVisitor implements JexlInfo.Detail { } @Override + protected Object visit(final ASTShiftRightNode node, final Object data) { + return infixChildren(node, " >> ", false, data); + } + + @Override + protected Object visit(final ASTShiftRightUnsignedNode node, final Object data) { + return infixChildren(node, " >>> ", false, data); + } + + @Override + protected Object visit(final ASTShiftLeftNode node, final Object data) { + return infixChildren(node, " << ", false, data); + } + + @Override protected Object visit(final ASTBitwiseComplNode node, final Object data) { return prefixChild(node, "~", data); } @@ -1059,6 +997,21 @@ public class Debugger extends ParserVisitor implements JexlInfo.Detail { } @Override + protected Object visit(final ASTSetShiftRightNode node, final Object data) { + return infixChildren(node, " >>= ", false, data); + } + + @Override + protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) { + return infixChildren(node, " >>>= ", false, data); + } + + @Override + protected Object visit(final ASTSetShiftLeftNode node, final Object data) { + return infixChildren(node, " <<= ", false, data); + } + + @Override protected Object visit(final ASTAnnotation node, final Object data) { final int num = node.jjtGetNumChildren(); builder.append('@'); diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java index 3590d9c..7141b0e 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java @@ -33,82 +33,7 @@ import org.apache.commons.jexl3.JxltEngine; import org.apache.commons.jexl3.introspection.JexlMethod; import org.apache.commons.jexl3.introspection.JexlPropertyGet; -import org.apache.commons.jexl3.parser.ASTAddNode; -import org.apache.commons.jexl3.parser.ASTAndNode; -import org.apache.commons.jexl3.parser.ASTAnnotatedStatement; -import org.apache.commons.jexl3.parser.ASTAnnotation; -import org.apache.commons.jexl3.parser.ASTArguments; -import org.apache.commons.jexl3.parser.ASTArrayAccess; -import org.apache.commons.jexl3.parser.ASTArrayLiteral; -import org.apache.commons.jexl3.parser.ASTAssignment; -import org.apache.commons.jexl3.parser.ASTBitwiseAndNode; -import org.apache.commons.jexl3.parser.ASTBitwiseComplNode; -import org.apache.commons.jexl3.parser.ASTBitwiseOrNode; -import org.apache.commons.jexl3.parser.ASTBitwiseXorNode; -import org.apache.commons.jexl3.parser.ASTBlock; -import org.apache.commons.jexl3.parser.ASTBreak; -import org.apache.commons.jexl3.parser.ASTConstructorNode; -import org.apache.commons.jexl3.parser.ASTContinue; -import org.apache.commons.jexl3.parser.ASTDivNode; -import org.apache.commons.jexl3.parser.ASTDoWhileStatement; -import org.apache.commons.jexl3.parser.ASTEQNode; -import org.apache.commons.jexl3.parser.ASTERNode; -import org.apache.commons.jexl3.parser.ASTEWNode; -import org.apache.commons.jexl3.parser.ASTEmptyFunction; -import org.apache.commons.jexl3.parser.ASTExtendedLiteral; -import org.apache.commons.jexl3.parser.ASTFalseNode; -import org.apache.commons.jexl3.parser.ASTForeachStatement; -import org.apache.commons.jexl3.parser.ASTFunctionNode; -import org.apache.commons.jexl3.parser.ASTGENode; -import org.apache.commons.jexl3.parser.ASTGTNode; -import org.apache.commons.jexl3.parser.ASTIdentifier; -import org.apache.commons.jexl3.parser.ASTIdentifierAccess; -import org.apache.commons.jexl3.parser.ASTIdentifierAccessJxlt; -import org.apache.commons.jexl3.parser.ASTIfStatement; -import org.apache.commons.jexl3.parser.ASTJexlLambda; -import org.apache.commons.jexl3.parser.ASTJexlScript; -import org.apache.commons.jexl3.parser.ASTJxltLiteral; -import org.apache.commons.jexl3.parser.ASTLENode; -import org.apache.commons.jexl3.parser.ASTLTNode; -import org.apache.commons.jexl3.parser.ASTMapEntry; -import org.apache.commons.jexl3.parser.ASTMapLiteral; -import org.apache.commons.jexl3.parser.ASTMethodNode; -import org.apache.commons.jexl3.parser.ASTModNode; -import org.apache.commons.jexl3.parser.ASTMulNode; -import org.apache.commons.jexl3.parser.ASTNENode; -import org.apache.commons.jexl3.parser.ASTNEWNode; -import org.apache.commons.jexl3.parser.ASTNRNode; -import org.apache.commons.jexl3.parser.ASTNSWNode; -import org.apache.commons.jexl3.parser.ASTNotNode; -import org.apache.commons.jexl3.parser.ASTNullLiteral; -import org.apache.commons.jexl3.parser.ASTNullpNode; -import org.apache.commons.jexl3.parser.ASTNumberLiteral; -import org.apache.commons.jexl3.parser.ASTOrNode; -import org.apache.commons.jexl3.parser.ASTRangeNode; -import org.apache.commons.jexl3.parser.ASTReference; -import org.apache.commons.jexl3.parser.ASTReferenceExpression; -import org.apache.commons.jexl3.parser.ASTRegexLiteral; -import org.apache.commons.jexl3.parser.ASTReturnStatement; -import org.apache.commons.jexl3.parser.ASTSWNode; -import org.apache.commons.jexl3.parser.ASTSetAddNode; -import org.apache.commons.jexl3.parser.ASTSetAndNode; -import org.apache.commons.jexl3.parser.ASTSetDivNode; -import org.apache.commons.jexl3.parser.ASTSetLiteral; -import org.apache.commons.jexl3.parser.ASTSetModNode; -import org.apache.commons.jexl3.parser.ASTSetMultNode; -import org.apache.commons.jexl3.parser.ASTSetOrNode; -import org.apache.commons.jexl3.parser.ASTSetSubNode; -import org.apache.commons.jexl3.parser.ASTSetXorNode; -import org.apache.commons.jexl3.parser.ASTSizeFunction; -import org.apache.commons.jexl3.parser.ASTStringLiteral; -import org.apache.commons.jexl3.parser.ASTSubNode; -import org.apache.commons.jexl3.parser.ASTTernaryNode; -import org.apache.commons.jexl3.parser.ASTTrueNode; -import org.apache.commons.jexl3.parser.ASTUnaryMinusNode; -import org.apache.commons.jexl3.parser.ASTUnaryPlusNode; -import org.apache.commons.jexl3.parser.ASTVar; -import org.apache.commons.jexl3.parser.ASTWhileStatement; -import org.apache.commons.jexl3.parser.JexlNode; +import org.apache.commons.jexl3.parser.*; /** * An interpreter of JEXL syntax. @@ -338,9 +263,6 @@ public class Interpreter extends InterpreterBase { protected Object visit(final ASTBitwiseOrNode node, final Object data) { final Object left = node.jjtGetChild(0).jjtAccept(this, data); final Object right = node.jjtGetChild(1).jjtAccept(this, data); - if (arithmetic.isStrict(JexlOperator.OR) && left == null || right == null) { - // boum - } try { final Object result = operators.tryOverload(node, JexlOperator.OR, left, right); return result != JexlEngine.TRY_FAILED ? result : arithmetic.or(left, right); @@ -362,6 +284,42 @@ public class Interpreter extends InterpreterBase { } @Override + protected Object visit(final ASTShiftLeftNode node, final Object data) { + final Object left = node.jjtGetChild(0).jjtAccept(this, data); + final Object right = node.jjtGetChild(1).jjtAccept(this, data); + try { + final Object result = operators.tryOverload(node, JexlOperator.SHIFTLEFT, left, right); + return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftLeft(left, right); + } catch (final ArithmeticException xrt) { + throw new JexlException(findNullOperand(node, left, right), "<< error", xrt); + } + } + + @Override + protected Object visit(final ASTShiftRightNode node, final Object data) { + final Object left = node.jjtGetChild(0).jjtAccept(this, data); + final Object right = node.jjtGetChild(1).jjtAccept(this, data); + try { + final Object result = operators.tryOverload(node, JexlOperator.SHIFTRIGHT, left, right); + return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftRight(left, right); + } catch (final ArithmeticException xrt) { + throw new JexlException(findNullOperand(node, left, right), ">> error", xrt); + } + } + + @Override + protected Object visit(final ASTShiftRightUnsignedNode node, final Object data) { + final Object left = node.jjtGetChild(0).jjtAccept(this, data); + final Object right = node.jjtGetChild(1).jjtAccept(this, data); + try { + final Object result = operators.tryOverload(node, JexlOperator.SHIFTRIGHTU, left, right); + return result != JexlEngine.TRY_FAILED ? result : arithmetic.shiftRightUnsigned(left, right); + } catch (final ArithmeticException xrt) { + throw new JexlException(findNullOperand(node, left, right), ">> error", xrt); + } + } + + @Override protected Object visit(final ASTEQNode node, final Object data) { final Object left = node.jjtGetChild(0).jjtAccept(this, data); final Object right = node.jjtGetChild(1).jjtAccept(this, data); @@ -1283,6 +1241,21 @@ public class Interpreter extends InterpreterBase { return executeAssign(node, JexlOperator.SELF_XOR, data); } + @Override + protected Object visit(final ASTSetShiftLeftNode node, final Object data) { + return executeAssign(node, JexlOperator.SELF_SHIFTLEFT, data); + } + + @Override + protected Object visit(final ASTSetShiftRightNode node, final Object data) { + return executeAssign(node, JexlOperator.SELF_SHIFTRIGHT, data); + } + + @Override + protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) { + return executeAssign(node, JexlOperator.SELF_SHIFTRIGHTU, data); + } + /** * Executes an assignment with an optional side-effect operator. * @param node the node diff --git a/src/main/java/org/apache/commons/jexl3/internal/Operators.java b/src/main/java/org/apache/commons/jexl3/internal/Operators.java index a72dc1d..e26d1ea 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Operators.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Operators.java @@ -187,6 +187,12 @@ public class Operators { return arithmetic.or(args[0], args[1]); case SELF_XOR: return arithmetic.xor(args[0], args[1]); + case SELF_SHIFTLEFT: + return arithmetic.shiftLeft(args[0], args[1]); + case SELF_SHIFTRIGHT: + return arithmetic.shiftRight(args[0], args[1]); + case SELF_SHIFTRIGHTU: + return arithmetic.shiftRightUnsigned(args[0], args[1]); default: // unexpected, new operator added? throw new UnsupportedOperationException(operator.getOperatorSymbol()); diff --git a/src/main/java/org/apache/commons/jexl3/internal/ScriptVisitor.java b/src/main/java/org/apache/commons/jexl3/internal/ScriptVisitor.java index 19afd27..bdcd51e 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/ScriptVisitor.java +++ b/src/main/java/org/apache/commons/jexl3/internal/ScriptVisitor.java @@ -18,81 +18,7 @@ package org.apache.commons.jexl3.internal; import org.apache.commons.jexl3.JexlExpression; import org.apache.commons.jexl3.JexlScript; -import org.apache.commons.jexl3.parser.ASTAddNode; -import org.apache.commons.jexl3.parser.ASTAndNode; -import org.apache.commons.jexl3.parser.ASTAnnotatedStatement; -import org.apache.commons.jexl3.parser.ASTAnnotation; -import org.apache.commons.jexl3.parser.ASTArguments; -import org.apache.commons.jexl3.parser.ASTArrayAccess; -import org.apache.commons.jexl3.parser.ASTArrayLiteral; -import org.apache.commons.jexl3.parser.ASTAssignment; -import org.apache.commons.jexl3.parser.ASTBitwiseAndNode; -import org.apache.commons.jexl3.parser.ASTBitwiseComplNode; -import org.apache.commons.jexl3.parser.ASTBitwiseOrNode; -import org.apache.commons.jexl3.parser.ASTBitwiseXorNode; -import org.apache.commons.jexl3.parser.ASTBlock; -import org.apache.commons.jexl3.parser.ASTBreak; -import org.apache.commons.jexl3.parser.ASTConstructorNode; -import org.apache.commons.jexl3.parser.ASTContinue; -import org.apache.commons.jexl3.parser.ASTDivNode; -import org.apache.commons.jexl3.parser.ASTDoWhileStatement; -import org.apache.commons.jexl3.parser.ASTEQNode; -import org.apache.commons.jexl3.parser.ASTERNode; -import org.apache.commons.jexl3.parser.ASTEWNode; -import org.apache.commons.jexl3.parser.ASTEmptyFunction; -import org.apache.commons.jexl3.parser.ASTExtendedLiteral; -import org.apache.commons.jexl3.parser.ASTFalseNode; -import org.apache.commons.jexl3.parser.ASTForeachStatement; -import org.apache.commons.jexl3.parser.ASTFunctionNode; -import org.apache.commons.jexl3.parser.ASTGENode; -import org.apache.commons.jexl3.parser.ASTGTNode; -import org.apache.commons.jexl3.parser.ASTIdentifier; -import org.apache.commons.jexl3.parser.ASTIdentifierAccess; -import org.apache.commons.jexl3.parser.ASTIfStatement; -import org.apache.commons.jexl3.parser.ASTJexlScript; -import org.apache.commons.jexl3.parser.ASTJxltLiteral; -import org.apache.commons.jexl3.parser.ASTLENode; -import org.apache.commons.jexl3.parser.ASTLTNode; -import org.apache.commons.jexl3.parser.ASTMapEntry; -import org.apache.commons.jexl3.parser.ASTMapLiteral; -import org.apache.commons.jexl3.parser.ASTMethodNode; -import org.apache.commons.jexl3.parser.ASTModNode; -import org.apache.commons.jexl3.parser.ASTMulNode; -import org.apache.commons.jexl3.parser.ASTNENode; -import org.apache.commons.jexl3.parser.ASTNEWNode; -import org.apache.commons.jexl3.parser.ASTNRNode; -import org.apache.commons.jexl3.parser.ASTNSWNode; -import org.apache.commons.jexl3.parser.ASTNotNode; -import org.apache.commons.jexl3.parser.ASTNullLiteral; -import org.apache.commons.jexl3.parser.ASTNullpNode; -import org.apache.commons.jexl3.parser.ASTNumberLiteral; -import org.apache.commons.jexl3.parser.ASTOrNode; -import org.apache.commons.jexl3.parser.ASTRangeNode; -import org.apache.commons.jexl3.parser.ASTReference; -import org.apache.commons.jexl3.parser.ASTReferenceExpression; -import org.apache.commons.jexl3.parser.ASTRegexLiteral; -import org.apache.commons.jexl3.parser.ASTReturnStatement; -import org.apache.commons.jexl3.parser.ASTSWNode; -import org.apache.commons.jexl3.parser.ASTSetAddNode; -import org.apache.commons.jexl3.parser.ASTSetAndNode; -import org.apache.commons.jexl3.parser.ASTSetDivNode; -import org.apache.commons.jexl3.parser.ASTSetLiteral; -import org.apache.commons.jexl3.parser.ASTSetModNode; -import org.apache.commons.jexl3.parser.ASTSetMultNode; -import org.apache.commons.jexl3.parser.ASTSetOrNode; -import org.apache.commons.jexl3.parser.ASTSetSubNode; -import org.apache.commons.jexl3.parser.ASTSetXorNode; -import org.apache.commons.jexl3.parser.ASTSizeFunction; -import org.apache.commons.jexl3.parser.ASTStringLiteral; -import org.apache.commons.jexl3.parser.ASTSubNode; -import org.apache.commons.jexl3.parser.ASTTernaryNode; -import org.apache.commons.jexl3.parser.ASTTrueNode; -import org.apache.commons.jexl3.parser.ASTUnaryMinusNode; -import org.apache.commons.jexl3.parser.ASTUnaryPlusNode; -import org.apache.commons.jexl3.parser.ASTVar; -import org.apache.commons.jexl3.parser.ASTWhileStatement; -import org.apache.commons.jexl3.parser.JexlNode; -import org.apache.commons.jexl3.parser.ParserVisitor; +import org.apache.commons.jexl3.parser.*; /** * Fully abstract to avoid public interface exposition. @@ -231,6 +157,21 @@ public class ScriptVisitor extends ParserVisitor { } @Override + protected Object visit(final ASTShiftLeftNode node, final Object data) { + return visitNode(node, data); + } + + @Override + protected Object visit(final ASTShiftRightUnsignedNode node, final Object data) { + return visitNode(node, data); + } + + @Override + protected Object visit(final ASTShiftRightNode node, final Object data) { + return visitNode(node, data); + } + + @Override protected Object visit(final ASTEQNode node, final Object data) { return visitNode(node, data); } @@ -486,6 +427,21 @@ public class ScriptVisitor extends ParserVisitor { } @Override + protected Object visit(final ASTSetShiftLeftNode node, final Object data) { + return visitNode(node, data); + } + + @Override + protected Object visit(final ASTSetShiftRightUnsignedNode node, final Object data) { + return visitNode(node, data); + } + + @Override + protected Object visit(final ASTSetShiftRightNode node, final Object data) { + return visitNode(node, data); + } + + @Override protected Object visit(final ASTJxltLiteral node, final Object data) { return visitNode(node, data); } diff --git a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt index 46fb92c..d167b36 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt +++ b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt @@ -195,6 +195,9 @@ TOKEN_MGR_DECLS : { | < and_assign : "&=" > | < or_assign : "|=" > | < xor_assign : "^=" > + | < lshift_assign : "<<=" > + | < rshiftu_assign : ">>>=" > + | < rshift_assign : ">>=" > | < assign : "=" > | < plus : "+" > @@ -209,6 +212,9 @@ TOKEN_MGR_DECLS : { | < and : "&" > | < or : "|" > | < xor : "^" > + | < lshift : "<<" > + | < rshiftu : ">>>" > + | < rshift : ">>" > | < tilda : "~" > | < range : ".." > @@ -505,6 +511,12 @@ void AssignmentExpression() #void : {} | <minus_assign> Expression() #SetSubNode(2) | + <lshift_assign> Expression() #SetShiftLeftNode(2) + | + <rshift_assign> Expression() #SetShiftRightNode(2) + | + <rshiftu_assign> Expression() #SetShiftRightUnsignedNode(2) + | <assign> Expression() #Assignment(2) ) )* } @@ -569,33 +581,44 @@ void EqualityExpression() #void : {} void RelationalExpression() #void : {} { - AdditiveExpression() + ShiftExpression() ( - (<lt> |<LT>) AdditiveExpression() #LTNode(2) + (<lt> |<LT>) ShiftExpression() #LTNode(2) | - (<gt> | <GT>) AdditiveExpression() #GTNode(2) + (<gt> | <GT>) ShiftExpression() #GTNode(2) | - (<le> | <LE>) AdditiveExpression() #LENode(2) + (<le> | <LE>) ShiftExpression() #LENode(2) | - (<ge> | <GE>) AdditiveExpression() #GENode(2) + (<ge> | <GE>) ShiftExpression() #GENode(2) | - <req> AdditiveExpression() #ERNode(2) // equals regexp + <req> ShiftExpression() #ERNode(2) // equals regexp | - <rne> AdditiveExpression() #NRNode(2) // not equals regexp + <rne> ShiftExpression() #NRNode(2) // not equals regexp | - <seq> AdditiveExpression() #SWNode(2) // starts with + <seq> ShiftExpression() #SWNode(2) // starts with | - <sne> AdditiveExpression() #NSWNode(2) // not starts with + <sne> ShiftExpression() #NSWNode(2) // not starts with | - <eeq> AdditiveExpression() #EWNode(2) // ends with + <eeq> ShiftExpression() #EWNode(2) // ends with | - <ene> AdditiveExpression() #NEWNode(2) // not ends with + <ene> ShiftExpression() #NEWNode(2) // not ends with )? } /*************************************** * Arithmetic ***************************************/ +void ShiftExpression() #void : {} +{ + AdditiveExpression() + ( LOOKAHEAD(2) ( + <lshift> AdditiveExpression() #ShiftLeftNode(2) // left shift + | + <rshift> AdditiveExpression() #ShiftRightNode(2) // right shift + | + <rshiftu> AdditiveExpression() #ShiftRightUnsignedNode(2) // right shift unsigned + ) )* +} void AdditiveExpression() #void : {} { diff --git a/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java b/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java index 876a61b..a656022 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java +++ b/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java @@ -78,6 +78,12 @@ public abstract class ParserVisitor { protected abstract Object visit(ASTBitwiseAndNode node, Object data); + protected abstract Object visit(ASTShiftLeftNode node, final Object data); + + protected abstract Object visit(ASTShiftRightNode node, final Object data); + + protected abstract Object visit(ASTShiftRightUnsignedNode node, final Object data); + protected abstract Object visit(ASTEQNode node, Object data); protected abstract Object visit(ASTNENode node, Object data); @@ -180,6 +186,12 @@ public abstract class ParserVisitor { protected abstract Object visit(ASTSetXorNode node, Object data); + protected abstract Object visit(ASTSetShiftLeftNode node, final Object data); + + protected abstract Object visit(ASTSetShiftRightNode node, final Object data); + + protected abstract Object visit(ASTSetShiftRightUnsignedNode node, final Object data); + protected abstract Object visit(ASTJxltLiteral node, Object data); protected abstract Object visit(ASTAnnotation node, Object data); diff --git a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java index 91f704c..8b8cacc 100644 --- a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java +++ b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java @@ -980,6 +980,18 @@ public class ArithmeticTest extends JexlTestCase { return new Var(lhs.value ^ rhs.value); } + public Var shiftRight(final Var lhs, final Var rhs) { + return new Var(lhs.value >> rhs.value); + } + + public Var shiftRightUnsigned(final Var lhs, final Var rhs) { + return new Var(lhs.value >>> rhs.value); + } + + public Var shiftLeft(final Var lhs, final Var rhs) { + return new Var(lhs.value << rhs.value); + } + public Boolean contains(final Var lhs, final Var rhs) { return lhs.toString().contains(rhs.toString()); } @@ -1163,6 +1175,24 @@ public class ArithmeticTest extends JexlTestCase { result = script.execute(jc, new Var(35), new Var(7)); Assert.assertEquals(36L, ((Var) result).value); + script = jexl.createScript("(x, y)->{ x << y }"); + result = script.execute(jc, 35, 1); + Assert.assertEquals(70L, result); + result = script.execute(jc, new Var(35), new Var(1)); + Assert.assertEquals(70L, ((Var) result).value); + + script = jexl.createScript("(x, y)->{ x >> y }"); + result = script.execute(jc, 42, 1); + Assert.assertEquals(21L, result); + result = script.execute(jc, new Var(42), new Var(1)); + Assert.assertEquals(21, ((Var) result).value); + + script = jexl.createScript("(x, y)->{ x >>> y }"); + result = script.execute(jc, 84, 2); + Assert.assertEquals(21L, result); + result = script.execute(jc, new Var(84), new Var(2)); + Assert.assertEquals(21, ((Var) result).value); + script = jexl.createScript("(x, y)->{ x & y }"); result = script.execute(jc, 35, 7); Assert.assertEquals(3L, result);
