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 2015/03/10 14:46:45 UTC

svn commit: r1665548 - 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/parser/ site/xdoc/reference/ test/java/org/apache/commons/jexl3/

Author: henrib
Date: Tue Mar 10 13:46:44 2015
New Revision: 1665548

URL: http://svn.apache.org/r1665548
Log:
JEXL:
Adding pragmas and set literals;
Various small fixes

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/SetBuilder.java   (with props)
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTSetLiteral.java   (with props)
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/NumberParser.java   (with props)
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java   (with props)
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java   (with props)
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/JexlScript.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/Scope.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/parser/ASTJexlScript.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/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/reference/syntax.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/LambdaTest.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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -267,6 +267,33 @@ public class JexlArithmetic {
     }
 
     /**
+     * Helper interface used when creating a set literal.
+     * <p>The default implementation creates a java.util.HashSet.</p>
+     */
+    public interface SetBuilder {
+        /**
+         * Adds a literal to the set.
+         * @param value the item to add
+         */
+        void add(Object value);
+
+        /**
+         * Creates the actual "set" 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 SetBuilder setBuilder(int size) {
+        return new org.apache.commons.jexl3.internal.SetBuilder(size);
+    }
+
+    /**
      * Helper interface used when creating a map literal.
      * <p>The default implementation creates a java.util.HashMap.</p>
      */

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
@@ -42,7 +43,7 @@ public interface JexlScript {
      * @return the source text
      */
     String getParsedText();
-    
+
     /**
      * Executes the script with the variables contained in the
      * supplied {@link JexlContext}.
@@ -90,6 +91,12 @@ public interface JexlScript {
     Set<List<String>> getVariables();
 
     /**
+     * Gets this script pragmas
+     * @return the pragmas map
+     */
+    Map<String, Object> getPragmas();
+
+    /**
      * Creates a Callable from this script.
      * <p>This allows to submit it to an executor pool and provides support for asynchronous calls.</p>
      * <p>The interpreter will handle interruption/cancellation gracefully if needed.</p>

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -70,6 +70,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTReferenceExpression;
 import org.apache.commons.jexl3.parser.ASTReturnStatement;
 import org.apache.commons.jexl3.parser.ASTSWNode;
+import org.apache.commons.jexl3.parser.ASTSetLiteral;
 import org.apache.commons.jexl3.parser.ASTSizeFunction;
 import org.apache.commons.jexl3.parser.ASTSizeMethod;
 import org.apache.commons.jexl3.parser.ASTStringLiteral;
@@ -643,6 +644,21 @@ public final class Debugger extends Pars
         return data;
     }
 
+    @Override
+    protected Object visit(ASTSetLiteral node, Object data) {
+        int num = node.jjtGetNumChildren();
+        builder.append("{ ");
+        if (num > 0) {
+            accept(node.jjtGetChild(0), data);
+            for (int i = 1; i < num; ++i) {
+                builder.append(",");
+                accept(node.jjtGetChild(i), data);
+            }
+        }
+        builder.append(" }");
+        return data;
+    }
+
     @Override
     protected Object visit(ASTMapLiteral node, Object data) {
         int num = node.jjtGetNumChildren();

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -493,14 +493,13 @@ public class Engine extends JexlEngine {
             xjexl = xany;
         } catch (Exception xany) {
             xjexl = new JexlException.Method(info, clazz.toString(), xany);
-        } finally {
-            if (xjexl != null) {
-                if (silent) {
-                    logger.warn(xjexl.getMessage(), xjexl.getCause());
-                    return null;
-                }
-                throw xjexl.clean();
+        }
+        if (xjexl != null) {
+            if (silent) {
+                logger.warn(xjexl.getMessage(), xjexl.getCause());
+                return null;
             }
+            throw xjexl.clean();
         }
         return result;
     }
@@ -513,9 +512,9 @@ public class Engine extends JexlEngine {
      * @return the set of variables, each as a list of strings (ant-ish variables use more than 1 string)
      *         or the empty set if no variables are used
      */
-    protected Set<List<String>> getVariables(JexlNode script) {
+    protected Set<List<String>> getVariables(ASTJexlScript script) {
         VarCollector collector = new VarCollector();
-        getVariables(script, collector);
+        getVariables(script, script, collector);
         return collector.collected();
     }
 
@@ -526,7 +525,7 @@ public class Engine extends JexlEngine {
         /**
          * The collected variables represented as a set of list of strings.
          */
-        private Set<List<String>> refs = new LinkedHashSet<List<String>>();
+        private final Set<List<String>> refs = new LinkedHashSet<List<String>>();
         /**
          * The current variable being collected.
          */
@@ -576,7 +575,7 @@ public class Engine extends JexlEngine {
      * @param node the node
      * @param collector the variable collector
      */
-    protected void getVariables(JexlNode node, VarCollector collector) {
+    protected void getVariables(final ASTJexlScript script, JexlNode node, VarCollector collector) {
         if (node instanceof ASTIdentifier) {
             JexlNode parent = node.jjtGetParent();
             if (parent instanceof ASTMethodNode || parent instanceof ASTFunctionNode) {
@@ -585,12 +584,14 @@ public class Engine extends JexlEngine {
                 return;
             }
             ASTIdentifier identifier = (ASTIdentifier) node;
-            if (identifier.getSymbol() < 0) {
+            int symbol = identifier.getSymbol();
+            // symbols that are hoisted are considered "global" variables
+            if (symbol >= 0 && script != null && !script.isHoistedSymbol(symbol)) {
+                collector.collect(null);
+            } else {
                 // start collecting from identifier
                 collector.collect(identifier);
                 collector.add(identifier.getName());
-            } else {
-                collector.collect(null);
             }
         } else if (node instanceof ASTIdentifierAccess) {
             JexlNode parent = node.jjtGetParent();
@@ -618,13 +619,13 @@ public class Engine extends JexlEngine {
                 } else {
                     collecting = false;
                     collector.collect(null);
-                    getVariables(child, collector);
+                    getVariables(script, child, collector);
                 }
             }
         } else {
             int num = node.jjtGetNumChildren();
             for (int i = 0; i < num; ++i) {
-                getVariables(node.jjtGetChild(i), collector);
+                getVariables(script, node.jjtGetChild(i), collector);
             }
             collector.collect(null);
         }

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -76,6 +76,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTReferenceExpression;
 import org.apache.commons.jexl3.parser.ASTReturnStatement;
 import org.apache.commons.jexl3.parser.ASTSWNode;
+import org.apache.commons.jexl3.parser.ASTSetLiteral;
 import org.apache.commons.jexl3.parser.ASTSizeFunction;
 import org.apache.commons.jexl3.parser.ASTSizeMethod;
 import org.apache.commons.jexl3.parser.ASTStringLiteral;
@@ -939,6 +940,21 @@ public class Interpreter extends ParserV
     }
 
     @Override
+    protected Object visit(ASTSetLiteral node, Object data) {
+        int childCount = node.jjtGetNumChildren();
+        JexlArithmetic.SetBuilder mb = arithmetic.setBuilder(childCount);
+        if (mb != null) {
+            for (int i = 0; i < childCount; i++) {
+                Object entry = node.jjtGetChild(i).jjtAccept(this, data);
+                mb.add(entry);
+            }
+            return mb.create();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
     protected Object visit(ASTMapLiteral node, Object data) {
         int childCount = node.jjtGetNumChildren();
         JexlArithmetic.MapBuilder mb = arithmetic.mapBuilder(childCount);
@@ -1368,7 +1384,7 @@ public class Interpreter extends ParserV
         Object object = null;
         JexlNode objectNode;
         StringBuilder variableName = null;
-        boolean isVariable = !(parent instanceof ASTReference);
+        boolean antish = !(parent instanceof ASTReference);
         int v = 0;
         main:
         for (int c = 0; c < numChildren; c++) {
@@ -1381,9 +1397,15 @@ public class Interpreter extends ParserV
             }
             // attempt to evaluate the property within the object
             object = objectNode.jjtAccept(this, object);
-            if (object == null && isVariable) {
+            if (object == null && antish) {
                 // if we still have a null object and we are evaluating 'x.y', check for an antish variable
                 if (v == 0) {
+                    // if the first node is a local variable or parameter, the object can not be null
+                    JexlNode first = node.jjtGetChild(0);
+                    if (first instanceof ASTIdentifier && ((ASTIdentifier) first).getSymbol() >= 0) {
+                        antish = false;
+                        break main;
+                    }
                     // first node must be an Identifier
                     if (objectNode instanceof ASTIdentifier) {
                         variableName = new StringBuilder(((ASTIdentifier) objectNode).getName());
@@ -1406,9 +1428,9 @@ public class Interpreter extends ParserV
                 // variableName can *not* be null; the code before this line made sure of that
                 object = context.get(variableName.toString());
             }
-            isVariable &= object == null;
+            antish &= object == null;
         }
-        if (object == null && isVariable && variableName != null && !isTernaryProtected(node)) {
+        if (object == null && antish && variableName != null && !isTernaryProtected(node)) {
             boolean undefined = !(context.has(variableName.toString()) || isLocalVariable(node, 0));
             // variable unknown in context and not a local
             return unsolvableVariable(node, variableName.toString(), undefined);
@@ -1457,7 +1479,7 @@ public class Interpreter extends ParserV
         }
         // 1: follow children till penultimate, resolve dot/array
         JexlNode objectNode = null;
-        boolean isVariable = true;
+        boolean antish = true;
         int v = 0;
         StringBuilder variableName = null;
         // start at 1 if symbol
@@ -1469,29 +1491,35 @@ public class Interpreter extends ParserV
             object = objectNode.jjtAccept(this, object);
             if (object != null) {
                 // disallow mixing antish variable & bean with same root; avoid ambiguity
-                isVariable = false;
+                antish = false;
                 continue;
             }
             // if we still have a null object, check for an antish variable
-            if (isVariable) {
+            if (antish) {
                 if (v == 0) {
+                    // if the first node is a local variable or parameter, the object can not be null
+                    JexlNode first = left.jjtGetChild(0);
+                    if (first instanceof ASTIdentifier && ((ASTIdentifier) first).getSymbol() >= 0) {
+                        antish = false;
+                        break;
+                    }
                     if (objectNode instanceof ASTIdentifier) {
                         variableName = new StringBuilder(((ASTIdentifier) objectNode).getName());
                         v = 1;
                     } else {
-                        isVariable = false;
+                        antish = false;
                     }
                 }
-                for (; isVariable && v <= c; ++v) {
+                for (; antish && v <= c; ++v) {
                     JexlNode child = left.jjtGetChild(v);
                     if (child instanceof ASTIdentifierAccess) {
                         variableName.append('.');
                         variableName.append(((ASTIdentifierAccess) objectNode).getName());
                     } else {
-                        isVariable = false;
+                        antish = false;
                     }
                 }
-                if (isVariable) {
+                if (antish) {
                     object = context.get(variableName.toString());
                 } else {
                     break;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java Tue Mar 10 13:46:44 2015
@@ -129,6 +129,15 @@ public final class Scope {
     }
 
     /**
+     * Checks whether a given symbol is hoisted.
+     * @param symbol the symbol number
+     * @return true if hoisted, false otherwise
+     */
+    public boolean isHoistedSymbol(int symbol) {
+        return hoistedVariables != null && hoistedVariables.containsKey(symbol);
+    }
+
+    /**
      * Declares a parameter.
      * <p>
      * This method creates an new entry in the symbol map.
@@ -246,15 +255,16 @@ public final class Scope {
     }
 
     /**
-     * Gets this script local variable, i.e. symbols assigned to local variables.
+     * Gets this script local variable, i.e. symbols assigned to local variables excluding hoisted variables.
      * @return the local variable names
      */
     public String[] getLocalVariables() {
         if (namedVariables != null && vars > 0) {
-            String[] pa = new String[parms];
+            String[] pa = new String[parms - (hoistedVariables == null? 0 : hoistedVariables.size())];
             int p = 0;
             for (Map.Entry<String, Integer> entry : namedVariables.entrySet()) {
-                if (entry.getValue().intValue() >= parms) {
+                int symnum = entry.getValue().intValue();
+                if (symnum >= parms && (hoistedVariables == null || !hoistedVariables.containsKey(symnum))) {
                     pa[p++] = entry.getKey();
                 }
             }

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -22,6 +22,7 @@ import org.apache.commons.jexl3.JexlExpr
 import org.apache.commons.jexl3.parser.ASTJexlScript;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
@@ -172,6 +173,16 @@ public class Script implements JexlScrip
     }
 
     /**
+     * Get this script pragmas
+     * <p>Pragma keys are ant-ish variables, their values are scalar literals..
+     * @return the pragmas
+     */
+    @Override
+    public Map<String, Object> getPragmas() {
+        return script.getPragmas();
+    }
+
+    /**
      * Creates a Callable from this script.
      * <p>This allows to submit it to an executor pool and provides support for asynchronous calls.</p>
      * <p>The interpreter will handle interruption/cancellation gracefully if needed.</p>

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/SetBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/SetBuilder.java?rev=1665548&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/SetBuilder.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/SetBuilder.java Tue Mar 10 13:46:44 2015
@@ -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 org.apache.commons.jexl3.JexlArithmetic;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Helper class to create set literals.
+ */
+public class SetBuilder implements JexlArithmetic.SetBuilder {
+    /** The set being created. */
+    private final Set<Object> set;
+
+    /**
+     * Creates a new builder.
+     * @param size the expected set size
+     */
+    public SetBuilder(int size) {
+        set = new HashSet<Object>(size);
+    }
+
+    @Override
+    public void add(Object value) {
+        set.add(value);
+    }
+
+    @Override
+    public Object create() {
+        return set;
+    }
+
+}

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

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java Tue Mar 10 13:46:44 2015
@@ -393,7 +393,7 @@ public final class TemplateEngine extend
 
         @Override
         protected void getVariables(Engine.VarCollector collector) {
-            jexl.getVariables(node, collector);
+            jexl.getVariables(node instanceof ASTJexlScript? (ASTJexlScript) node : null, node, collector);
         }
 
         @Override

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java Tue Mar 10 13:46:44 2015
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3.parser;
 
 import org.apache.commons.jexl3.internal.Scope;
+import java.util.Map;
 
 /**
  * Enhanced script to allow parameters declaration.
@@ -24,6 +25,8 @@ import org.apache.commons.jexl3.internal
 public class ASTJexlScript extends JexlNode {
     /** The script scope. */
     protected Scope scope = null;
+    /** The pragmas. */
+    protected Map<String, Object> pragmas = null;
 
     public ASTJexlScript(int id) {
         super(id);
@@ -81,6 +84,13 @@ public class ASTJexlScript extends JexlN
     }
 
     /**
+     * @return this script pragmas
+     */
+    public Map<String,Object> getPragmas() {
+        return pragmas;
+    }
+
+    /**
      * Creates an array of arguments by copying values up to the number of parameters.
      * @param values the argument values
      * @return the arguments array
@@ -126,4 +136,13 @@ public class ASTJexlScript extends JexlN
     public String[] getLocalVariables() {
         return scope != null? scope.getLocalVariables() : null;
     }
+
+    /**
+     * Checks whether a given symbol is hoisted.
+     * @param symbol the symbol number
+     * @return true if hoisted, false otherwise
+     */
+    public boolean isHoistedSymbol(int symbol) {
+        return scope != null? scope.isHoistedSymbol(symbol) : false;
+    }
 }

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -16,54 +16,30 @@
  */
 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.Constant<Number> {
-    /** The type literal value. */
-    private Number literal = null;
-    /** The expected class. */
-    private Class<?> clazz = null;
-
+   private final NumberParser nlp;
     ASTNumberLiteral(int id) {
         super(id);
+        nlp = new NumberParser();
     }
 
     ASTNumberLiteral(Parser p, int id) {
         super(p, id);
+        nlp = new NumberParser();
     }
 
     static final DecimalFormat BIGDF = new DecimalFormat("0.0b");
 
     @Override
     public String toString() {
-        if (literal == null || clazz == null || Double.isNaN(literal.doubleValue())) {
-            return "NaN";
-        }
-        if (BigDecimal.class.equals(clazz)) {
-              return BIGDF.format(literal);
-        }
-        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 nlp.toString();
     }
 
     @Override
     public Number getLiteral() {
-        return literal;
+        return nlp.getLiteralValue();
     }
 
     @Override
@@ -72,11 +48,11 @@ public final class ASTNumberLiteral exte
     }
 
     public Class<?> getLiteralClass() {
-        return clazz;
+        return nlp.getLiteralClass();
     }
 
     public boolean isInteger() {
-        return Integer.class.equals(clazz);
+        return nlp.isInteger();
     }
 
     /**
@@ -85,49 +61,7 @@ public final class ASTNumberLiteral exte
      * @param s the natural as string
      */
     void setNatural(String s) {
-        Number result;
-        Class<?> rclass;
-        // determine the base
-        final int base;
-        if (s.charAt(0) == '0') {
-            if ((s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))) {
-                base = 16;
-                s = s.substring(2); // Trim the 0x off the front
-            } else {
-                base = 8;
-            }
-        } else {
-            base = 10;
-        }
-        final int last = s.length() - 1;
-        switch (s.charAt(last)) {
-            case 'l':
-            case 'L': {
-                rclass = Long.class;
-                result = Long.valueOf(s.substring(0, last), base);
-                break;
-            }
-            case 'h':
-            case 'H': {
-                rclass = BigInteger.class;
-                result = new BigInteger(s.substring(0, last), base);
-                break;
-            }
-            default: {
-                rclass = Integer.class;
-                try {
-                    result = Integer.valueOf(s, base);
-                } catch (NumberFormatException take2) {
-                    try {
-                        result = Long.valueOf(s, base);
-                    } catch (NumberFormatException take3) {
-                        result = new BigInteger(s, base);
-                    }
-                }
-            }
-        }
-        literal = result;
-        clazz = rclass;
+        nlp.setNatural(s);
     }
 
     /**
@@ -136,44 +70,7 @@ public final class ASTNumberLiteral exte
      * @param s the real as string
      */
     void setReal(String s) {
-        Number result;
-        Class<?> rclass;
-        if ("#NaN".equals(s) || "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;
-                }
-            }
-        }
-        literal = result;
-        clazz = rclass;
+        nlp.setReal(s);
     }
 
     @Override

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTSetLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTSetLiteral.java?rev=1665548&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTSetLiteral.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTSetLiteral.java Tue Mar 10 13:46:44 2015
@@ -0,0 +1,64 @@
+/*
+ * 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.parser;
+
+import org.apache.commons.jexl3.internal.Debugger;
+
+public final class ASTSetLiteral extends JexlNode {
+    /** Whether this set is constant or not. */
+    private boolean constant = false;
+
+    ASTSetLiteral(int id) {
+        super(id);
+    }
+
+    ASTSetLiteral(Parser p, int id) {
+        super(p, id);
+    }
+
+    @Override
+    public String toString() {
+        Debugger dbg = new Debugger();
+        return dbg.data(this);
+    }
+
+    @Override
+    protected boolean isConstant(boolean literal) {
+        return constant;
+    }
+
+    /** {@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.isConstant()) {
+                    constant = false;
+                }
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Object jjtAccept(ParserVisitor visitor, Object data) {
+        return visitor.visit(this, data);
+    }
+
+}

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

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -23,6 +23,9 @@ import org.apache.commons.jexl3.JexlExce
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.internal.Scope;
 
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 import java.util.Stack;
 
 /**
@@ -40,6 +43,10 @@ public abstract class JexlParser extends
      */
     protected Scope frame = null;
     protected Stack<Scope> frames = new Stack<Scope>();
+    /**
+     * The list of pragma declarations.
+     */
+    protected Map<String, Object> pragmas = null;
 
 
     /**
@@ -120,6 +127,18 @@ public abstract class JexlParser extends
     }
 
     /**
+     * Adds a pragma declaration.
+     * @param key the pragma key
+     * @param value the pragma value
+     */
+    public void declarePragma(String key, Object value) {
+        if (pragmas == null) {
+            pragmas = new TreeMap<String, Object>();
+        }
+        pragmas.put(key, value);
+    }
+
+    /**
      * Declares a local parameter.
      * <p> This method creates an new entry in the symbol map. </p>
      * @param identifier the parameter name
@@ -175,6 +194,29 @@ public abstract class JexlParser extends
         }
     }
 
+    /**
+     * Utility function to create '.' separated string from a list of string.
+     * @param lstr the list of strings
+     * @return the dotted version
+     */
+    String stringify(List<String> lstr) {
+        StringBuilder strb = new StringBuilder();
+        boolean dot = false;
+        for(String str : lstr) {
+            if (!dot) {
+               dot = true;
+            } else {
+               strb.append('.');
+            }
+            strb.append(str);
+        }
+        return strb.toString();
+    }
+
+    /**
+     * Throws a parsing exception.
+     * @param node the node that caused it
+     */
     protected void throwParsingException(JexlNode node) {
         throwParsingException(null, node);
     }
@@ -182,7 +224,7 @@ public abstract class JexlParser extends
     /**
      * Throws a parsing exception.
      * @param xclazz the class of exception
-     * @param node the node that provoqued it
+     * @param node the node that caused it
      */
     private void throwParsingException(Class<? extends JexlException> xclazz, JexlNode node) {
         final JexlInfo dbgInfo;

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/NumberParser.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/NumberParser.java?rev=1665548&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/NumberParser.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/NumberParser.java Tue Mar 10 13:46:44 2015
@@ -0,0 +1,179 @@
+/*
+ * 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.parser;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.DecimalFormat;
+
+public final class NumberParser {
+    /** The type literal value. */
+    private Number literal = null;
+    /** The expected class. */
+    private Class<?> clazz = null;
+
+    static final DecimalFormat BIGDF = new DecimalFormat("0.0b");
+
+
+    @Override
+    public String toString() {
+        if (literal == null || clazz == null || Double.isNaN(literal.doubleValue())) {
+            return "NaN";
+        }
+        if (BigDecimal.class.equals(clazz)) {
+              return BIGDF.format(literal);
+        }
+        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();
+    }
+
+
+    Class<?> getLiteralClass() {
+        return clazz;
+    }
+
+    boolean isInteger() {
+        return Integer.class.equals(clazz);
+    }
+
+    Number getLiteralValue() {
+        return literal;
+    }
+
+    static Number parseInteger(String s) {
+        NumberParser np  = new NumberParser();
+        np.setNatural(s);
+        return np.getLiteralValue();
+    }
+
+    static Number parseDouble(String s) {
+        NumberParser np  = new NumberParser();
+        np.setReal(s);
+        return np.getLiteralValue();
+    }
+
+    /**
+     * Sets this node as a natural literal.
+     * Originally from OGNL.
+     * @param s the natural as string
+     */
+    void setNatural(String s) {
+        Number result;
+        Class<?> rclass;
+        // determine the base
+        final int base;
+        if (s.charAt(0) == '0') {
+            if ((s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))) {
+                base = 16;
+                s = s.substring(2); // Trim the 0x off the front
+            } else {
+                base = 8;
+            }
+        } else {
+            base = 10;
+        }
+        final int last = s.length() - 1;
+        switch (s.charAt(last)) {
+            case 'l':
+            case 'L': {
+                rclass = Long.class;
+                result = Long.valueOf(s.substring(0, last), base);
+                break;
+            }
+            case 'h':
+            case 'H': {
+                rclass = BigInteger.class;
+                result = new BigInteger(s.substring(0, last), base);
+                break;
+            }
+            default: {
+                rclass = Integer.class;
+                try {
+                    result = Integer.valueOf(s, base);
+                } catch (NumberFormatException take2) {
+                    try {
+                        result = Long.valueOf(s, base);
+                    } catch (NumberFormatException take3) {
+                        result = new BigInteger(s, base);
+                    }
+                }
+            }
+        }
+        literal = result;
+        clazz = rclass;
+    }
+
+    /**
+     * Sets this node as a real literal.
+     * Originally from OGNL.
+     * @param s the real as string
+     */
+    void setReal(String s) {
+        Number result;
+        Class<?> rclass;
+        if ("#NaN".equals(s) || "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;
+                }
+            }
+        }
+        literal = result;
+        clazz = rclass;
+    }
+
+}

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

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -31,6 +31,10 @@ PARSER_BEGIN(Parser)
 
 package org.apache.commons.jexl3.parser;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.LinkedList;
+
 import java.io.Reader;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.JexlException;
@@ -51,6 +55,9 @@ public final class Parser extends JexlPa
             ReInit(new java.io.StringReader(jexlSrc));
             frame = scope;
             ASTJexlScript script = expr? JexlExpression(scope) : JexlScript(scope) ;
+            script.pragmas = pragmas != null
+                             ? Collections.<String,Object>unmodifiableMap(pragmas)
+                             : Collections.<String,Object>emptyMap();
             script.value = info;
             return script;
         } catch (TokenMgrError xtme) {
@@ -103,6 +110,7 @@ PARSER_END(Parser)
     | < LAMBDA : "->" >
     | < BREAK : "break" >
     | < CONTINUE : "continue" >
+    | < PRAGMA : "#pragma" >
 }
 
 <FOR_EACH_IN> TOKEN : /* foreach in */
@@ -212,7 +220,7 @@ ASTJexlScript JexlScript(Scope frame) :
     jjtThis.setScope(frame);
 }
 {
-   ( Statement() )* <EOF>
+   (LOOKAHEAD(<LCURLY> Expression() <SEMICOL>) Block() | ( Statement() )*) <EOF>
    {
         return jjtThis.script();
    }
@@ -231,7 +239,6 @@ ASTJexlScript JexlExpression(Scope frame
 void Statement() #void : {}
 {
     <SEMICOL>
-    | LOOKAHEAD(3) Block()
     | IfStatement()
     | ForeachStatement()
     | WhileStatement()
@@ -240,6 +247,7 @@ void Statement() #void : {}
     | Continue()
     | Break()
     | Var()
+    | Pragma()
 }
 
 void Block() #Block : {}
@@ -256,13 +264,13 @@ void ExpressionStatement() #void : {}
 
 void IfStatement() : {}
 {
-    <IF> <LPAREN> Expression() <RPAREN> Statement() ( LOOKAHEAD(1) <ELSE> Statement() )?
+    <IF> <LPAREN> Expression() <RPAREN>  (LOOKAHEAD(1) Block() | Statement()) ( LOOKAHEAD(1) <ELSE>  (LOOKAHEAD(1) Block() | Statement()) )?
 }
 
 
 void WhileStatement() : {}
 {
-    <WHILE> <LPAREN> Expression() <RPAREN>  { loopCount += 1; } Statement() { loopCount -= 1; }
+    <WHILE> <LPAREN> Expression() <RPAREN>  { loopCount += 1; }  (LOOKAHEAD(1) Block() | Statement()) { loopCount -= 1; }
 }
 
 void ReturnStatement() : {}
@@ -282,9 +290,9 @@ void Break() #Break : {}
 
 void ForeachStatement() : {}
 {
-    <FOR> <LPAREN> ForEachVar() <COLON>  Expression() <RPAREN> { loopCount += 1; } Statement() { loopCount -= 1; }
+    <FOR> <LPAREN> ForEachVar() <COLON>  Expression() <RPAREN> { loopCount += 1; } (LOOKAHEAD(1) Block() | Statement()) { loopCount -= 1; }
 |
-    <FOREACH> <LPAREN> ForEachVar() <IN>  Expression() <RPAREN>  { loopCount += 1; } Statement() { loopCount -= 1; }
+    <FOREACH> <LPAREN> ForEachVar() <IN>  Expression() <RPAREN>  { loopCount += 1; } (LOOKAHEAD(1) Block() | Statement()){ loopCount -= 1; }
 }
 
 void ForEachVar() #Reference : {}
@@ -307,6 +315,40 @@ void DeclareVar() #Var :
     t=<IDENTIFIER> { declareVariable(jjtThis, t.image); }
 }
 
+void Pragma() #void :
+{
+    LinkedList<String> lstr = new LinkedList<String>();
+    Object value;
+}
+{
+<PRAGMA> pragmaKey(lstr)  value=pragmaValue() { declarePragma(stringify(lstr), value); }
+}
+
+void pragmaKey(LinkedList<String> lstr) #void :
+{
+    Token t;
+}
+{
+    t=<IDENTIFIER> (LOOKAHEAD(2) <DOT> pragmaKey(lstr) )* { lstr.addFirst(t.image); }
+}
+
+Object pragmaValue() #void :
+{
+Token v;
+LinkedList<String> lstr = new LinkedList<String>();
+}
+{
+      LOOKAHEAD(1) v=<INTEGER_LITERAL> { return NumberParser.parseInteger(v.image); }
+    | LOOKAHEAD(1) v=<FLOAT_LITERAL> { return NumberParser.parseDouble(v.image); }
+    | LOOKAHEAD(1) v=<STRING_LITERAL> { return Parser.buildString(v.image, true); }
+    | LOOKAHEAD(1)  pragmaKey(lstr) { return stringify(lstr); }
+    | LOOKAHEAD(1) <TRUE> { return true; }
+    | LOOKAHEAD(1) <FALSE> { return false; }
+    | LOOKAHEAD(1) <NULL> { return null; }
+    | LOOKAHEAD(1) <NAN_LITERAL> { return Double.NaN; }
+}
+
+
 /***************************************
  *      Expression syntax
  ***************************************/
@@ -555,6 +597,10 @@ void MapEntry() : {}
     Expression() <COLON> Expression()
 }
 
+void SetLiteral() : {}
+{
+  <LCURLY> (Expression() ( <COMMA> Expression() )*)? <RCURLY>
+}
 
 /***************************************
  *      Functions & Methods
@@ -615,6 +661,8 @@ void LambdaLookahead() #void() : {}
   <FUNCTION> Parameters()
   |
   Parameters() <LAMBDA>
+  |
+  Parameter() <LAMBDA>
 }
 
 void Lambda() #JexlLambda() :
@@ -625,6 +673,8 @@ void Lambda() #JexlLambda() :
   <FUNCTION> Parameters() Block()
   |
   Parameters() <LAMBDA> Block()
+  |
+  Parameter() <LAMBDA> Block()
 }
 
 
@@ -670,7 +720,13 @@ void PrimaryExpression() #void : {}
     |
        LOOKAHEAD( <LPAREN> ) ReferenceExpression()
     |
-       LOOKAHEAD( <LCURLY> ) MapLiteral()
+       LOOKAHEAD( <LCURLY> Expression() <COLON>) MapLiteral()
+    |
+       LOOKAHEAD( <LCURLY> <COLON>) MapLiteral()
+    |
+       LOOKAHEAD( <LCURLY> Expression() ) SetLiteral()
+    |
+       LOOKAHEAD( <LCURLY> <RCURLY> ) SetLiteral()
     |
        LOOKAHEAD( <LBRACKET> ) ArrayLiteral()
     |

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=1665548&r1=1665547&r2=1665548&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 Tue Mar 10 13:46:44 2015
@@ -49,7 +49,7 @@ public abstract class ParserVisitor {
     protected abstract Object visit(ASTWhileStatement node, Object data);
 
     protected abstract Object visit(ASTContinue node, Object data);
-    
+
     protected abstract Object visit(ASTBreak node, Object data);
 
     protected abstract Object visit(ASTForeachStatement node, Object data);
@@ -126,6 +126,8 @@ public abstract class ParserVisitor {
 
     protected abstract Object visit(ASTStringLiteral node, Object data);
 
+    protected abstract Object visit(ASTSetLiteral node, Object data);
+
     protected abstract Object visit(ASTArrayLiteral node, Object data);
 
     protected abstract Object visit(ASTRangeNode node, Object data);

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=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml Tue Mar 10 13:46:44 2015
@@ -148,6 +148,16 @@
             the most appropriate non ambiguous method to call.</p>
           </td>
         </tr>
+        <tr>
+          <td>#pragma</td>
+          <td>
+            Declares a pragma, a method to communicate information from a script to its execution environment, e.g.
+            <source>#pragma execution.option 42</source> will declare a pragma named <code>execution.option</code> with
+            a value of <code>42</code>.
+            <p>Pragma keys can be identifiers or antish names, pragma values can be literals (boolean, integer,
+            real, string, null, NaN) and antish names</p>
+          </td>
+        </tr>
       </table>
     </section>
     <section name="Literals">
@@ -255,6 +265,15 @@
           </td>
         </tr>
         <tr>
+          <td>Set literal</td>
+          <td>
+            A <code>{</code> followed by one or more expressions separated by <code>,</code> and ending
+            with <code>}</code>, e.g.
+            <source>{ "one" , 2, "more"}</source>
+            <p>This syntax creates a <code>HashSet&lt;Object&gt;</code>.</p>
+          </td>
+        </tr>
+        <tr>
           <td>Map literal</td>
           <td>
             A <code>{</code> followed by one or more sets of <code>key : value</code> pairs separated by <code>,</code> and ending

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java Tue Mar 10 13:46:44 2015
@@ -164,4 +164,20 @@ public class AssignTest extends JexlTest
         o = JEXL.getProperty(quux, "['froboz']['value']");
         assertEquals("Result is not 1000", new Integer(1000), o);
     }
+
+    public void testRejectLocal() throws Exception {
+        JexlContext jc = new MapContext();
+        JexlScript assign = JEXL.createScript("var quux = null; quux.froboz.value = 10");
+        try {
+            Object o = assign.execute(jc);
+            fail("quux is local and null, should fail");
+        } catch (JexlException xjexl) {
+            String x = xjexl.toString();
+            String y = x;
+        }
+        // quux is a global antish var
+        assign = JEXL.createScript("quux.froboz.value = 10");
+        Object o = assign.execute(jc);
+        assertEquals(10, o);
+    }
 }
\ No newline at end of file

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java Tue Mar 10 13:46:44 2015
@@ -50,7 +50,7 @@ public class IssuesTest extends JexlTest
         JexlEngine jexl = new Engine();
         Map<String, Object> vars = new HashMap<String, Object>();
         JexlContext ctxt = new MapContext(vars);
-        String stmt = "{a = 'b'; c = 'd';}";
+        String stmt = "a = 'b'; c = 'd';";
         JexlScript expr = jexl.createScript(stmt);
         /* Object value = */ expr.execute(ctxt);
         assertTrue("JEXL-49 is not fixed", vars.get("a").equals("b") && vars.get("c").equals("d"));
@@ -362,8 +362,8 @@ public class IssuesTest extends JexlTest
         for (char v = 'a'; v <= 'z'; ++v) {
             ctxt.set(Character.toString(v), 10);
         }
-        String input =
-                "(((((((((((((((((((((((((z+y)/x)*w)-v)*u)/t)-s)*r)/q)+p)-o)*n)-m)+l)*k)+j)/i)+h)*g)+f)/e)+d)-c)/b)+a)";
+        String input
+                = "(((((((((((((((((((((((((z+y)/x)*w)-v)*u)/t)-s)*r)/q)+p)-o)*n)-m)+l)*k)+j)/i)+h)*g)+f)/e)+d)-c)/b)+a)";
 
         JexlExpression script;
         // Make sure everything is loaded...
@@ -601,7 +601,6 @@ public class IssuesTest extends JexlTest
         value = expr.evaluate(context);
         assertEquals("FirstValue=9.0", value);
 
-
         context.set("x", -10);
         context.set("y", 1);
         value = expr.evaluate(context);
@@ -1077,7 +1076,7 @@ public class IssuesTest extends JexlTest
 
         jc.set("one", 1);
         jc.set("two", 2);
-        int[] o1 = (int[])e147.evaluate(jc);
+        int[] o1 = (int[]) e147.evaluate(jc);
         assertEquals(1, o1[0]);
         assertEquals(2, o1[1]);
 
@@ -1087,4 +1086,20 @@ public class IssuesTest extends JexlTest
         assertEquals(10, o2[0]);
         assertEquals(20, o2[1]);
     }
+
+    public void test148() throws Exception {
+        String[] scripts = {"var x = new ('java.util.HashMap'); x.one = 1; x.two = 2; x.one", // results to 1
+            "x = new ('java.util.HashMap'); x.one = 1; x.two = 2; x.one",// results to 1
+            "x = new ('java.util.HashMap'); x.one = 1; x.two = 2; x['one']",//results to 1
+            "var x = new ('java.util.HashMap'); x.one = 1; x.two = 2; x['one']"// result to null?
+        };
+
+        JexlEngine JEXL = new Engine();
+        JexlContext jc = new MapContext();
+        for (String s : scripts) {
+            Object o = JEXL.createScript(s).execute(jc);
+            Assert.assertEquals(1, o);
+        }
+    }
+
 }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java?rev=1665548&r1=1665547&r2=1665548&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java Tue Mar 10 13:46:44 2015
@@ -17,6 +17,8 @@
 package org.apache.commons.jexl3;
 
 import org.apache.commons.jexl3.internal.Engine;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Callable;
 
 /**
@@ -30,7 +32,7 @@ public class LambdaTest extends JexlTest
 
     public void testScriptArguments() throws Exception {
         JexlEngine jexl = new Engine();
-        JexlScript s = jexl.createScript("{ x + x }", "x");
+        JexlScript s = jexl.createScript(" x + x ", "x");
         JexlScript s42 = jexl.createScript("s(21)", "s");
         Object result = s42.execute(null, s);
         assertEquals(42, result);
@@ -49,6 +51,9 @@ public class LambdaTest extends JexlTest
         assertEquals(42, result);
         result = s42.execute(ctxt);
         assertEquals(42, result);
+         s = jexl.createScript("x-> { x + x }");
+        result = s42.execute(ctxt);
+        assertEquals(42, result);
     }
 
     public void testLambda() throws Exception {
@@ -124,6 +129,40 @@ public class LambdaTest extends JexlTest
         assertEquals(42, result);
     }
 
+    public void testHoistLambada() throws Exception {
+        JexlEngine jexl = new Engine();
+        JexlContext ctx = null;
+        JexlScript s42;
+        Object result;
+        JexlScript s15;
+        String[] localv;
+        Set<List<String>> hvars;
+        String strs;
+
+        // hosted variables are NOT local variables
+        strs = "(x)->{ (y)->{ x + y } }";
+        s42 = jexl.createScript(strs);
+        result = s42.execute(ctx, 15);
+        assertTrue(result instanceof JexlScript);
+        s15 = (JexlScript) result;
+        localv = s15.getLocalVariables();
+        assertNull(localv);
+        hvars = s15.getVariables();
+        assertEquals(1, hvars.size());
+
+        // declaring a local that overrides hoisted
+        strs = "(x)->{ (y)->{ var x; x + y } }";
+        s42 = jexl.createScript(strs);
+        result = s42.execute(ctx, 15);
+        assertTrue(result instanceof JexlScript);
+        s15 = (JexlScript) result;
+        localv = s15.getLocalVariables();
+        assertNotNull(localv);
+        assertEquals(1, localv.length);
+        hvars = s15.getVariables();
+        assertEquals(0, hvars.size());
+    }
+
     public void testRecurse() throws Exception {
         JexlEngine jexl = new Engine();
         JexlContext jc = new MapContext();

Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java?rev=1665548&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java (added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java Tue Mar 10 13:46:44 2015
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import java.util.Map;
+import org.junit.Assert;
+
+/**
+ * Tests for pragmas
+ */
+public class PragmaTest extends JexlTestCase {
+    /**
+     * Create a new test case.
+     * @param name case name
+     */
+    public PragmaTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test creating a script from a string.
+     */
+    public void testPragmas() throws Exception {
+        JexlContext jc = new MapContext();
+        try {
+        JexlScript script = JEXL.createScript("#pragma one 1\n#pragma the.very.hard 'truth'\n2;");
+        Assert.assertTrue(script != null);
+        Map<String, Object> pragmas = script.getPragmas();
+        Assert.assertEquals(2, pragmas.size());
+        Assert.assertEquals(1, pragmas.get("one"));
+        Assert.assertEquals("truth", pragmas.get("the.very.hard"));
+        } catch(JexlException xjexl) {
+            String s = xjexl.toString();
+        }
+    }
+
+
+}

Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/PragmaTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java?rev=1665548&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java (added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java Tue Mar 10 13:46:44 2015
@@ -0,0 +1,132 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Tests for set literals
+ * @since 3.0
+ */
+public class SetLiteralTest extends JexlTestCase {
+
+    public SetLiteralTest() {
+        super("SetLiteralTest");
+    }
+
+    static private Set<?> createSet(Object... args) {
+        return new HashSet<Object>(Arrays.asList(args));
+    }
+
+    public void testSetLiteralWithStrings() throws Exception {
+        JexlExpression e = JEXL.createExpression("{ 'foo' , 'bar' }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.evaluate(jc);
+        Set<?> check = createSet("foo", "bar");
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testLiteralWithOneEntry() throws Exception {
+        JexlExpression e = JEXL.createExpression("{ 'foo' }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.evaluate(jc);
+        Set<?> check = createSet("foo");
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testSetLiteralWithStringsScript() throws Exception {
+        JexlScript e = JEXL.createScript("{ 'foo' , 'bar' }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.execute(jc);
+        Set<?> check = createSet("foo", "bar");
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testSetLiteralWithOneEntryScript() throws Exception {
+        JexlScript e = JEXL.createScript("{ 'foo' }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.execute(jc);
+        Set<?> check = createSet("foo");
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testSetLiteralWithOneEntryBlock() throws Exception {
+        JexlScript e = JEXL.createScript("{ { 'foo' }; }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.execute(jc);
+        Set<?> check = createSet("foo");
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testSetLiteralWithNumbers() throws Exception {
+        JexlExpression e = JEXL.createExpression("{ 5.0 , 10 }");
+        JexlContext jc = new MapContext();
+
+        Object o = e.evaluate(jc);
+        Set<?> check = createSet(new Double(5.0), new Integer(10));
+        assertTrue(Objects.equals(check, o));
+    }
+
+    public void testSetLiteralWithNulls() throws Exception {
+        String[] exprs = {
+            "{ 10 }",
+            "{ 10 , null }",
+            "{ 10 , null , 20}",
+            "{ '10' , null }",
+            "{ null, '10' , 20 }"
+        };
+        Set<?>[] checks = {
+            createSet(new Integer(10)),
+            createSet(new Integer(10), null),
+            createSet(new Integer(10), null, new Integer(20)),
+            createSet("10", null),
+            createSet(null, "10", new Integer(20))
+        };
+        JexlContext jc = new MapContext();
+        for (int t = 0; t < exprs.length; ++t) {
+            JexlExpression e = JEXL.createExpression(exprs[t]);
+            Object o = e.evaluate(jc);
+            assertTrue(exprs[t], Objects.equals(checks[t], o));
+        }
+
+    }
+
+    public void testSizeOfSimpleSetLiteral() throws Exception {
+        JexlExpression e = JEXL.createExpression("size({ 'foo' , 'bar'})");
+        JexlContext jc = new MapContext();
+
+        Object o = e.evaluate(jc);
+        assertEquals(new Integer(2), o);
+    }
+
+    public void testNotEmptySimpleSetLiteral() throws Exception {
+        JexlExpression e = JEXL.createExpression("empty({ 'foo' , 'bar' })");
+        JexlContext jc = new MapContext();
+
+        Object o = e.evaluate(jc);
+        assertFalse(((Boolean) o).booleanValue());
+    }
+
+}

Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SetLiteralTest.java
------------------------------------------------------------------------------
    svn:eol-style = native