commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hen...@apache.org
Subject svn commit: r1337453 [1/3] - in /commons/proper/jexl/trunk: ./ src/main/java/org/apache/commons/jexl3/ src/main/java/org/apache/commons/jexl3/internal/ src/main/java/org/apache/commons/jexl3/internal/introspection/ src/main/java/org/apache/commons/jexl...
Date Sat, 12 May 2012 06:52:23 GMT
Author: henrib
Date: Sat May 12 06:52:21 2012
New Revision: 1337453

URL: http://svn.apache.org/viewvc?rev=1337453&view=rev
Log:
JEXL-123:
Reworked classloader change handling so that script ASTs purge references to cached methods & ctors;
Lots of nitpicking names, Javadoc, etc

Modified:
    commons/proper/jexl/trunk/RELEASE-NOTES.txt
    commons/proper/jexl/trunk/pom.xml
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlExpression.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/Main.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Introspector.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlSandbox.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngineFactory.java
    commons/proper/jexl/trunk/src/site/site.xml
    commons/proper/jexl/trunk/src/site/xdoc/changes.xml
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JexlTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PropertyAccessTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/examples/MethodPropertyTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/Util.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/parser/ParserTest.java
    commons/proper/jexl/trunk/src/test/scripts/test1.jexl

Modified: commons/proper/jexl/trunk/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/RELEASE-NOTES.txt?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/RELEASE-NOTES.txt (original)
+++ commons/proper/jexl/trunk/RELEASE-NOTES.txt Sat May 12 06:52:21 2012
@@ -36,35 +36,69 @@ Its goal is to expose scripting features
   http://commons.apache.org/jexl/
 
 
-Due to binary and source incompatibilities and the scope of modifications, JEXL has moved to the org.apache.commons.jexl3
-package.
-Also note that JEXL now requires Java 6.
+========================================================================================================================
+Release 3.0
+========================================================================================================================
+
+Version 3.0 is a major release changing the public JEXL API.
+
+Due to binary and source incompatibilities and the scope of modifications, JEXL has moved to the
+org.apache.commons.jexl3 package.
 However, this is a drop-in replacement through JSR-223 and casual code usage should find easy equivalence between
 jexl-2.x and 3.x (besides the package name).
+Also note that JEXL 3.0 now requires Java 6.
 
 
-3.0
-==================
-
 What's new in 3.0:
 ==================
 * A redesigned API that properly segregates the "public" part and the "internal" parts of JEXL.
 * The ability to create JEXL functions in script, closure/variables hoisting included.
 
 New features in 3.0:
-====================	
+====================
 * JEXL-128:     ObjectContext<> should implement NamespaceResolver
 * JEXL-127:     Allow the creation of functions
-* JEXL-126:     Decimal numbers literals should be 'double' by default (instead of 'float')
 * JEXL-123:     Redesign API for stability
 * JEXL-122:     Move JEXL from org.apache.comms.jexl2 to org.apache.commons.jexl3
 
 
-Previous Releases:
-==================
+========================================================================================================================
+Release 2.1.2:
+========================================================================================================================
 
-2.1
-==================
+Version 2.1.2 is a micro release to fix few issues detected in 2.1.1:
+
+* JEXL-131:     UnifiedJexl parsing may fail with NPE
+* JEXL-130:     Ternary Conditional fails for Object values
+* JEXL-126:     Decimal numbers literals should be 'double' by default (instead of 'float')
+
+There are no other changes.
+
+
+========================================================================================================================
+Release 2.1.1
+========================================================================================================================
+
+Version 2.1.2 is a micro release to fix a regression detected in 2.1:
+
+* JEXL-124:     Array parameters to methods don't work anymore (Jexl 2.1.1)
+
+There are no other changes.
+
+
+========================================================================================================================
+Release 2.1
+========================================================================================================================
+
+Version 2.1 is a minor release adding new features and fixing known issues detected in 2.0.
+
+Compatibility with previous releases
+====================================
+Version 2.1 is binary compatible with 2.0.1.
+
+However it is not source compatible.
+New methods have been added to the org.apache.commons.jexl2.Script and org.apache.commons.jexl2.JexlInfo interfaces.
+Any source code that implements these interfaces will need to be updated.
 
 What's new in 2.1:
 ==================
@@ -77,7 +111,7 @@ What's new in 2.1:
 * Extensions to UnifiedJEXL that allow the creation of templates.
 
 New features in 2.1:
-====================	
+====================
 * JEXL-114:     Allow scripts to create local variables // Add return keyword
 * JEXL-113:     Add functions to extract which variables, parameters and local variables are used to evaluate a script
 * JEXL-118:     Provide an IN operator
@@ -97,7 +131,7 @@ Bugs Fixed in 2.1:
 * JEXL-101:     Vararg methods where the first argument is no vararg can not be called with only the fixed parameters given
 * JEXL-105:     Array literals are considered constant even when they are not
 * JEXL-104:     NPE in JexlArithmetic when an Array-Expression containing a null is used.
-* JEXL-112:     Cannot parse Integer.MIN_VALUE	
+* JEXL-112:     Cannot parse Integer.MIN_VALUE
 * JEXL-111:     expression execute error
 
 Bugs fixed in 2.0.1:
@@ -181,7 +215,7 @@ Other Changes:
 
 o Add @since 2.0 tags to code so we can track API additions via Javadoc
 
-Upgrading from JEXL 1.x 
+Upgrading from JEXL 1.x
 =======================
 
 JEXL now requires Java 1.5 or later.

Modified: commons/proper/jexl/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/pom.xml?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/pom.xml (original)
+++ commons/proper/jexl/trunk/pom.xml Sat May 12 06:52:21 2012
@@ -110,15 +110,6 @@
             <version>4.10</version>
             <scope>test</scope>
         </dependency>
-        <!-- For JSR-223 API -->
-        <!--
-        <dependency>
-            <groupId>org.apache.bsf</groupId>
-            <artifactId>bsf-api</artifactId>
-            <version>3.1</version>
-            <scope>provided</scope>
-        </dependency>
-        -->
     </dependencies>
 
     <properties>
@@ -128,6 +119,8 @@
         <commons.release.version>3.0</commons.release.version>
         <!-- The RC version used in the staging repository URL. -->
         <commons.rc.version>RC1</commons.rc.version>
+        <commons.release.3.version>2.1</commons.release.3.version>
+        <commons.release.3.binary.suffix>2.1.1</commons.release.3.binary.suffix>
         <commons.release.2.version>1.1</commons.release.2.version>
         <commons.release.2.binary.suffix />
         <commons.jira.id>JEXL</commons.jira.id>

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java Sat May 12 06:52:21 2012
@@ -28,7 +28,7 @@ import java.math.MathContext;
  * The 5 arithmetic operators (+, - , *, /, %) follow the same evaluation rules regarding their arguments.
  * <ol>
  * <li>If both are null, result is 0</li>
- * <li>If either is a BigDecimal, coerce both to BigDecimal and  perform operation</li>
+ * <li>If either is a BigDecimal, coerce both to BigDecimal and perform operation</li>
  * <li>If either is a floating point number, coerce both to Double and perform operation</li>
  * <li>Else treat as BigInteger, perform operation and attempt to narrow result:
  * <ol>
