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 2012/07/05 09:08:07 UTC

svn commit: r1357476 [1/2] - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/ main/java/org/apache/commons/jexl3/internal/ main/java/org/apache/commons/jexl3/internal/introspection/ main/java/org/apache/commons/jexl3/parser/ site/...

Author: henrib
Date: Thu Jul  5 07:08:06 2012
New Revision: 1357476

URL: http://svn.apache.org/viewvc?rev=1357476&view=rev
Log:

Added range operator (x .. y)  and supporting class (IntegerRange);
Added startsWith/endsWith (=^ and =$)  operators;
Added #NaN to grammar;

Added  charset support in JexlEngine & builder options;
Rafactored code for map and array literals (MapBuilder/ArrayBuilder), allow override in JexlArithmetic to customize behavior;
Updated constant JexlNode determination;
Updated exception handling during parsing,  more precise message and info;

Moved ReadonlyContext to test dir;
Moved some tests from 'issues' to arithmetic;
Updated doc and changes;

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java   (with props)
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java   (with props)
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java   (with props)
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
      - copied, changed from r1338871, commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BitwiseOperatorTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ReadonlyContext.java
      - copied, changed from r1338871, commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/ReadonlyContext.java
Removed:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/ReadonlyContext.java
Modified:
    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/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/introspection/ArrayListWrapper.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/package.html
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTMapLiteral.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTStringLiteral.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/parser/ParserVisitor.java
    commons/proper/jexl/trunk/src/site/xdoc/changes.xml
    commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.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/JexlEvalContext.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/internal/Util.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/parser/ParserTest.java

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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -16,8 +16,6 @@
  */
 package org.apache.commons.jexl3;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.MathContext;
@@ -110,6 +108,82 @@ public class JexlArithmetic {
     }
 
     /**
+     * Helper interface used when creating an array literal.
+     * <p>The default implementation creates an array and attempts to type it strictly.
+     * <ul>
+     * <li>If all objects are of the same type, the array returned will be an array of that same type</li>
+     * <li>If all objects are Numbers, the array returned will be an array of Numbers</li>
+     * <li>If all objects are convertible to a primitive type, the array returned will be an array
+     * of the primitive type</li>
+     * </ul>
+     * </p>
+     */
+    public interface ArrayBuilder {
+        /**
+         * Adds a literal to the array.
+         * @param value the item to add
+         */
+        void add(Object value);
+
+        /**
+         * Creates the actual "array" instance.
+         * @return the array
+         */
+        Object create();
+    }
+
+    /**
+     * Called by the interpreter when evaluating a literal array.
+     * @param size the number of elements in the array
+     * @return the array builder
+     */
+    public ArrayBuilder arrayBuilder(int size) {
+        return new org.apache.commons.jexl3.internal.ArrayBuilder(size);
+    }
+
+    /**
+     * Helper interface used when creating a map literal.
+     * <p>The default implementation creates a java.util.HashMap.</p>
+     */
+    public interface MapBuilder {
+        /**
+         * Adds a new entry to the map.
+         * @param key   the map entry key
+         * @param value the map entry value
+         */
+        void put(Object key, Object value);
+
+        /**
+         * Creates the actual "map" instance.
+         * @return the map
+         */
+        Object create();
+    }
+
+    /**
+     * Called by the interpreter when evaluating a literal map.
+     * @param size the number of elements in the map
+     * @return the map builder
+     */
+    public MapBuilder mapBuilder(int size) {
+        return new org.apache.commons.jexl3.internal.MapBuilder(size);
+    }
+
+    /**
+     * Creates a literal range.
+     * <p>The default implementation only accepts integers.</p>
+     * @param from the included lower bound value (null if none)
+     * @param to   the included upper bound value (null if none)
+     * @return the range as an iterable
+     * @throws ArithmeticException as an option if creation fails
+     */
+    public Iterable<?> createRange(Object from, Object to) throws ArithmeticException {
+        final int ifrom = toInteger(from);
+        final int ito = toInteger(to);
+        return new org.apache.commons.jexl3.internal.IntegerRange(ifrom, ito);
+    }
+
+    /**
      * Checks whether this JexlArithmetic instance
      * strictly considers null as an error when used as operand unexpectedly.
      * @return true if strict, false if lenient
@@ -365,96 +439,22 @@ public class JexlArithmetic {
     }
 
     /**
-     * Given an array of objects, attempt to type it more strictly.
-     * <p>This is a placeholder for derivation that calls the static typeArray method.</p>
-     * @param untyped an untyped array
-     * @return the original array if the attempt to strictly type the array fails, a typed array otherwise
-     */
-    public Object narrowArrayType(Object[] untyped) {
-        return typeArray(untyped);
-    }
-
-    /**
-     * Given an array of objects, attempt to type it more strictly.
-     * <ul>
-     * <li>If all objects are of the same type, the array returned will be an array of that same type</li>
-     * <li>If all objects are Numbers, the array returned will be an array of Numbers</li>
-     * <li>If all objects are convertible to a primitive type, the array returned will be an array
-     * of the primitive type</li>
-     * </ul>
-     * @param untyped an untyped array
-     * @return the original array if the attempt to strictly type the array fails, a typed array otherwise
-     */
-    public static Object typeArray(Object[] untyped) {
-        final int size = untyped.length;
-        Class<?> commonClass = null;
-        if (size > 0) {
-            boolean isNumber = true;
-            // for all children after first...
-            for (int u = 0; u < size && !Object.class.equals(commonClass); ++u) {
-                if (untyped[u] != null) {
-                    Class<?> eclass = untyped[u].getClass();
-                    // base common class on first non-null entry
-                    if (commonClass == null) {
-                        commonClass = eclass;
-                        isNumber &= Number.class.isAssignableFrom(commonClass);
-                    } else if (!commonClass.equals(eclass)) {
-                        // if both are numbers...
-                        if (isNumber && Number.class.isAssignableFrom(eclass)) {
-                            commonClass = Number.class;
-                        } else {
-                            // attempt to find valid superclass
-                            do {
-                                eclass = eclass.getSuperclass();
-                                if (eclass == null) {
-                                    commonClass = Object.class;
-                                    break;
-                                }
-                            } while (!commonClass.isAssignableFrom(eclass));
-                        }
-                    }
-                } else {
-                    isNumber = false;
-                }
-            }
-            // convert array to the common class if not Object.class
-            if (commonClass != null && !Object.class.equals(commonClass)) {
-                // if the commonClass has an equivalent primitive type, get it
-                if (isNumber) {
-                    try {
-                        final Field type = commonClass.getField("TYPE");
-                        commonClass = (Class<?>) type.get(null);
-                    } catch (Exception xany) {
-                        // ignore
-                    }
-                }
-                // allocate and fill up the typed array
-                Object typed = Array.newInstance(commonClass, size);
-                for (int i = 0; i < size; ++i) {
-                    Array.set(typed, i, untyped[i]);
-                }
-                return typed;
-            }
-        }
-        return untyped;
-    }
-
-    /**
      * 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;
         for (int a = 0; a < args.length; ++a) {
             Object arg = args[a];
             if (arg instanceof Number) {
-                Object narg = narrow((Number) arg);
-                if (narg != arg) {
+                Number narg = (Number) arg;
+                Number narrow = narrow(narg);
+                if (!narg.equals(narrow)) {
                     narrowed = true;
                 }
-                args[a] = narg;
+                args[a] = narrow;
             }
         }
         return narrowed;
@@ -519,7 +519,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);
         }
@@ -537,7 +537,7 @@ 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);
     }
@@ -559,7 +559,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);
         }
@@ -578,7 +578,7 @@ public class JexlArithmetic {
         BigInteger result = l.mod(r);
         if (BigInteger.ZERO.equals(r)) {
             throw new ArithmeticException("%");
-            }
+        }
         return narrowBigInteger(left, right, result);
     }
 
@@ -1022,7 +1022,7 @@ public class JexlArithmetic {
             return new BigInteger(val.toString());
         } else if (val instanceof String) {
             String string = (String) val;
-            if ("".equals(string.trim())) {
+            if ("".equals(string)) {
                 return BigInteger.ZERO;
             } else {
                 return new BigInteger(string);
@@ -1052,7 +1052,7 @@ public class JexlArithmetic {
             controlNullOperand();
             return BigDecimal.ZERO;
         } else if (val instanceof String) {
-            String string = ((String) val).trim();
+            String string = (String) val;
             if ("".equals(string)) {
                 return BigDecimal.ZERO;
             }
@@ -1094,7 +1094,7 @@ public class JexlArithmetic {
         } else if (val instanceof Boolean) {
             return ((Boolean) val).booleanValue() ? 1. : 0.;
         } else if (val instanceof String) {
-            String string = ((String) val).trim();
+            String string = (String) val;
             if ("".equals(string)) {
                 return Double.NaN;
             } else {

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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.jexl3;
 
+import java.nio.charset.Charset;
 import org.apache.commons.jexl3.internal.Engine;
 import java.util.Map;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
@@ -99,6 +100,10 @@ public class JexlBuilder {
      */
     protected int cacheThreshold = CACHE_THRESHOLD;
     /**
+     * The charset.
+     */
+    protected Charset charset = Charset.defaultCharset();
+    /**
      * The class loader.
      */
     protected ClassLoader loader = null;
