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 2011/06/14 15:33:10 UTC

svn commit: r1135562 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl2/ main/java/org/apache/commons/jexl2/internal/introspection/ main/java/org/apache/commons/jexl2/parser/ test/java/org/apache/commons/jexl2/

Author: henrib
Date: Tue Jun 14 13:33:09 2011
New Revision: 1135562

URL: http://svn.apache.org/viewvc?rev=1135562&view=rev
Log:
JEXL-24, JEXL-112: added syntax for literals of type long integer, big integer, double, big decimal

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java
      - copied, changed from r1127914, commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java
Removed:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java
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/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArithmeticTest.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=1135562&r1=1135561&r2=1135562&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 Jun 14 13:33:09 2011
@@ -34,14 +34,12 @@ import org.apache.commons.jexl2.parser.A
 import org.apache.commons.jexl2.parser.ASTERNode;
 import org.apache.commons.jexl2.parser.ASTEmptyFunction;
 import org.apache.commons.jexl2.parser.ASTFalseNode;
-import org.apache.commons.jexl2.parser.ASTFloatLiteral;
 import org.apache.commons.jexl2.parser.ASTForeachStatement;
 import org.apache.commons.jexl2.parser.ASTFunctionNode;
 import org.apache.commons.jexl2.parser.ASTGENode;
 import org.apache.commons.jexl2.parser.ASTGTNode;
 import org.apache.commons.jexl2.parser.ASTIdentifier;
 import org.apache.commons.jexl2.parser.ASTIfStatement;
-import org.apache.commons.jexl2.parser.ASTIntegerLiteral;
 import org.apache.commons.jexl2.parser.ASTJexlScript;
 import org.apache.commons.jexl2.parser.ASTLENode;
 import org.apache.commons.jexl2.parser.ASTLTNode;
@@ -53,6 +51,7 @@ import org.apache.commons.jexl2.parser.A
 import org.apache.commons.jexl2.parser.ASTNENode;
 import org.apache.commons.jexl2.parser.ASTNRNode;
 import org.apache.commons.jexl2.parser.ASTNotNode;
+import org.apache.commons.jexl2.parser.ASTNumberLiteral;
 import org.apache.commons.jexl2.parser.ASTNullLiteral;
 import org.apache.commons.jexl2.parser.ASTOrNode;
 import org.apache.commons.jexl2.parser.ASTReference;
@@ -376,11 +375,6 @@ final class Debugger implements ParserVi
     }
 
     /** {@inheritDoc} */
-    public Object visit(ASTFloatLiteral node, Object data) {
-        return check(node, node.image, data);
-    }
-
-    /** {@inheritDoc} */
     public Object visit(ASTForeachStatement node, Object data) {
         builder.append("for(");
         accept(node.jjtGetChild(0), data);
@@ -430,7 +424,7 @@ final class Debugger implements ParserVi
     }
 
     /** {@inheritDoc} */
