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/07/27 12:02:50 UTC
svn commit: r1692852 [3/3] - in /commons/proper/jexl/trunk/src:
main/java/org/apache/commons/jexl3/
main/java/org/apache/commons/jexl3/internal/
main/java/org/apache/commons/jexl3/internal/introspection/
main/java/org/apache/commons/jexl3/introspection...
Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java?rev=1692852&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java Mon Jul 27 10:02:49 2015
@@ -0,0 +1,406 @@
+/*
+ * 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 org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlOperator;
+import org.apache.commons.jexl3.introspection.JexlMethod;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
+import org.apache.commons.jexl3.parser.JexlNode;
+
+/**
+ * Helper class to deal with operator overloading and specifics.
+ * @since 3.0
+ */
+public class Operators {
+ /** The owner. */
+ protected final Interpreter interpreter;
+ /** The overloaded arithmetic operators. */
+ protected final JexlArithmetic.Uberspect operators;
+
+ /**
+ * Constructor.
+ * @param owner the owning interpreter
+ */
+ protected Operators(Interpreter owner) {
+ final JexlArithmetic arithmetic = owner.arithmetic;
+ final JexlUberspect uberspect = owner.uberspect;
+ this.interpreter = owner;
+ this.operators = uberspect.getArithmetic(arithmetic);
+ }
+
+ /**
+ * Checks whether a method returns a boolean or a Boolean
+ * @param vm the JexlMethod (may be null)
+ * @return true of false
+ */
+ private boolean returnsBoolean(JexlMethod vm) {
+ if (vm !=null) {
+ Class<?> rc = vm.getReturnType();
+ return Boolean.TYPE.equals(rc) || Boolean.class.equals(rc);
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to call a monadic operator.
+ * <p>
+ * This takes care of finding and caching the operator method when appropriate
+ * @param node the syntactic node
+ * @param operator the operator
+ * @param arg the argument
+ * @return the result of the operator evaluation or TRY_FAILED
+ */
+ protected Object tryOverload(JexlNode node, JexlOperator operator, Object arg) {
+ if (operators != null && operators.overloads(operator)) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final boolean cache = interpreter.cache;
+ if (cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof JexlMethod) {
+ JexlMethod me = (JexlMethod) cached;
+ Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, arg);
+ if (!me.tryFailed(eval)) {
+ return eval;
+ }
+ }
+ }
+ try {
+ JexlMethod emptym = operators.getOperator(operator, arg);
+ if (emptym != null) {
+ Object result = emptym.invoke(arithmetic, arg);
+ if (cache) {
+ node.jjtSetValue(emptym);
+ }
+ return result;
+ }
+ } catch (Exception xany) {
+ interpreter.operatorError(node, operator, xany);
+ }
+ }
+ return JexlEngine.TRY_FAILED;
+ }
+
+ /**
+ * Attempts to call a diadic operator.
+ * <p>
+ * This takes care of finding and caching the operator method when appropriate
+ * @param node the syntactic node
+ * @param operator the operator
+ * @param lhs the left hand side argument
+ * @param rhs the right hand side argument
+ * @return the result of the operator evaluation or TRY_FAILED
+ */
+ protected Object tryOverload(JexlNode node, JexlOperator operator, Object lhs, Object rhs) {
+ if (operators != null && operators.overloads(operator)) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final boolean cache = interpreter.cache;
+ if (cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof JexlMethod) {
+ JexlMethod me = (JexlMethod) cached;
+ Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, lhs, rhs);
+ if (!me.tryFailed(eval)) {
+ return eval;
+ }
+ }
+ }
+ try {
+ JexlMethod emptym = operators.getOperator(operator, lhs, rhs);
+ if (emptym != null) {
+ Object result = emptym.invoke(arithmetic, lhs, rhs);
+ if (cache) {
+ node.jjtSetValue(emptym);
+ }
+ return result;
+ }
+ } catch (Exception xany) {
+ interpreter.operatorError(node, operator, xany);
+ }
+ }
+ return JexlEngine.TRY_FAILED;
+ }
+
+ /**
+ * Evaluates an assign operator.
+ * <p>
+ * This takes care of finding and caching the operator method when appropriate.
+ * If an overloads returns Operator.ASSIGN, it means the side-effect is complete.
+ * Otherwise, a += b <=> a = a + b
+ * </p>
+ * @param node the syntactic node
+ * @param operator the operator
+ * @param lhs the left hand side, target of the side-effect
+ * @param rhs the right hand side, argument of the (base) operator
+ * @return the result of the operator evaluation
+ */
+ protected Object tryAssignOverload(JexlNode node, JexlOperator operator, Object lhs, Object rhs) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ // try to call overload on side effect
+ Object result = tryOverload(node, operator, lhs, rhs);
+ if (result != JexlEngine.TRY_FAILED) {
+ return result;
+ }
+ // call base operator
+ JexlOperator base = operator.getBaseOperator();
+ if (base == null) {
+ throw new IllegalArgumentException("must be called with a side-effect operator");
+ }
+ if (operators != null && operators.overloads(base)) {
+ // in case there is an overload
+ try {
+ JexlMethod emptym = operators.getOperator(base, lhs, rhs);
+ if (emptym != null) {
+ result = emptym.invoke(arithmetic, lhs, rhs);
+ if (result != JexlEngine.TRY_FAILED) {
+ return result;
+ }
+ }
+ } catch (Exception xany) {
+ interpreter.operatorError(node, base, xany);
+ }
+ }
+ // base eval
+ switch (operator) {
+ case SELF_ADD:
+ return arithmetic.add(lhs, rhs);
+ case SELF_SUBTRACT:
+ return arithmetic.subtract(lhs, rhs);
+ case SELF_MULTIPLY:
+ return arithmetic.multiply(lhs, rhs);
+ case SELF_DIVIDE:
+ return arithmetic.divide(lhs, rhs);
+ case SELF_MOD:
+ return arithmetic.mod(lhs, rhs);
+ case SELF_AND:
+ return arithmetic.and(lhs, rhs);
+ case SELF_OR:
+ return arithmetic.or(lhs, rhs);
+ case SELF_XOR:
+ return arithmetic.xor(lhs, rhs);
+ default:
+ throw new JexlException.Operator(node, operator.getOperatorSymbol(), null);
+ }
+ }
+
+ /**
+ * The 'startsWith' operator implementation.
+ * @param node the node
+ * @param operator the calling operator, $= or $!
+ * @param left the left operand
+ * @param right the right operand
+ * @return true if left starts with right, false otherwise
+ */
+ protected boolean startsWith(JexlNode node, String operator, Object left, Object right) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final JexlUberspect uberspect = interpreter.uberspect;
+ try {
+ // try operator overload
+ Object result = tryOverload(node, JexlOperator.STARTSWITH, left, right);
+ if (result instanceof Boolean) {
+ return (Boolean) result;
+ }
+ // use arithmetic / pattern matching ?
+ Boolean matched = arithmetic.startsWith(left, right);
+ if (matched != null) {
+ return matched;
+ }
+ // try a startsWith method (duck type)
+ try {
+ Object[] argv = {right};
+ JexlMethod vm = uberspect.getMethod(left, "startsWith", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ } else if (arithmetic.narrowArguments(argv)) {
+ vm = uberspect.getMethod(left, "startsWith", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ }
+ }
+ } catch (Exception e) {
+ throw new JexlException(node, operator + " error", e);
+ }
+ // defaults to equal
+ return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
+ } catch (ArithmeticException xrt) {
+ throw new JexlException(node, operator + " error", xrt);
+ }
+ }
+
+ /**
+ * The 'endsWith' operator implementation.
+ * @param node the node
+ * @param operator the calling operator, ^= or ^!
+ * @param left the left operand
+ * @param right the right operand
+ * @return true if left ends with right, false otherwise
+ */
+ protected boolean endsWith(JexlNode node, String operator, Object left, Object right) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final JexlUberspect uberspect = interpreter.uberspect;
+ try {
+ // try operator overload
+ Object result = tryOverload(node, JexlOperator.ENDSWITH, left, right);
+ if (result instanceof Boolean) {
+ return (Boolean) result;
+ }
+ // use arithmetic / pattern matching ?
+ Boolean matched = arithmetic.endsWith(left, right);
+ if (matched != null) {
+ return matched;
+ }
+ // try a endsWith method (duck type)
+ try {
+ Object[] argv = {right};
+ JexlMethod vm = uberspect.getMethod(left, "endsWith", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ } else if (arithmetic.narrowArguments(argv)) {
+ vm = uberspect.getMethod(left, "endsWith", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ }
+ }
+ } catch (Exception e) {
+ throw new JexlException(node, operator + " error", e);
+ }
+ // defaults to equal
+ return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE;
+ } catch (ArithmeticException xrt) {
+ throw new JexlException(node, operator + " error", xrt);
+ }
+ }
+
+ /**
+ * The 'match'/'in' operator implementation.
+ * <p>
+ * Note that 'x in y' or 'x matches y' means 'y contains x' ;
+ * the JEXL operator arguments order syntax is the reverse of this method call.
+ * </p>
+ * @param node the node
+ * @param op the calling operator, =~ or !=
+ * @param right the left operand
+ * @param left the right operand
+ * @return true if left matches right, false otherwise
+ */
+ protected boolean contains(JexlNode node, String op, Object left, Object right) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final JexlUberspect uberspect = interpreter.uberspect;
+ try {
+ // try operator overload
+ Object result = tryOverload(node, JexlOperator.CONTAINS, left, right);
+ if (result instanceof Boolean) {
+ return (Boolean) result;
+ }
+ // use arithmetic / pattern matching ?
+ Boolean matched = arithmetic.contains(left, right);
+ if (matched != null) {
+ return matched;
+ }
+ // try a contains method (duck type set)
+ try {
+ Object[] argv = {right};
+ JexlMethod vm = uberspect.getMethod(left, "contains", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ } else if (arithmetic.narrowArguments(argv)) {
+ vm = uberspect.getMethod(left, "contains", argv);
+ if (returnsBoolean(vm)) {
+ return (Boolean) vm.invoke(left, argv);
+ }
+ }
+ } catch (Exception e) {
+ throw new JexlException(node, op + " error", e);
+ }
+ // defaults to equal
+ return arithmetic.equals(left, right);
+ } catch (ArithmeticException xrt) {
+ throw new JexlException(node, op + " error", xrt);
+ }
+ }
+
+ /**
+ * Check for emptyness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty()
+ * method.
+ *
+ * @param node the node holding the object
+ * @param object the object to check the emptyness of.
+ * @return the boolean
+ */
+ protected Boolean empty(JexlNode node, Object object) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final JexlUberspect uberspect = interpreter.uberspect;
+ if (object == null) {
+ return Boolean.TRUE;
+ }
+ Object opcall = Operators.this.tryOverload(node, JexlOperator.EMPTY, object);
+ if (opcall instanceof Boolean) {
+ return (Boolean) opcall;
+ }
+ Boolean result = arithmetic.isEmpty(object);
+ if (result == null) {
+ result = false;
+ // check if there is an isEmpty method on the object that returns a
+ // boolean and if so, just use it
+ JexlMethod vm = uberspect.getMethod(object, "isEmpty", Interpreter.EMPTY_PARAMS);
+ if (returnsBoolean(vm)) {
+ try {
+ result = (Boolean) vm.invoke(object, Interpreter.EMPTY_PARAMS);
+ } catch (Exception xany) {
+ interpreter.operatorError(node, JexlOperator.EMPTY, xany);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Calculate the <code>size</code> of various types:
+ * Collection, Array, Map, String, and anything that has a int size() method.
+ *
+ * @param node the node that gave the value to size
+ * @param object the object to get the size of.
+ * @return the size of val
+ */
+ protected Integer size(JexlNode node, Object object) {
+ final JexlArithmetic arithmetic = interpreter.arithmetic;
+ final JexlUberspect uberspect = interpreter.uberspect;
+ if (object == null) {
+ return 0;
+ }
+ Object opcall = Operators.this.tryOverload(node, JexlOperator.SIZE, object);
+ if (opcall instanceof Integer) {
+ return (Integer) opcall;
+ }
+ Integer result = arithmetic.size(object);
+ if (result == null) {
+ // check if there is a size method on the object that returns an
+ // integer and if so, just use it
+ JexlMethod vm = uberspect.getMethod(object, "size", Interpreter.EMPTY_PARAMS);
+ if (vm != null && (Integer.TYPE.equals(vm.getReturnType()) || Integer.class.equals(vm.getReturnType()))) {
+ try {
+ result = (Integer) vm.invoke(object, Interpreter.EMPTY_PARAMS);
+ } catch (Exception xany) {
+ interpreter.operatorError(node, JexlOperator.SIZE, xany);
+ }
+ }
+ }
+ return result;
+ }
+}
Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java Mon Jul 27 10:02:49 2015
@@ -18,8 +18,8 @@ package org.apache.commons.jexl3.interna
import org.apache.commons.jexl3.JexlArithmetic;
-import org.apache.commons.jexl3.JexlArithmetic.Operator;
import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlOperator;
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
import org.apache.commons.jexl3.introspection.JexlPropertySet;
@@ -66,7 +66,7 @@ public class Uberspect implements JexlUb
* <p>This keeps track of which operator methods are overloaded per JexlArithemtic classes
* allowing a fail fast test during interpretation by avoiding seeking a method when there is none.
*/
- private final Map<Class<? extends JexlArithmetic>, Set<Operator>> operatorMap;
+ private final Map<Class<? extends JexlArithmetic>, Set<JexlOperator>> operatorMap;
/**
* Creates a new Uberspect.
@@ -76,7 +76,7 @@ public class Uberspect implements JexlUb
rlog = runtimeLogger;
ref = new SoftReference<Introspector>(null);
loader = new SoftReference<ClassLoader>(getClass().getClassLoader());
- operatorMap = new ConcurrentHashMap<Class<? extends JexlArithmetic>, Set<Operator>>();
+ operatorMap = new ConcurrentHashMap<Class<? extends JexlArithmetic>, Set<JexlOperator>>();
version = new AtomicInteger(0);
}
@@ -370,14 +370,14 @@ public class Uberspect implements JexlUb
/** The arithmetic instance being analyzed. */
private final JexlArithmetic arithmetic;
/** The set of overloaded operators. */
- private final EnumSet<Operator> overloads;
+ private final EnumSet<JexlOperator> overloads;
/**
* Creates an instance.
* @param theArithmetic the arithmetic instance
* @param theOverloads the overloaded operators
*/
- private ArithmeticUberspect(JexlArithmetic theArithmetic, Set<Operator> theOverloads) {
+ private ArithmeticUberspect(JexlArithmetic theArithmetic, Set<JexlOperator> theOverloads) {
this.arithmetic = theArithmetic;
this.overloads = EnumSet.copyOf(theOverloads);
// register this arithmetic class in the operator map
@@ -385,21 +385,21 @@ public class Uberspect implements JexlUb
}
@Override
- public JexlMethod getOperator(JexlArithmetic.Operator operator, Object arg) {
+ public JexlMethod getOperator(JexlOperator operator, Object arg) {
return overloads.contains(operator) && arg != null
? getMethod(arithmetic, operator.getMethodName(), arg)
: null;
}
@Override
- public JexlMethod getOperator(JexlArithmetic.Operator operator, Object lhs, Object rhs) {
+ public JexlMethod getOperator(JexlOperator operator, Object lhs, Object rhs) {
return overloads.contains(operator) && lhs != null && rhs != null
? getMethod(arithmetic, operator.getMethodName(), lhs, rhs)
: null;
}
@Override
- public boolean overloads(Operator operator) {
+ public boolean overloads(JexlOperator operator) {
return overloads.contains(operator);
}
}
@@ -408,10 +408,10 @@ public class Uberspect implements JexlUb
public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
JexlArithmetic.Uberspect jau = null;
if (arithmetic != null) {
- Set<Operator> ops = operatorMap.get(arithmetic.getClass());
+ Set<JexlOperator> ops = operatorMap.get(arithmetic.getClass());
if (ops == null) {
- ops = EnumSet.noneOf(Operator.class);
- for (JexlArithmetic.Operator op : JexlArithmetic.Operator.values()) {
+ ops = EnumSet.noneOf(JexlOperator.class);
+ for (JexlOperator op : JexlOperator.values()) {
Method[] methods = getMethods(arithmetic.getClass(), op.getMethodName());
if (methods != null) {
for (Method method : methods) {
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java Mon Jul 27 10:02:49 2015
@@ -88,6 +88,7 @@ public interface JexlUberspect {
* Gets an arithmetic operator resolver for a given arithmetic instance.
* @param arithmetic the arithmetic instance
* @return the arithmetic uberspect or null if no operator method were override
+ * @since 3.0
*/
JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic);
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=1692852&r1=1692851&r2=1692852&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 Mon Jul 27 10:02:49 2015
@@ -157,17 +157,27 @@ PARSER_END(Parser)
}
<*> TOKEN : { /* OPERATORS */
- < assign : "=" >
- | < mod : "%" | "mod" >
- | < div : "/" | "div" >
- | < not : "!" | "not" >
+ < plus_assign : "+=" >
+ | < minus_assign : "-=" >
+ | < mult_assign : "*=" >
+ | < div_assign : "/=" >
+ | < mod_assign : "%=" >
+ | < and_assign : "&=" >
+ | < or_assign : "|=" >
+ | < xor_assign : "^=" >
+
+ | < assign : "=" >
| < plus : "+" >
| < minus : "-" >
| < mult : "*" >
- | < tilda : "~" >
+ | < div : "/" | "div" >
+ | < mod : "%" | "mod" >
+ | < not : "!" | "not" >
| < and : "&" >
| < or : "|" >
| < xor : "^" >
+
+ | < tilda : "~" >
| < range : ".." >
}
@@ -368,7 +378,26 @@ void Expression() #void : {}
void AssignmentExpression() #void : {}
{
- ConditionalExpression() [ LOOKAHEAD( <assign> ) <assign> Expression() #Assignment(2) ]
+ ConditionalExpression()
+ ( LOOKAHEAD(2) (
+ <plus_assign> Expression() #SetAddNode(2)
+ |
+ <mult_assign> Expression() #SetMultNode(2)
+ |
+ <div_assign> Expression() #SetDivNode(2)
+ |
+ <mod_assign> Expression() #SetModNode(2)
+ |
+ <and_assign> Expression() #SetAndNode(2)
+ |
+ <or_assign> Expression() #SetOrNode(2)
+ |
+ <xor_assign> Expression() #SetXorNode(2)
+ |
+ <minus_assign> Expression() #SetSubNode(2)
+ |
+ <assign> Expression() #Assignment(2)
+ ) )*
}
/***************************************
@@ -481,17 +510,17 @@ void MultiplicativeExpression() #void :
void UnaryExpression() #void : {}
{
- <minus> UnaryExpression() #UnaryMinusNode(1)
-|
- <tilda> UnaryExpression() #BitwiseComplNode(1)
-|
- <not> UnaryExpression() #NotNode(1)
-|
- <EMPTY> UnaryExpression() #EmptyFunction(1)
-|
- <SIZE> UnaryExpression() #SizeFunction(1)
-|
- ValueExpression()
+ <minus> UnaryExpression() #UnaryMinusNode(1)
+ |
+ <tilda> UnaryExpression() #BitwiseComplNode(1)
+ |
+ <not> UnaryExpression() #NotNode(1)
+ |
+ <EMPTY> UnaryExpression() #EmptyFunction(1)
+ |
+ <SIZE> UnaryExpression() #SizeFunction(1)
+ |
+ ValueExpression()
}
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=1692852&r1=1692851&r2=1692852&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 Mon Jul 27 10:02:49 2015
@@ -159,4 +159,20 @@ public abstract class ParserVisitor {
protected abstract Object visit(ASTArguments node, Object data);
protected abstract Object visit(ASTReferenceExpression node, Object data);
+
+ protected abstract Object visit(ASTSetAddNode node, Object data);
+
+ protected abstract Object visit(ASTSetSubNode node, Object data);
+
+ protected abstract Object visit(ASTSetMultNode node, Object data);
+
+ protected abstract Object visit(ASTSetDivNode node, Object data);
+
+ protected abstract Object visit(ASTSetModNode node, Object data);
+
+ protected abstract Object visit(ASTSetAndNode node, Object data);
+
+ protected abstract Object visit(ASTSetOrNode node, Object data);
+
+ protected abstract Object visit(ASTSetXorNode node, Object data);
}
Modified: commons/proper/jexl/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/changes.xml?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Mon Jul 27 10:02:49 2015
@@ -26,6 +26,9 @@
</properties>
<body>
<release version="3.0" date="unreleased">
+ <action dev="henrib" type="add" issue="JEXL-170">
+ Implement assignment operators
+ </action>
<action dev="henrib" type="fix" issue="JEXL-169" due-to="Robert NeÃelrath">
A string is wrongly identified as FloatingPointNumber
</action>
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.java Mon Jul 27 10:02:49 2015
@@ -26,6 +26,7 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.jexl3.junit.Asserter;
+import java.util.Arrays;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -127,6 +128,14 @@ public class ArithmeticOperatorTest exte
return values.iterator();
}
+ public boolean contains(int i) {
+ return values.contains(i);
+ }
+
+ public boolean contains(int[] i) {
+ return values.containsAll(Arrays.asList(i));
+ }
+
public boolean startsWith(int i) {
return values.first().equals(i);
}
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java Mon Jul 27 10:02:49 2015
@@ -16,6 +16,7 @@
*/
package org.apache.commons.jexl3;
+import static org.apache.commons.jexl3.JexlArithmetic.FLOAT_PATTERN;
import org.apache.commons.jexl3.junit.Asserter;
import java.io.ByteArrayInputStream;
@@ -27,7 +28,6 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
-import static org.apache.commons.jexl3.JexlArithmetic.FLOAT_PATTERN;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -412,7 +412,6 @@ public class ArithmeticTest extends Jexl
Assert.assertTrue((Boolean) result);
}
-
@Test
public void testAddWithStringsLenient() throws Exception {
JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(false)).create();
@@ -568,7 +567,7 @@ public class ArithmeticTest extends Jexl
}
public static class Var {
- final int value;
+ int value;
Var(int v) {
value = v;
@@ -630,15 +629,15 @@ public class ArithmeticTest extends Jexl
return new Var(-arg.value);
}
- public Var bitwiseAnd(Var lhs, Var rhs) {
+ public Var and(Var lhs, Var rhs) {
return new Var(lhs.value & rhs.value);
}
- public Var bitwiseOr(Var lhs, Var rhs) {
+ public Var or(Var lhs, Var rhs) {
return new Var(lhs.value | rhs.value);
}
- public Var bitwiseXor(Var lhs, Var rhs) {
+ public Var xor(Var lhs, Var rhs) {
return new Var(lhs.value ^ rhs.value);
}
@@ -654,7 +653,7 @@ public class ArithmeticTest extends Jexl
return lhs.toString().endsWith(rhs.toString());
}
- public Var bitwiseComplement(Var arg) {
+ public Var complement(Var arg) {
return new Var(~arg.value);
}
@@ -683,6 +682,7 @@ public class ArithmeticTest extends Jexl
JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new ArithmeticPlus(false)).create();
JexlContext jc = new EmptyTestContext();
runOverload(jexl, jc);
+ runOverload(jexl, jc);
}
@Test
@@ -854,15 +854,21 @@ public class ArithmeticTest extends Jexl
result = script.execute(jc, 3155, 15);
Assert.assertFalse((Boolean) result);
result = script.execute(jc, new Var(3155), new Var(15));
+ Assert.assertFalse((Boolean) result);
+ result = script.execute(jc, new Var(15), new Var(3155));
Assert.assertTrue((Boolean) result);
script = jexl.createScript("(x, y)->{ x !~ y }");
result = script.execute(jc, 3115, 15);
Assert.assertTrue((Boolean) result);
result = script.execute(jc, new Var(3155), new Var(15));
+ Assert.assertTrue((Boolean) result);
+ result = script.execute(jc, new Var(15), new Var(3155));
Assert.assertFalse((Boolean) result);
+
}
+
public static class Arithmetic132 extends JexlArithmetic {
public Arithmetic132() {
super(false);
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayAccessTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayAccessTest.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayAccessTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayAccessTest.java Mon Jul 27 10:02:49 2015
@@ -22,7 +22,9 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.jexl3.junit.Asserter;
+import org.junit.Assert;
import org.junit.Before;
+import org.junit.Test;
/**
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=1692852&r1=1692851&r2=1692852&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 Mon Jul 27 10:02:49 2015
@@ -22,14 +22,26 @@ import java.math.MathContext;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.jexl3.internal.introspection.Uberspect;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+//import org.apache.commons.beanutils.LazyDynaMap;
/**
* Test cases for reported issue .
@@ -1051,16 +1063,19 @@ public class IssuesTest extends JexlTest
public static class Question42 extends MapContext {
public String functionA(String arg) {
- return "a".equals(arg)? "A" : "";
+ return "a".equals(arg) ? "A" : "";
}
+
public String functionB(String arg) {
- return "b".equals(arg)? "B" : "";
+ return "b".equals(arg) ? "B" : "";
}
+
public String functionC(String arg) {
- return "c".equals(arg)? "C" : "";
+ return "c".equals(arg) ? "C" : "";
}
+
public String functionD(String arg) {
- return "d".equals(arg)? "D" : "";
+ return "d".equals(arg) ? "D" : "";
}
}
@@ -1069,15 +1084,23 @@ public class IssuesTest extends JexlTest
super(false);
}
- public Object bitwiseAnd(String lhs, String rhs) {
- if (rhs.isEmpty()) { return ""; }
- if (lhs.isEmpty()) { return ""; }
+ public Object and(String lhs, String rhs) {
+ if (rhs.isEmpty()) {
+ return "";
+ }
+ if (lhs.isEmpty()) {
+ return "";
+ }
return lhs + rhs;
}
- public Object bitwiseOr(String lhs, String rhs) {
- if (rhs.isEmpty()) { return lhs; }
- if (lhs.isEmpty()) { return rhs; }
+ public Object or(String lhs, String rhs) {
+ if (rhs.isEmpty()) {
+ return lhs;
+ }
+ if (lhs.isEmpty()) {
+ return rhs;
+ }
return lhs + rhs;
}
}
@@ -1109,4 +1132,117 @@ public class IssuesTest extends JexlTest
Object r1 = jexl.createExpression("463.0B * 0.1B").evaluate(jc);
Assert.assertEquals(java.math.BigDecimal.class, r1.getClass());
}
+
+//
+//
+// @Test
+// public void testUnderscoreInName() {
+// JexlEngine jexl = new Engine();
+// String jexlExp = "(x.length_mm * x.width)";
+// JexlExpression e = jexl.createExpression( jexlExp );
+// JexlContext jc = new MapContext();
+//
+// LazyDynaMap object = new LazyDynaMap();
+// object.set("length_mm", "10.0");
+// object.set("width", "5.0");
+//
+// jc.set("x", object );
+//
+// Assert.assertEquals(null, ((Double)e.evaluate(jc)).doubleValue(), 50d, 0d);
+// }
+//
+// @Test
+// public void testFullStopInName() {
+// JexlEngine jexl = new Engine();
+// String jexlExp = "(x.length.mm * x.width)";
+// JexlExpression e = jexl.createExpression( jexlExp );
+// JexlContext jc = new MapContext();
+//
+// LazyDynaMap object = new LazyDynaMap();
+// object.set("length.mm", "10.0");
+// object.set("width", "5.0");
+//
+// Assert.assertEquals(null, object.get("length.mm"), "10.0");
+//
+// jc.set("x", object );
+//
+// Assert.assertEquals(null, ((Double)e.evaluate(jc)).doubleValue(), 50d, 0d);
+// }
+//
+// @Test
+// public void testFullStopInNameMakingSubObject() {
+// JexlEngine jexl = new Engine();
+// String jexlExp = "(x.length.mm * x.width)";
+// JexlExpression e = jexl.createExpression( jexlExp );
+// JexlContext jc = new MapContext();
+//
+// LazyDynaMap object = new LazyDynaMap();
+// LazyDynaMap subObject = new LazyDynaMap();
+// object.set("length", subObject);
+// subObject.set("mm", "10.0");
+// object.set("width", "5.0");
+//
+// jc.set("x", object );
+//
+// Assert.assertEquals(null, ((Double)e.evaluate(jc)).doubleValue(), 50d, 0d);
+// }
+
+
+ @Test
+ public void test161() throws Exception {
+ final JexlEngine jexl = new Engine();
+ final JexlContext jc = new MapContext();
+
+ Document xml = getDocument("<node info='123'/>");
+ NamedNodeMap nnm = xml.getLastChild().getAttributes();
+ Attr info = (Attr) nnm.getNamedItem("info");
+ Assert.assertEquals("123", info.getValue());
+
+ jc.set("x", xml.getLastChild());
+ final String y = "456";
+ jc.set("y", y);
+ JexlScript s = jexl.createScript("x.attribute.info = y");
+ Object r = s.execute(jc);
+ nnm = xml.getLastChild().getAttributes();
+ info = (Attr) nnm.getNamedItem("info");
+ Assert.assertEquals(y, r);
+ Assert.assertEquals(y, info.getValue());
+ }
+
+ public static class XmlArithmetic extends JexlArithmetic {
+ public XmlArithmetic(boolean lenient) {
+ super(lenient);
+ }
+ public boolean empty(org.w3c.dom.Element elt) {
+ return !elt.hasAttributes() && !elt.hasChildNodes();
+ }
+ }
+
+ @Test
+ public void test162() throws Exception {
+ JexlEngine jexl = //new JexlBuilder().arithmetic(new JexlArithmetic(false)).create();
+new JexlBuilder().arithmetic(new XmlArithmetic(false)).create();
+ JexlScript s0 = jexl.createScript("x.empty()", "x");
+ Document xml;
+ Node x;
+ Boolean r;
+ xml = getDocument("<node info='123'/>");
+ x = xml.getLastChild();
+ r = (Boolean) s0.execute(null, x);
+ Assert.assertFalse(r);
+ xml = getDocument("<node>some content</node>");
+ x = xml.getLastChild();
+ r = (Boolean) s0.execute(null, x);
+ Assert.assertFalse(r);
+ xml = getDocument("<node/>");
+ x = xml.getLastChild();
+ r = (Boolean) s0.execute(null, x);
+ Assert.assertTrue(r);
+ }
+
+ private static Document getDocument(String xml) throws IOException, SAXException, ParserConfigurationException {
+ DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputStream stringInputStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
+ return xmlBuilder.parse(stringInputStream);
+ }
}
Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java?rev=1692852&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java (added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java Mon Jul 27 10:02:49 2015
@@ -0,0 +1,404 @@
+/*
+ * 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.apache.commons.jexl3.junit.Asserter;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Tests for array access operator []
+ *
+ * @since 2.0
+ */
+@SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
+public class SideEffectTest extends JexlTestCase {
+
+ private Asserter asserter;
+
+ public SideEffectTest() {
+ super("SideEffectTest");
+ }
+
+ @Override
+ @Before
+ public void setUp() {
+ asserter = new Asserter(JEXL);
+ }
+
+ @Test
+ public void testSideEffectVar() throws Exception {
+ Map<String,Object> context = asserter.getVariables();
+ Integer i41 = Integer.valueOf(4141);
+ Object foo = i41;
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo += 2", i41 + 2);
+ Assert.assertEquals(context.get("foo"), i41 + 2);
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo -= 2", i41 - 2);
+ Assert.assertEquals(context.get("foo"), i41 - 2);
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo *= 2", i41 * 2);
+ Assert.assertEquals(context.get("foo"), i41 * 2);
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo /= 2", i41 / 2);
+ Assert.assertEquals(context.get("foo"), i41 / 2);
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo %= 2", i41 % 2);
+ Assert.assertEquals(context.get("foo"), i41 % 2);
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo &= 3", (long) (i41 & 3));
+ Assert.assertEquals(context.get("foo"), (long)(i41 & 3));
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo |= 2", (long)(i41 | 2));
+ Assert.assertEquals(context.get("foo"), (long)(i41 | 2));
+
+ context.put("foo", foo);
+ asserter.assertExpression("foo ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(context.get("foo"), (long)(i41 ^ 2));
+ }
+
+ @Test
+ public void testSideEffectArray() throws Exception {
+ Integer i41 = Integer.valueOf(4141);
+ Integer i42 = Integer.valueOf(42);
+ Integer i43 = Integer.valueOf(43);
+ String s42 = "fourty-two";
+ String s43 = "fourty-three";
+ Object[] foo = new Object[3];
+ foo[1] = i42;
+ foo[2] = i43;
+ asserter.setVariable("foo", foo);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] += 2", i41 + 2);
+ Assert.assertEquals(foo[0], i41 + 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] -= 2", i41 - 2);
+ Assert.assertEquals(foo[0], i41 - 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] *= 2", i41 * 2);
+ Assert.assertEquals(foo[0], i41 * 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] /= 2", i41 / 2);
+ Assert.assertEquals(foo[0], i41 / 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] %= 2", i41 % 2);
+ Assert.assertEquals(foo[0], i41 % 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] &= 3", (long) (i41 & 3));
+ Assert.assertEquals(foo[0], (long)(i41 & 3));
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] |= 2", (long)(i41 | 2));
+ Assert.assertEquals(foo[0], (long)(i41 | 2));
+ foo[0] = i41;
+ asserter.assertExpression("foo[0] ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(foo[0], (long)(i41 ^ 2));
+ }
+
+ @Test
+ public void testSideEffectAntishArray() throws Exception {
+ Integer i41 = Integer.valueOf(4141);
+ Integer i42 = Integer.valueOf(42);
+ Integer i43 = Integer.valueOf(43);
+ Object[] foo = new Object[3];
+ foo[1] = i42;
+ foo[2] = i43;
+ asserter.setVariable("foo.bar", foo);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] += 2", i41 + 2);
+ Assert.assertEquals(foo[0], i41 + 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] -= 2", i41 - 2);
+ Assert.assertEquals(foo[0], i41 - 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] *= 2", i41 * 2);
+ Assert.assertEquals(foo[0], i41 * 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] /= 2", i41 / 2);
+ Assert.assertEquals(foo[0], i41 / 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] %= 2", i41 % 2);
+ Assert.assertEquals(foo[0], i41 % 2);
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] &= 3", (long) (i41 & 3));
+ Assert.assertEquals(foo[0], (long)(i41 & 3));
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] |= 2", (long)(i41 | 2));
+ Assert.assertEquals(foo[0], (long)(i41 | 2));
+ foo[0] = i41;
+ asserter.assertExpression("foo.bar[0] ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(foo[0], (long)(i41 ^ 2));
+ }
+
+ public static class Foo {
+ int value;
+ Foo(int v) {
+ value = v;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+
+ public void setValue(long v) {
+ value = (int) v;
+ }
+ public int getValue() {
+ return value;
+ }
+
+ public void setBar(int x, long v) {
+ value = (int) v + x;
+ }
+
+ public int getBar(int x) {
+ return value + x;
+ }
+ }
+
+ @Test
+ public void testSideEffectBean() throws Exception {
+ Integer i41 = Integer.valueOf(4141);
+ Foo foo = new Foo(0);
+ asserter.setVariable("foo", foo);
+ foo.value = i41;
+ asserter.assertExpression("foo.value += 2", i41 + 2);
+ Assert.assertEquals(foo.value, i41 + 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.value -= 2", i41 - 2);
+ Assert.assertEquals(foo.value, i41 - 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.value *= 2", i41 * 2);
+ Assert.assertEquals(foo.value, i41 * 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.value /= 2", i41 / 2);
+ Assert.assertEquals(foo.value, i41 / 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.value %= 2", i41 % 2);
+ Assert.assertEquals(foo.value, i41 % 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.value &= 3", (long) (i41 & 3));
+ Assert.assertEquals(foo.value, (long)(i41 & 3));
+ foo.value = i41;
+ asserter.assertExpression("foo.value |= 2", (long)(i41 | 2));
+ Assert.assertEquals(foo.value, (long)(i41 | 2));
+ foo.value = i41;
+ asserter.assertExpression("foo.value ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(foo.value, (long)(i41 ^ 2));
+ }
+
+ @Test
+ public void testSideEffectBeanContainer() throws Exception {
+ Integer i41 = Integer.valueOf(4141);
+ Foo foo = new Foo(0);
+ asserter.setVariable("foo", foo);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] += 2", i41 + 2);
+ Assert.assertEquals(foo.value, i41 + 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[1] += 2", i41 + 3);
+ Assert.assertEquals(foo.value, i41 + 4);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] -= 2", i41 - 2);
+ Assert.assertEquals(foo.value, i41 - 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] *= 2", i41 * 2);
+ Assert.assertEquals(foo.value, i41 * 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] /= 2", i41 / 2);
+ Assert.assertEquals(foo.value, i41 / 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] %= 2", i41 % 2);
+ Assert.assertEquals(foo.value, i41 % 2);
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] &= 3", (long) (i41 & 3));
+ Assert.assertEquals(foo.value, (long)(i41 & 3));
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] |= 2", (long)(i41 | 2));
+ Assert.assertEquals(foo.value, (long)(i41 | 2));
+ foo.value = i41;
+ asserter.assertExpression("foo.bar[0] ^= 2", (long)(i41 ^ 2));
+ Assert.assertEquals(foo.value, (long)(i41 ^ 2));
+ }
+
+ @Test
+ public void testArithmeticSelf() throws Exception {
+ JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new SelfArithmetic(false)).create();
+ JexlContext jc = null;
+ runSelfOverload(jexl, jc);
+ runSelfOverload(jexl, jc);
+ }
+
+ @Test
+ public void testArithmeticSelfNoCache() throws Exception {
+ JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new SelfArithmetic(false)).create();
+ JexlContext jc = null;
+ runSelfOverload(jexl, jc);
+ }
+
+ protected void runSelfOverload(JexlEngine jexl, JexlContext jc) {
+ JexlScript script;
+ Object result;
+ script = jexl.createScript("(x, y)->{ x += y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115 + 15, result);
+ Var v0 = new Var(3115);
+ result = script.execute(jc, v0, new Var(15));
+ Assert.assertEquals(result, v0);
+ Assert.assertEquals(3115 + 15, v0.value);
+
+ script = jexl.createScript("(x, y)->{ x -= y}");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115 - 15, result);
+ Var v1 = new Var(3115);
+ result = script.execute(jc, v1, new Var(15));
+ Assert.assertNotEquals(result, v1); // not a real side effect
+ Assert.assertEquals(3115 - 15, ((Var) result).value);
+
+ script = jexl.createScript("(x, y)->{ x *= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115 * 15, result);
+ Var v2 = new Var(3115);
+ result = script.execute(jc, v2, new Var(15));
+ Assert.assertEquals(result, v2);
+ Assert.assertEquals(3115 * 15, v2.value);
+
+ script = jexl.createScript("(x, y)->{ x /= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115 / 15, result);
+ Var v3 = new Var(3115);
+ result = script.execute(jc, v3, new Var(15));
+ Assert.assertEquals(result, v3);
+ Assert.assertEquals(3115 / 15, v3.value);
+
+ script = jexl.createScript("(x, y)->{ x %= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115 % 15, result);
+ Var v4 = new Var(3115);
+ result = script.execute(jc, v4, new Var(15));
+ Assert.assertEquals(result, v4);
+ Assert.assertEquals(3115 % 15, v4.value);
+
+ script = jexl.createScript("(x, y)->{ x &= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115L & 15, result);
+ Var v5 = new Var(3115);
+ result = script.execute(jc, v5, new Var(15));
+ Assert.assertEquals(result, v5);
+ Assert.assertEquals(3115 & 15, v5.value);
+
+ script = jexl.createScript("(x, y)->{ x |= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115L | 15, result);
+ Var v6 = new Var(3115);
+ result = script.execute(jc, v6, new Var(15));
+ Assert.assertEquals(result, v6);
+ Assert.assertEquals(3115L | 15, v6.value);
+
+ script = jexl.createScript("(x, y)->{ x ^= y }");
+ result = script.execute(jc, 3115, 15);
+ Assert.assertEquals(3115L ^ 15, result);
+ Var v7 = new Var(3115);
+ result = script.execute(jc, v7, new Var(15));
+ Assert.assertEquals(result, v7);
+ Assert.assertEquals(3115L ^ 15, v7.value);
+ }
+
+ public static class Var {
+ int value;
+
+ Var(int v) {
+ value = v;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+ }
+
+ // an arithmetic that performs side effects
+ public static class SelfArithmetic extends JexlArithmetic {
+ public SelfArithmetic(boolean strict) {
+ super(strict);
+ }
+
+ public JexlOperator selfAdd(Var lhs, Var rhs) {
+ lhs.value += rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ // for kicks, this one does not side effect but overloads nevertheless
+ public Var selfSubtract(Var lhs, Var rhs) {
+ return new Var(lhs.value - rhs.value);
+ }
+
+ public JexlOperator selfDivide(Var lhs, Var rhs) {
+ lhs.value /= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ public JexlOperator selfMultiply(Var lhs, Var rhs) {
+ lhs.value *= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ public JexlOperator selfMod(Var lhs, Var rhs) {
+ lhs.value %= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ public Var and(Var lhs, Var rhs) {
+ return new Var(lhs.value & rhs.value);
+ }
+
+ public JexlOperator selfAnd(Var lhs, Var rhs) {
+ lhs.value &= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ public Var or(Var lhs, Var rhs) {
+ return new Var(lhs.value | rhs.value);
+ }
+
+ public JexlOperator selfOr(Var lhs, Var rhs) {
+ lhs.value |= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+
+ public Var xor(Var lhs, Var rhs) {
+ return new Var(lhs.value ^ rhs.value);
+ }
+
+ public JexlOperator selfXor(Var lhs, Var rhs) {
+ lhs.value ^= rhs.value;
+ return JexlOperator.ASSIGN;
+ }
+ }
+}
Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/junit/Asserter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/junit/Asserter.java?rev=1692852&r1=1692851&r2=1692852&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/junit/Asserter.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/junit/Asserter.java Mon Jul 27 10:02:49 2015
@@ -151,4 +151,21 @@ public class Asserter extends Assert {
public Object removeVariable(String name) {
return variables.remove(name);
}
+
+ /**
+ * Gets a variable of a certain name.
+ *
+ * @param name variable name
+ * @return value variable value
+ */
+ public Object getVariable(String name) {
+ return variables.get(name);
+ }
+
+ /**
+ * @return the variables map
+ */
+ public Map<String, Object> getVariables() {
+ return variables;
+ }
}