This is an automated email from the ASF dual-hosted git repository. henrib pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push: new d7d55e3d JEXL: getting ready for 3.3; d7d55e3d is described below commit d7d55e3dce7cec682fa00ef4afe18e35f47e60c3 Author: henrib <hen...@apache.org> AuthorDate: Sat Mar 4 15:38:20 2023 +0100 JEXL: getting ready for 3.3; --- .../java/org/apache/commons/jexl3/JexlOptions.java | 2 +- .../org/apache/commons/jexl3/internal/Engine.java | 23 +++-- .../apache/commons/jexl3/internal/Interpreter.java | 10 +-- .../commons/jexl3/internal/InterpreterBase.java | 10 ++- .../internal/introspection/PermissionsParser.java | 2 +- .../org/apache/commons/jexl3/package-info.java | 99 +--------------------- .../org/apache/commons/jexl3/parser/JexlNode.java | 3 +- .../apache/commons/jexl3/parser/JexlParser.java | 9 +- src/site/xdoc/reference/examples.xml | 2 +- src/site/xdoc/reference/syntax.xml | 9 +- .../java/org/apache/commons/jexl3/LexicalTest.java | 2 +- 11 files changed, 46 insertions(+), 125 deletions(-) diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java b/src/main/java/org/apache/commons/jexl3/JexlOptions.java index 2f85b5c1..ac24a672 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java +++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java @@ -213,7 +213,7 @@ public final class JexlOptions { * <p>After a symbol is defined as local, dereferencing it outside its * scope will trigger an error instead of seeking a global variable of the * same name. To further reduce potential naming ambiguity errors, - * global variables (ie non local) must be declared to be assigned (@link JexlContext#has(String) ) + * global variables (ie non-local) must be declared to be assigned (@link JexlContext#has(String) ) * when this flag is on; attempting to set an undeclared global variables will * raise an error. * @return true if lexical shading is applied, false otherwise diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java b/src/main/java/org/apache/commons/jexl3/internal/Engine.java index 81b3e2ce..ff228295 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java @@ -215,7 +215,8 @@ public class Engine extends JexlEngine { options.setMathContext(arithmetic.getMathContext()); options.setMathScale(arithmetic.getMathScale()); options.setStrictArithmetic(arithmetic.isStrict()); - this.functions = conf.namespaces() == null ? Collections.emptyMap() : conf.namespaces(); + final Map<String, Object> ns = conf.namespaces(); + this.functions = ns == null || ns.isEmpty()? Collections.emptyMap() : ns; // should we make a copy? this.classNameSolver = new FqcnResolver(uberspect, conf.imports()); // parsing & features: final JexlFeatures features = conf.features() == null? DEFAULT_FEATURES : conf.features(); @@ -333,6 +334,15 @@ public class Engine extends JexlEngine { return charset; } + /** + * Solves a namespace using this engine map of functions. + * @param name the namespoce name + * @return the object associated + */ + final Object getNamespace(String name) { + return functions.get(name); + } + /** * Solves an optional option. * @param conf the option as configured, may be null @@ -446,16 +456,17 @@ public class Engine extends JexlEngine { } } else if (key.startsWith(PRAGMA_JEXLNS)) { if (ns == null) { - ns = new LinkedHashMap<>(functions); + ns = new LinkedHashMap<>(); } processPragmaNamespace(ns, key, value); } else if (key.startsWith(PRAGMA_MODULE)) { if (ns == null) { - ns = new LinkedHashMap<>(functions); + ns = new LinkedHashMap<>(); } processModulePragma(ns, key, value, script.jexlInfo(), context); } if (processor != null) { + opts.setNamespaces(ns); processor.processPragma(opts, key, value); } } @@ -466,14 +477,14 @@ public class Engine extends JexlEngine { /** * Utility to deal with single value or set of values. * @param value the value or the set - * @param vfunc the consumer of values + * @param consumer the consumer of values */ - private void withValueSet(Object value, Consumer<Object> vfunc) { + private void withValueSet(Object value, Consumer<Object> consumer) { final Set<?> values = value instanceof Set<?> ? (Set<?>) value : Collections.singleton(value); for (final Object o : values) { - vfunc.accept(o); + consumer.accept(o); } } diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java index 3487c373..d243a816 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java @@ -667,7 +667,7 @@ public class Interpreter extends InterpreterBase { /* last child node is the statement to execute */ final int numChildren = node.jjtGetNumChildren(); final JexlNode statement = numChildren >= 3 ? node.jjtGetChild(numChildren - 1) : null; - // get an iterator for the collection/array etc via the introspector. + // get an iterator for the collection/array/etc. via the introspector. forEach = operators.tryOverload(node, JexlOperator.FOR_EACH, iterableValue); final Iterator<?> itemsIterator = forEach instanceof Iterator ? (Iterator<?>) forEach @@ -1395,7 +1395,7 @@ public class Interpreter extends InterpreterBase { } /** - * Executes an assignment with an optional side-effect operator. + * Executes an assignment with an optional side effect operator. * @param node the node * @param assignop the assignment operator or null if simply assignment * @param data the data @@ -1529,7 +1529,7 @@ public class Interpreter extends InterpreterBase { : null; final Object property; if (propertyId != null) { - // deal with creating/assignining antish variable + // deal with creating/assigning antish variable if (antish && ant != null && object == null && !propertyId.isSafe() && !propertyId.isExpression()) { ant.append('.'); ant.append(propertyId.getName()); @@ -1537,7 +1537,7 @@ public class Interpreter extends InterpreterBase { if (assignop == null) { setContextVariable(propertyNode, name, right); } else { - final Object self = actual = context.get(ant.toString()); + final Object self = context.get(ant.toString()); final JexlNode pnode = propertyNode; final Consumer<Object> assign = r -> setContextVariable(pnode, name, r); actual = operators.tryAssignOverload(node, assignop, assign, self, right); @@ -1606,7 +1606,7 @@ public class Interpreter extends InterpreterBase { /** * Execute a method call, ie syntactically written as name.call(...). * @param node the actual method call node - * @param antish non null when name.call is an antish variable + * @param antish non-null when name.call is an antish variable * @param data the context * @return the method call result */ diff --git a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java index 69f479c0..2c3deb4d 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java +++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java @@ -81,7 +81,7 @@ public abstract class InterpreterBase extends ParserVisitor { protected final Operators operators; /** The map of 'prefix:function' to object resolving as namespaces. */ protected final Map<String, Object> functions; - /** The map of dynamically creates namespaces, NamespaceFunctor or duck-types of those. */ + /** The map of dynamically created namespaces, NamespaceFunctor or duck-types of those. */ protected Map<String, Object> functors; /** @@ -114,8 +114,7 @@ public abstract class InterpreterBase extends ParserVisitor { acancel = ((JexlContext.CancellationHandle) context).getCancellation(); } this.cancelled = acancel != null? acancel : new AtomicBoolean(false); - final Map<String,Object> ons = options.getNamespaces(); - this.functions = ons.isEmpty()? jexl.functions : ons; + this.functions = options.getNamespaces(); this.functors = null; this.operators = new Operators(this); // the import package facility @@ -176,7 +175,7 @@ public abstract class InterpreterBase extends ParserVisitor { * Resolves a namespace, eventually allocating an instance using context as constructor argument. * <p> * The lifetime of such instances span the current expression or script evaluation.</p> - * @param prefix the prefix name (may be null for global namespace) + * @param prefix the prefix name (can be null for global namespace) * @param node the AST node * @return the namespace instance */ @@ -195,6 +194,9 @@ public abstract class InterpreterBase extends ParserVisitor { namespace = ns.resolveNamespace(prefix); if (namespace == null) { namespace = functions.get(prefix); + if (namespace == null) { + namespace = jexl.getNamespace(prefix); + } if (prefix != null && namespace == null) { throw new JexlException(node, "no such function namespace " + prefix, null); } diff --git a/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java b/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java index ad6ec0c1..d5084c9d 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java +++ b/src/main/java/org/apache/commons/jexl3/internal/introspection/PermissionsParser.java @@ -85,7 +85,7 @@ public class PermissionsParser { * @param srcs the sources * @return the permissions map */ - Permissions parse(Set<String> wildcards, Map<String, Permissions.NoJexlPackage> packages, final String... srcs) { + synchronized Permissions parse(Set<String> wildcards, Map<String, Permissions.NoJexlPackage> packages, final String... srcs) { if (srcs == null || srcs.length == 0) { return Permissions.UNRESTRICTED; } diff --git a/src/main/java/org/apache/commons/jexl3/package-info.java b/src/main/java/org/apache/commons/jexl3/package-info.java index a84514ba..27acf230 100644 --- a/src/main/java/org/apache/commons/jexl3/package-info.java +++ b/src/main/java/org/apache/commons/jexl3/package-info.java @@ -348,105 +348,8 @@ * For example, this would be the case if you wanted '+' to operate on arrays; you'd need to derive * JexlArithmetic and implement 'public Object add(Set<?;> x, Set<?;> y)' method. * Note however that you can <em>not</em> change the operator precedence. - * The list of operator / method matches is the following: + * The list of operator / method matches is described in {@link org.apache.commons.jexl3.JexlOperator}: * </p> - * <table><caption>Operators</caption> - * <tr> - * <th>Operator</th> - * <th>Method Name</th> - * <th>Example</th> - * </tr> - * <tr> - * <td>+</td> - * <td>add</td> - * <td>add(x, y)</td> - * </tr> - * <tr> - * <td>-</td> - * <td>subtract</td> - * <td>subtract(x, y)</td> - * </tr> - * <tr> - * <td>*</td> - * <td>multiply</td> - * <td>multiply(x, y)</td> - * </tr> - * <tr> - * <td>/</td> - * <td>divide</td> - * <td>divide(x, y)</td> - * </tr> - * <tr> - * <td>%</td> - * <td>mod</td> - * <td>mod(x, y)</td> - * </tr> - * <tr> - * <td>&</td> - * <td>bitwiseAnd</td> - * <td>bitwiseAnd(x, y)</td> - * </tr> - * <tr> - * <td>|</td> - * <td>bitwiseOr</td> - * <td>bitwiseOr(x, y)</td> - * </tr> - * <tr> - * <td>^</td> - * <td>bitwiseXor</td> - * <td>bitwiseXor(x, y)</td> - * </tr> - * <tr> - * <td>!</td> - * <td>logicalNot</td> - * <td>logicalNot(x)</td> - * </tr> - * <tr> - * <td>-</td> - * <td>bitwiseComplement</td> - * <td>bitiwiseComplement(x)</td> - * </tr> - * <tr> - * <td>==</td> - * <td>equals</td> - * <td>equals(x, y)</td> - * </tr> - * <tr> - * <td><</td> - * <td>lessThan</td> - * <td>lessThan(x, y)</td> - * </tr> - * <tr> - * <td><=</td> - * <td>lessThanOrEqual</td> - * <td>lessThanOrEqual(x, y)</td> - * </tr> - * <tr> - * <td>></td> - * <td>greaterThan</td> - * <td>greaterThan(x, y)</td> - * </tr> - * <tr> - * <td>>=</td> - * <td>greaterThanOrEqual</td> - * <td>greaterThanOrEqual(x, y)</td> - * </tr> - * <tr> - * <td>-</td> - * <td>negate</td> - * <td>negate(x)</td> - * </tr> - * <tr> - * <td>size</td> - * <td>size</td> - * <td>size(x)</td> - * </tr> - * <tr> - * <td>empty</td> - * <td>empty</td> - * <td>empty(x)</td> - * </tr> - * </table> * <p> * You can also add methods to overload property getters and setters operators behaviors. * Public methods of the JexlArithmetic instance named propertyGet/propertySet/arrayGet/arraySet are potential diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java index 9a00abd4..fe0dbb0a 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java @@ -110,7 +110,8 @@ public abstract class JexlNode extends SimpleNode { if (value instanceof JexlPropertyGet || value instanceof JexlPropertySet || value instanceof JexlMethod - || value instanceof Funcall ) { + || value instanceof Funcall + || value instanceof Class ) { jjtSetValue(null); } for (int n = 0; n < jjtGetNumChildren(); ++n) { diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java index 487fcc46..eb2cbc0d 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java @@ -695,19 +695,20 @@ public abstract class JexlParser extends StringParser { return true; } Scope blockScope = blockScopes.get(block); + int lexical = symbol; for (LexicalUnit unit : blocks) { Scope unitScope = blockScopes.get(unit); // follow through potential capture if (blockScope != unitScope) { - int cs = blockScope.getCaptureDeclaration(symbol); - if (cs >= 0) { - symbol = cs; + int declared = blockScope.getCaptureDeclaration(lexical); + if (declared >= 0) { + lexical = declared; } if (unitScope != null) { blockScope = unitScope; } } - if (unit.isConstant(symbol)) { + if (unit.isConstant(lexical)) { return true; } } diff --git a/src/site/xdoc/reference/examples.xml b/src/site/xdoc/reference/examples.xml index 29adf331..2101bab6 100644 --- a/src/site/xdoc/reference/examples.xml +++ b/src/site/xdoc/reference/examples.xml @@ -55,7 +55,7 @@ <ul> <li>An <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlEngine.html">engine</a> to create expressions,</li> <li>A <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlContext.html">context</a> containing any variables, and</li> - <li>An <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/Expression.html">expression</a></li> + <li>An <a href="https://commons.apache.org/jexl/apidocs/org/apache/commons/jexl3/JexlExpression.html">expression</a></li> </ul> </p> <p> diff --git a/src/site/xdoc/reference/syntax.xml b/src/site/xdoc/reference/syntax.xml index cbbb468a..83f3a40c 100644 --- a/src/site/xdoc/reference/syntax.xml +++ b/src/site/xdoc/reference/syntax.xml @@ -874,6 +874,9 @@ <li>&=</li> <li>|=</li> <li>^=</li> + <li><<=</li> + <li>>>=</li> + <li>>>>=</li> </ul> </td> </tr> @@ -889,7 +892,7 @@ <td> The unary <code>+</code> operator is used. It performs an integral promotion meaning that byte, short, char arguments will be promoted to integer as a result. - For example <code>+12</code> or <code>-(a * b)</code> + For example <code>+12</code> or <code>+(a * b)</code> </td> </tr> <tr> @@ -1022,7 +1025,7 @@ <td>while</td> <td> Loop until a condition is satisfied, e.g. - <code>while (x lt 10) { + <code>while (x < 10) { x = x + 2; }</code> </td> @@ -1033,7 +1036,7 @@ Loop until a condition is satisfied, e.g. <code>do { x = x + 2; - } while (x lt 10)</code> + } while (x < 10)</code> </td> </tr> <tr> diff --git a/src/test/java/org/apache/commons/jexl3/LexicalTest.java b/src/test/java/org/apache/commons/jexl3/LexicalTest.java index be97c44d..62ecfbc3 100644 --- a/src/test/java/org/apache/commons/jexl3/LexicalTest.java +++ b/src/test/java/org/apache/commons/jexl3/LexicalTest.java @@ -930,7 +930,7 @@ public class LexicalTest { } @Test - public void testConstb0() { + public void testConst0b() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlScript script = jexl.createScript(