-    public Object visit(ASTIntegerLiteral node, Object data) {
+    public Object visit(ASTNumberLiteral node, Object data) {
         return check(node, node.image, data);
     }
 

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=1135562&r1=1135561&r2=1135562&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 Jun 14 13:33:09 2011
@@ -19,8 +19,6 @@ package org.apache.commons.jexl2;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
-import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -49,13 +47,11 @@ import org.apache.commons.jexl2.parser.A
 import org.apache.commons.jexl2.parser.ASTEmptyFunction;
 import org.apache.commons.jexl2.parser.ASTFalseNode;
 import org.apache.commons.jexl2.parser.ASTFunctionNode;
-import org.apache.commons.jexl2.parser.ASTFloatLiteral;
 import org.apache.commons.jexl2.parser.ASTForeachStatement;
 import org.apache.commons.jexl2.parser.ASTGENode;
 import org.apache.commons.jexl2.parser.ASTGTNode;
 import org.apache.commons.jexl2.parser.ASTIdentifier;
 import org.apache.commons.jexl2.parser.ASTIfStatement;
-import org.apache.commons.jexl2.parser.ASTIntegerLiteral;
 import org.apache.commons.jexl2.parser.ASTJexlScript;
 import org.apache.commons.jexl2.parser.ASTLENode;
 import org.apache.commons.jexl2.parser.ASTLTNode;
@@ -68,6 +64,7 @@ import org.apache.commons.jexl2.parser.A
 import org.apache.commons.jexl2.parser.ASTNRNode;
 import org.apache.commons.jexl2.parser.ASTNotNode;
 import org.apache.commons.jexl2.parser.ASTNullLiteral;
+import org.apache.commons.jexl2.parser.ASTNumberLiteral;
 import org.apache.commons.jexl2.parser.ASTOrNode;
 import org.apache.commons.jexl2.parser.ASTReference;
 import org.apache.commons.jexl2.parser.ASTReferenceExpression;
@@ -273,7 +270,7 @@ public class Interpreter implements Pars
         // allow namespace to be instantiated as functor with context if possible, not an error otherwise
         if (namespace instanceof Class<?>) {
             Object[] args = new Object[]{context};
-            Constructor<?> ctor = uberspect.getConstructor(namespace,args, node);
+            Constructor<?> ctor = uberspect.getConstructor(namespace, args, node);
             if (ctor != null) {
                 try {
                     namespace = ctor.newInstance(args);
@@ -299,7 +296,7 @@ public class Interpreter implements Pars
          * be caught explicitly and rethrown.
          */
         Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        for(int c = 2, size = node.jjtGetNumChildren(); c < size; c += 2) {
+        for (int c = 2, size = node.jjtGetNumChildren(); c < size; c += 2) {
             Object right = node.jjtGetChild(c).jjtAccept(this, data);
             try {
                 JexlNode op = node.jjtGetChild(c - 1);
@@ -387,13 +384,13 @@ public class Interpreter implements Pars
         }
         return literal;
     }
-    
+
     /** {@inheritDoc} */
     public Object visit(ASTAssignment node, Object data) {
         // left contains the reference to assign to
         JexlNode left = node.jjtGetChild(0);
         if (!(left instanceof ASTReference)) {
-            throw new JexlException(left, "illegal assignment form");
+            throw new JexlException(left, "illegal assignment form 0");
         }
         // right is the value expression to assign
         Object right = node.jjtGetChild(1).jjtAccept(this, data);
@@ -422,7 +419,7 @@ public class Interpreter implements Pars
                     variableName = new StringBuilder(left.jjtGetChild(0).image);
                     v = 1;
                 }
-                for(; v <= c; ++v) {
+                for (; v <= c; ++v) {
                     variableName.append('.');
                     variableName.append(left.jjtGetChild(v).image);
                 }
@@ -441,8 +438,8 @@ public class Interpreter implements Pars
         if (propertyNode instanceof ASTIdentifier) {
             property = ((ASTIdentifier) propertyNode).image;
             antVar = true;
-        } else if (propertyNode instanceof ASTIntegerLiteral) {
-            property = ((ASTIntegerLiteral) propertyNode).getLiteral();
+        } else if (propertyNode instanceof ASTNumberLiteral && ((ASTNumberLiteral)propertyNode).isInteger()) {
+            property = ((ASTNumberLiteral)propertyNode).getLiteral();
             antVar = true;
         } else if (propertyNode instanceof ASTArrayAccess) {
             // first objectNode is the identifier
@@ -468,7 +465,7 @@ public class Interpreter implements Pars
             }
             property = narray.jjtGetChild(last).jjtAccept(this, null);
         } else {
-            throw new JexlException(objectNode, "illegal assignment form");
+                throw new JexlException(objectNode, "illegal assignment form");
         }
         // deal with ant variable; set context
         if (antVar) {
@@ -594,11 +591,11 @@ public class Interpreter implements Pars
             return Boolean.TRUE;
         }
         if (o instanceof Collection<?>) {
-            return ((Collection<?>) o).isEmpty()? Boolean.TRUE : Boolean.FALSE;
+            return ((Collection<?>) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE;
         }
         // Map isn't a collection
         if (o instanceof Map<?, ?>) {
-            return ((Map<?,?>) o).isEmpty()? Boolean.TRUE : Boolean.FALSE;
+            return ((Map<?, ?>) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE;
         }
         return Boolean.FALSE;
     }
@@ -620,14 +617,6 @@ public class Interpreter implements Pars
     }
 
     /** {@inheritDoc} */
-    public Object visit(ASTFloatLiteral node, Object data) {
-        if (data != null) {
-            return getAttribute(data, node.getLiteral(), node);
-        }
-        return node.getLiteral();
-    }
-
-    /** {@inheritDoc} */
     public Object visit(ASTForeachStatement node, Object data) {
         Object result = null;
         /* first objectNode is the loop variable */
@@ -697,8 +686,8 @@ public class Interpreter implements Pars
             }
             Object value = context.get(name);
             if (value == null
-                && !(node.jjtGetParent() instanceof ASTReference)
-                && !context.has(name)) {
+                    && !(node.jjtGetParent() instanceof ASTReference)
+                    && !context.has(name)) {
                 JexlException xjexl = new JexlException(node, "undefined variable " + name);
                 return unknownVariable(xjexl);
             }
@@ -736,8 +725,8 @@ public class Interpreter implements Pars
     }
 
     /** {@inheritDoc} */
-    public Object visit(ASTIntegerLiteral node, Object data) {
-        if (data != null) {
+    public Object visit(ASTNumberLiteral node, Object data) {
+        if (data != null && node.isInteger()) {
             return getAttribute(data, node.getLiteral(), node);
         }
         return node.getLiteral();
@@ -1000,7 +989,7 @@ public class Interpreter implements Pars
             throw new JexlException(node, "!~ error", xrt);
         }
     }
-    
+
     /** {@inheritDoc} */
     public Object visit(ASTNotNode node, Object data) {
         Object val = node.jjtGetChild(0).jjtAccept(this, data);
@@ -1051,7 +1040,7 @@ public class Interpreter implements Pars
         for (int c = 0; c < numChildren; c++) {
             JexlNode theNode = node.jjtGetChild(c);
             // integer literals may be part of an antish var name only if no bean was found so far
-            if (result == null && theNode instanceof ASTIntegerLiteral) {
+            if (result == null && theNode instanceof ASTNumberLiteral && theNode.image.matches("\\d*")) {
                 isVariable &= v > 0;
             } else {
                 isVariable &= (theNode instanceof ASTIdentifier);
@@ -1083,7 +1072,7 @@ public class Interpreter implements Pars
         ASTArrayAccess upper = (ASTArrayAccess) node;
         return visit(upper, data);
     }
-    
+
     /**
      * Check if a null evaluated expression is protected by a ternary expression.
      * The rationale is that the ternary / elvis expressions are meant for the user to explictly take
@@ -1093,7 +1082,7 @@ public class Interpreter implements Pars
      * @return true if nullable variable, false otherwise
      */
     private boolean isTernaryProtected(JexlNode node) {
-        for(JexlNode walk = node.jjtGetParent(); walk != null; walk = walk.jjtGetParent()) {
+        for (JexlNode walk = node.jjtGetParent(); walk != null; walk = walk.jjtGetParent()) {
             if (walk instanceof ASTTernaryNode) {
                 return true;
             } else if (!(walk instanceof ASTReference || walk instanceof ASTArrayAccess)) {
@@ -1148,37 +1137,21 @@ public class Interpreter implements Pars
     public Object visit(ASTTrueNode node, Object data) {
         return Boolean.TRUE;
     }
-
+    
     /** {@inheritDoc} */
     public Object visit(ASTUnaryMinusNode node, Object data) {
         JexlNode valNode = node.jjtGetChild(0);
         Object val = valNode.jjtAccept(this, data);
-        if (val instanceof Byte) {
-            byte valueAsByte = ((Byte) val).byteValue();
-            return Byte.valueOf((byte) -valueAsByte);
-        } else if (val instanceof Short) {
-            short valueAsShort = ((Short) val).shortValue();
-            return Short.valueOf((short) -valueAsShort);
-        } else if (val instanceof Integer) {
-            int valueAsInt = ((Integer) val).intValue();
-            return Integer.valueOf(-valueAsInt);
-        } else if (val instanceof Long) {
-            long valueAsLong = ((Long) val).longValue();
-            return Long.valueOf(-valueAsLong);
-        } else if (val instanceof Float) {
-            float valueAsFloat = ((Float) val).floatValue();
-            return new Float(-valueAsFloat);
-        } else if (val instanceof Double) {
-            double valueAsDouble = ((Double) val).doubleValue();
-            return new Double(-valueAsDouble);
-        } else if (val instanceof BigDecimal) {
-            BigDecimal valueAsBigD = (BigDecimal) val;
-            return valueAsBigD.negate();
-        } else if (val instanceof BigInteger) {
-            BigInteger valueAsBigI = (BigInteger) val;
-            return valueAsBigI.negate();
+        try {
+            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());
+            }
+            return number;
+        } catch (RuntimeException xrt) {
+            throw new JexlException(valNode, "arithmetic error", xrt);
         }
-        throw new JexlException(valNode, "not a number");
     }
 
     /** {@inheritDoc} */
@@ -1348,8 +1321,8 @@ public class Interpreter implements Pars
         }
         if (xjexl == null) {
             String error = "unable to set object property"
-                           + ", class: " + object.getClass().getName()
-                           + ", property: " + attribute;
+                    + ", class: " + object.getClass().getName()
+                    + ", property: " + attribute;
             if (node == null) {
                 throw new UnsupportedOperationException(error);
             }
@@ -1382,5 +1355,4 @@ public class Interpreter implements Pars
     public Object visit(ASTAmbiguous node, Object data) {
         throw new UnsupportedOperationException("unexpected type of node");
     }
-
 }

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=1135562&r1=1135561&r2=1135562&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 Jun 14 13:33:09 2011
@@ -516,6 +516,40 @@ public class JexlArithmetic {
         BigInteger result = l.subtract(r);
         return narrowBigInteger(left, right, result);
     }
+    
+    /**
+     * Negates a value (unary minus for numbers).
+     * @param val the value to negate
+     * @return the negated value
+     */
+    public Object negate(Object val) {
+        if (val instanceof Byte) {
+            byte valueAsByte = ((Byte) val).byteValue();
+            return Byte.valueOf((byte) -valueAsByte);
+        } else if (val instanceof Short) {
+            short valueAsShort = ((Short) val).shortValue();
+            return Short.valueOf((short) -valueAsShort);
+        } else if (val instanceof Integer) {
+            int valueAsInt = ((Integer) val).intValue();
+            return Integer.valueOf(-valueAsInt);
+        } else if (val instanceof Long) {
+            long valueAsLong = -((Long) val).longValue();
+            return Long.valueOf(valueAsLong);
+        } else if (val instanceof Float) {
+            float valueAsFloat = ((Float) val).floatValue();
+            return new Float(-valueAsFloat);
+        } else if (val instanceof Double) {
+            double valueAsDouble = ((Double) val).doubleValue();
+            return new Double(-valueAsDouble);
+        } else if (val instanceof BigDecimal) {
+            BigDecimal valueAsBigD = (BigDecimal) val;
+            return valueAsBigD.negate();
+        } else if (val instanceof BigInteger) {
+            BigInteger valueAsBigI = (BigInteger) val;
+            return valueAsBigI.negate();
+        }
+        throw new IllegalArgumentException(val.toString() + ": negate can only be applied to a number");
+    }
 
     /**
      * Test if left regexp matches right.
@@ -848,6 +882,26 @@ public class JexlArithmetic {
      * @return a value of the smallest type the original number will fit into.
      */
     public Number narrow(Number original) {
+        return narrowNumber(original, null);
+    }
+    
+    /**
+     * Whether we consider the narrow class as a potential candidate for narrowing the source.
+     * @param narrow the target narrow class
+     * @param source the orginal source class
+     * @return 
+     */
+    protected boolean narrowAccept(Class<?> narrow, Class<?> source) {
+        return narrow == null || narrow.equals(source);
+    }
+    
+    /**
+     * Given a Number, return back the value attempting to narrow it to a target class.
+     * @param original the original number
+     * @param narrow the attempted target class
+     * @return  the narrowed number or the source if no narrowing was possible
+     */
+    protected Number narrowNumber(Number original, Class<?> narrow) {
         if (original == null) {
             return original;
         }
@@ -861,9 +915,9 @@ public class JexlArithmetic {
                 try {
                     long l = bigd.longValueExact();
                     // coerce to int when possible (int being so often used in method parms)
-                    if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
+                    if (narrowAccept(narrow, Integer.class) && l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
                         return Integer.valueOf((int) l);
-                    } else {
+                    } else if (narrowAccept(narrow, Long.class)) {
                         return Long.valueOf(l);
                     }
                 } catch (ArithmeticException xa) {
@@ -873,7 +927,7 @@ public class JexlArithmetic {
         }
         if (original instanceof Double || original instanceof Float || original instanceof BigDecimal) {
             double value = original.doubleValue();
-            if (value <= Float.MAX_VALUE && value >= Float.MIN_VALUE) {
+            if (narrowAccept(narrow, Float.class) && value <= Float.MAX_VALUE && value >= Float.MIN_VALUE) {
                 result = Float.valueOf(result.floatValue());
             }
             // else it fits in a double only
@@ -887,12 +941,12 @@ public class JexlArithmetic {
                 }
             }
             long value = original.longValue();
-            if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
+            if (narrowAccept(narrow, Byte.class) && value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
                 // it will fit in a byte
                 result = Byte.valueOf((byte) value);
-            } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
+            } else if (narrowAccept(narrow, Short.class) && value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
                 result = Short.valueOf((short) value);
-            } else if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
+            } else if (narrowAccept(narrow, Integer.class) && value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
                 result = Integer.valueOf((int) value);
             }
             // else it fits in a long

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.java?rev=1135562&r1=1135561&r2=1135562&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.java Tue Jun 14 13:33:09 2011
@@ -20,7 +20,6 @@ package org.apache.commons.jexl2.interna
 import java.lang.reflect.Method;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
-import java.util.Arrays;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Iterator;

Copied: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java (from r1127914, commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java)
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java?p2=commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java&p1=commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java&r1=1127914&r2=1135562&rev=1135562&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java Tue Jun 14 13:33:09 2011
@@ -16,23 +16,28 @@
  */
 package org.apache.commons.jexl2.parser;
 
-public final class ASTFloatLiteral extends JexlNode implements JexlNode.Literal<Float> {
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class ASTNumberLiteral extends JexlNode implements JexlNode.Literal<Number> {
     /** The type literal value. */
-    Float literal = null;
+    Number literal = null;
+    /** The expected class. */
+    Class<?> clazz = null;
 
-    public ASTFloatLiteral(int id) {
+    public ASTNumberLiteral(int id) {
         super(id);
     }
 
-    public ASTFloatLiteral(Parser p, int id) {
+    public ASTNumberLiteral(Parser p, int id) {
         super(p, id);
     }
     
     /**
      * Gets the literal value.
-     * @return the float literal
+     * @return the number literal
      */
-    public Float getLiteral() {
+    public Number getLiteral() {
         return literal;
     }
     
@@ -41,4 +46,74 @@ public final class ASTFloatLiteral exten
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);
     }
+    
+    public Class<?> getLiteralClass() {
+        return clazz;
+    }
+    
+    public boolean isInteger() {
+        return Integer.class.equals(clazz);
+    }
+        
+    public boolean isDouble() {
+        return Double.class.equals(clazz);
+    }
+    
+    public void setNatural(String s) {
+        Number result;
+        Class<?> rclass;
+        int last = s.length() - 1;
+        switch (s.charAt(last)) {
+            case 'l':
+            case 'L':
+                result = Long.valueOf(s.substring(0, last));
+                rclass = Long.class;
+                break;
+            case 'h':
+            case 'H':
+                result = new BigInteger(s.substring(0, last));
+                rclass = BigInteger.class;
+                break;
+            default:
+                rclass = Integer.class;
+                try {
+                    result = Integer.valueOf(s);
+                } catch(NumberFormatException xnumber) {
+                    result = Long.valueOf(s);
+                }
+                break;
+        }
+        literal = result;
+        clazz = rclass;
+    }
+
+    public void setReal(String s) {
+        Number result;
+        Class<?> rclass;
+        int last = s.length() - 1;
+        switch (s.charAt(last)) {
+            case 'b':
+            case 'B':
+                result = new BigDecimal(s.substring(0, last));
+                rclass = BigDecimal.class;
+                break;
+            case 'd':
+            case 'D':
+                result = Double.valueOf(s);
+                rclass = Double.class;
+                break;
+            case 'f':
+            case 'F':
+            default:
+                rclass = Float.class;
+                try {
+                    result = Float.valueOf(s);
+                } catch(NumberFormatException xnumber) {
+                    result = Double.valueOf(s);
+                }
+                break;
+        }
+        literal = result;
+        clazz = rclass;
+    }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt?rev=1135562&r1=1135561&r2=1135562&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt Tue Jun 14 13:33:09 2011
@@ -15,14 +15,6 @@
  * limitations under the License.
  */
 
-/**
- *  Jexl : Java Expression Language
- *
- *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
- *  @author <a href="mailto:mhw@kremvax.net">Mark H. Wilkinson</a>
- *
- *  @version $Id$
- */
 
 options
 {
@@ -173,9 +165,12 @@ PARSER_END(Parser)
 
 <*> TOKEN : /* LITERALS */
 {
-  < INTEGER_LITERAL: (<DIGIT>)+ >
-|
-  < FLOAT_LITERAL: (<DIGIT>)+ "."(<DIGIT>)+ >
+    < INTEGER_LITERAL:
+        ( "0" (["0"-"7"])* | ["1"-"9"] (["0"-"9"])* | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ )
+        (["l","L","h","H"])?
+    >
+ |
+  < FLOAT_LITERAL: (<DIGIT>)+ "."(<DIGIT>)+ (["d","D","f","F","b","B"])? >
 }
 
 <*> TOKEN :
@@ -419,22 +414,23 @@ void BooleanLiteral() #void :
   <FALSE> #FalseNode
 }
 
-void IntegerLiteral() :
+void IntegerLiteral() #NumberLiteral :
 {
   Token t;
 }
 {
   t=<INTEGER_LITERAL>
-  { jjtThis.image = t.image; jjtThis.literal = Integer.valueOf(t.image); }
+  { jjtThis.image = t.image; jjtThis.setNatural(t.image); }
 }
 
-void FloatLiteral() :
+
+void FloatLiteral() #NumberLiteral:
 {
   Token t;
 }
 {
   t=<FLOAT_LITERAL>
-  { jjtThis.image = t.image; jjtThis.literal = Float.valueOf(t.image); }
+  { jjtThis.image = t.image; jjtThis.setReal(t.image); }
 }
 
 void StringLiteral() :

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArithmeticTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArithmeticTest.java?rev=1135562&r1=1135561&r2=1135562&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArithmeticTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArithmeticTest.java Tue Jun 14 13:33:09 2011
@@ -82,7 +82,7 @@ public class ArithmeticTest extends Jexl
     public void testNullOperand() throws Exception {
         asserter.setVariable("right", null);
         asserter.failExpression("~right", ".*null.*");
-        asserter.failExpression("-right", ".*number.*");
+        asserter.failExpression("-right", ".*arithmetic.*");
     }
 
     public void testBigDecimal() throws Exception {

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=1135562&r1=1135561&r2=1135562&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 Jun 14 13:33:09 2011
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl2;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.math.MathContext;
 import org.apache.commons.jexl2.introspection.Uberspect;
 import org.apache.commons.jexl2.internal.Introspector;
@@ -35,6 +36,33 @@ public class IssuesTest extends JexlTest
         // ensure jul logging is only error to avoid warning in silent mode
         java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
     }
+    
+    // JEXL-24: long integers (and doubles)
+    public void test24() throws Exception {
+        Map<String, Object> vars = new HashMap<String, Object>();
+        JexlContext ctxt = new MapContext(vars);
+        String stmt = "{a = 10L; b = 10l; c = 42.0D; d = 42.0d;}";
+        Script expr = JEXL.createScript(stmt);
+        /* Object value = */ expr.execute(ctxt);
+        assertEquals(10L, vars.get("a"));
+        assertEquals(10l, vars.get("b"));
+        assertEquals(42.0D, vars.get("c"));
+        assertEquals(42.0d, vars.get("d"));
+        
+    }
+    // JEXL-24: big integers and big decimals
+    public void test24B() throws Exception {
+        Map<String, Object> vars = new HashMap<String, Object>();
+        JexlContext ctxt = new MapContext(vars);
+        String stmt = "{a = 10H; b = 10h; c = 42.0B; d = 42.0b;}";
+        Script expr = JEXL.createScript(stmt);
+        /* Object value = */ expr.execute(ctxt);
+        assertEquals(new BigInteger("10"), vars.get("a"));
+        assertEquals(new BigInteger("10"), vars.get("b"));
+        assertEquals(new BigDecimal("42.0"), vars.get("c"));
+        assertEquals(new BigDecimal("42.0"), vars.get("d"));
+        
+    }
 
     // JEXL-49: blocks not parsed (fixed)
     public void test49() throws Exception {
@@ -600,7 +628,7 @@ public class IssuesTest extends JexlTest
         assertEquals("SecondValue=-10.0", value);
     }
 
-    public void test112() throws Exception {
+    public void testScaleIssue() throws Exception {
         JexlArithmetic arithmetic = new JexlThreadedArithmetic(false);
         JexlEngine jexlX = new JexlEngine(null, arithmetic, null, null);
         String expStr1 = "result == salary/month * work.percent/100.00";
@@ -618,4 +646,16 @@ public class IssuesTest extends JexlTest
         JexlThreadedArithmetic.setMathScale(2);
         assertFalse((Boolean) exp1.evaluate(ctx));
     }
+    
+    public void test112() throws Exception {
+        Object result;
+        JexlEngine jexl = new JexlEngine();
+        result = jexl.createScript(Integer.toString(Integer.MAX_VALUE)).execute(null);
+        assertEquals(Integer.MAX_VALUE, result);
+        result = jexl.createScript(Integer.toString(Integer.MIN_VALUE+1)).execute(null); 
+        assertEquals(Integer.MIN_VALUE+1, result);
+        result = jexl.createScript(Integer.toString(Integer.MIN_VALUE)).execute(null);
+        assertEquals(Integer.MIN_VALUE, result);
+    }
+
 }



Re: svn commit: r1135562 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl2/ main/java/org/apache/commons/jexl2/internal/introspection/ main/java/org/apache/commons/jexl2/parser/ test/java/org/apache/commons/jexl2/

Posted by sebb <se...@gmail.com>.
On 14 June 2011 14:33,  <he...@apache.org> wrote:
> Author: henrib
> Date: Tue Jun 14 13:33:09 2011
> New Revision: 1135562
>
> URL: http://svn.apache.org/viewvc?rev=1135562&view=rev
> Log:
> JEXL-24, JEXL-112: added syntax for literals of type long integer, big integer, double, big decimal
>

...

> --- 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 Jun 14 13:33:09 2011
> @@ -19,8 +19,6 @@ package org.apache.commons.jexl2;

...

>     public Object visit(ASTNotNode node, Object data) {
>         Object val = node.jjtGetChild(0).jjtAccept(this, data);
> @@ -1051,7 +1040,7 @@ public class Interpreter implements Pars
>         for (int c = 0; c < numChildren; c++) {
>             JexlNode theNode = node.jjtGetChild(c);
>             // integer literals may be part of an antish var name only if no bean was found so far
> -            if (result == null && theNode instanceof ASTIntegerLiteral) {
> +            if (result == null && theNode instanceof ASTNumberLiteral && theNode.image.matches("\\d*")) {

Is the empty string allowed as a number? I would expect to see at
least one digit, i.e. "\\d+"
If there is a good reason for allowing no digits, please add a comment
to say why.

>                 isVariable &= v > 0;
>             } else {
>                 isVariable &= (theNode instanceof ASTIdentifier);
> @@ -1083,7 +1072,7 @@ public class Interpreter implements Pars
>         ASTArrayAccess upper = (ASTArrayAccess) node;
>         return visit(upper, data);

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org