@@ -179,6 +184,21 @@ public class JexlBuilder {
     }
 
     /**
+     * Sets the charset to use.
+     * @param arg the charset
+     * @return this builder
+     */
+    public JexlBuilder loader(Charset arg) {
+        this.charset = arg;
+        return this;
+    }
+
+    /** @return the charset */
+    public Charset charset() {
+        return charset;
+    }
+
+    /**
      * Sets whether the engine will throw JexlException during evaluation when an error is triggered.
      * @param flag true means no JexlException will occur, false allows them
      * @return this builder

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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -20,11 +20,12 @@ import org.apache.commons.jexl3.introspe
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.math.MathContext;
 import java.net.URL;
+import java.nio.charset.Charset;
 
 /**
  * Creates and evaluates JexlExpression and JexlScript objects.
@@ -49,6 +50,11 @@ public abstract class JexlEngine {
      */
     public interface Options {
         /**
+         * The charset used for parsing.
+         * @return the charset
+         */
+        Charset getCharset();
+        /**
          * Sets whether the engine will throw a {@link JexlException} when an error is encountered during evaluation.
          * @return true if silent, false otherwise
          */
@@ -114,6 +120,12 @@ public abstract class JexlEngine {
     private static final int JXLT_CACHE_SIZE = 256;
 
     /**
+     * Gets the charset used for parsing.
+     * @return the charset
+     */
+    public abstract Charset getCharset();
+
+    /**
      * Gets this engine underlying {@link JexlUberspect}.
      * @return the uberspect
      */
@@ -473,7 +485,7 @@ public abstract class JexlEngine {
         }
         BufferedReader reader = null;
         try {
-            reader = new BufferedReader(new FileReader(file));
+            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), getCharset()));
             return toString(reader);
         } catch (IOException xio) {
             throw new JexlException(createInfo(file.toString(), 1, 1), "could not read source File", xio);
@@ -482,7 +494,7 @@ public abstract class JexlEngine {
                 try {
                     reader.close();
                 } catch (IOException xignore) {
-                    // cant to much
+                    // cant do much
                 }
             }
         }
