You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2022/02/15 15:20:57 UTC

[commons-jexl] branch JEXL-360 created (now 9f768d7)

This is an automated email from the ASF dual-hosted git repository.

henrib pushed a change to branch JEXL-360
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git.


      at 9f768d7  JEXL-360: added operators, syntax, basic tests

This branch includes the following new commits:

     new 9f768d7  JEXL-360: added operators, syntax, basic tests

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[commons-jexl] 01/01: JEXL-360: added operators, syntax, basic tests

Posted by he...@apache.org.
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 <he...@apache.org>
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 &lt;&lt; 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 &gt;&gt; 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 &gt;&gt;&gt; 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);