@@ -43,6 +43,9 @@ import java.math.MathContext;
  * @since 2.0
  */
 public class JexlArithmetic {
+    /** Maker class for null operand exceptions. */
+    public static class NullOperand extends ArithmeticException {
+    }
     /** Double.MAX_VALUE as BigDecimal. */
     protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
     /** Double.MIN_VALUE as BigDecimal. */
@@ -70,14 +73,14 @@ public class JexlArithmetic {
 
     /**
      * Creates a JexlArithmetic.
-     * @param astrict whether this arithmetic is lenient or strict
+     * @param astrict     whether this arithmetic is lenient or strict
      * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals.
-     * @param bigdScale the scale used for big decimals.
+     * @param bigdScale   the scale used for big decimals.
      */
     public JexlArithmetic(boolean astrict, MathContext bigdContext, int bigdScale) {
         this.strict = astrict;
-        this.mathContext = bigdContext == null? MathContext.DECIMAL128 : bigdContext;
-        this.mathScale = bigdScale == Integer.MIN_VALUE? BIGD_SCALE : bigdScale;
+        this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext;
+        this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale;
     }
 
     /**
@@ -98,8 +101,8 @@ public class JexlArithmetic {
             bigdScale = mathScale;
         }
         if ((ostrict != this.strict)
-             || bigdScale != this.mathScale
-             || bigdContext != this.mathContext) {
+                || bigdScale != this.mathScale
+                || bigdContext != this.mathContext) {
             return new JexlArithmetic(ostrict, bigdContext, bigdScale);
         } else {
             return this;
@@ -152,7 +155,7 @@ public class JexlArithmetic {
      */
     protected Object controlNullNullOperands() {
         if (isStrict()) {
-            throw new ArithmeticException(JexlException.NULL_OPERAND);
+            throw new NullOperand();
         }
         return Integer.valueOf(0);
     }
@@ -163,7 +166,7 @@ public class JexlArithmetic {
      */
     protected void controlNullOperand() {
         if (isStrict()) {
-            throw new ArithmeticException(JexlException.NULL_OPERAND);
+            throw new NullOperand();
         }
     }
 
@@ -210,6 +213,21 @@ public class JexlArithmetic {
     }
 
     /**
+     * Given a Number, return back the value using the smallest type the result
+     * will fit into.
+     * <p>This works hand in hand with parameter 'widening' in java
+     * method calls, e.g. a call to substring(int,int) with an int and a long
+     * will fail, but a call to substring(int,int) with an int and a short will
+     * succeed.</p>
+     *
+     * @param original the original number.
+     * @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
@@ -222,8 +240,8 @@ public class JexlArithmetic {
     /**
      * 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
+     * @param narrow   the attempted target class
+     * @return the narrowed number or the source if no narrowing was possible
      */
     public Number narrowNumber(Number original, Class<?> narrow) {
         if (original == null) {
@@ -233,7 +251,8 @@ public class JexlArithmetic {
         if (original instanceof BigDecimal) {
             BigDecimal bigd = (BigDecimal) original;
             // if it's bigger than a double it can't be narrowed
-            if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0) {
+            if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
+                    || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
                 return original;
             } else {
                 try {
@@ -251,7 +270,7 @@ public class JexlArithmetic {
                 }
             }
         }
-        if (original instanceof Double || original instanceof Float || original instanceof BigDecimal) {
+        if (original instanceof Double || original instanceof Float) {
             double value = original.doubleValue();
             if (narrowAccept(narrow, Float.class)
                     && value <= Float.MAX_VALUE
@@ -296,8 +315,8 @@ public class JexlArithmetic {
      * if either arguments is a BigInteger, no narrowing will occur
      * if either arguments is a Long, no narrowing to Integer will occur
      * </p>
-     * @param lhs the left hand side operand that lead to the bigi result
-     * @param rhs the right hand side operand that lead to the bigi result
+     * @param lhs  the left hand side operand that lead to the bigi result
+     * @param rhs  the right hand side operand that lead to the bigi result
      * @param bigi the BigInteger to narrow
      * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise
      */
@@ -323,8 +342,8 @@ public class JexlArithmetic {
      * Given a BigDecimal, attempt to narrow it to an Integer or Long if it fits if
      * one of the arguments is a numberable.
      *
-     * @param lhs the left hand side operand that lead to the bigd result
-     * @param rhs the right hand side operand that lead to the bigd result
+     * @param lhs  the left hand side operand that lead to the bigd result
+     * @param rhs  the right hand side operand that lead to the bigd result
      * @param bigd the BigDecimal to narrow
      * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise
      */
@@ -414,7 +433,7 @@ public class JexlArithmetic {
      * Replace all numbers in an arguments array with the smallest type that will fit.
      * @param args the argument array
      * @return true if some arguments were narrowed and args array is modified,
-     *         false if no narrowing occured and args array has not been modified
+     * false if no narrowing occured and args array has not been modified
      */
     public boolean narrowArguments(Object[] args) {
         boolean narrowed = false;
@@ -437,45 +456,45 @@ public class JexlArithmetic {
      * If any numeric add fails on coercion to the appropriate type,
      * treat as Strings and do concatenation.
      * </p>
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return left + right.
      */
-        public Object add(Object left, Object right) {
-            if (left == null && right == null) {
-                return controlNullNullOperands();
+    public Object add(Object left, Object right) {
+        if (left == null && right == null) {
+            return controlNullNullOperands();
+        }
+        try {
+            // if either are bigdecimal use that type
+            if (left instanceof BigDecimal || right instanceof BigDecimal) {
+                BigDecimal l = toBigDecimal(left);
+                BigDecimal r = toBigDecimal(right);
+                BigDecimal result = l.add(r, getMathContext());
+                return narrowBigDecimal(left, right, result);
             }
-            try {
-                // if either are bigdecimal use that type
-                if (left instanceof BigDecimal || right instanceof BigDecimal) {
-                    BigDecimal l = toBigDecimal(left);
-                    BigDecimal r = toBigDecimal(right);
-                    BigDecimal result = l.add(r, getMathContext());
-                    return narrowBigDecimal(left, right, result);
-                }
-                // if either are floating point (double or float) use double
-                if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
-                    double l = toDouble(left);
-                    double r = toDouble(right);
-                    return new Double(l + r);
-                }
-                // otherwise treat as integers
-                BigInteger l = toBigInteger(left);
-                BigInteger r = toBigInteger(right);
-                BigInteger result = l.add(r);
-                return narrowBigInteger(left, right, result);
-            } catch (java.lang.NumberFormatException nfe) {
-                // Well, use strings!
-                if (left == null || right == null) {
-                    controlNullOperand();
-                }
-                return toString(left).concat(toString(right));
+            // if either are floating point (double or float) use double
+            if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
+                double l = toDouble(left);
+                double r = toDouble(right);
+                return new Double(l + r);
+            }
+            // otherwise treat as integers
+            BigInteger l = toBigInteger(left);
+            BigInteger r = toBigInteger(right);
+            BigInteger result = l.add(r);
+            return narrowBigInteger(left, right, result);
+        } catch (java.lang.NumberFormatException nfe) {
+            // Well, use strings!
+            if (left == null || right == null) {
+                controlNullOperand();
             }
+            return toString(left).concat(toString(right));
         }
+    }
 
     /**
      * Divide the left value by the right.
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return left / right
      * @throws ArithmeticException if right == 0
@@ -490,7 +509,7 @@ public class JexlArithmetic {
             BigDecimal r = toBigDecimal(right);
             if (BigDecimal.ZERO.equals(r)) {
                 throw new ArithmeticException("/");
-            }
+                }
             BigDecimal result = l.divide(r, getMathContext());
             return narrowBigDecimal(left, right, result);
         }
@@ -508,14 +527,14 @@ public class JexlArithmetic {
         BigInteger r = toBigInteger(right);
         if (BigInteger.ZERO.equals(r)) {
             throw new ArithmeticException("/");
-        }
+            }
         BigInteger result = l.divide(r);
         return narrowBigInteger(left, right, result);
     }
 
     /**
      * left value mod right.
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return left mod right
      * @throws ArithmeticException if right == 0.0
@@ -530,7 +549,7 @@ public class JexlArithmetic {
             BigDecimal r = toBigDecimal(right);
             if (BigDecimal.ZERO.equals(r)) {
                 throw new ArithmeticException("%");
-            }
+                }
             BigDecimal remainder = l.remainder(r, getMathContext());
             return narrowBigDecimal(left, right, remainder);
         }
@@ -549,13 +568,13 @@ public class JexlArithmetic {
         BigInteger result = l.mod(r);
         if (BigInteger.ZERO.equals(r)) {
             throw new ArithmeticException("%");
-        }
+            }
         return narrowBigInteger(left, right, result);
     }
 
     /**
      * Multiply the left value by the right.
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return left * right.
      */
@@ -585,7 +604,7 @@ public class JexlArithmetic {
 
     /**
      * Subtract the right value from the left.
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return left - right.
      */
@@ -652,7 +671,7 @@ public class JexlArithmetic {
     /**
      * Test if left regexp matches right.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -675,7 +694,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise and.
-     * @param left the left operand
+     * @param left  the left operand
      * @param right the right operator
      * @return left & right
      */
@@ -687,7 +706,7 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise or.
-     * @param left the left operand
+     * @param left  the left operand
      * @param right the right operator
      * @return left | right
      */
@@ -699,9 +718,9 @@ public class JexlArithmetic {
 
     /**
      * Performs a bitwise xor.
-     * @param left the left operand
+     * @param left  the left operand
      * @param right the right operator
-     * @return left  right
+     * @return left right
      */
     public Object bitwiseXor(Object left, Object right) {
         long l = toLong(left);
@@ -721,10 +740,10 @@ public class JexlArithmetic {
 
     /**
      * Performs a comparison.
-     * @param left the left operand
-     * @param right the right operator
+     * @param left     the left operand
+     * @param right    the right operator
      * @param operator the operator
-     * @return -1 if left  &lt; right; +1 if left &gt > right; 0 if left == right
+     * @return -1 if left &lt; right; +1 if left &gt > right; 0 if left == right
      * @throws ArithmeticException if either left or right is null
      */
     protected int compare(Object left, Object right, String operator) {
@@ -786,7 +805,7 @@ public class JexlArithmetic {
     /**
      * Test if left and right are equal.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -803,9 +822,9 @@ public class JexlArithmetic {
     }
 
     /**
-     * Test if left < right.
+     * Test if left &lt; right.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -819,9 +838,9 @@ public class JexlArithmetic {
     }
 
     /**
-     * Test if left > right.
+     * Test if left &gt; right.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -834,9 +853,9 @@ public class JexlArithmetic {
     }
 
     /**
-     * Test if left <= right.
+     * Test if left &lt;= right.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -851,9 +870,9 @@ public class JexlArithmetic {
     }
 
     /**
-     * Test if left >= right.
+     * Test if left &gt;= right.
      *
-     * @param left first value
+     * @param left  first value
      * @param right second value
      * @return test result.
      */
@@ -868,7 +887,8 @@ public class JexlArithmetic {
     }
 
     /**
-     * Coerce to a boolean (not a java.lang.Boolean).
+     * Coerce to a primitive boolean.
+     * <p>Double.NaN, null, "false" and empty string coerce to false.</p>
      *
      * @param val Object to be coerced.
      * @return the boolean value if coercion is possible, true if value was not null.
@@ -892,20 +912,24 @@ public class JexlArithmetic {
     }
 
     /**
-     * Coerce to a int.
+     * Coerce to a primitive int.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
      *
      * @param val Object to be coerced.
      * @return The int coerced value.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public int toInteger(Object val) {
         if (val == null) {
             controlNullOperand();
             return 0;
         } else if (val instanceof Double) {
-            if (!Double.isNaN(((Double) val).doubleValue())) {
+            Double dval = (Double) val;
+            if (Double.isNaN(dval.doubleValue())) {
                 return 0;
             } else {
-                return ((Double) val).intValue();
+                return dval.intValue();
             }
         } else if (val instanceof Number) {
             return ((Number) val).intValue();
@@ -925,26 +949,30 @@ public class JexlArithmetic {
     }
 
     /**
-     * Coerce to a long (not a java.lang.Long).
+     * Coerce to a primitive long.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
      *
      * @param val Object to be coerced.
      * @return The long coerced value.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public long toLong(Object val) {
         if (val == null) {
             controlNullOperand();
             return 0L;
         } else if (val instanceof Double) {
-            if (!Double.isNaN(((Double) val).doubleValue())) {
-                return 0;
+            Double dval = (Double) val;
+            if (Double.isNaN(dval.doubleValue())) {
+                return 0L;
             } else {
-                return ((Double) val).longValue();
+                return dval.longValue();
             }
         } else if (val instanceof Number) {
             return ((Number) val).longValue();
         } else if (val instanceof String) {
             if ("".equals(val)) {
-                return 0;
+                return 0L;
             } else {
                 return Long.parseLong((String) val);
             }
@@ -959,11 +987,13 @@ public class JexlArithmetic {
     }
 
     /**
-     * Get a BigInteger from the object passed.
-     * Null and empty string maps to zero.
+     * Coerce to a BigInteger.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
      * @param val the object to be coerced.
      * @return a BigDecimal.
-     * @throws NullPointerException if val is null and mode is strict.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public BigInteger toBigInteger(Object val) {
         if (val == null) {
@@ -972,10 +1002,11 @@ public class JexlArithmetic {
         } else if (val instanceof BigInteger) {
             return (BigInteger) val;
         } else if (val instanceof Double) {
-            if (!Double.isNaN(((Double) val).doubleValue())) {
-                return new BigInteger(val.toString());
-            } else {
+            Double dval = (Double) val;
+            if (Double.isNaN(dval.doubleValue())) {
                 return BigInteger.ZERO;
+            } else {
+                return new BigInteger(dval.toString());
             }
         } else if (val instanceof Number) {
             return new BigInteger(val.toString());
@@ -996,11 +1027,13 @@ public class JexlArithmetic {
     }
 
     /**
-     * Get a BigDecimal from the object passed.
-     * Null and empty string maps to zero.
+     * Coerce to a BigDecimal.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
+     *
      * @param val the object to be coerced.
      * @return a BigDecimal.
-     * @throws NullPointerException if val is null and mode is strict.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public BigDecimal toBigDecimal(Object val) {
         if (val instanceof BigDecimal) {
@@ -1015,10 +1048,10 @@ public class JexlArithmetic {
             }
             return roundBigDecimal(new BigDecimal(string, getMathContext()));
         } else if (val instanceof Double) {
-            if (!Double.isNaN(((Double) val).doubleValue())) {
-                return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
-            } else {
+            if (Double.isNaN(((Double) val).doubleValue())) {
                 return BigDecimal.ZERO;
+            } else {
+                return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
             }
         } else if (val instanceof Number) {
             return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
@@ -1026,17 +1059,17 @@ public class JexlArithmetic {
             int i = ((Character) val).charValue();
             return new BigDecimal(i);
         }
-
         throw new ArithmeticException("BigDecimal coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
 
     /**
-     * Coerce to a double.
-     *
+     * Coerce to a primitive double.
+     * <p>Double.NaN, null and empty string coerce to zero.</p>
+     * <p>Boolean false is 0, true is 1.</p>
      * @param val Object to be coerced.
      * @return The double coerced value.
-     * @throws NullPointerException if val is null and mode is strict.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public double toDouble(Object val) {
         if (val == null) {
@@ -1062,17 +1095,17 @@ public class JexlArithmetic {
             int i = ((Character) val).charValue();
             return i;
         }
-
         throw new ArithmeticException("Double coercion: "
                 + val.getClass().getName() + ":(" + val + ")");
     }
 
     /**
      * Coerce to a string.
+     * <p>Double.NaN coerce to the empty string.</p>
      *
      * @param val Object to be coerced.
      * @return The String coerced value.
-     * @throws NullPointerException if val is null and mode is strict.
+     * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible.
      */
     public String toString(Object val) {
         if (val == null) {
@@ -1089,18 +1122,4 @@ public class JexlArithmetic {
             return val.toString();
         }
     }
-
-    /**
-     * Given a Number, return back the value using the smallest type the result
-     * will fit into. This works hand in hand with parameter 'widening' in java
-     * method calls, e.g. a call to substring(int,int) with an int and a long
-     * will fail, but a call to substring(int,int) with an int and a short will
-     * succeed.
-     *
-     * @param original the original number.
-     * @return a value of the smallest type the original number will fit into.
-     */
-    public Number narrow(Number original) {
-        return narrowNumber(original, null);
-    }
 }
\ No newline at end of file

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java Sat May 12 06:52:21 2012
@@ -54,6 +54,10 @@ import org.apache.commons.logging.Log;
  */
 public class JexlBuilder {
     /**
+     * The default maximum expression length to hit the expression cache.
+     */
+    protected static final int CACHE_THRESHOLD = 64;
+    /**
      * The JexlUberspect instance.
      */
     protected JexlUberspect uberspect = null;
@@ -91,6 +95,10 @@ public class JexlBuilder {
      */
     protected int cache = -1;
     /**
+     * The maximum expression length to hit the expression cache.
+     */
+    protected int cacheThreshold = CACHE_THRESHOLD;
+    /**
      * The class loader.
      */
     protected ClassLoader loader = null;
@@ -124,7 +132,7 @@ public class JexlBuilder {
     public JexlArithmetic arithmetic() {
         return this.arithmetic;
     }
-    
+
     /**
      * Sets the sandbox the engine will use.
      * @param box the sandbox
@@ -134,7 +142,7 @@ public class JexlBuilder {
         this.sandbox = box;
         return this;
     }
-    
+
     /** @return the sandbox */
     public JexlSandbox sandbox() {
         return this.sandbox;
@@ -154,7 +162,7 @@ public class JexlBuilder {
     public Log logger() {
         return this.logger;
     }
-    
+
     /**
      * Sets the class loader to use.
      * @param l the class loader
@@ -164,7 +172,7 @@ public class JexlBuilder {
         this.loader = l;
         return this;
     }
-    
+
     /** @return the class loader */
     public ClassLoader loader() {
         return loader;
@@ -254,8 +262,8 @@ public class JexlBuilder {
 
     /**
      * Sets the expression cache size the engine will use.
-     * <p>The cache will contain at most <code>size</code> expressions. Note that
-     * all JEXL caches are held through SoftReferences and may be garbage-collected.</p>
+     * <p>The cache will contain at most <code>size</code> expressions of at most <code>cacheThreshold</code> length.
+     * Note that all JEXL caches are held through SoftReferences and may be garbage-collected.</p>
      * @param size if not strictly positive, no cache is used.
      * @return this builder
      */
@@ -270,6 +278,25 @@ public class JexlBuilder {
     }
 
     /**
+     * Sets the maximum length for an expression to be cached.
+     * <p>Expression whose length is greater than this expression cache length threshold will
+     * bypass the cache.</p>
+     * <p>It is expected that a "long" script will be parsed once and its reference kept
+     * around in user-space structures; the jexl expression cache has no added-value in this case.</p>
+     * @param length if not strictly positive, the value is silently replaced by the default value (64).
+     * @return this builder
+     */
+    public JexlBuilder cacheThreshold(int length) {
+        this.cacheThreshold = length > 0? length : CACHE_THRESHOLD;
+        return this;
+    }
+
+    /**@return the cache threshold */
+    public int cacheThreshold() {
+        return cacheThreshold;
+    }
+
+    /**
      * @return a {@link JexlEngine} instance
      */
     public JexlEngine create() {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEngine.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEngine.java Sat May 12 06:52:21 2012
@@ -16,22 +16,24 @@
  */
 package org.apache.commons.jexl3;
 
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
-import java.io.Reader;
-import java.net.URL;
+import java.io.InputStreamReader;
 import java.math.MathContext;
-import org.apache.commons.jexl3.introspection.JexlUberspect;
+import java.net.URL;
 
 /**
  * Creates and evaluates JexlExpression and JexlScript objects.
  * Determines the behavior of expressions & scripts during their evaluation with respect to:
  * <ul>
- *  <li>Introspection, see {@link JexlUberspect}</li>
- *  <li>Arithmetic & comparison, see {@link JexlArithmetic}</li>
- *  <li>Error reporting</li>
- *  <li>Logging</li>
+ * <li>Introspection, see {@link JexlUberspect}</li>
+ * <li>Arithmetic & comparison, see {@link JexlArithmetic}</li>
+ * <li>Error reporting</li>
+ * <li>Logging</li>
  * </ul>
  * <p>
  * Note that methods that evaluate expressions may throw <em>unchecked</em> exceptions;
@@ -131,83 +133,145 @@ public abstract class JexlEngine {
      * Creates an JexlExpression from a String containing valid JEXL syntax.
      * This method parses the expression which must contain either a reference or an expression.
      *
+     * @param info       An info structure to carry debugging information if needed
      * @param expression A String containing valid JEXL syntax
      * @return An {@link JexlExpression} which can be evaluated using a {@link JexlContext}
-     * @throws JexlException An exception can be thrown if there is a problem parsing this expression, or if the
-     * expression is neither an expression nor a reference.
+     * @throws JexlException if there is a problem parsing the script
      */
-    public abstract JexlExpression createExpression(String expression);
+    public abstract JexlExpression createExpression(JexlInfo info, String expression);
 
     /**
-     * Creates an JexlExpression from a String containing valid JEXL syntax.
-     * This method parses the expression which  must contain either a reference or an expression.
+     * Creates a JexlScript from a String containing valid JEXL syntax.
+     * This method parses the script and validates the syntax.
+     *
+     * @param info   An info structure to carry debugging information if needed
+     * @param source A string containing valid JEXL syntax
+     * @param names  The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation
+     * @return A {@link JexlScript} which can be executed using a {@link JexlContext}
+     * @throws JexlException if there is a problem parsing the script
+     */
+    public abstract JexlScript createScript(JexlInfo info, String source, String[] names);
+
+    /**
+     * Creates a JexlExpression from a String containing valid JEXL syntax.
+     * This method parses the expression which must contain either a reference or an expression.
      *
      * @param expression A String containing valid JEXL syntax
-     * @param info An info structure to carry debugging information if needed
      * @return An {@link JexlExpression} which can be evaluated using a {@link JexlContext}
-     * @throws JexlException An exception can be thrown if there is a problem parsing this expression, or if the
-     * expression is neither an expression or a reference.
+     * @throws JexlException if there is a problem parsing the script
      */
-    public abstract JexlExpression createExpression(String expression, JexlInfo info);
+    public final JexlExpression createExpression(String expression) {
+        return createExpression(null, expression);
+    }
 
     /**
      * Creates a Script from a String containing valid JEXL syntax.
-     * This method parses the script which validates the syntax.
+     * This method parses the script and validates the syntax.
      *
      * @param scriptText A String containing valid JEXL syntax
      * @return A {@link JexlScript} which can be executed using a {@link JexlContext}
      * @throws JexlException if there is a problem parsing the script.
      */
-    public abstract JexlScript createScript(String scriptText);
+    public final JexlScript createScript(String scriptText) {
+        return createScript(null, scriptText, null);
+    }
 
     /**
      * Creates a Script from a String containing valid JEXL syntax.
-     * This method parses the script which validates the syntax.
+     * This method parses the script and validates the syntax.
      *
      * @param scriptText A String containing valid JEXL syntax
-     * @param names the script parameter names
+     * @param names      The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation
      * @return A {@link JexlScript} which can be executed using a {@link JexlContext}
-     * @throws JexlException if there is a problem parsing the script.
+     * @throws JexlException if there is a problem parsing the script
      */
-    public abstract JexlScript createScript(String scriptText, String... names);
+    public final JexlScript createScript(String scriptText, String... names) {
+        return createScript(null, scriptText, names);
+    }
 
     /**
-     * Creates a Script from a String containing valid JEXL syntax.
-     * This method parses the script which validates the syntax.
-     * It uses an array of parameter names that will be resolved during parsing;
-     * a corresponding array of arguments containing values should be used during evaluation.
+     * Creates a Script from a {@link File} containing valid JEXL syntax.
+     * This method parses the script and validates the syntax.
      *
-     * @param scriptText A String containing valid JEXL syntax
-     * @param info An info structure to carry debugging information if needed
-     * @param names the script parameter names
-     * @return A {@link JexlScript} which can be executed using a {@link JexlContext}
-     * @throws JexlException if there is a problem parsing the script.
+     * @param scriptFile A {@link File} containing valid JEXL syntax. Must not be null. Must be a readable file.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
      */
-    public abstract JexlScript createScript(String scriptText, JexlInfo info, String[] names);
+    public final JexlScript createScript(File scriptFile) {
+        return createScript(null, readSource(scriptFile), null);
+    }
 
     /**
      * Creates a Script from a {@link File} containing valid JEXL syntax.
      * This method parses the script and validates the syntax.
      *
      * @param scriptFile A {@link File} containing valid JEXL syntax. Must not be null. Must be a readable file.
-     * @return A {@link JexlScript} which can be executed with a
-     * {@link JexlContext}.
-     * @throws IOException if there is a problem reading the script.
-     * @throws JexlException if there is a problem parsing the script.
+     * @param names      The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
      */
-    public abstract JexlScript createScript(File scriptFile) throws IOException;
+    public final JexlScript createScript(File scriptFile, String... names) {
+        return createScript(null, readSource(scriptFile), names);
+    }
+
+    /**
+     * Creates a Script from a {@link File} containing valid JEXL syntax.
+     * This method parses the script and validates the syntax.
+     *
+     * @param info       An info structure to carry debugging information if needed
+     * @param scriptFile A {@link File} containing valid JEXL syntax. Must not be null. Must be a readable file.
+     * @param names      The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
+     */
+    public final JexlScript createScript(JexlInfo info, File scriptFile, String[] names) {
+        return createScript(info, readSource(scriptFile), names);
+    }
 
     /**
      * Creates a Script from a {@link URL} containing valid JEXL syntax.
      * This method parses the script and validates the syntax.
      *
-     * @param scriptUrl A {@link URL} containing valid JEXL syntax. Must not be null. Must be a readable file.
-     * @return A {@link JexlScript} which can be executed with a
-     * {@link JexlContext}.
-     * @throws IOException if there is a problem reading the script.
-     * @throws JexlException if there is a problem parsing the script.
+     * @param scriptUrl A {@link URL} containing valid JEXL syntax. Must not be null.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
+     */
+    public final JexlScript createScript(URL scriptUrl) {
+        return createScript(null, readSource(scriptUrl), null);
+    }
+
+    /**
+     * Creates a Script from a {@link URL} containing valid JEXL syntax.
+     * This method parses the script and validates the syntax.
+     *
+     * @param scriptUrl A {@link URL} containing valid JEXL syntax. Must not be null.
+     * @param names     The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
+     */
+    public final JexlScript createScript(URL scriptUrl, String[] names) {
+        return createScript(null, readSource(scriptUrl), names);
+    }
+
+    /**
+     * Creates a Script from a {@link URL} containing valid JEXL syntax.
+     * This method parses the script and validates the syntax.
+     *
+     * @param info      An info structure to carry debugging information if needed
+     * @param scriptUrl A {@link URL} containing valid JEXL syntax. Must not be null.
+     * @param names     The script parameter names used during parsing; a corresponding array of arguments containing
+     * values should be used during evaluation.
+     * @return A {@link JexlScript} which can be executed with a {@link JexlContext}.
+     * @throws JexlException if there is a problem reading or parsing the script.
      */
-    public abstract JexlScript createScript(URL scriptUrl) throws IOException;
+    public final JexlScript createScript(JexlInfo info, URL scriptUrl, String[] names) {
+        return createScript(info, readSource(scriptUrl), names);
+    }
 
     /**
      * Accesses properties of a bean using an expression.
@@ -233,8 +297,8 @@ public abstract class JexlEngine {
      * </p>
      *
      * @param context the evaluation context
-     * @param bean the bean to get properties from
-     * @param expr the property expression
+     * @param bean    the bean to get properties from
+     * @param expr    the property expression
      * @return the value of the property
      * @throws JexlException if there is an error parsing the expression or during evaluation
      */
@@ -250,8 +314,8 @@ public abstract class JexlEngine {
      * If the JEXL engine is silent, errors will be logged through its logger as warning.
      * </p>
      *
-     * @param bean the bean to set properties in
-     * @param expr the property expression
+     * @param bean  the bean to set properties in
+     * @param expr  the property expression
      * @param value the value of the property
      * @throws JexlException if there is an error parsing the expression or during evaluation
      */
@@ -262,16 +326,16 @@ public abstract class JexlEngine {
      * its logger as warning. </p>
      *
      * @param context the evaluation context
-     * @param bean the bean to set properties in
-     * @param expr the property expression
-     * @param value the value of the property
+     * @param bean    the bean to set properties in
+     * @param expr    the property expression
+     * @param value   the value of the property
      * @throws JexlException if there is an error parsing the expression or during evaluation
      */
     public abstract void setProperty(JexlContext context, Object bean, String expr, Object value);
 
     /**
      * Invokes an object's method by name and arguments.
-     * @param obj the method's invoker object
+     * @param obj  the method's invoker object
      * @param meth the method's name
      * @param args the method's arguments
      * @return the method returned value or null if it failed and engine is silent
@@ -281,9 +345,9 @@ public abstract class JexlEngine {
 
     /**
      * Creates a new instance of an object using the most appropriate constructor based on the arguments.
-     * @param <T> the type of object
+     * @param <T>   the type of object
      * @param clazz the class to instantiate
-     * @param args the constructor arguments
+     * @param args  the constructor arguments
      * @return the created object instance or null on failure when silent
      */
     public abstract <T> T newInstance(Class<? extends T> clazz, Object... args);
@@ -291,63 +355,118 @@ public abstract class JexlEngine {
     /**
      * Creates a new instance of an object using the most appropriate constructor based on the arguments.
      * @param clazz the name of the class to instantiate resolved through this engine's class loader
-     * @param args the constructor arguments
+     * @param args  the constructor arguments
      * @return the created object instance or null on failure when silent
      */
     public abstract Object newInstance(String clazz, Object... args);
 
     /**
-     * Trims the expression from front & ending spaces.
-     * @param str expression to clean
-     * @return trimmed expression ending in a semi-colon
-     */
-    public static String cleanExpression(CharSequence str) {
-        if (str != null) {
-            int start = 0;
-            int end = str.length();
-            if (end > 0) {
-                // trim front spaces
-                while (start < end && str.charAt(start) == ' ') {
-                    ++start;
-                }
-                // trim ending spaces
-                while (end > 0 && str.charAt(end - 1) == ' ') {
-                    --end;
+     * Creates a JexlInfo instance.
+     * @param fn url/file/template/script user given name
+     * @param l  line number
+     * @param c  column number
+     * @return a JexlInfo instance
+     */
+    protected JexlInfo createInfo(String fn, int l, int c) {
+        return new JexlInfo(fn, l, c);
+    }
+
+    /**
+     * Create an information structure for dynamic set/get/invoke/new.
+     * <p>This gathers the class, method and line number of the first calling method
+     * outside of o.a.c.jexl3.</p>
+     * @return a JexlInfo instance
+     */
+    protected JexlInfo createInfo() {
+        JexlInfo info = null;
+        Throwable xinfo = new Throwable();
+        xinfo.fillInStackTrace();
+        StackTraceElement[] stack = xinfo.getStackTrace();
+        StackTraceElement se = null;
+        String name = getClass().getName();
+        for (int s = 1; s < stack.length; ++s) {
+            se = stack[s];
+            String className = se.getClassName();
+            if (!className.equals(name)) {
+                // go deeper if called from jexl3 implementation classes
+                if (className.startsWith("org.apache.commons.jexl3.internal.")
+                    || className.startsWith("org.apache.commons.jexl3.J")) {
+                    name = className;
+                } else {
+                    break;
                 }
-                return str.subSequence(start, end).toString();
             }
-            return "";
         }
-        return null;
+        if (se != null) {
+            info = createInfo(se.getClassName() + "." + se.getMethodName(), se.getLineNumber(), 0);
+        }
+        return info;
     }
 
     /**
-     * Read from a reader into a local buffer and return a String with the contents of the reader.
-     * @param scriptReader to be read.
+     * Creates a string from a reader.
+     * @param reader to be read.
      * @return the contents of the reader as a String.
      * @throws IOException on any error reading the reader.
      */
-    public static String readerToString(Reader scriptReader) throws IOException {
+    protected static String toString(BufferedReader reader) throws IOException {
         StringBuilder buffer = new StringBuilder();
-        BufferedReader reader;
-        if (scriptReader instanceof BufferedReader) {
-            reader = (BufferedReader) scriptReader;
-        } else {
-            reader = new BufferedReader(scriptReader);
+        String line;
+        while ((line = reader.readLine()) != null) {
+            buffer.append(line).append('\n');
         }
+        return buffer.toString();
+    }
+
+    /**
+     * Reads a Jexl source from a File.
+     * @param file the script file
+     * @return the source
+     */
+    protected String readSource(final File file) {
+        if (file == null) {
+            throw new NullPointerException("source file is null");
+        }
+        BufferedReader reader = null;
         try {
-            String line;
-            while ((line = reader.readLine()) != null) {
-                buffer.append(line).append('\n');
-            }
-            return buffer.toString();
+            reader = new BufferedReader(new FileReader(file));
+            return toString(reader);
+        } catch (IOException xio) {
+            throw new JexlException(createInfo(file.toString(), 1, 1), "could not read source File", xio);
         } finally {
-            try {
-                reader.close();
-            } catch (IOException xio) {
-                // ignore
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException xignore) {
+                    // cant to much
+                }
             }
         }
+    }
 
+    /**
+     * Reads a Jexl source from an URL.
+     * @param url the script url
+     * @return the source
+     */
+    protected String readSource(final URL url) {
+        if (url == null) {
+            throw new NullPointerException("source URL is null");
+        }
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new InputStreamReader(url.openStream()));
+            return toString(reader);
+        } catch (IOException xio) {
+            throw new JexlException(createInfo(url.toString(), 1, 1), "could not read source URL", xio);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException xignore) {
+                    // cant to much
+                }
+            }
+        }
     }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java Sat May 12 06:52:21 2012
@@ -35,17 +35,13 @@ public class JexlException extends Runti
     private final transient JexlNode mark;
     /** The debug info. */
     private final transient JexlInfo info;
-    /** A marker to use in NPEs stating a null operand error. */
-    public static final String NULL_OPERAND = "jexl.null";
-    /** Minimum number of characters around exception location. */
-    private static final int MIN_EXCHARLOC = 10;
     /** Maximum number of characters around exception location. */
-    private static final int MAX_EXCHARLOC = 15;
+    private static final int MAX_EXCHARLOC = 32;
 
     /**
      * Creates a new JexlException.
      * @param node the node causing the error
-     * @param msg the error message
+     * @param msg  the error message
      */
     public JexlException(JexlNode node, String msg) {
         this(node, msg, null);
@@ -53,28 +49,28 @@ public class JexlException extends Runti
 
     /**
      * Creates a new JexlException.
-     * @param node the node causing the error
-     * @param msg the error message
+     * @param node  the node causing the error
+     * @param msg   the error message
      * @param cause the exception causing the error
      */
     public JexlException(JexlNode node, String msg, Throwable cause) {
-        this(node != null ? node.jexlInfo() : null, msg, cause);
+        this(node != null ? node.jexlInfo() : null, msg != null ? msg : "", cause);
     }
 
     /**
      * Creates a new JexlException.
      * @param jinfo the debugging information associated
-     * @param msg the error message
+     * @param msg   the error message
      * @param cause the exception causing the error
      */
     public JexlException(JexlInfo jinfo, String msg, Throwable cause) {
-        super(msg, clean(unwrap(cause)));
+        super(msg, unwrap(cause));
         mark = null;
         info = jinfo;
     }
 
     /**
-     * Cleans a JexlException from any org.apache.commons.jexl3 stack trace element.
+     * Cleans a JexlException from any org.apache.commons.jexl3.internal stack trace element.
      * @return this exception
      */
     public JexlException clean() {
@@ -82,8 +78,8 @@ public class JexlException extends Runti
     }
 
     /**
-     * Cleans a Throwable from any org.apache.commons.jexl3 stack trace element.
-     * @param <X> the throwable type
+     * Cleans a Throwable from any org.apache.commons.jexl3.internal stack trace element.
+     * @param <X>    the throwable type
      * @param xthrow the thowable
      * @return the throwable
      */
@@ -91,11 +87,11 @@ public class JexlException extends Runti
         if (xthrow != null) {
             StackTraceElement[] stack = xthrow.getStackTrace();
             List<StackTraceElement> stackJexl = new ArrayList<StackTraceElement>();
-            stackJexl.add(stack[0]);
-            for (int s = 1; s < stack.length; ++s) {
+            for (int s = 0; s < stack.length; ++s) {
                 StackTraceElement se = stack[s];
                 String className = se.getClassName();
-                if (!className.startsWith("org.apache.commons.jexl3")) {
+                if (!className.startsWith("org.apache.commons.jexl3.internal")
+                    && !className.startsWith("org.apache.commons.jexl3.parser")) {
                     stackJexl.add(se);
                 }
             }
@@ -121,7 +117,7 @@ public class JexlException extends Runti
 
     /**
      * Accesses detailed message.
-     * @return  the message
+     * @return the message
      */
     protected String detailedMessage() {
         return super.getMessage();
@@ -130,21 +126,21 @@ public class JexlException extends Runti
     /**
      * Formats an error message from the parser.
      * @param prefix the prefix to the message
-     * @param expr the expression in error
+     * @param expr   the expression in error
      * @return the formatted message
      */
     protected String parserError(String prefix, String expr) {
-        int begin = info.getColumn();
-        int end = begin + MIN_EXCHARLOC;
-        begin -= MIN_EXCHARLOC;
-        if (begin < 0) {
-            end += MIN_EXCHARLOC;
-            begin = 0;
-        }
         int length = expr.length();
         if (length < MAX_EXCHARLOC) {
             return prefix + " error in '" + expr + "'";
         } else {
+            int begin = info.getColumn();
+            int end = begin + (MAX_EXCHARLOC / 2);
+            begin -= (MAX_EXCHARLOC / 2);
+            if (begin < 0) {
+                end -= begin;
+                begin = 0;
+            }
             return prefix + " error near '... "
                     + expr.substring(begin, end > length ? length : end) + " ...'";
         }
@@ -157,17 +153,16 @@ public class JexlException extends Runti
     public static class Tokenization extends JexlException {
         /**
          * Creates a new Tokenization exception instance.
-         * @param info the location info
-         * @param expr the expression
+         * @param info  the location info
          * @param cause the javacc cause
          */
-        public Tokenization(JexlInfo info, CharSequence expr, TokenMgrError cause) {
-            super(merge(info, cause), expr.toString(), cause);
+        public Tokenization(JexlInfo info, TokenMgrError cause) {
+            super(merge(info, cause), cause.getAfter(), null);
         }
 
         /**
          * Merge the node info and the cause info to obtain best possible location.
-         * @param info the node
+         * @param info  the node
          * @param cause the cause
          * @return the info to use
          */
@@ -183,15 +178,15 @@ public class JexlException extends Runti
         }
 
         /**
-         * @return the expression
+         * @return the last good token
          */
-        public String getExpression() {
+        public String getDetail() {
             return super.detailedMessage();
         }
 
         @Override
         protected String detailedMessage() {
-            return parserError("tokenization", getExpression());
+            return parserError("tokenization", getDetail());
         }
     }
 
@@ -202,17 +197,25 @@ public class JexlException extends Runti
     public static class Parsing extends JexlException {
         /**
          * Creates a new Variable exception instance.
-         * @param info the location information
-         * @param expr the offending source
+         * @param info  the location information
          * @param cause the javacc cause
          */
-        public Parsing(JexlInfo info, CharSequence expr, ParseException cause) {
-            super(merge(info, cause), expr.toString(), cause);
+        public Parsing(JexlInfo info, ParseException cause) {
+            super(merge(info, cause), cause.getAfter(), null);
         }
 
         /**
-         * Merge the node info and the cause info to obtain best possible location.
+         * Creates a new Variable exception instance.
          * @param info the location information
+         * @param msg  the message
+         */
+        public Parsing(JexlInfo info, String msg) {
+            super(info, msg, null);
+        }
+
+        /**
+         * Merge the node info and the cause info to obtain best possible location.
+         * @param info  the location information
          * @param cause the cause
          * @return the info to use
          */
@@ -228,19 +231,15 @@ public class JexlException extends Runti
         }
 
         /**
-         * @return the expression
+         * @return the last good token
          */
-        public String getExpression() {
+        public String getDetail() {
             return super.detailedMessage();
         }
 
         @Override
         protected String detailedMessage() {
-            if (getCause() == null) {
-                return getExpression();
-            } else {
-                return parserError("parsing", getExpression());
-            }
+            return parserError("parsing", getDetail());
         }
     }
 
@@ -252,7 +251,7 @@ public class JexlException extends Runti
         /**
          * Creates a new Variable exception instance.
          * @param node the offending ASTnode
-         * @param var the unknown variable
+         * @param var  the unknown variable
          */
         public Variable(JexlNode node, String var) {
             super(node, var, null);
@@ -279,7 +278,7 @@ public class JexlException extends Runti
         /**
          * Creates a new Property exception instance.
          * @param node the offending ASTnode
-         * @param var the unknown variable
+         * @param var  the unknown variable
          */
         public Property(JexlNode node, String var) {
             this(node, var, null);
@@ -287,8 +286,8 @@ public class JexlException extends Runti
 
         /**
          * Creates a new Property exception instance.
-         * @param node the offending ASTnode
-         * @param var the unknown variable
+         * @param node  the offending ASTnode
+         * @param var   the unknown variable
          * @param cause the exception causing the error
          */
         public Property(JexlNode node, String var, Throwable cause) {
@@ -315,8 +314,8 @@ public class JexlException extends Runti
     public static class Method extends JexlException {
         /**
          * Creates a new Method exception instance.
-         * @param node the offending ASTnode
-         * @param name the unknown method
+         * @param node  the offending ASTnode
+         * @param name  the unknown method
          * @param cause the exception causing the error
          */
         public Method(JexlNode node, String name, Throwable cause) {
@@ -325,8 +324,8 @@ public class JexlException extends Runti
 
         /**
          * Creates a new Method exception instance.
-         * @param info the location information
-         * @param name the unknown method
+         * @param info  the location information
+         * @param name  the unknown method
          * @param cause the exception causing the error
          */
         public Method(JexlInfo info, String name, Throwable cause) {
@@ -356,8 +355,8 @@ public class JexlException extends Runti
 
         /**
          * Creates a new instance of Return.
-         * @param node the return node
-         * @param msg the message
+         * @param node  the return node
+         * @param msg   the message
          * @param value the returned value
          */
         public Return(JexlNode node, String msg, Object value) {
@@ -404,7 +403,7 @@ public class JexlException extends Runti
                 offsets[0] = dbg.start();
                 offsets[1] = dbg.end();
             }
-            return dbg.data();
+            return dbg.toString();
         }
         return "";
     }
@@ -431,13 +430,13 @@ public class JexlException extends Runti
             msg.append(",");
             msg.append(dbg.end());
             msg.append("]: '");
-            msg.append(dbg.data());
+            msg.append(dbg.toString());
             msg.append("'");
         }
         msg.append(' ');
         msg.append(detailedMessage());
         Throwable cause = getCause();
-        if (cause != null && (Object) NULL_OPERAND == cause.getMessage()) {
+        if (cause instanceof JexlArithmetic.NullOperand) {
             msg.append(" caused by null operand");
         }
         return msg.toString();

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlExpression.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlExpression.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlExpression.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlExpression.java Sat May 12 06:52:21 2012
@@ -47,7 +47,7 @@ public interface JexlExpression {
      * Returns the JEXL expression this JexlExpression was created with.
      * @return The JEXL expression to be evaluated
      */
-    String getExpression();
+    CharSequence getParsedText();
 
     /**
      * Returns the JEXL expression by reconstructing it from the parsed tree.

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java Sat May 12 06:52:21 2012
@@ -28,12 +28,12 @@ public class JexlInfo {
     protected final int column;
     /** name. */
     protected final String name;
-    
-    /** 
+
+    /**
      * Create info.
      * @param tn template name
      * @param l line number
-     * @param c column
+     * @param c column number
      */
     public JexlInfo(String tn, int l, int c) {
         name = tn;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java Sat May 12 06:52:21 2012
@@ -28,16 +28,16 @@ import java.util.concurrent.Callable;
  * <p>The statements can be <code>blocks</code> (curly braces containing code),
  * Control statements such as <code>if</code> and <code>while</code>
  * as well as expressions and assignment statements.</p>
- *  
+ *
  * @since 1.1
  */
 public interface JexlScript extends JexlExpression {
     /**
      * Executes the script with the variables contained in the
-     * supplied {@link JexlContext}. 
-     * 
+     * supplied {@link JexlContext}.
+     *
      * @param context A JexlContext containing variables.
-     * @return The result of this script, usually the result of 
+     * @return The result of this script, usually the result of
      *      the last statement.
      */
     Object execute(JexlContext context);
@@ -46,10 +46,10 @@ public interface JexlScript extends Jexl
      * Executes the script with the variables contained in the
      * supplied {@link JexlContext} and a set of arguments corresponding to the
      * parameters used during parsing.
-     * 
+     *
      * @param context A JexlContext containing variables.
      * @param args the arguments
-     * @return The result of this script, usually the result of 
+     * @return The result of this script, usually the result of
      *      the last statement.
      * @since 2.1
      */
@@ -59,7 +59,7 @@ public interface JexlScript extends Jexl
      * Returns the text of this Script.
      * @return The script to be executed.
      */
-    String getText();
+    String getSourceText();
 
     /**
      * Gets this script parameters.
@@ -77,7 +77,7 @@ public interface JexlScript extends Jexl
 
     /**
      * Gets this script variables.
-     * <p>Note that since variables can be in an ant-ish form (ie foo.bar.quux), each variable is returned as 
+     * <p>Note that since variables can be in an ant-ish form (ie foo.bar.quux), each variable is returned as
      * a list of strings where each entry is a fragment of the variable ({"foo", "bar", "quux"} in the example.</p>
      * @return the variables or null
      * @since 2.1

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/Main.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/Main.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/Main.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/Main.java Sat May 12 06:52:21 2012
@@ -30,16 +30,16 @@ import java.io.InputStreamReader;
 public class Main {
     /**
      * Test application for JEXL
-     * 
+     *
      * If a single argument is present, it is treated as a filename of a JEXL
      * script to be executed as a script. Any exceptions terminate the application.
-     * 
+     *
      * Otherwise, lines are read from standard input and evaluated.
      * ParseExceptions and JexlExceptions are logged, and do not cause the application to exit.
      * This is done so that interactive testing is easier.
-     * 
+     *
      * @param args (optional) filename to execute. Stored in the args variable.
-     * 
+     *
      * @throws Exception if parsing or IO fail
      */
     public static void main(String[] args) throws Exception {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java Sat May 12 06:52:21 2012
@@ -44,10 +44,10 @@ public class Closure extends Script {
     }
 
     @Override
-    public String getExpression() {
+    public String getParsedText() {
         Debugger debug = new Debugger();
         boolean d = debug.debug(script);
-        return debug.data();
+        return debug.toString();
     }
 
     @Override
@@ -92,5 +92,5 @@ public class Closure extends Script {
             }
         };
     }
-    
+
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1337453&r1=1337452&r2=1337453&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java Sat May 12 06:52:21 2012
@@ -16,7 +16,6 @@
  */
 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;
@@ -86,22 +85,22 @@ import java.util.regex.Pattern;
  */
 public final class Debugger extends ParserVisitor {
     /** The builder to compose messages. */
-    private final StringBuilder builder;
+    private final StringBuilder builder = new StringBuilder();
     /** The cause of the issue to debug. */
-    private JexlNode cause;
+    private JexlNode cause = null;
     /** The starting character location offset of the cause in the builder. */
-    private int start;
+    private int start = 0;
     /** The ending character location offset of the cause in the builder. */
-    private int end;
+    private int end = 0;
+    /** The indentation level. */
+    private int indentLevel = 0;
+    /** Perform indentation?. */
+    private boolean indent = true;
 
     /**
      * Creates a Debugger.
      */
     public Debugger() {
-        builder = new StringBuilder();
-        cause = null;
-        start = 0;
-        end = 0;
     }
 
     /**
@@ -138,9 +137,11 @@ public final class Debugger extends Pars
     public boolean debug(JexlNode node) {
         start = 0;
         end = 0;
+        indentLevel = 0;
+        indent = true;
         if (node != null) {
             builder.setLength(0);
-            this.cause = node;
+            cause = node;
             // make arg cause become the root cause
             JexlNode root = node;
             while (root.jjtGetParent() != null) {
@@ -154,7 +155,8 @@ public final class Debugger extends Pars
     /**
      * @return The rebuilt expression
      */
-    public String data() {
+    @Override
+    public String toString() {
         return builder.toString();
     }
 
@@ -167,6 +169,8 @@ public final class Debugger extends Pars
     public String data(JexlNode node) {
         start = 0;
         end = 0;
+        indentLevel = 0;
+        indent = true;
         if (node != null) {
             builder.setLength(0);
             this.cause = node;
@@ -209,27 +213,37 @@ public final class Debugger extends Pars
     /**
      * Adds a statement node to the rebuilt expression.
      * @param child the child node
-     * @param data visitor pattern argument
+     * @param data  visitor pattern argument
      * @return visitor pattern value
      */
     private Object acceptStatement(JexlNode child, Object data) {
+        if (indent) {
+            for (int i = 0; i < indentLevel; ++i) {
+                builder.append("    ");
+            }
+        }
         Object value = accept(child, data);
         // blocks, if, for & while dont need a ';' at end
-        if (child instanceof ASTBlock
+        if (!(child instanceof ASTJexlScript
+                || child instanceof ASTBlock
                 || child instanceof ASTIfStatement
                 || child instanceof ASTForeachStatement
-                || child instanceof ASTWhileStatement) {
-            return value;
+                || child instanceof ASTWhileStatement)) {
+            builder.append(";");
+            if (indent) {
+                builder.append("\n");
+            } else {
+                builder.append(' ');
+            }
         }
-        builder.append(";");
         return value;
     }
 
     /**
      * Checks if a terminal node is the the cause to debug &amp; adds its representation to the rebuilt expression.
-     * @param node the child node
+     * @param node  the child node
      * @param image the child node token image (may be null)
-     * @param data visitor pattern argument
+     * @param data  visitor pattern argument
      * @return visitor pattern value
      */
     private Object check(JexlNode node, String image, Object data) {
@@ -250,10 +264,10 @@ public final class Debugger extends Pars
     /**
      * Checks if the children of a node using infix notation is the cause to debug, adds their representation to the
      * rebuilt expression.
-     * @param node the child node
+     * @param node  the child node
      * @param infix the child node token
      * @param paren whether the child should be parenthesized
-     * @param data visitor pattern argument
+     * @param data  visitor pattern argument
      * @return visitor pattern value
      */
     private Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
@@ -276,9 +290,9 @@ public final class Debugger extends Pars
     /**
      * Checks if the child of a node using prefix notation is the cause to debug, adds their representation to the
      * rebuilt expression.
-     * @param node the node
+     * @param node   the node
      * @param prefix the node token
-     * @param data visitor pattern argument
+     * @param data   visitor pattern argument
      * @return visitor pattern value
      */
     private Object prefixChild(JexlNode node, String prefix, Object data) {
@@ -307,7 +321,7 @@ public final class Debugger extends Pars
     /**
      * Rebuilds an additive expression.
      * @param node the node
-     * @param op the operator
+     * @param op   the operator
      * @param data visitor pattern argument
      * @return visitor pattern value
      */
@@ -391,13 +405,20 @@ public final class Debugger extends Pars
 
     @Override
     protected Object visit(ASTBlock node, Object data) {
-        builder.append("{ ");
+        builder.append("{");
+        if (indent) {
+            builder.append("\n");
+        } else {
+            builder.append(' ');
+        }
+        indentLevel += 1;
         int num = node.jjtGetNumChildren();
         for (int i = 0; i < num; ++i) {
             JexlNode child = node.jjtGetChild(i);
             acceptStatement(child, data);
         }
-        builder.append(" }");
+        indentLevel -= 1;
+        builder.append("}");
         return data;
     }
 
@@ -496,8 +517,6 @@ public final class Debugger extends Pars
             if (node.jjtGetNumChildren() > 2) {
                 builder.append(" else ");
                 acceptStatement(node.jjtGetChild(2), data);
-            } else {
-                builder.append(';');
             }
         } else {
             builder.append(';');
@@ -512,6 +531,7 @@ public final class Debugger extends Pars
 
     @Override
     protected Object visit(ASTJexlScript node, Object data) {
+        boolean ii = true;
         if (node instanceof ASTJexlLambda) {
             JexlNode parent = node.jjtGetParent();
             // use lambda syntax if not assigned
@@ -533,12 +553,23 @@ public final class Debugger extends Pars
                 builder.append(' ');
             } else {
                 builder.append("->");
+                ii = false;
             }
         }
+        if (!ii) {
+            indent = false;
+        }
         int num = node.jjtGetNumChildren();
-        for (int i = 0; i < num; ++i) {
-            JexlNode child = node.jjtGetChild(i);
-            acceptStatement(child, data);
+        if (num == 1 && !(node instanceof ASTJexlLambda)) {
+            data = accept(node.jjtGetChild(0), data);
+        } else {
+            for (int i = 0; i < num; ++i) {
+                JexlNode child = node.jjtGetChild(i);
+                acceptStatement(child, data);
+            }
+        }
+        if (!ii) {
+            indent = true;
         }
         return data;
     }
@@ -568,7 +599,7 @@ public final class Debugger extends Pars
         if (num > 0) {
             accept(node.jjtGetChild(0), data);
             for (int i = 1; i < num; ++i) {
-                builder.append(", ");
+                builder.append(",");
                 accept(node.jjtGetChild(i), data);
             }
         } else {



Mime
View raw message