@@ -499,7 +511,7 @@ public abstract class JexlEngine {
         }
         BufferedReader reader = null;
         try {
-            reader = new BufferedReader(new InputStreamReader(url.openStream()));
+            reader = new BufferedReader(new InputStreamReader(url.openStream(), getCharset()));
             return toString(reader);
         } catch (IOException xio) {
             throw new JexlException(createInfo(url.toString(), 1, 1), "could not read source URL", xio);
@@ -508,7 +520,7 @@ public abstract class JexlEngine {
                 try {
                     reader.close();
                 } catch (IOException xignore) {
-                    // cant to much
+                    // cant do 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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -73,7 +73,7 @@ public class JexlException extends Runti
      * @param cause the exception causing the error
      */
     public JexlException(JexlInfo jinfo, String msg, Throwable cause) {
-        super(msg, unwrap(cause));
+        super(msg != null ? msg : "", unwrap(cause));
         mark = null;
         info = jinfo;
     }
@@ -213,7 +213,7 @@ public class JexlException extends Runti
      */
     public static class Parsing extends JexlException {
         /**
-         * Creates a new Variable exception instance.
+         * Creates a new Parsing exception instance.
          * @param info  the location information
          * @param cause the javacc cause
          */
@@ -222,7 +222,7 @@ public class JexlException extends Runti
         }
 
         /**
-         * Creates a new Variable exception instance.
+         * Creates a new Parsing exception instance.
          * @param info the location information
          * @param msg  the message
          */
@@ -244,6 +244,46 @@ public class JexlException extends Runti
     }
 
     /**
+     * Thrown when parsing fails due to an ambiguous statement.
+     * @since 3.0
+     */
+    public static class Ambiguous extends Parsing {
+        /**
+         * Creates a new Ambiguous statement exception instance.
+         * @param info  the location information
+         * @param expr  the source expression line
+         */
+        public Ambiguous(JexlInfo info, String expr) {
+            super(info, expr);
+        }
+
+        @Override
+        protected String detailedMessage() {
+            return parserError("ambiguous statement", getDetail());
+        }
+    }
+
+    /**
+     * Thrown when parsing fails due to an invalid assigment.
+     * @since 3.0
+     */
+    public static class Assignment extends Parsing {
+        /**
+         * Creates a new Assignment statement exception instance.
+         * @param info  the location information
+         * @param expr  the source expression line
+         */
+        public Assignment(JexlInfo info, String expr) {
+            super(info, expr);
+        }
+
+        @Override
+        protected String detailedMessage() {
+            return parserError("assignement", getDetail());
+        }
+    }
+
+    /**
      * Thrown when a variable is unknown.
      * @since 3.0
      */

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java?rev=1357476&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java Thu Jul  5 07:08:06 2012
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3.internal;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import org.apache.commons.jexl3.JexlArithmetic;
+
+/**
+ * Helper class to create typed arrays.
+ */
+public class ArrayBuilder implements JexlArithmetic.ArrayBuilder {
+    /** The intended class array. */
+    private Class<?> commonClass = null;
+    /** Whether the array stores numbers. */
+    private boolean isNumber = true;
+    /** The untyped list of items being added. */
+    private final Object[] untyped;
+    /** Number of added items. */
+    private int added = 0;
+
+    /**
+     * Creates a new builder.
+     * @param size the exact array size
+     */
+    public ArrayBuilder(int size) {
+        untyped = new Object[size];
+    }
+
+    @Override
+    public void add(Object value) {
+        // for all children after first...
+        if (!Object.class.equals(commonClass)) {
+            if (value == null) {
+                isNumber = false;
+            } else {
+                Class<?> eclass = value.getClass();
+                // base common class on first non-null entry
+                if (commonClass == null) {
+                    commonClass = eclass;
+                    isNumber &= Number.class.isAssignableFrom(commonClass);
+                } else if (!commonClass.equals(eclass)) {
+                    // if both are numbers...
+                    if (isNumber && Number.class.isAssignableFrom(eclass)) {
+                        commonClass = Number.class;
+                    } else {
+                        // attempt to find valid superclass
+                        do {
+                            eclass = eclass.getSuperclass();
+                            if (eclass == null) {
+                                commonClass = Object.class;
+                                break;
+                            }
+                        } while (!commonClass.isAssignableFrom(eclass));
+                    }
+                }
+            }
+        }
+        if (added >= untyped.length) {
+            throw new IllegalArgumentException("add() over size");
+        }
+        untyped[added++] = value;
+    }
+
+    @Override
+    public Object create() {
+        if (untyped != null) {
+            int size = untyped.length;
+            // convert untyped array to the common class if not Object.class
+            if (commonClass != null && !Object.class.equals(commonClass)) {
+                // if the commonClass is a number, it has an equivalent primitive type, get it
+                if (isNumber) {
+                    try {
+                        final Field type = commonClass.getField("TYPE");
+                        commonClass = (Class<?>) type.get(null);
+                    } catch (Exception xany) {
+                        // ignore
+                    }
+                }
+                // allocate and fill up the typed array
+                Object typed = Array.newInstance(commonClass, size);
+                for (int i = 0; i < size; ++i) {
+                    Array.set(typed, i, untyped[i]);
+                }
+                return typed;
+            } else {
+                return untyped;
+            }
+        } else {
+            return new Object[0];
+        }
+    }
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -46,7 +46,7 @@ public class Closure extends Script {
     @Override
     public String getParsedText() {
         Debugger debug = new Debugger();
-        boolean d = debug.debug(script);
+        debug.debug(script);
         return debug.toString();
     }
 

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=1357476&r1=1357475&r2=1357476&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 Thu Jul  5 07:08:06 2012
@@ -54,10 +54,13 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTMulNode;
 import org.apache.commons.jexl3.parser.ASTNENode;
 import org.apache.commons.jexl3.parser.ASTNRNode;
+import org.apache.commons.jexl3.parser.ASTEWNode;
+import org.apache.commons.jexl3.parser.ASTSWNode;
 import org.apache.commons.jexl3.parser.ASTNotNode;
 import org.apache.commons.jexl3.parser.ASTNullLiteral;
 import org.apache.commons.jexl3.parser.ASTNumberLiteral;
 import org.apache.commons.jexl3.parser.ASTOrNode;
+import org.apache.commons.jexl3.parser.ASTRangeNode;
 import org.apache.commons.jexl3.parser.ASTReference;
 import org.apache.commons.jexl3.parser.ASTReferenceExpression;
 import org.apache.commons.jexl3.parser.ASTReturnStatement;
@@ -377,6 +380,11 @@ public final class Debugger extends Pars
     }
 
     @Override
+    protected Object visit(ASTRangeNode node, Object data) {
+        return infixChildren(node, " .. ", false, data);
+    }
+
+    @Override
     protected Object visit(ASTAssignment node, Object data) {
         return infixChildren(node, " = ", false, data);
     }
@@ -452,6 +460,16 @@ public final class Debugger extends Pars
     }
 
     @Override
+    protected Object visit(ASTSWNode node, Object data) {
+        return infixChildren(node, " =^ ", false, data);
+    }
+
+    @Override
+    protected Object visit(ASTEWNode node, Object data) {
+        return infixChildren(node, " =$ ", false, data);
+    }
+
+    @Override
     protected Object visit(ASTFalseNode node, Object data) {
         return check(node, "false", data);
     }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java Thu Jul  5 07:08:06 2012
@@ -41,8 +41,6 @@ import org.apache.commons.jexl3.parser.P
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import java.io.Reader;
-
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -53,6 +51,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 
 import java.lang.ref.SoftReference;
+import java.nio.charset.Charset;
 
 /**
  * A JexlEngine implementation.
@@ -118,6 +117,11 @@ public class Engine extends JexlEngine {
      */
     protected final int cacheThreshold;
     /**
+     * The default charset.
+     */
+    protected final Charset charset;
+
+    /**
      * The default cache load factor.
      */
     private static final float LOAD_FACTOR = 0.75f;
@@ -153,6 +157,7 @@ public class Engine extends JexlEngine {
         this.arithmetic = conf.arithmetic() == null ? new JexlArithmetic(this.strict) : conf.arithmetic();
         this.cache = conf.cache() <= 0 ? null : new SoftCache<String, ASTJexlScript>(conf.cache());
         this.cacheThreshold = conf.cacheThreshold();
+        this.charset = conf.charset();
     }
 
     /**
@@ -192,7 +197,7 @@ public class Engine extends JexlEngine {
     }
 
     @Override
-    public final boolean isStrict() {
+    public boolean isStrict() {
         return strict;
     }
 
@@ -202,6 +207,11 @@ public class Engine extends JexlEngine {
     }
 
     @Override
+    public Charset getCharset() {
+        return charset;
+    }
+
+    @Override
     public TemplateEngine createJxltEngine(int cacheSize, char immediate, char deferred) {
         return new TemplateEngine(this, cacheSize, immediate, deferred);
     }
@@ -618,8 +628,7 @@ public class Engine extends JexlEngine {
                     }
                 }
             }
-            Reader reader = new StringReader(expr);
-            script = parser.parse(info, reader, scope, registers);
+            script = parser.parse(info, expr, scope, registers);
             if (cached) {
                 cache.put(expr, script);
             }

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java?rev=1357476&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java Thu Jul  5 07:08:06 2012
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3.internal;
+
+import java.util.Iterator;
+
+/**
+ * A range of integers.
+ */
+public class IntegerRange implements Iterable<Integer> {
+    /** The lower boundary. */
+    private final int low;
+    /** The upper boundary. */
+    private final int high;
+
+    /**
+     * Creates a new range.
+     * @param from the lower inclusive boundary
+     * @param to  the higher inclusive boundary
+     */
+    public IntegerRange(int from, int to) {
+        low = from;
+        high = to;
+    }
+
+    @Override
+    public Iterator<Integer> iterator() {
+        return new IntegerIterator(low, high);
+    }
+}
+
+/**
+ * An iterator on an integer range.
+ */
+class IntegerIterator implements Iterator<Integer> {
+    /** The lower boundary. */
+    private final int low;
+    /** The upper boundary. */
+    private final int high;
+    /** The current value. */
+    private int cursor;
+    /**
+     * Creates a iterator on the range.
+     * @param l low boundary
+     * @param h high boundary
+     */
+    public IntegerIterator(int l, int h) {
+        low = l;
+        high = h;
+        cursor = low;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return cursor <= high;
+    }
+
+    @Override
+    public Integer next() {
+        if (cursor <= high) {
+            int next = cursor;
+            cursor += 1;
+            return Integer.valueOf(next);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/IntegerRange.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Thu Jul  5 07:08:06 2012
@@ -40,6 +40,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTDivNode;
 import org.apache.commons.jexl3.parser.ASTEQNode;
 import org.apache.commons.jexl3.parser.ASTERNode;
+import org.apache.commons.jexl3.parser.ASTEWNode;
 import org.apache.commons.jexl3.parser.ASTEmptyFunction;
 import org.apache.commons.jexl3.parser.ASTEmptyMethod;
 import org.apache.commons.jexl3.parser.ASTFalseNode;
@@ -72,6 +73,8 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTSizeMethod;
 import org.apache.commons.jexl3.parser.ASTStringLiteral;
 import org.apache.commons.jexl3.parser.ASTSubNode;
+import org.apache.commons.jexl3.parser.ASTSWNode;
+import org.apache.commons.jexl3.parser.ASTRangeNode;
 import org.apache.commons.jexl3.parser.ASTTernaryNode;
 import org.apache.commons.jexl3.parser.ASTTrueNode;
 import org.apache.commons.jexl3.parser.ASTUnaryMinusNode;
@@ -322,17 +325,17 @@ public class Interpreter extends ParserV
 
     @Override
     protected Object visit(ASTArrayLiteral node, Object data) {
-        Object literal = node.getLiteral();
-        if (literal == null) {
-            int childCount = node.jjtGetNumChildren();
-            Object[] array = new Object[childCount];
+        int childCount = node.jjtGetNumChildren();
+        JexlArithmetic.ArrayBuilder ab = arithmetic.arrayBuilder(childCount);
+        if (ab != null) {
             for (int i = 0; i < childCount; i++) {
                 Object entry = node.jjtGetChild(i).jjtAccept(this, data);
-                array[i] = entry;
+                ab.add(entry);
             }
-            literal = arithmetic.narrowArrayType(array);
+            return ab.create();
+        } else {
+            return null;
         }
-        return literal;
     }
 
     @Override
@@ -500,10 +503,87 @@ public class Interpreter extends ParserV
     }
 
     @Override
-    protected Object visit(ASTERNode node, Object data) {
+    protected Object visit(ASTSWNode node, Object data) {
         Object left = node.jjtGetChild(0).jjtAccept(this, data);
         Object right = node.jjtGetChild(1).jjtAccept(this, data);
         try {
+            if (left == null || right == null) {
+                return false;
+            }
+            if (left instanceof String) {
+                return ((String) left).startsWith(arithmetic.toString(right));
+            } else {
+                // try a startsWith method (duck type)
+                try {
+                    Object[] argv = {right};
+                    JexlMethod vm = uberspect.getMethod(left, "startsWith", argv);
+                    if (vm != null) {
+                        return arithmetic.toBoolean(vm.invoke(left, argv)) ? Boolean.TRUE : Boolean.FALSE;
+                    } else if (arithmetic.narrowArguments(argv)) {
+                        vm = uberspect.getMethod(left, "startsWith", argv);
+                        if (vm != null) {
+                            return arithmetic.toBoolean(vm.invoke(left, argv)) ? Boolean.TRUE : Boolean.FALSE;
+                        }
+                    }
+                } catch (InvocationTargetException e) {
+                    throw new JexlException(node, "=^ invocation error", e.getCause());
+                } catch (Exception e) {
+                    throw new JexlException(node, "=^ error", e);
+                }
+            }
+            // defaults to equal
+            return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
+        } catch (ArithmeticException xrt) {
+            throw new JexlException(node, "=^ error", xrt);
+        }
+    }
+
+    @Override
+    protected Object visit(ASTEWNode node, Object data) {
+        Object left = node.jjtGetChild(0).jjtAccept(this, data);
+        Object right = node.jjtGetChild(1).jjtAccept(this, data);
+        try {
+            if (left == null || right == null) {
+                return false;
+            }
+            if (left instanceof String) {
+                return ((String) left).endsWith(arithmetic.toString(right));
+            } else {
+                // try a endsWith method (duck type)
+                try {
+                    Object[] argv = {right};
+                    JexlMethod vm = uberspect.getMethod(left, "endsWith", argv);
+                    if (vm != null) {
+                        return arithmetic.toBoolean(vm.invoke(left, argv)) ? Boolean.TRUE : Boolean.FALSE;
+                    } else if (arithmetic.narrowArguments(argv)) {
+                        vm = uberspect.getMethod(left, "endsWith", argv);
+                        if (vm != null) {
+                            return arithmetic.toBoolean(vm.invoke(left, argv)) ? Boolean.TRUE : Boolean.FALSE;
+                        }
+                    }
+                } catch (InvocationTargetException e) {
+                    throw new JexlException(node, "=$ invocation error", e.getCause());
+                } catch (Exception e) {
+                    throw new JexlException(node, "=$ error", e);
+                }
+                // defaults to equal
+                return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
+            }
+        } catch (ArithmeticException xrt) {
+            throw new JexlException(node, "=$ error", xrt);
+        }
+    }
+
+    /**
+     * The 'match'/'in' operator implementation.
+     * @param node the node
+     * @param op the calling operator, =~ or !=
+     * @param left the left operand
+     * @param right the right operand
+     * @return true if left matches right, false otherwise
+     */
+    protected Object matches(JexlNode node, String op, Object left, Object right) {
+        try {
             // use arithmetic / pattern matching ?
             if (right instanceof java.util.regex.Pattern || right instanceof String) {
                 return arithmetic.matches(left, right) ? Boolean.TRUE : Boolean.FALSE;
@@ -534,9 +614,9 @@ public class Interpreter extends ParserV
                     }
                 }
             } catch (InvocationTargetException e) {
-                throw new JexlException(node, "=~ invocation error", e.getCause());
+                throw new JexlException(node, op +" invocation error", e.getCause());
             } catch (Exception e) {
-                throw new JexlException(node, "=~ error", e);
+                throw new JexlException(node, op + " error", e);
             }
             // try iterative comparison
             Iterator<?> it = uberspect.getIterator(right);
@@ -552,11 +632,26 @@ public class Interpreter extends ParserV
             // defaults to equal
             return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
         } catch (ArithmeticException xrt) {
-            throw new JexlException(node, "=~ error", xrt);
+            throw new JexlException(node, op + " error", xrt);
         }
     }
 
     @Override
+    protected Object visit(ASTERNode node, Object data) {
+        Object left = node.jjtGetChild(0).jjtAccept(this, data);
+        Object right = node.jjtGetChild(1).jjtAccept(this, data);
+        return matches(node, "=~", left, right);
+    }
+
+    @Override
+    protected Object visit(ASTNRNode node, Object data) {
+        Object left = node.jjtGetChild(0).jjtAccept(this, data);
+        Object right = node.jjtGetChild(1).jjtAccept(this, data);
+        Object result = matches(node, "!~", left, right);
+        return arithmetic.toBoolean(result) ? Boolean.FALSE : Boolean.TRUE;
+    }
+
+    @Override
     protected Object visit(ASTIfStatement node, Object data) {
         int n = 0;
         try {
@@ -621,14 +716,28 @@ public class Interpreter extends ParserV
     @Override
     protected Object visit(ASTMapLiteral node, Object data) {
         int childCount = node.jjtGetNumChildren();
-        Map<Object, Object> map = new HashMap<Object, Object>();
-
-        for (int i = 0; i < childCount; i++) {
-            Object[] entry = (Object[]) (node.jjtGetChild(i)).jjtAccept(this, data);
-            map.put(entry[0], entry[1]);
+        JexlArithmetic.MapBuilder mb = arithmetic.mapBuilder(childCount);
+        if (mb != null) {
+            for (int i = 0; i < childCount; i++) {
+                Object[] entry = (Object[]) (node.jjtGetChild(i)).jjtAccept(this, data);
+                mb.put(entry[0], entry[1]);
+            }
+            return mb.create();
+        } else {
+            return null;
         }
+    }
 
-        return map;
+    @Override
+    protected Object visit(ASTRangeNode node, Object data) {
+        Object left = node.jjtGetChild(0).jjtAccept(this, data);
+        Object right = node.jjtGetChild(1).jjtAccept(this, data);
+        try {
+            return arithmetic.createRange(left, right);
+        } catch (ArithmeticException xrt) {
+            JexlNode xnode = findNullOperand(xrt, node, left, right);
+            throw new JexlException(xnode, ".. error", xrt);
+        }
     }
 
     @Override
@@ -671,62 +780,6 @@ public class Interpreter extends ParserV
     }
 
     @Override
-    protected Object visit(ASTNRNode node, Object data) {
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        try {
-            if (right instanceof java.util.regex.Pattern || right instanceof String) {
-                // use arithmetic / pattern matching
-                return arithmetic.matches(left, right) ? Boolean.FALSE : Boolean.TRUE;
-            }
-            // try contains on collection
-            if (right instanceof Set<?>) {
-                return ((Set<?>) right).contains(left) ? Boolean.FALSE : Boolean.TRUE;
-            }
-            // try contains on map key
-            if (right instanceof Map<?, ?>) {
-                return ((Map<?, ?>) right).containsKey(left) ? Boolean.FALSE : Boolean.TRUE;
-            }
-            // try contains on collection
-            if (right instanceof Collection<?>) {
-                return ((Collection<?>) right).contains(left) ? Boolean.FALSE : Boolean.TRUE;
-            }
-            // try a contains method (duck type set)
-            try {
-                Object[] argv = {left};
-                JexlMethod vm = uberspect.getMethod(right, "contains", argv);
-                if (vm != null) {
-                    return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE;
-                } else if (arithmetic.narrowArguments(argv)) {
-                    vm = uberspect.getMethod(right, "contains", argv);
-                    if (vm != null) {
-                        return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE;
-                    }
-                }
-            } catch (InvocationTargetException e) {
-                throw new JexlException(node, "!~ invocation error", e.getCause());
-            } catch (Exception e) {
-                throw new JexlException(node, "!~ error", e);
-            }
-            // try iterative comparison
-            Iterator<?> it = uberspect.getIterator(right);//, node.jjtGetChild(1));
-            if (it != null) {
-                while (it.hasNext()) {
-                    Object next = it.next();
-                    if (next == left || (next != null && next.equals(left))) {
-                        return Boolean.FALSE;
-                    }
-                }
-                return Boolean.TRUE;
-            }
-            // defaults to not equal
-            return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE;
-        } catch (ArithmeticException xrt) {
-            throw new JexlException(node, "!~ error", xrt);
-        }
-    }
-
-    @Override
     protected Object visit(ASTNotNode node, Object data) {
         Object val = node.jjtGetChild(0).jjtAccept(this, data);
         return arithmetic.toBoolean(val) ? Boolean.FALSE : Boolean.TRUE;

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java?rev=1357476&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java Thu Jul  5 07:08:06 2012
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.jexl3.JexlArithmetic;
+
+/**
+ * Helper class to create map literals.
+ */
+public class MapBuilder implements JexlArithmetic.MapBuilder {
+    /** The map being created. */
+    private final Map<Object, Object> map;
+
+    /**
+     * Creates a new builder.
+     * @param size the expected map size
+     */
+    public MapBuilder(int size) {
+        map = new HashMap<Object, Object>(size);
+    }
+
+    @Override
+    public void put(Object key, Object value) {
+        map.put(key, value);
+    }
+
+    @Override
+    public Object create() {
+        return map;
+    }
+
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/MapBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java Thu Jul  5 07:08:06 2012
@@ -103,7 +103,7 @@ public class Script implements JexlScrip
     @Override
     public String getParsedText() {
         Debugger debug = new Debugger();
-        boolean d = debug.debug(script);
+        debug.debug(script);
         return debug.toString();
     }
 
@@ -112,7 +112,7 @@ public class Script implements JexlScrip
         CharSequence src = source;
         if (src == null) {
             Debugger debug = new Debugger();
-            boolean d = debug.debug(script);
+            debug.debug(script);
             src = debug.toString();
         }
         return src == null ? "/*no source*/" : src.toString();

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ArrayListWrapper.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ArrayListWrapper.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ArrayListWrapper.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ArrayListWrapper.java Thu Jul  5 07:08:06 2012
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.RandomAccess;
 
 /**
  * A class that wraps an array within an AbstractList.
@@ -30,7 +31,7 @@ import java.util.ListIterator;
  * for any method is thus always ArrayListWrapper.
  * </p>
  */
-public class ArrayListWrapper extends AbstractList<Object> {
+public class ArrayListWrapper extends AbstractList<Object> implements RandomAccess {
     /** the array to wrap. */
     private final Object array;
 
@@ -115,7 +116,7 @@ public class ArrayListWrapper extends Ab
     public boolean contains(Object o) {
         return indexOf(o) != -1;
     }
-    
+
     @Override
     public boolean isEmpty() {
         return super.isEmpty();
@@ -125,7 +126,7 @@ public class ArrayListWrapper extends Ab
     public Iterator<Object> iterator() {
         return super.iterator();
     }
-    
+
     @Override
     public boolean containsAll(Collection<?> c) {
         return super.containsAll(c);
@@ -150,7 +151,7 @@ public class ArrayListWrapper extends Ab
     public List<Object> subList(int fromIndex, int toIndex) {
         return super.subList(fromIndex, toIndex);
     }
-    
+
     @Override
     public boolean add(Object o) {
         throw new UnsupportedOperationException("Not supported.");

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java Thu Jul  5 07:08:06 2012
@@ -29,9 +29,9 @@ import org.apache.commons.jexl3.introspe
  */
 public final class SandboxUberspect implements JexlUberspect {
     /** The base uberspect. */
-    protected final JexlUberspect uberspect;
+    private final JexlUberspect uberspect;
     /**  The sandbox. */
-    protected final JexlSandbox sandbox;
+    private final JexlSandbox sandbox;
 
     /**
      * A constructor for JexlSandbox uberspect.
@@ -127,7 +127,7 @@ public final class SandboxUberspect impl
         return null;
 
     }
-    
+
     /**
      * {@inheritDoc}
      */

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html Thu Jul  5 07:08:06 2012
@@ -311,7 +311,8 @@
 
         <h3><a name="dynamic_configuration">Dynamic Configuration</a></h3>
         <p>
-            Those configuration options can be overriden during evaluation by implementing a {@link org.apache.commons.jexl3.JexlContext}
+            Those configuration options can be overriden during evaluation by implementing a
+            {@link org.apache.commons.jexl3.JexlContext}
             that also implements {@link org.apache.commons.jexl3.JexlEngine$Options} to carry evaluation options.
             An example of such a class exists in the test package.
         </p>
@@ -346,12 +347,16 @@
         <p>
             {@link org.apache.commons.jexl3.JexlArithmetic}
             is the class to derive if you need to change how operators behave or add types upon which they
-            operate. For example, this would
-            be the case if you wanted '+' to operate on arrays; you'd need to derive JexlArithmetic and
-            implement your own version of Add.
-            Note however that you can not change the operator precedence.
-
+            operate.
+            For example, this would be the case if you wanted '+' to operate on arrays; you'd need to derive
+            JexlArithmetic and implement your own version of Add.
+
+            There are 3 entry points that allow customizing the type of objects created for respectively
+            array literals {@link org.apache.commons.jexl3.JexlArithmetic#arrayBuilder},
+            map literals {@link org.apache.commons.jexl3.JexlArithmetic#mapBuilder}
+            and range objects {@link org.apache.commons.jexl3.JexlArithmetic#createRange}.
 
+            Note however that you can <em>not</em> change the operator precedence.
         </p>
 
         <h2><a name="extension">Extending JEXL</a></h2>

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java Thu Jul  5 07:08:06 2012
@@ -16,12 +16,9 @@
  */
 package org.apache.commons.jexl3.parser;
 
-import org.apache.commons.jexl3.JexlArithmetic;
 import org.apache.commons.jexl3.internal.Debugger;
 
-public final class ASTArrayLiteral extends JexlNode implements JexlNode.Literal<Object> {
-    /** The type literal value. */
-    private Object array = null;
+public final class ASTArrayLiteral extends JexlNode {
     /** Whether this array is constant or not. */
     private boolean constant = false;
 
@@ -40,31 +37,29 @@ public final class ASTArrayLiteral exten
     }
 
     @Override
-    public Object getLiteral() {
-        return array;
+    protected boolean isConstant(boolean literal) {
+        return constant;
     }
 
-    /** {@inheritDoc} */
+    /** {
+     * @inheritDoc} */
     @Override
     public void jjtClose() {
-        if (children == null || children.length == 0) {
-            array = new Object[0];
-            constant = true;
-        } else {
-            constant = isConstant();
-            if (constant) {
-                Object[] cc = new Object[children.length];
-                for(int c = 0; c < children.length; ++c) {
-                    cc[c] = ((JexlNode.Literal<?>) children[c]).getLiteral();
+        constant = true;
+        if (children != null) {
+            for (int c = 0; c < children.length && constant; ++c) {
+                JexlNode child = children[c];
+                if (child instanceof ASTReference) {
+                    constant = child.isConstant(true);
+                } else if (!child.isConstant()) {
+                    constant = false;
                 }
-                array = JexlArithmetic.typeArray(cc);
-            } else {
-                array = null;
             }
         }
     }
 
-    /** {@inheritDoc} */
+    /** {
+     * @inheritDoc} */
     @Override
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTMapLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTMapLiteral.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTMapLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTMapLiteral.java Thu Jul  5 07:08:06 2012
@@ -16,13 +16,9 @@
  */
 package org.apache.commons.jexl3.parser;
 
-import java.util.Collections;
-import java.util.Map;
 import org.apache.commons.jexl3.internal.Debugger;
 
-public final class ASTMapLiteral extends JexlNode implements JexlNode.Literal<Object> {
-    /** The type literal value. */
-    private Map<?,?> map = null;
+public final class ASTMapLiteral extends JexlNode {
     /** Whether this array is constant or not. */
     private boolean constant = false;
 
@@ -34,7 +30,6 @@ public final class ASTMapLiteral extends
         super(p, id);
     }
 
-
     @Override
     public String toString() {
         Debugger dbg = new Debugger();
@@ -42,21 +37,23 @@ public final class ASTMapLiteral extends
     }
 
     @Override
-    public Map<?,?> getLiteral() {
-        return map;
+    protected boolean isConstant(boolean literal) {
+        return constant;
     }
 
-    /**
-     * Sets the literal value only if the descendants of this node compose a constant.
-     * @param literal the literal array value
-     * @throws IllegalArgumentException if literal is not an array or null
-     */
-    void setLiteral(Object literal) {
-        if (constant) {
-            if (!(literal instanceof Map<?,?>)) {
-                throw new IllegalArgumentException(literal.getClass() + " is not a map");
+    /** {@inheritDoc} */
+    @Override
+    public void jjtClose() {
+        constant = true;
+        if (children != null) {
+            for (int c = 0; c < children.length && constant; ++c) {
+                JexlNode child = children[c];
+                if (child instanceof ASTMapEntry) {
+                    constant = child.isConstant(true);
+                } else if (!child.isConstant()) {
+                    constant = false;
+                }
             }
-            this.map = (Map<?,?>) literal;
         }
     }
 
@@ -66,14 +63,4 @@ public final class ASTMapLiteral extends
         return visitor.visit(this, data);
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public void jjtClose() {
-        if (children == null || children.length == 0) {
-            map = Collections.EMPTY_MAP;
-            constant = true;
-        } else {
-            constant = isConstant();
-        }
-    }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java Thu Jul  5 07:08:06 2012
@@ -18,8 +18,9 @@ package org.apache.commons.jexl3.parser;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.text.DecimalFormat;
 
-public final class ASTNumberLiteral extends JexlNode implements JexlNode.Literal<Number> {
+public final class ASTNumberLiteral extends JexlNode implements JexlNode.Constant<Number> {
     /** The type literal value. */
     private Number literal = null;
     /** The expected class. */
@@ -33,23 +34,29 @@ public final class ASTNumberLiteral exte
         super(p, id);
     }
 
+    static final DecimalFormat BIGDF = new DecimalFormat("0.0b");
+
     @Override
     public String toString() {
-        StringBuilder strb = new StringBuilder(literal.toString());
-        if (clazz != null) {
-            if (Float.class.equals(clazz)) {
-                strb.append('f');
-            } else if (Double.class.equals(clazz)) {
-                strb.append('d');
-            } else if (BigDecimal.class.equals(clazz)) {
-                strb.append('b');
-            } else if (BigInteger.class.equals(clazz)) {
-                strb.append('h');
-            } else if (Long.class.equals(clazz)) {
-                strb.append('l');
+        if (BigDecimal.class.equals(clazz)) {
+              return BIGDF.format(literal);
+        } else {
+            StringBuilder strb = new StringBuilder(literal.toString());
+            if (clazz != null) {
+                if (Float.class.equals(clazz)) {
+                    strb.append('f');
+                } else if (Double.class.equals(clazz)) {
+                    strb.append('d');
+                } else if (BigDecimal.class.equals(clazz)) {
+                    strb.append('b');
+                } else if (BigInteger.class.equals(clazz)) {
+                    strb.append('h');
+                } else if (Long.class.equals(clazz)) {
+                    strb.append('l');
+                }
             }
+            return strb.toString();
         }
-        return strb.toString();
     }
 
     @Override
@@ -57,7 +64,6 @@ public final class ASTNumberLiteral exte
         return literal;
     }
 
-    /** {@inheritDoc} */
     @Override
     protected boolean isConstant(boolean literal) {
         return true;
@@ -127,43 +133,47 @@ public final class ASTNumberLiteral exte
      * Originally from OGNL.
      * @param s the real as string
      */
-     void setReal(String s) {
+    void setReal(String s) {
         Number result;
         Class<?> rclass;
-        final int last = s.length() - 1;
-        switch (s.charAt(last)) {
-            case 'b':
-            case 'B': {
-                rclass = BigDecimal.class;
-                result = new BigDecimal(s.substring(0, last));
-                break;
-            }
-            case 'f':
-            case 'F': {
-                rclass = Float.class;
-                result = Float.valueOf(s.substring(0, last));
-                break;
-            }
-            case 'd':
-            case 'D':
-                rclass = Double.class;
-                result = Double.valueOf(s.substring(0, last));
-                break;
-            default: {
-                rclass = Double.class;
-                try {
-                    result = Double.valueOf(s);
-                } catch (NumberFormatException take3) {
-                    result = new BigDecimal(s);
+        if ("#NaN".equals(s)) {
+            result = Double.NaN;
+            rclass = Double.class;
+        } else {
+            final int last = s.length() - 1;
+            switch (s.charAt(last)) {
+                case 'b':
+                case 'B': {
+                    rclass = BigDecimal.class;
+                    result = new BigDecimal(s.substring(0, last));
+                    break;
+                }
+                case 'f':
+                case 'F': {
+                    rclass = Float.class;
+                    result = Float.valueOf(s.substring(0, last));
+                    break;
+                }
+                case 'd':
+                case 'D':
+                    rclass = Double.class;
+                    result = Double.valueOf(s.substring(0, last));
+                    break;
+                default: {
+                    rclass = Double.class;
+                    try {
+                        result = Double.valueOf(s);
+                    } catch (NumberFormatException take3) {
+                        result = new BigDecimal(s);
+                    }
+                    break;
                 }
-                break;
             }
         }
         literal = result;
         clazz = rclass;
     }
 
-    /** {@inheritDoc} */
     @Override
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTStringLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTStringLiteral.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTStringLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTStringLiteral.java Thu Jul  5 07:08:06 2012
@@ -16,7 +16,7 @@
  */
 package org.apache.commons.jexl3.parser;
 
-public final class ASTStringLiteral extends JexlNode implements JexlNode.Literal<String> {
+public final class ASTStringLiteral extends JexlNode implements JexlNode.Constant<String> {
 
     ASTStringLiteral(int id) {
         super(id);
@@ -46,7 +46,7 @@ public final class ASTStringLiteral exte
     protected boolean isConstant(boolean literal) {
         return true;
     }
-    
+
     void setLiteral(String literal) {
         value = literal;
     }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java Thu Jul  5 07:08:06 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.jexl3.parser;
 
+import org.apache.commons.jexl3.JexlException;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.introspection.JexlMethod;
 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
@@ -28,11 +29,10 @@ import org.apache.commons.jexl3.introspe
  */
 public abstract class JexlNode extends SimpleNode {
     /**
-     * A marker interface for literals.
-     *
+     * A marker interface for constants.
      * @param <T> the literal type
      */
-    public interface Literal<T> {
+    public interface Constant<T> {
         T getLiteral();
     }
 
@@ -84,8 +84,8 @@ public abstract class JexlNode extends S
      *
      * @return true if constant, false otherwise
      */
-    public final boolean isConstant() {
-        return isConstant(this instanceof JexlNode.Literal<?>);
+    public boolean isConstant() {
+        return isConstant(this instanceof JexlNode.Constant<?>);
     }
 
     protected boolean isConstant(boolean literal) {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java Thu Jul  5 07:08:06 2012
@@ -16,6 +16,9 @@
  */
 package org.apache.commons.jexl3.parser;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
 import org.apache.commons.jexl3.JexlException;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.internal.Scope;
@@ -26,6 +29,10 @@ import java.util.Stack;
  * The base class for parsing, manages the parameter/local variable frame.
  */
 public abstract class JexlParser extends StringParser {
+    /** Whether the parser will allow user-named registers (aka #0 syntax). */
+    protected boolean ALLOW_REGISTERS = false;
+    /** The source being processed. */
+    protected String source = null;
     /**
      * The map of named registers aka script parameters.
      * <p>Each parameter is associated to a register and is materialized
@@ -34,6 +41,14 @@ public abstract class JexlParser extends
     protected Scope frame = null;
     protected Stack<Scope> frames = new Stack<Scope>();
 
+
+    /**
+     * Internal, for debug purpose only.
+     */
+    public void allowRegisters(boolean registers) {
+        ALLOW_REGISTERS = registers;
+    }
+    
     /**
      * Sets the frame to use by this parser.
      * <p> This is used to allow parameters to be declared before parsing. </p>
@@ -77,7 +92,7 @@ public abstract class JexlParser extends
     /**
      * Checks whether an identifier is a local variable or argument, ie a symbol, stored in a register.
      * @param identifier the identifier
-     * @param image the identifier image
+     * @param image      the identifier image
      * @return the image
      */
     public String checkVariable(ASTIdentifier identifier, String image) {
@@ -94,7 +109,7 @@ public abstract class JexlParser extends
      * Declares a local variable.
      * <p> This method creates an new entry in the symbol map. </p>
      * @param identifier the identifier used to declare
-     * @param image the variable name
+     * @param image      the variable name
      */
     public void declareVariable(ASTVar identifier, String image) {
         if (frame == null) {
@@ -150,27 +165,48 @@ public abstract class JexlParser extends
                 script.setScope(frame);
             }
             popFrame();
-        } else if (node instanceof ASTAmbiguous && node.jjtGetNumChildren() > 0) {
-            final JexlInfo dbgInfo;
-            Token tok = this.getToken(0);
-            if (tok != null) {
-                dbgInfo = new JexlInfo(tok.image, tok.beginLine, tok.beginColumn);
-            } else {
-                dbgInfo = node.jexlInfo();
-            }
-            throw new JexlException.Parsing(dbgInfo, "Ambiguous statement, missing ';' between expressions");
+        } else if (node instanceof ASTAmbiguous) {
+            throwParsingException(JexlException.Ambiguous.class, node);
         } else if (node instanceof ASTAssignment) {
             JexlNode lv = node.jjtGetChild(0);
             if (!lv.isLeftValue()) {
-                final JexlInfo dbgInfo;
-                Token tok = this.getToken(0);
-                if (tok != null) {
-                    dbgInfo = new JexlInfo(tok.image, tok.beginLine, tok.beginColumn);
-                } else {
-                    dbgInfo = node.jexlInfo();
+                throwParsingException(JexlException.Assignment.class, lv);
+            }
+        }
+    }
+
+    /**
+     * Throws a parsing exception.
+     * @param xclazz the class of exception
+     * @param node the node that provoqued it
+     */
+    private void throwParsingException(Class<? extends JexlException> xclazz, JexlNode node) {
+        final JexlInfo dbgInfo;
+        Token tok = this.getToken(0);
+        if (tok != null) {
+            dbgInfo = new JexlInfo(tok.image, tok.beginLine, tok.beginColumn);
+        } else {
+            dbgInfo = node.jexlInfo();
+        }
+        String msg = null;
+        try {
+            if (source != null) {
+                BufferedReader reader = new BufferedReader(new StringReader(source));
+                for (int l = 0; l < dbgInfo.getLine(); ++l) {
+                    msg = reader.readLine();
                 }
-                throw new JexlException.Parsing(dbgInfo, "Invalid assignment expression");
+            } else {
+                msg = "";
             }
+        } catch (IOException xio) {
+            // ignore
+        }
+        if (JexlException.Ambiguous.class.equals(xclazz)) {
+            throw new JexlException.Ambiguous(dbgInfo, msg);
+        }
+        if (JexlException.Assignment.class.equals(xclazz)) {
+            throw new JexlException.Assignment(dbgInfo, msg);
         }
+        throw new JexlException.Parsing(dbgInfo, msg);
     }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Thu Jul  5 07:08:06 2012
@@ -38,16 +38,15 @@ import org.apache.commons.jexl3.internal
 
 public final class Parser extends JexlParser
 {
-    private boolean ALLOW_REGISTERS = false;
-
-    public ASTJexlScript parse(JexlInfo info, Reader reader, Scope scope, boolean registers) {
+    public ASTJexlScript parse(JexlInfo info, String jexlSrc, Scope scope, boolean registers) {
         try {
             // If registers are allowed, the default parser state has to be REGISTERS.
             if (registers || ALLOW_REGISTERS) {
                 token_source.defaultLexState = REGISTERS;
             }
             // lets do the 'Unique Init' in here to be safe - it's a pain to remember
-            ReInit(reader);
+            source = jexlSrc;
+            ReInit(new java.io.StringReader(jexlSrc));
             frame = scope;
             ASTJexlScript script = JexlScript(scope);
             script.value = info;
@@ -57,18 +56,11 @@ public final class Parser extends JexlPa
         } catch (ParseException xparse) {
             throw new JexlException.Parsing(info, xparse).clean();
         } finally {
+            source = null;
             frame = null;
             token_source.defaultLexState = DEFAULT;
         }
     }
-
-    /**
-     * Internal, for debug purpose only.
-     */
-    public void allowRegisters(boolean registers) {
-        ALLOW_REGISTERS = registers;
-    }
-
 }
 
 PARSER_END(Parser)
@@ -139,6 +131,8 @@ PARSER_END(Parser)
     | < ne : "!=" | "ne" >
     | < req : "=~" >
     | < rne : "!~" >
+    | < sw : "=^" >
+    | < ew : "=$" >
     | < gt : ">" | "gt" >
     | < ge : ">=" | "ge" >
     | < lt : "<" | "lt" >
@@ -157,6 +151,7 @@ PARSER_END(Parser)
     | < and : "&" >
     | < or : "|" >
     | < xor : "^" >
+    | < range : ".." >
 }
 
 /***************************************
@@ -184,7 +179,10 @@ PARSER_END(Parser)
         (["l","L","h","H"])?
     >
  |
-  < FLOAT_LITERAL: (<DIGIT>)+ "." (<DIGIT>)+ ((["e","E"])(["+","-"])?(<DIGIT>)+)? (["d","D","f","F","b","B"])? >
+  < FLOAT_LITERAL:
+    "#NaN"
+    |
+    (<DIGIT>)+ "." (<DIGIT>)+ ((["e","E"])(["+","-"])?(<DIGIT>)+)? (["d","D","f","F","b","B"])? >
 }
 
 <*> TOKEN :
@@ -338,8 +336,10 @@ void EqualityExpression() #void : {}
   RelationalExpression()
   (
      <eq> RelationalExpression() #EQNode(2)
-|
+   |
      <ne> RelationalExpression() #NENode(2)
+   |
+     <range> RelationalExpression() #RangeNode(2) // range
   )?
 }
 
@@ -358,6 +358,10 @@ void RelationalExpression() #void : {}
     <req> AdditiveExpression() #ERNode(2) // equals regexp
    |
     <rne> AdditiveExpression() #NRNode(2) // not equals regexp
+   |
+    <sw> AdditiveExpression() #SWNode(2) // starts with
+   |
+    <ew> AdditiveExpression() #EWNode(2) // ends with
   )?
 }
 

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java Thu Jul  5 07:08:06 2012
@@ -85,6 +85,10 @@ public abstract class ParserVisitor {
 
     protected abstract Object visit(ASTNRNode node, Object data);
 
+    protected abstract Object visit(ASTSWNode node, Object data);
+
+    protected abstract Object visit(ASTEWNode node, Object data);
+
     protected abstract Object visit(ASTAddNode node, Object data);
 
     protected abstract Object visit(ASTSubNode node, Object data);
@@ -115,6 +119,8 @@ public abstract class ParserVisitor {
 
     protected abstract Object visit(ASTArrayLiteral node, Object data);
 
+    protected abstract Object visit(ASTRangeNode node, Object data);
+
     protected abstract Object visit(ASTMapLiteral node, Object data);
 
     protected abstract Object visit(ASTMapEntry node, Object data);

Modified: commons/proper/jexl/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/changes.xml?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Thu Jul  5 07:08:06 2012
@@ -2,22 +2,22 @@
 
 <!--
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
 
 <document>
     <properties>
@@ -25,7 +25,13 @@
         <author email="dev@commons.apache.org">Commons Developers</author>
     </properties>
     <body>
-        <release version="3.0" date="2012-06-01">
+        <release version="3.0" date="2012-07-30">
+            <action dev="henrib" type="add" issue="JEXL-131" due-to="Alfred Reibenschuh">
+                String matching Operator short-hand inspired by CSS3
+            </action>
+            <action dev="henrib" type="add" >
+                Range operator
+            </action>
             <action dev="henrib" type="add" issue="JEXL-128" due-to="Matteo Trotta">
                 ObjectContext should implement NamespaceResolver
             </action>
@@ -39,7 +45,10 @@
                 Move JEXL from org.apache.comms.jexl2 to org.apache.commons.jexl3
             </action>
         </release>
-        <release version="2.1.2" date="2012-05-30">
+        <release version="2.1.2" date="2012-07-30">
+            <action dev="henrib" type="fix" issue="JEXL-134" due-to="Manoj Mokashi">
+                Issue with evaluation of concat of variables : \r + \n gives 0
+            </action>
             <action dev="henrib" type="fix" issue="JEXL-131" due-to="Clay Bruce">
                 UnifiedJexl parsing may fail with NPE
             </action>

Modified: commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml?rev=1357476&r1=1357475&r2=1357476&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml Thu Jul  5 07:08:06 2012
@@ -327,7 +327,7 @@
             Those variables values are bound in the function environment at definition time.</p>
             <code>var t = 20; var s = function(x, y) {x + y + t}; t = 54; s(15, 7)</code>
             The function closure hoists 't' when defined; the result of the evaluation will
-            lead to <code>15 +7 + 20 = 42</code>. 
+            lead to <code>15 +7 + 20 = 42</code>.
           </td>
         </tr>
       </table>
@@ -485,12 +485,40 @@
             For example
             <code>"abcdef" !~ "abc.*</code> returns <code>false</code>.
             It also checks whether any collection, set or map (on keys) does not contain a value; in that case, it behaves
-            as "not in" operator. Note that it also applies to arrays as well as "duck-typed" collection, ie classes exposing a "contains"
-            method.
+            as "not in" operator.
             <code> "a" !~ ["a","b","c","d","e",f"]</code> returns <code>true</code>.
+            Note that through duck-typing, user classes exposing a public 'contains' method will allow their instances
+            to behave has right-hand-size operands of this operator.
+          </td>
+        </tr>
+        <tr>
+          <td>Starts With<code>=^</code></td>
+          <td>
+            The syntactically CSS3 inspired <code>=^</code> operator is a short-hand for the 'startsWith' method.
+            For example,
+            <code> "abcdef" ^= "abc" </code> returns <code>true</code>.
+            Note that through duck-typing, user classes exposing a public 'startsWith' method will allow their instances
+            to behave has left-hand-size operands of this operator.
           </td>
         </tr>
         <tr>
+          <td>Ends With<code>=$</code></td>
+          <td>The syntactically CSS3 inspired <code>=$</code> operator is a short-hand for the 'endsWith' method.
+            For example,
+            <code> "abcdef" $= "def" </code> returns <code>true</code>.
+            Note that through duck-typing, user classes exposing an 'endsWith' method will allow their instances
+            to behave has left-hand-size operands of this operator.
+          </td>
+        </tr>
+        <tr>
+            <td>Range<code>..</code></td>
+            <td>
+                This operator creates a 'range' of values (in the form of a java iterable).
+                For example,
+                <code>for(var x: 1 .. 3) {}</code> will loop 3 times with the value of 'x' being 1, 2 and 3.
+            </td>
+        </tr>
+        <tr>
           <td>Addition</td>
           <td>
             The usual <code>+</code> operator is used.
@@ -579,7 +607,7 @@
           <td>
             Loop through items of an Array, Collection, Map, Iterator or Enumeration, e.g.
             <source>for(item : list) {
-    x = x + item; 
+    x = x + item;
 }</source>
             Where <code>item</code> and <code>list</code> are variables.
             The JEXL 1.1 syntax using <code>foreach(item in list)</code> is now <strong>deprecated</strong>.
@@ -590,7 +618,7 @@
           <td>
             Loop until a condition is satisfied, e.g.
             <source>while (x lt 10) {
-    x = x + 2; 
+    x = x + 2;
 }</source>
           </td>
         </tr>