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/09/03 19:05:23 UTC
svn commit: r1701076 - 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/ main...
Author: henrib
Date: Thu Sep 3 17:05:22 2015
New Revision: 1701076
URL: http://svn.apache.org/r1701076
Log:
JEXL:
Better location information, tracks tokens from source;
Cleaned method/function resolution;
More tests (coverage up);
Various nitpicks on Javadoc;
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/JexlInfo.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/introspection/ConstructorMethod.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticOperatorTest.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
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.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=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java Thu Sep 3 17:05:22 2015
@@ -519,7 +519,7 @@ public class JexlArithmetic {
* Replace all numbers in an arguments array with the smallest type that will fit.
* @param args the argument array
* @return true if some arguments were narrowed and args array is modified,
- * false if no narrowing occured and args array has not been modified
+ * false if no narrowing occurred and args array has not been modified
*/
public boolean narrowArguments(Object[] args) {
boolean narrowed = false;
@@ -529,9 +529,9 @@ public class JexlArithmetic {
Number narg = (Number) arg;
Number narrow = narrow(narg);
if (!narg.equals(narrow)) {
+ args[a] = narrow;
narrowed = true;
}
- args[a] = narrow;
}
}
return narrowed;
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java?rev=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlInfo.java Thu Sep 3 17:05:22 2015
@@ -41,7 +41,7 @@ public class JexlInfo {
*/
public interface Detail {
/**
- * @return he start column on the line that triggered the error
+ * @return the start column on the line that triggered the error
*/
int start();
/**
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=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Thu Sep 3 17:05:22 2015
@@ -102,7 +102,6 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.JexlNode;
import org.apache.commons.jexl3.parser.Node;
import org.apache.commons.jexl3.parser.ParserVisitor;
-import org.apache.commons.jexl3.parser.StringParser;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -268,12 +267,12 @@ public class Interpreter extends ParserV
* @return throws JexlException if isStrict, null otherwise
*/
protected Object unsolvableVariable(JexlNode node, String var, boolean undef) {
- if (strictEngine && (undef || arithmetic.isStrict())) {
- throw new JexlException.Variable(node, var, undef);
- }
if (!silent) {
logger.warn(JexlException.variableError(node, var, undef));
}
+ if (strictEngine && (undef || arithmetic.isStrict())) {
+ throw new JexlException.Variable(node, var, undef);
+ }
return null;
}
@@ -284,12 +283,12 @@ public class Interpreter extends ParserV
* @return throws JexlException if isStrict, null otherwise
*/
protected Object unsolvableMethod(JexlNode node, String method) {
- if (strictEngine) {
- throw new JexlException.Method(node, method);
- }
if (!silent) {
logger.warn(JexlException.methodError(node, method));
}
+ if (strictEngine) {
+ throw new JexlException.Method(node, method);
+ }
return null;
}
@@ -301,12 +300,12 @@ public class Interpreter extends ParserV
* @return throws JexlException if isStrict, null otherwise
*/
protected Object unsolvableProperty(JexlNode node, String var, Throwable cause) {
- if (strictEngine) {
- throw new JexlException.Property(node, var, cause);
- }
if (!silent) {
logger.warn(JexlException.propertyError(node, var), cause);
}
+ if (strictEngine) {
+ throw new JexlException.Property(node, var, cause);
+ }
return null;
}
@@ -319,12 +318,12 @@ public class Interpreter extends ParserV
*/
protected void operatorError(JexlNode node, JexlOperator operator, Throwable cause) {
if (cause != null) {
- if (strictEngine) {
- throw new JexlException.Operator(node, operator.getOperatorSymbol(), cause);
- }
if (!silent) {
logger.warn(JexlException.operatorError(node, operator.getOperatorSymbol()), cause);
}
+ if (strictEngine) {
+ throw new JexlException.Operator(node, operator.getOperatorSymbol(), cause);
+ }
}
}
@@ -334,12 +333,12 @@ public class Interpreter extends ParserV
* @return throws JexlException if isStrict, null otherwise
*/
protected Object invocationFailed(JexlException xjexl) {
- if (strictEngine || xjexl instanceof JexlException.Return) {
- throw xjexl;
- }
if (!silent) {
logger.warn(xjexl.getMessage(), xjexl.getCause());
}
+ if (strictEngine || xjexl instanceof JexlException.Return) {
+ throw xjexl;
+ }
return null;
}
@@ -1413,29 +1412,155 @@ public class Interpreter extends ParserV
return result;
}
+ @Override
+ protected Object visit(ASTFunctionNode node, Object data) {
+ int argc = node.jjtGetNumChildren();
+ if (argc == 2) {
+ Object namespace = resolveNamespace(null, node);
+ if (namespace == null) {
+ namespace = context;
+ }
+ ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
+ ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
+ return call(node, namespace, functionNode, argNode);
+ } else {
+ // objectNode 0 is the prefix
+ String prefix = ((ASTIdentifier) node.jjtGetChild(0)).getName();
+ Object namespace = resolveNamespace(prefix, node);
+ // objectNode 1 is the identifier , the others are parameters.
+ ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(1);
+ ASTArguments argNode = (ASTArguments) node.jjtGetChild(2);
+ return call(node, namespace, functionNode, argNode);
+ }
+ }
+
+ /**
+ * Concatenate arguments in call(...).
+ * <p>When target == context, we are dealing with a global namespace function call
+ * @param target the pseudo-method owner, first to-be argument
+ * @param args the other arguments
+ * @return the arguments array
+ */
+ private Object[] functionArguments(Object target, Object[] args) {
+ if (args == null) {
+ return new Object[]{target};
+ }
+ if (context == target) {
+ return args;
+ }
+ Object[] nargv = new Object[args.length + 1];
+ nargv[0] = target;
+ System.arraycopy(args, 0, nargv, 1, args.length);
+ return nargv;
+ }
+
+ /**
+ * Narrow arguments in call(...).
+ * @param narrow predicate
+ * @param args the arguments to narrow
+ * @return the narrowed arguments (or the original ones)
+ */
+ private Object[] narrowArguments(boolean narrow, Object[] args) {
+ if (narrow) {
+ arithmetic.narrowArguments(args);
+ }
+ return args;
+ }
+
+ /**
+ * Cached function call.
+ */
+ private static class Funcall {
+ /** Whether narrow should be applied to arguments. */
+ protected final boolean narrow;
+ /** The JexlMethod to delegate the call to. */
+ protected final JexlMethod me;
+ /**
+ * Constructor.
+ * @param jme the method
+ * @param flag the narrow flag
+ */
+ protected Funcall(JexlMethod jme, boolean flag) {
+ this.me = jme;
+ this.narrow = flag;
+ }
+
+ /**
+ * Try invocation.
+ * @param ii the interpreter
+ * @param name the method name
+ * @param target the method target
+ * @param args the method arguments
+ * @return the method invocation result (or JexlEngine.TRY_FAILED)
+ */
+ protected Object tryInvoke(Interpreter ii, String name, Object target, Object[] args) {
+ return me.tryInvoke(name, target, ii.narrowArguments(narrow, args));
+ }
+ }
+
+ /**
+ * Cached arithmetic function call.
+ */
+ private static class ArithmeticFuncall extends Funcall {
+ /**
+ * Constructor.
+ * @param jme the method
+ * @param flag the narrow flag
+ */
+ protected ArithmeticFuncall(JexlMethod jme, boolean flag) {
+ super(jme, flag);
+ }
+
+ @Override
+ protected Object tryInvoke(Interpreter ii, String name, Object target, Object[] args) {
+ Object[] nargs = ii.functionArguments(target, args);
+ return me.tryInvoke(name, ii.arithmetic, ii.narrowArguments(narrow, nargs));
+ }
+ }
+ /**
+ * Cached context function call.
+ */
+ private static class ContextFuncall extends Funcall {
+ /**
+ * Constructor.
+ * @param jme the method
+ * @param flag the narrow flag
+ */
+ protected ContextFuncall(JexlMethod jme, boolean flag) {
+ super(jme, flag);
+ }
+
+ @Override
+ protected Object tryInvoke(Interpreter ii, String name, Object target, Object[] args) {
+ Object[] nargs = ii.functionArguments(target, args);
+ return me.tryInvoke(name, ii.context, ii.narrowArguments(narrow, nargs));
+ }
+ }
+
/**
* Calls a method (or function).
* <p>
* Method resolution is a follows:
- * 1 - attempt to find a method in the bean passed as parameter;
- * 3 - if this fails, seeks a JexlScript or JexlMethod as a property of that bean;
- * 2 - if this fails, narrow the arguments and try again
+ * 1 - attempt to find a method in the target passed as parameter;
+ * 2 - if this fails, seeks a JexlScript or JexlMethod or a duck-callable* as a property of that target;
+ * 3 - if this fails, narrow the arguments and try again 1
+ * 4 - if this fails, seeks a context or arithmetic method with the proper name taking the target as first argument;
* </p>
+ * *duck-callable: an object where a "call" function exists
*
* @param node the method node
- * @param bean the bean this method should be invoked upon
- * @param functor the object carrying the method or function
+ * @param target the target of the method, what it should be invoked upon
+ * @param functor the object carrying the method or function or the method identifier
* @param argNode the node carrying the arguments
* @return the result of the method invocation
*/
- protected Object call(JexlNode node, Object bean, Object functor, ASTArguments argNode) {
+ protected Object call(final JexlNode node, Object target, Object functor, final ASTArguments argNode) {
if (isCancelled()) {
throw new JexlException.Cancel(node);
}
JexlException xjexl;
// evaluate the arguments
Object[] argv = visit(argNode, null);
-
// get the method name if identifier
String methodName = null;
int symbol = -1;
@@ -1450,47 +1575,51 @@ public class Interpreter extends ParserV
}
try {
boolean cacheable = cache;
- boolean narrow = true;
+ // attempt to reuse last funcall cached in volatile JexlNode.value
+ if (cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof Funcall) {
+ Object eval = ((Funcall) cached).tryInvoke(this, methodName, target, argv);
+ if (JexlEngine.TRY_FAILED != eval) {
+ return eval;
+ }
+ }
+ }
+ boolean narrow = false;
JexlMethod vm = null;
+ Funcall funcall = null;
// pseudo loop and a half
while (true) {
if (methodName != null) {
- // attempt to reuse last executor cached in volatile JexlNode.value
- if (cache) {
- Object cached = node.jjtGetValue();
- if (cached instanceof JexlMethod) {
- JexlMethod me = (JexlMethod) cached;
- Object eval = me.tryInvoke(methodName, bean, argv);
- if (!me.tryFailed(eval)) {
- return eval;
- }
- }
- }
// try a method
- vm = uberspect.getMethod(bean, methodName, argv);
- if (vm != null || !narrow) {
- // if there is a method name, we will exit here on first or second pass
+ vm = uberspect.getMethod(target, methodName, argv);
+ if (vm != null) {
+ if (cacheable && vm.isCacheable()) {
+ funcall = new Funcall(vm, narrow);
+ }
break;
}
}
- // could not find a method, try as a var
- if (functor == null) {
+ // could not find a method, try as a var (local, global) or property (performed once)
+ if (functor == null && !narrow) {
if (symbol >= 0) {
functor = frame.get(symbol);
} else {
- JexlPropertyGet get = uberspect.getPropertyGet(bean, methodName);
+ // the method may be a functor stored in a property of the target
+ JexlPropertyGet get = uberspect.getPropertyGet(target, methodName);
if (get != null) {
- functor = get.tryInvoke(bean, methodName);
+ functor = get.tryInvoke(target, methodName);
}
}
}
+ // this may happen without the above when we are chaining call like x(a)(b)
if (functor != null) {
// lambda, script or jexl method will do
if (functor instanceof JexlScript) {
return ((JexlScript) functor).execute(context, argv);
}
if (functor instanceof JexlMethod) {
- return ((JexlMethod) functor).invoke(bean, argv);
+ return ((JexlMethod) functor).invoke(target, argv);
}
// a generic callable
vm = uberspect.getMethod(functor, "call", argv);
@@ -1498,26 +1627,49 @@ public class Interpreter extends ParserV
return vm.invoke(functor, argv);
}
}
- // if we did not find an exact method by name and we haven't tried yet,
- // attempt to narrow the parameters and if this succeeds, try again in next loop
- if (methodName == null || !arithmetic.narrowArguments(argv)) {
- break;
- } else {
- narrow = false;
+ // try JexlArithmetic or JexlContext function
+ if (methodName != null) {
+ // when target == context, we are dealing with a global namespace function call
+ Object[] nargv = functionArguments(target, argv);
+ vm = uberspect.getMethod(context, methodName, nargv);
+ if (vm != null) {
+ argv = nargv;
+ target = context;
+ if (cacheable && vm.isCacheable()) {
+ funcall = new ContextFuncall(vm, narrow);
+ }
+ break;
+ }
+ vm = uberspect.getMethod(arithmetic, methodName, nargv);
+ if (vm != null) {
+ argv = nargv;
+ target = arithmetic;
+ if (cacheable && vm.isCacheable()) {
+ funcall = new ArithmeticFuncall(vm, narrow);
+ }
+ break;
+ }
+ // if we did not find an exact method by name and we haven't tried yet,
+ // attempt to narrow the parameters and if this succeeds, try again in next loop
+ if (arithmetic.narrowArguments(argv)) {
+ narrow = true;
+ continue;
+ }
}
+ // we are done trying
+ break;
}
// we have either evaluated and returned or might have found a method
if (vm != null) {
// vm cannot be null if xjexl is null
- Object eval = vm.invoke(bean, argv);
+ Object eval = vm.invoke(target, argv);
// cache executor in volatile JexlNode.value
- if (cacheable && vm.isCacheable()) {
- node.jjtSetValue(vm);
+ if (funcall != null) {
+ node.jjtSetValue(funcall);
}
return eval;
- } else {
- return unsolvableMethod(node, methodName);
}
+ return unsolvableMethod(node, methodName);
} catch (JexlException.Method xmethod) {
throw xmethod;
} catch (Exception xany) {
@@ -1527,28 +1679,6 @@ public class Interpreter extends ParserV
}
@Override
- protected Object visit(ASTFunctionNode node, Object data) {
- int argc = node.jjtGetNumChildren();
- if (argc == 2) {
- Object namespace = resolveNamespace(null, node);
- if (namespace == null) {
- namespace = context;
- }
- ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(0);
- ASTArguments argNode = (ASTArguments) node.jjtGetChild(1);
- return call(node, namespace, functionNode, argNode);
- } else {
- // objectNode 0 is the prefix
- String prefix = ((ASTIdentifier) node.jjtGetChild(0)).getName();
- Object namespace = resolveNamespace(prefix, node);
- // objectNode 1 is the identifier , the others are parameters.
- ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(1);
- ASTArguments argNode = (ASTArguments) node.jjtGetChild(2);
- return call(node, namespace, functionNode, argNode);
- }
- }
-
- @Override
protected Object visit(ASTConstructorNode node, Object data) {
if (isCancelled()) {
throw new JexlException.Cancel(node);
@@ -1763,4 +1893,5 @@ public class Interpreter extends ParserV
}
return null;
}
+
}
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ConstructorMethod.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ConstructorMethod.java?rev=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ConstructorMethod.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ConstructorMethod.java Thu Sep 3 17:05:22 2015
@@ -120,5 +120,5 @@ public final class ConstructorMethod imp
public Class<?> getReturnType() {
return ctor.getDeclaringClass();
}
-
+
}
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java?rev=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java Thu Sep 3 17:05:22 2015
@@ -506,14 +506,10 @@ public final class MethodKey {
LinkedList<T> maximals = new LinkedList<T>();
for (T app : applicables) {
Class<?>[] appArgs = getParameterTypes(app);
-
boolean lessSpecific = false;
-
- for (Iterator<T> maximal = maximals.iterator();
- !lessSpecific && maximal.hasNext();) {
+ Iterator<T> maximal = maximals.iterator();
+ while(!lessSpecific && maximal.hasNext()) {
T max = maximal.next();
-
- // CSOFF: MissingSwitchDefault
switch (moreSpecific(appArgs, getParameterTypes(max))) {
case MORE_SPECIFIC:
/*
@@ -533,8 +529,10 @@ public final class MethodKey {
lessSpecific = true;
break;
+ default:
+ // nothing do do
}
- } // CSON: MissingSwitchDefault
+ }
if (!lessSpecific) {
maximals.addLast(app);
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=1701076&r1=1701075&r2=1701076&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 Thu Sep 3 17:05:22 2015
@@ -105,7 +105,7 @@ public interface JexlUberspect {
@Override
public final JexlPropertySet getPropertySet(JexlUberspect uber, Object obj, Object identifier, Object arg) {
- return uber.getPropertySet(Collections.<PropertyResolver>singletonList(this), obj, identifier);
+ return uber.getPropertySet(Collections.<PropertyResolver>singletonList(this), obj, identifier, arg);
}
}
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java?rev=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java Thu Sep 3 17:05:22 2015
@@ -27,6 +27,9 @@ import org.apache.commons.jexl3.introspe
* @since 2.0
*/
public abstract class JexlNode extends SimpleNode {
+ // line + column encoded: up to 4096 columns (ie 20 bits for line + 12 bits for column)
+ private int lc = -1;
+
/**
* A marker interface for constants.
* @param <T> the literal type
@@ -43,6 +46,16 @@ public abstract class JexlNode extends S
super(p, id);
}
+ public void jjtSetFirstToken(Token t) {
+ // 0xc = 12, 12 bits -> 4096
+ // 0xfff, 12 bits mask
+ this.lc = (t.beginLine << 0xc) | (0xfff & t.beginColumn);
+ }
+
+ public void jjtSetLastToken(Token t) {
+ // nothing
+ }
+
/**
* Gets the associated JexlInfo instance.
*
@@ -52,7 +65,15 @@ public abstract class JexlNode extends S
JexlNode node = this;
while (node != null) {
if (node.value instanceof JexlInfo) {
- return (JexlInfo) node.value;
+ JexlInfo info = (JexlInfo) node.value;
+ if (lc >= 0) {
+ int c = lc & 0xfff;
+ int l = lc >> 0xc;
+ return info.at(l, c);
+ } else {
+ // weird though; no jjSetFirstToken(...) ever called?
+ return info;
+ }
}
node = node.jjtGetParent();
}
@@ -61,13 +82,14 @@ public abstract class JexlNode extends S
/**
* Clears any cached value of type JexlProperty{G,S}et or JexlMethod.
- * <p>This is called when the engine detects the evaluation of a script occurs with a class loader
+ * <p>
+ * This is called when the engine detects the evaluation of a script occurs with a class loader
* different that the one that created it.</p>
*/
public void clearCache() {
if (value instanceof JexlPropertyGet
- || value instanceof JexlPropertySet
- || value instanceof JexlMethod) {
+ || value instanceof JexlPropertySet
+ || value instanceof JexlMethod) {
value = null;
}
if (children != null) {
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=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Thu Sep 3 17:05:22 2015
@@ -24,6 +24,8 @@ options
NODE_SCOPE_HOOK=true;
NODE_CLASS="JexlNode";
UNICODE_INPUT=true;
+ KEEP_LINE_COLUMN=true;
+ TRACK_TOKENS=true;
//DEBUG_PARSER=true;
}
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=1701076&r1=1701075&r2=1701076&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 Thu Sep 3 17:05:22 2015
@@ -26,7 +26,12 @@ import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.jexl3.junit.Asserter;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -284,4 +289,129 @@ public class ArithmeticOperatorTest exte
result = script.execute(null);
Assert.assertEquals(Integer.valueOf(0), result);
}
+
+ public static class DateArithmetic extends JexlArithmetic {
+ DateArithmetic(boolean flag) {
+ super(flag);
+ }
+
+ protected Object getDateValue(Date date, String key) {
+ try {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ if ("yyyy".equals(key)) {
+ return cal.get(Calendar.YEAR);
+ } else if ("MM".equals(key)) {
+ return cal.get(Calendar.MONTH) + 1;
+ } else if ("dd".equals(key)) {
+ return cal.get(Calendar.DAY_OF_MONTH);
+ }
+ // Otherwise treat as format mask
+ SimpleDateFormat df = new SimpleDateFormat(key);//, dfs);
+ return df.format(date);
+
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
+
+ protected Object setDateValue(Date date, String key, Object value) throws Exception {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ if ("yyyy".equals(key)) {
+ cal.set(Calendar.YEAR, toInteger(value));
+ } else if ("MM".equals(key)) {
+ cal.set(Calendar.MONTH, toInteger(value) - 1);
+ } else if ("dd".equals(key)) {
+ cal.set(Calendar.DAY_OF_MONTH, toInteger(value));
+ }
+ date.setTime(cal.getTimeInMillis());
+ return date;
+ }
+
+ public Object propertyGet(Date date, String identifier) {
+ return getDateValue(date, identifier);
+ }
+
+ public Object propertySet(Date date, String identifier, Object value) throws Exception {
+ return setDateValue(date, identifier, value);
+ }
+
+ public Object arrayGet(Date date, String identifier) {
+ return getDateValue(date, identifier);
+ }
+
+ public Object arraySet(Date date, String identifier, Object value) throws Exception {
+ return setDateValue(date, identifier, value);
+ }
+
+ public String format(Number number, String fmt) {
+ return new DecimalFormat(fmt).format(number);
+ }
+ }
+
+ public static class DateContext extends MapContext {
+ private Locale locale = Locale.US;
+
+ void setLocale(Locale l10n) {
+ this.locale = l10n;
+ }
+
+ public String format(Date date, String fmt) {
+ SimpleDateFormat sdf = new SimpleDateFormat(fmt, locale);
+ return sdf.format(date);
+ }
+ }
+
+ @Test
+ public void testDateArithmetic() throws Exception {
+ Date d = new Date();
+ JexlContext jc = new MapContext();
+ JexlEngine jexl = new JexlBuilder().cache(32).arithmetic(new DateArithmetic(true)).create();
+ JexlScript expr0 = jexl.createScript("date.yyyy = 1969; date.MM=7; date.dd=20; ", "date");
+ Object value0 = expr0.execute(jc, d);
+ Assert.assertNotNull(value0);
+ value0 = d;
+ //d = new Date();
+ Assert.assertEquals(1969, jexl.createScript("date.yyyy", "date").execute(jc, value0));
+ Assert.assertEquals(7, jexl.createScript("date.MM", "date").execute(jc, value0));
+ Assert.assertEquals(20, jexl.createScript("date.dd", "date").execute(jc, value0));
+ }
+
+ @Test
+ public void testFormatArithmetic() throws Exception {
+ Calendar cal = Calendar.getInstance();
+ cal.set(1969, 7, 20);
+ Date x0 = cal.getTime();
+ String y0 = "MM/yy/dd";
+ Number x1 = 42.12345;
+ String y1 = "##0.##";
+ DateContext jc = new DateContext();
+ JexlEngine jexl = new JexlBuilder().cache(32).arithmetic(new DateArithmetic(true)).create();
+ JexlScript expr0 = jexl.createScript("x.format(y)", "x", "y");
+ Object value10 = expr0.execute(jc, x0, y0);
+ Object value20 = expr0.execute(jc, x0, y0);
+ Assert.assertEquals(value10, value20);
+ Object value11 = expr0.execute(jc, x1, y1);
+ Object value21 = expr0.execute(jc, x1, y1);
+ Assert.assertEquals(value11, value21);
+ value10 = expr0.execute(jc, x0, y0);
+ Assert.assertEquals(value10, value20);
+ value11 = expr0.execute(jc, x1, y1);
+ Assert.assertEquals(value11, value21);
+ value10 = expr0.execute(jc, x0, y0);
+ Assert.assertEquals(value10, value20);
+ value11 = expr0.execute(jc, x1, y1);
+ Assert.assertEquals(value11, value21);
+
+ JexlScript expr1 = jexl.createScript("format(x, y)", "x", "y");
+ value10 = expr1.execute(jc, x0, y0);
+ Assert.assertEquals(value10, value20);
+ Object s0 = expr1.execute(jc, x0, "EEE dd MMM yyyy");
+ Assert.assertEquals("Wed 20 Aug 1969", s0);
+ jc.setLocale(Locale.FRANCE);
+ s0 = expr1.execute(jc, x0, "EEE dd MMM yyyy");
+ Assert.assertEquals("mer. 20 août 1969", s0);
+ }
}
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=1701076&r1=1701075&r2=1701076&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 Thu Sep 3 17:05:22 2015
@@ -24,9 +24,14 @@ import java.util.Map;
import org.apache.commons.jexl3.internal.introspection.Uberspect;
import java.io.File;
import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
import java.util.List;
+import java.util.Set;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -1110,6 +1115,16 @@ public class IssuesTest extends JexlTest
Assert.assertEquals("CD", value1);
}
+ @Test
+ public void test179() throws Exception {
+ JexlContext jc = new MapContext();
+ JexlEngine jexl = new JexlBuilder().create();
+ String src = "x = new ('java.util.HashSet'); x.add(1); x";
+ JexlScript e = jexl.createScript(src);
+ Object o = e.execute(jc);
+ Assert.assertTrue(o instanceof Set);
+ Assert.assertTrue(((Set) o).contains(1));
+ }
//
//
// @Test
@@ -1163,4 +1178,5 @@ public class IssuesTest extends JexlTest
//
// Assert.assertEquals(null, ((Double)e.evaluate(jc)).doubleValue(), 50d, 0d);
// }
+
}
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=1701076&r1=1701075&r2=1701076&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 Thu Sep 3 17:05:22 2015
@@ -128,8 +128,15 @@ public class LambdaTest extends JexlTest
JexlContext ctx = null;
String strs = "(x)->{ (y)->{ x + y } }";
JexlScript s42 = jexl.createScript(strs);
+ JexlScript s42b = jexl.createScript(s42.toString());
+ Assert.assertEquals(s42.hashCode(), s42b.hashCode());
+ Assert.assertEquals(s42, s42b);
Object result = s42.execute(ctx, 15);
Assert.assertTrue(result instanceof JexlScript);
+ Object resultb = s42.execute(ctx, 15);
+ Assert.assertEquals(result.hashCode(), resultb.hashCode());
+ Assert.assertEquals(result, resultb);
+ Assert.assertEquals(result, jexl.createScript(resultb.toString(), "x").execute(ctx, 15));
JexlScript s15 = (JexlScript) result;
Callable<Object> s15b = s15.callable(ctx, 27);
result = s15.execute(ctx, 27);
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java?rev=1701076&r1=1701075&r2=1701076&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java Thu Sep 3 17:05:22 2015
@@ -17,6 +17,9 @@
package org.apache.commons.jexl3;
import org.apache.commons.jexl3.internal.Engine;
+import org.apache.commons.jexl3.introspection.JexlPropertyGet;
+import org.apache.commons.jexl3.introspection.JexlPropertySet;
+import org.apache.commons.jexl3.introspection.JexlUberspect;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
@@ -58,17 +61,40 @@ public class StrategyTest extends JexlTe
}
@Test
+ public void testRawResolvers() throws Exception {
+ Object map = new HashMap<String, Object>();
+ final JexlEngine jexl = new JexlBuilder().create();
+ JexlUberspect uberspect = jexl.getUberspect();
+ JexlUberspect.PropertyResolver rfieldp = JexlUberspect.JexlResolver.FIELD;
+ JexlPropertyGet fget = rfieldp.getPropertyGet(uberspect, map, "key");
+ Assert.assertNull(fget);
+ JexlPropertySet fset = rfieldp.getPropertySet(uberspect, map, "key", "value");
+ Assert.assertNull(fset);
+ JexlUberspect.PropertyResolver rmap = JexlUberspect.JexlResolver.MAP;
+ JexlPropertyGet mget = rmap.getPropertyGet(uberspect, map, "key");
+ Assert.assertNotNull(mget);
+ JexlPropertySet mset = rmap.getPropertySet(uberspect, map, "key", "value");
+ Assert.assertNotNull(mset);
+ }
+
+ @Test
public void testJexlStrategy() throws Exception {
final JexlEngine jexl = new Engine();
run171(jexl, true);
}
@Test
- public void testMapStrategy() throws Exception {
+ public void testMyMapStrategy() throws Exception {
final JexlEngine jexl = new JexlBuilder().arithmetic( new MapArithmetic(true)).create();
run171(jexl, false);
}
+ @Test
+ public void testMapStrategy() throws Exception {
+ final JexlEngine jexl = new JexlBuilder().strategy(JexlUberspect.MAP_STRATEGY).create();
+ run171(jexl, false);
+ }
+
public void run171(JexlEngine jexl, boolean std) throws Exception {
Object result;
Map<String, Object> i = new HashMap<String, Object>();