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 2019/03/28 17:20:52 UTC

[commons-jexl] branch master updated: JEXL-295: positivize performs integral promotion of char, byte, short Task #JEXL-295 - Add unary plus operator

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 76af65b  JEXL-295: positivize performs integral promotion of char, byte, short Task #JEXL-295 - Add unary plus operator
76af65b is described below

commit 76af65b52c04ed9962372388db824041d008fe01
Author: henrib <he...@apache.org>
AuthorDate: Thu Mar 28 18:20:25 2019 +0100

    JEXL-295: positivize performs integral promotion of char, byte, short
    Task #JEXL-295 - Add unary plus operator
---
 .../org/apache/commons/jexl3/JexlArithmetic.java   | 48 ++++++++--------
 .../org/apache/commons/jexl3/JexlOperator.java     |  4 +-
 .../apache/commons/jexl3/internal/Interpreter.java | 21 +++++--
 .../apache/commons/jexl3/internal/Operators.java   |  8 ++-
 .../org/apache/commons/jexl3/ArithmeticTest.java   | 66 ++++++++++++----------
 5 files changed, 83 insertions(+), 64 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
index 6078bab..5a2c015 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
@@ -466,7 +466,7 @@ public class JexlArithmetic {
             BigDecimal bigd = (BigDecimal) original;
             // if it's bigger than a double it can't be narrowed
             if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
-                    || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
+                || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
                 return original;
             } else {
                 try {
@@ -827,34 +827,32 @@ public class JexlArithmetic {
     }
 
     /**
-     * Absolute (positive) value (unary plus for numbers).
-     *
-     * @param val the value to get the absolute value from
+     * Positivize value (unary plus for numbers).
+     * <p>C/C++/C#/Java perform integral promotion of the operand, ie
+     * cast to int if type can represented as int without loss of precision.
+     * @param val the value to positivize
      * @return the positive value
      */
     public Object positivize(Object val) {
-        if (val instanceof Integer) {
-            return Math.abs((Integer) val);
-        } else if (val instanceof Double) {
-            return Math.abs((Double) val);
-        } else if (val instanceof Long) {
-            return Math.abs((Long) val);
-        } else if (val instanceof BigDecimal) {
-            return ((BigDecimal) val).abs();
-        } else if (val instanceof BigInteger) {
-            return ((BigInteger) val).abs();
-        } else if (val instanceof Float) {
-            return Math.abs((Float) val);
-        } else if (val instanceof Short) {
-            return (short) Math.abs((Short) val);
-        } else if (val instanceof Byte) {
-            return (byte) Math.abs((Byte) val);
-        } else if (val instanceof Boolean) {
-            return Boolean.TRUE;
-        } else if (val instanceof AtomicBoolean) {
-            return Boolean.TRUE;
+        if (val instanceof Short) {
+            return ((Short) val).intValue();
+        }
+        if (val instanceof Byte) {
+            return ((Byte) val).intValue();
+        }
+        if (val instanceof Number) {
+            return val;
+        }
+        if (val instanceof Character) {
+            return (int) (Character) val;
+        }
+        if (val instanceof Boolean) {
+            return val;
+        }
+        if (val instanceof AtomicBoolean) {
+            return ((AtomicBoolean) val).get();
         }
-        throw new ArithmeticException("Object abs:(" + val + ")");
+        throw new ArithmeticException("Object positivize:(" + val + ")");
     }
     
     /**
diff --git a/src/main/java/org/apache/commons/jexl3/JexlOperator.java b/src/main/java/org/apache/commons/jexl3/JexlOperator.java
index eab309e..f510612 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlOperator.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlOperator.java
@@ -193,9 +193,9 @@ public enum JexlOperator {
     NEGATE("-", "negate", 1),
     
     /**
-     * Absolute operator.
+     * Positivize operator.
      * <br><strong>Syntax:</strong> <code>+x</code>
-     * <br><strong>Method:</strong> <code>T plus(L x);</code>.
+     * <br><strong>Method:</strong> <code>T positivize(L x);</code>.
      * @see JexlArithmetic#positivize
      */
     POSITIVIZE("+", "positivize", 1),
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 aaea4d9..8b5b284 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -582,6 +582,11 @@ public class Interpreter extends InterpreterBase {
 
     @Override
     protected Object visit(ASTUnaryMinusNode node, Object data) {
+        // use cached value if literal
+        Object value = node.jjtGetValue();
+        if (value != null && !(value instanceof JexlMethod)) {
+            return value;
+        }
         JexlNode valNode = node.jjtGetChild(0);
         Object val = valNode.jjtAccept(this, data);
         try {
@@ -591,8 +596,12 @@ public class Interpreter extends InterpreterBase {
             }
             Object number = arithmetic.negate(val);
             // attempt to recoerce to literal class
-            if (valNode instanceof ASTNumberLiteral && number instanceof Number) {
-                number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass());
+            if ((number instanceof Number)) {
+                // cache it
+                if (valNode instanceof ASTNumberLiteral) {
+                    number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass());
+                    node.jjtSetValue(number);
+                }
             }
             return number;
         } catch (ArithmeticException xrt) {
@@ -602,6 +611,11 @@ public class Interpreter extends InterpreterBase {
     
     @Override
     protected Object visit(ASTUnaryPlusNode node, Object data) {
+        // use cached value if literal
+        Object value = node.jjtGetValue();
+        if (value != null && !(value instanceof JexlMethod)) {
+            return value;
+        }
         JexlNode valNode = node.jjtGetChild(0);
         Object val = valNode.jjtAccept(this, data);
         try {
@@ -610,9 +624,8 @@ public class Interpreter extends InterpreterBase {
                 return result;
             }
             Object number = arithmetic.positivize(val);
-            // attempt to recoerce to literal class
             if (valNode instanceof ASTNumberLiteral && number instanceof Number) {
-                number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass());
+                node.jjtSetValue(number);
             }
             return number;
         } catch (ArithmeticException xrt) {
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 d157445..a4ab493 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Operators.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Operators.java
@@ -107,14 +107,16 @@ public class Operators {
      * @param node     the syntactic node
      * @param operator the operator
      * @param args     the arguments, the first one being the target of assignment
-     * @return the result of the operator evaluation
+     * @return JexlOperator.ASSIGN if operation assignment has been performed,
+     *         JexlEngine.TRY_FAILED if no operation was performed,
+     *         the value to use as the side effect argument otherwise
      */
     protected Object tryAssignOverload(JexlNode node, JexlOperator operator, Object...args) {
         final JexlArithmetic arithmetic = interpreter.arithmetic;
         if (args.length != operator.getArity()) {
             return JexlEngine.TRY_FAILED;
         }
-        // try to call overload on side effect
+        // try to call overload with side effect
         Object result = tryOverload(node, operator, args);
         if (result != JexlEngine.TRY_FAILED) {
             return result;
@@ -125,7 +127,7 @@ public class Operators {
             throw new IllegalArgumentException("must be called with a side-effect operator");
         }
         if (operators != null && operators.overloads(base)) {
-            // in case there is an overload
+            // in case there is an overload on the base operator
             try {
                 JexlMethod vm = operators.getOperator(base, args);
                 if (vm != null) {
diff --git a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
index 3a50d66..ce9ccae 100644
--- a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
+++ b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
@@ -142,42 +142,48 @@ public class ArithmeticTest extends JexlTestCase {
         asserter.setVariable("aBigInteger", new BigInteger("7"));
         asserter.setVariable("aBigDecimal", new BigDecimal("8.8"));
 
-        asserter.assertExpression("-3", new Integer("-3"));
-        asserter.assertExpression("-3.0", new Double("-3.0"));
-        asserter.assertExpression("-aByte", new Byte((byte) -1));
-        asserter.assertExpression("-aShort", new Short((short) -2));
-        asserter.assertExpression("-anInteger", new Integer(-3));
-        asserter.assertExpression("-aLong", new Long(-4));
-        asserter.assertExpression("-aFloat", new Float(-5.5));
-        asserter.assertExpression("-aDouble", new Double(-6.6));
-        asserter.assertExpression("-aBigInteger", new BigInteger("-7"));
-        asserter.assertExpression("-aBigDecimal", new BigDecimal("-8.8"));
+        // loop to allow checking caching of constant numerals (debug)
+        for(int i = 0 ; i < 2; ++i) {
+            asserter.assertExpression("-3", new Integer("-3"));
+            asserter.assertExpression("-3.0", new Double("-3.0"));
+            asserter.assertExpression("-aByte", new Byte((byte) -1));
+            asserter.assertExpression("-aShort", new Short((short) -2));
+            asserter.assertExpression("-anInteger", new Integer(-3));
+            asserter.assertExpression("-aLong", new Long(-4));
+            asserter.assertExpression("-aFloat", new Float(-5.5));
+            asserter.assertExpression("-aDouble", new Double(-6.6));
+            asserter.assertExpression("-aBigInteger", new BigInteger("-7"));
+            asserter.assertExpression("-aBigDecimal", new BigDecimal("-8.8"));
+        }
     }
     
     /**
      * test some simple mathematical calculations
      */
     @Test
-    public void testUnaryPlusus() throws Exception {
-        asserter.setVariable("aByte", new Byte((byte) -1));
-        asserter.setVariable("aShort", new Short((short) -2));
-        asserter.setVariable("anInteger", new Integer(-3));
-        asserter.setVariable("aLong", new Long(-4));
-        asserter.setVariable("aFloat", new Float(-5.5));
-        asserter.setVariable("aDouble", new Double(-6.6));
-        asserter.setVariable("aBigInteger", new BigInteger("-7"));
-        asserter.setVariable("aBigDecimal", new BigDecimal("-8.8"));
-
-        asserter.assertExpression("+3", new Integer("3"));
-        asserter.assertExpression("+3.0", new Double("3.0"));
-        asserter.assertExpression("+aByte", new Byte((byte) 1));
-        asserter.assertExpression("+aShort", new Short((short) 2));
-        asserter.assertExpression("+anInteger", new Integer(3));
-        asserter.assertExpression("+aLong", new Long(4));
-        asserter.assertExpression("+aFloat", new Float(5.5));
-        asserter.assertExpression("+aDouble", new Double(6.6));
-        asserter.assertExpression("+aBigInteger", new BigInteger("7"));
-        asserter.assertExpression("+aBigDecimal", new BigDecimal("8.8"));
+    public void testUnaryPlus() throws Exception {
+        asserter.setVariable("aByte", new Byte((byte) 1));
+        asserter.setVariable("aShort", new Short((short) 2));
+        asserter.setVariable("anInteger", new Integer(3));
+        asserter.setVariable("aLong", new Long(4));
+        asserter.setVariable("aFloat", new Float(5.5));
+        asserter.setVariable("aDouble", new Double(6.6));
+        asserter.setVariable("aBigInteger", new BigInteger("7"));
+        asserter.setVariable("aBigDecimal", new BigDecimal("8.8"));
+
+        // loop to allow checking caching of constant numerals (debug)
+        for(int i = 0 ; i < 2; ++i) {
+            asserter.assertExpression("+3", new Integer("3"));
+            asserter.assertExpression("+3.0", new Double("3.0"));
+            asserter.assertExpression("+aByte", new Integer(1));
+            asserter.assertExpression("+aShort", new Integer(2));
+            asserter.assertExpression("+anInteger", new Integer(3));
+            asserter.assertExpression("+aLong", new Long(4));
+            asserter.assertExpression("+aFloat", new Float(5.5));
+            asserter.assertExpression("+aDouble", new Double(6.6));
+            asserter.assertExpression("+aBigInteger", new BigInteger("7"));
+            asserter.assertExpression("+aBigDecimal", new BigDecimal("8.8"));
+        }
     }
     
     /**