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<Object></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