Author: henrib
Date: Wed Oct 1 08:57:12 2014
New Revision: 1628650
URL: http://svn.apache.org/r1628650
Log:
Fixing JEXL-146;
Better error reporting and improved arithmetic overloading;
Clean up javadoc/checkstyle;
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/JexlContext.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.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/JxltEngine.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.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/internal/introspection/PropertySetExecutor.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
commons/proper/jexl/trunk/src/site/xdoc/changes.xml
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ExceptionTest.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/introspection/SandboxTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/scripting/JexlScriptEngineTest.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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -44,28 +44,47 @@ import java.math.MathContext;
*/
public class JexlArithmetic {
/**
- * The overridable operators.
+ * The overload-able operators.
+ * Note that logical and (ie &&) and logical or (ie ||) are not in this
list to avoid breaking
+ * their shortcut semantics.
* @since 3.0
*/
public enum Operator {
+ /** add(x, y). */
ADD("+", "add", 2),
+ /** subtract(x, y). */
SUBTRACT("-", "subtract", 2),
+ /** multiply(x, y). */
MULTIPLY("*", "multiply", 2),
+ /** divide(x, y). */
DIVIDE("/", "divide", 2),
+ /** mod(x, y). */
MOD("%", "mod", 2),
+ /** bitwiseAnd(x, y). */
AND("&", "bitwiseAnd", 2),
+ /** bitwiseOr(x, y). */
OR("|", "bitwiseOr", 2),
+ /** bitwiseXor(x, y). */
XOR("^", "bitwiseXor", 2),
+ /** logicalNot(x). */
NOT("!", "logicalNot", 1),
+ /** bitiwiseComplement(x). */
COMPLEMENT("-", "bitwiseComplement", 1),
+ /** equals(x, y). */
EQ("==", "equals", 2),
+ /** lessThan(x, y). */
LT("<", "lessThan", 2),
+ /** lessThanOrEqual(x, y). */
LTE("<=", "lessThanOrEqual", 2),
+ /** greaterThan(x, y). */
GT(">", "greaterThan", 2),
+ /** greaterThanOrEqual(x, y). */
GTE(">=", "greaterThanOrEqual", 2),
- ABS("+", "abs", 1),
+ /** negate(x). */
NEGATE("-", "negate", 1),
+ /** size(x). */
SIZE("size", "size", 1),
+ /** empty(x). */
EMPTY("empty", "empty", 1);
/**
@@ -85,12 +104,12 @@ public class JexlArithmetic {
* Creates an operator.
* @param o the operator name
* @param m the method name associated to this operator in a
JexlArithmetic
- * @param arity the number of parameters for the method
+ * @param argc the number of parameters for the method
*/
- Operator(String o, String m, int arity) {
+ Operator(String o, String m, int argc) {
this.operator = o;
this.methodName = m;
- this.arity = arity;
+ this.arity = argc;
}
/**
@@ -124,13 +143,19 @@ public class JexlArithmetic {
*/
public interface Uberspect {
/**
+ * Checks whether this uberspect has overloads for a given operator.
+ * @param operator the operator to check
+ * @return true if an overload exists, false otherwise
+ */
+ boolean overloads(JexlArithmetic.Operator operator);
+
+ /**
* Gets the most specific method for a monadic operator.
* @param operator the operator
* @param arg the argument
* @return the most specific method or null if no specific override
could be found
*/
JexlMethod getOperator(JexlArithmetic.Operator operator, Object arg);
- Object tryInvokeOperator(JexlArithmetic.Operator operator, Object arg);
/**
* Gets the most specific method for a diadic operator.
@@ -140,10 +165,9 @@ public class JexlArithmetic {
* @return the most specific method or null if no specific override
could be found
*/
JexlMethod getOperator(JexlArithmetic.Operator operator, Object lhs,
Object rhs);
- Object tryInvokeOperator(JexlArithmetic.Operator operator, Object lhs,
Object rhs);
}
- /** Maker class for null operand exceptions. */
+ /** Marker class for null operand exceptions. */
public static class NullOperand extends ArithmeticException {}
/** Double.MAX_VALUE as BigDecimal. */
protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE =
BigDecimal.valueOf(Double.MAX_VALUE);
@@ -190,7 +214,7 @@ public class JexlArithmetic {
public JexlArithmetic options(JexlEngine.Options options) {
boolean ostrict = options.isStrictArithmetic() == null
? this.strict
- : options.isStrictArithmetic().booleanValue();
+ : options.isStrictArithmetic();
MathContext bigdContext = options.getArithmeticMathContext();
if (bigdContext == null) {
bigdContext = mathContext;
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlContext.java
Wed Oct 1 08:57:12 2014
@@ -100,10 +100,10 @@ public interface JexlContext {
* A marker interface that indicates the interpreter to put this context
in the JexlEngine thread local context
* instance during evaluation.
* This allows user functions or methods to access the context during a
call.
- * Note that the usual caveats wrt using thread local apply
(caching/leaking references, etc.); in particular, keeping
- * a reference to such a context is to be considered with great care and
caution.
- * It should also be noted that sharing such a context between threads
should implicate synchronizing variable access
- * in the implementation class.
+ * Note that the usual caveats wrt using thread local apply
(caching/leaking references, etc.); in particular,
+ * keeping a reference to such a context is to be considered with great
care and caution.
+ * It should also be noted that sharing such a context between threads
should implicate synchronizing variable
+ * accessing the implementation class.
* @see JexlEngine#setThreadContext()
* @see JexlEngine#getThreadContext()
*/
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlException.java
Wed Oct 1 08:57:12 2014
@@ -83,9 +83,36 @@ public class JexlException extends Runti
* @return the information
*/
public JexlInfo getInfo() {
- if (info != null && mark != null) {
+ return getInfo(mark, info);
+ }
+
+ /**
+ * Creates a string builder pre-filled with common error information (if
possible).
+ * @param node the node
+ * @return a string builder
+ */
+ private static StringBuilder errorAt(JexlNode node) {
+ JexlInfo info = node != null? getInfo(node, node.jexlInfo()) : null;
+ StringBuilder msg = new StringBuilder();
+ if (info != null) {
+ msg.append(info.toString());
+ } else {
+ msg.append("?:");
+ }
+ msg.append(' ');
+ return msg;
+ }
+
+ /**
+ * Gets the most specific information attached to a node.
+ * @param node the node
+ * @param info the information
+ * @return the information or null
+ */
+ public static JexlInfo getInfo(JexlNode node, JexlInfo info) {
+ if (info != null && node != null) {
final Debugger dbg = new Debugger();
- if (dbg.debug(mark)) {
+ if (dbg.debug(node)) {
return new JexlInfo(info) {
@Override
public JexlInfo.Detail getDetail() {
@@ -300,12 +327,26 @@ public class JexlException extends Runti
*/
public static class Variable extends JexlException {
/**
+ * Undefined variable flag.
+ */
+ private final boolean undefined;
+ /**
* Creates a new Variable exception instance.
* @param node the offending ASTnode
* @param var the unknown variable
+ * @param undef whether the variable is undefined or evaluated as null
*/
- public Variable(JexlNode node, String var) {
+ public Variable(JexlNode node, String var, boolean undef) {
super(node, var, null);
+ undefined = undef;
+ }
+
+ /**
+ * Whether the variable causing an error is undefined or evaluated as
null.
+ * @return true if undefined, false otherwise
+ */
+ public boolean isUndefined() {
+ return undefined;
}
/**
@@ -317,8 +358,27 @@ public class JexlException extends Runti
@Override
protected String detailedMessage() {
- return "undefined variable " + getVariable();
+ return (undefined? "undefined" : "null value") + " variable " +
getVariable();
+ }
+ }
+
+ /**
+ * Generates a message for a variable error.
+ * @param node the node where the error occurred
+ * @param variable the variable
+ * @param undef whether the variable is null or undefined
+ * @return the error message
+ */
+ public static String variableError(JexlNode node, String variable, boolean
undef) {
+ StringBuilder msg = errorAt(node);
+ if (undef) {
+ msg.append("undefined");
+ } else {
+ msg.append("null value");
}
+ msg.append(" variable ");
+ msg.append(variable);
+ return msg.toString();
}
/**
@@ -359,6 +419,20 @@ public class JexlException extends Runti
}
/**
+ * Generates a message for an unsolvable property error.
+ * @param node the node where the error occurred
+ * @param var the variable
+ * @return the error message
+ */
+ public static String propertyError(JexlNode node, String var) {
+ StringBuilder msg = errorAt(node);
+ msg.append("unsolvable property '");
+ msg.append(var);
+ msg.append('\'');
+ return msg.toString();
+ }
+
+ /**
* Thrown when a method or ctor is unknown, ambiguous or inaccessible.
* @since 3.0
*/
@@ -366,11 +440,10 @@ public class JexlException extends Runti
/**
* Creates a new Method exception instance.
* @param node the offending ASTnode
- * @param name the unknown method
- * @param cause the exception causing the error
+ * @param name the method name
*/
- public Method(JexlNode node, String name, Throwable cause) {
- super(node, name, cause);
+ public Method(JexlNode node, String name) {
+ super(node, name);
}
/**
@@ -397,6 +470,20 @@ public class JexlException extends Runti
}
/**
+ * Generates a message for a unsolvable method error.
+ * @param node the node where the error occurred
+ * @param method the method name
+ * @return the error message
+ */
+ public static String methodError(JexlNode node, String method) {
+ StringBuilder msg = errorAt(node);
+ msg.append("unsolvable function/method '");
+ msg.append(method);
+ msg.append('\'');
+ return msg.toString();
+ }
+
+ /**
* Thrown to return a value.
* @since 3.0
*/
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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -37,14 +37,20 @@ public class JexlInfo {
}
/**
- * Describes errors more precicely.
+ * Describes errors more precisely.
*/
- public static interface Detail {
- /** The start column on the line that triggered the error. */
+ public interface Detail {
+ /**
+ * @return he start column on the line that triggered the error
+ */
int start();
- /** The end column on the line that triggered the error. */
+ /**
+ * @return the end column on the line that triggered the error
+ */
int end();
- /** The actual part of code that triggered the error. */
+ /**
+ * @return the actual part of code that triggered the error
+ */
@Override
String toString();
}
@@ -61,10 +67,20 @@ public class JexlInfo {
column = c;
}
+ /**
+ * Creates info reusing the name.
+ * @param l the line
+ * @param c the column
+ * @return a new info instance
+ */
public JexlInfo at(int l, int c) {
return new JexlInfo(name, l, c);
}
+ /**
+ * The copy constructor.
+ * @param copy the instance to copy
+ */
protected JexlInfo(JexlInfo copy) {
name = copy.getName();
line = copy.getLine();
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JxltEngine.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JxltEngine.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JxltEngine.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JxltEngine.java
Wed Oct 1 08:57:12 2014
@@ -16,7 +16,6 @@
*/
package org.apache.commons.jexl3;
-import org.apache.commons.jexl3.internal.TemplateEngine;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
@@ -49,6 +48,7 @@ public abstract class JxltEngine {
/**
* Creates an Exception.
+ * @param info the contextual information
* @param msg the exception message
* @param cause the exception cause
*/
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/ArrayBuilder.java
Wed Oct 1 08:57:12 2014
@@ -26,8 +26,9 @@ import java.util.Map;
* Helper class to create typed arrays.
*/
public class ArrayBuilder implements JexlArithmetic.ArrayBuilder {
- /** The boxing types to primitive conversion map. */
+ /** The number of primitive types. */
private static final int PRIMITIVE_SIZE = 8;
+ /** The boxing types to primitive conversion map. */
private static final Map<Class<?>, Class<?>> BOXING_CLASSES;
static {
BOXING_CLASSES = new IdentityHashMap<Class<?>,
Class<?>>(PRIMITIVE_SIZE);
@@ -41,6 +42,11 @@ public class ArrayBuilder implements Jex
BOXING_CLASSES.put(Short.class, Short.TYPE);
}
+ /**
+ * Gets the primitive type of a given class (when it exists).
+ * @param parm a class
+ * @return the primitive type or null it the argument is not unboxable
+ */
private static Class<?> unboxingClass(Class<?> parm) {
Class<?> prim = BOXING_CLASSES.get(parm);
return prim == null ? parm : prim;
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Closure.java
Wed Oct 1 08:57:12 2014
@@ -44,12 +44,38 @@ public class Closure extends Script {
}
@Override
+ public String toString() {
+ return getParsedText();
+ }
+
+ @Override
public String getParsedText() {
Debugger debug = new Debugger();
- debug.debug(script);
+ debug.debug(script, false);
return debug.toString();
}
+ /**
+ * Sets the hoisted index of a given symbol, ie the target index of a
parent hoisted symbol in this closure's frame.
+ * <p>This is meant to allow a locally defined function to "see" and call
itself as a local (hoisted) variable;
+ * in other words, this allows recursive call of a function.
+ * @param symbol the symbol index (in the caller of this closure)
+ * @param value the value to set in the local frame
+ */
+ public void setHoisted(int symbol, Object value) {
+ if (script instanceof ASTJexlLambda) {
+ ASTJexlLambda lambda = (ASTJexlLambda) script;
+ Scope scope = lambda.getScope();
+ if (scope != null) {
+ Integer reg = scope.getHoisted(symbol);
+ if (reg != null) {
+ frame.set(reg, value);
+ return;
+ }
+ }
+ }
+ }
+
@Override
public Object evaluate(JexlContext context) {
return execute(context, (Object[])null);
@@ -74,10 +100,11 @@ public class Closure extends Script {
@Override
public Callable<Object> callable(JexlContext context, Object... args) {
+ Scope.Frame local = null;
if (frame != null) {
- frame.assign(args);
+ local = frame.assign(args);
}
- final Interpreter interpreter = jexl.createInterpreter(context, frame);
+ final Interpreter interpreter = jexl.createInterpreter(context, local);
interpreter.functors = functors;
return new Callable<Object>() {
/** Use interpreter as marker for not having run. */
@@ -87,7 +114,7 @@ public class Closure extends Script {
public Object call() throws Exception {
if (result == interpreter) {
JexlNode block =
script.jjtGetChild(script.jjtGetNumChildren() - 1);
- return interpreter.interpret(block);
+ result = interpreter.interpret(block);
}
return result;
}
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
Wed Oct 1 08:57:12 2014
@@ -144,6 +144,9 @@ public final class Debugger extends Pars
* @return true if the cause was located, false otherwise
*/
public boolean debug(JexlNode node) {
+ return debug(node, true);
+ }
+ public boolean debug(JexlNode node, boolean r) {
start = 0;
end = 0;
indentLevel = 0;
@@ -153,9 +156,11 @@ public final class Debugger extends Pars
cause = node;
// make arg cause become the root cause
JexlNode root = node;
+ if (r) {
while (root.jjtGetParent() != null) {
root = root.jjtGetParent();
}
+ }
root.jjtAccept(this, null);
}
return end > 0;
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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -123,8 +123,8 @@ public class Interpreter extends ParserV
protected final JexlContext context;
/** The context to store/retrieve variables. */
protected final JexlContext.NamespaceResolver ns;
- /** Strict interpreter flag. */
- protected final boolean strictEngine;
+ /** Strict interpreter flag (may temporarily change during when calling
size & empty as functions). */
+ protected boolean strictEngine;
/** Strict interpreter flag. */
protected final boolean strictArithmetic;
/** Silent intepreter flag. */
@@ -153,8 +153,8 @@ public class Interpreter extends ParserV
JexlEngine.Options opts = (JexlEngine.Options) context;
Boolean ostrict = opts.isStrict();
Boolean osilent = opts.isSilent();
- this.strictEngine = ostrict == null ? jexl.isStrict() :
ostrict.booleanValue();
- this.silent = osilent == null ? jexl.isSilent() :
osilent.booleanValue();
+ this.strictEngine = ostrict == null ? jexl.isStrict() : ostrict;
+ this.silent = osilent == null ? jexl.isSilent() : osilent;
this.arithmetic = jexl.arithmetic.options(opts);
} else {
this.strictEngine = jexl.isStrict();
@@ -199,7 +199,7 @@ public class Interpreter extends ParserV
}
throw xjexl.clean();
} finally {
- if (functors != null && AUTOCLOSEABLE != null ) {
+ if (functors != null && AUTOCLOSEABLE != null) {
for(Object functor : functors.values()) {
if (functor != null &&
AUTOCLOSEABLE.isAssignableFrom(functor.getClass())) {
try {
@@ -250,20 +250,56 @@ public class Interpreter extends ParserV
}
/**
- * Triggered when variable can not be resolved.
- * @param xjexl the JexlException ("undefined variable " + variable)
+ * Triggered when a variable can not be resolved.
+ * @param node the node where the error originated from
+ * @param var the variable name
+ * @param undef whether the variable is undefined or null
* @return throws JexlException if isStrict, null otherwise
*/
- protected Object unknownVariable(JexlException xjexl) {
+ 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));
+ }
+ return null;
+ }
+
+ /**
+ * Triggered when a method can not be resolved.
+ * @param node the node where the error originated from
+ * @param method the method name
+ * @return throws JexlException if isStrict, null otherwise
+ */
+ protected Object unsolvableMethod(JexlNode node, String method) {
if (strictEngine) {
- throw xjexl;
+ throw new JexlException.Method(node, method);
}
if (!silent) {
- logger.warn(xjexl.getMessage());
+ logger.warn(JexlException.methodError(node, method));
+ }
+ return null;
+ }
+
+ /**
+ * Triggered when a property can not be resolved.
+ * @param node the node where the error originated from
+ * @param var the property name
+ * @param cause the cause if any
+ * @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));
}
return null;
}
+
/**
* Triggered when method, function or constructor invocation fails.
* @param xjexl the JexlException wrapping the original error
@@ -341,6 +377,79 @@ public class Interpreter extends ParserV
}
}
+ /**
+ * 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 callOperator(JexlNode node, Operator operator, Object
arg) {
+ if (operators != null && operators.overloads(operator)) {
+ 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) {
+ return invocationFailed(new JexlException(node,
operator.getMethodName(), 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 callOperator(JexlNode node, Operator operator, Object
lhs, Object rhs) {
+ if (operators != null && operators.overloads(operator)) {
+ 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) {
+ return invocationFailed(new JexlException(node,
operator.getMethodName(), xany));
+ }
+ }
+ return JexlEngine.TRY_FAILED;
+ }
+
@Override
protected Object visit(ASTAndNode node, Object data) {
/**
@@ -389,13 +498,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.ADD,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.add(left, right);
+ Object result = callOperator(node, Operator.ADD, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.add(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "+ error", xrt);
}
@@ -406,13 +510,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.SUBTRACT,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.subtract(left, right);
+ Object result = callOperator(node, Operator.SUBTRACT, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.subtract(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "- error", xrt);
}
@@ -423,13 +522,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.AND,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.bitwiseAnd(left, right);
+ Object result = callOperator(node, Operator.AND, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.bitwiseAnd(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "& error", xrt);
}
@@ -437,15 +531,10 @@ public class Interpreter extends ParserV
@Override
protected Object visit(ASTBitwiseComplNode node, Object data) {
- Object left = node.jjtGetChild(0).jjtAccept(this, data);
+ Object arg = node.jjtGetChild(0).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result =
operators.tryInvokeOperator(Operator.COMPLEMENT, left);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.bitwiseComplement(left);
+ Object result = callOperator(node, Operator.COMPLEMENT, arg);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.bitwiseComplement(arg);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "~ error", xrt);
}
@@ -456,13 +545,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.OR, left,
right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.bitwiseOr(left, right);
+ Object result = callOperator(node, Operator.OR, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.bitwiseOr(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "| error", xrt);
}
@@ -473,13 +557,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.XOR,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.bitwiseXor(left, right);
+ Object result = callOperator(node, Operator.XOR, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.bitwiseXor(left, right);
} catch (ArithmeticException xrt) {
throw new JexlException(node, "^ error", xrt);
}
@@ -500,16 +579,11 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.DIVIDE,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.divide(left, right);
+ Object result = callOperator(node, Operator.DIVIDE, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.divide(left, right);
} catch (ArithmeticException xrt) {
if (!strictArithmetic) {
- return new Double(0.0);
+ return 0.0d;
}
JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "divide error", xrt);
@@ -521,13 +595,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.EQ, left,
right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.equals(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ Object result = callOperator(node, Operator.EQ, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.equals(left, right) ? Boolean.TRUE :
Boolean.FALSE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, "== error", xrt);
}
@@ -595,13 +666,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.GTE,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.greaterThanOrEqual(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ Object result = callOperator(node, Operator.GTE, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.greaterThanOrEqual(left, right) ? Boolean.TRUE
: Boolean.FALSE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, ">= error", xrt);
}
@@ -612,13 +680,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.GT, left,
right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.greaterThan(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ Object result = callOperator(node, Operator.GT, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.greaterThan(left, right) ? Boolean.TRUE :
Boolean.FALSE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, "> error", xrt);
}
@@ -844,13 +909,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.LTE,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.lessThanOrEqual(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ Object result = callOperator(node, Operator.LTE, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.lessThanOrEqual(left, right) ?
Boolean.TRUE : Boolean.FALSE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, "<= error", xrt);
}
@@ -861,13 +923,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.LT, left,
right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.lessThan(left, right) ? Boolean.TRUE :
Boolean.FALSE;
+ Object result = callOperator(node, Operator.LT, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.lessThan(left, right) ? Boolean.TRUE :
Boolean.FALSE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, "< error", xrt);
}
@@ -912,16 +971,11 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.MOD,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.mod(left, right);
+ Object result = callOperator(node, Operator.MOD, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.mod(left, right);
} catch (ArithmeticException xrt) {
if (!strictArithmetic) {
- return new Double(0.0);
+ return 0.0d;
}
JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "% error", xrt);
@@ -933,13 +987,8 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.MULTIPLY,
left, right);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.multiply(left, right);
+ Object result = callOperator(node, Operator.MULTIPLY, left, right);
+ return result != JexlEngine.TRY_FAILED? result :
arithmetic.multiply(left, right);
} catch (ArithmeticException xrt) {
JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "* error", xrt);
@@ -951,13 +1000,10 @@ public class Interpreter extends ParserV
Object left = node.jjtGetChild(0).jjtAccept(this, data);
Object right = node.jjtGetChild(1).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.EQ, left,
right);
- if (result != JexlEngine.TRY_FAILED) {
- return arithmetic.toBoolean(result)? Boolean.FALSE :
Boolean.TRUE;
- }
- }
- return arithmetic.equals(left, right) ? Boolean.FALSE :
Boolean.TRUE;
+ Object result = callOperator(node, Operator.EQ, left, right);
+ return result != JexlEngine.TRY_FAILED
+ ? arithmetic.toBoolean(result) ? Boolean.FALSE :
Boolean.TRUE
+ : arithmetic.equals(left, right) ? Boolean.FALSE :
Boolean.TRUE;
} catch (ArithmeticException xrt) {
JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "!= error", xrt);
@@ -968,13 +1014,10 @@ public class Interpreter extends ParserV
protected Object visit(ASTNotNode node, Object data) {
Object val = node.jjtGetChild(0).jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.NOT, val);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
- }
- return arithmetic.toBoolean(val) ? Boolean.FALSE : Boolean.TRUE;
+ Object result = callOperator(node, Operator.NOT, val);
+ return result != JexlEngine.TRY_FAILED
+ ? result
+ : arithmetic.toBoolean(val) ? Boolean.FALSE : Boolean.TRUE;
} catch (ArithmeticException xrt) {
throw new JexlException(node, "arithmetic error", xrt);
}
@@ -1054,13 +1097,11 @@ public class Interpreter extends ParserV
JexlNode valNode = node.jjtGetChild(0);
Object val = valNode.jjtAccept(this, data);
try {
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.NEGATE,
val);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
+ Object result = callOperator(node, Operator.NEGATE, val);
+ if (result != JexlEngine.TRY_FAILED) {
+ return result;
}
- Object number = arithmetic.negate(val);
+ Object number = result != JexlEngine.TRY_FAILED? result :
arithmetic.negate(val);
// attempt to recoerce to literal class
if (valNode instanceof ASTNumberLiteral && number instanceof
Number) {
number = arithmetic.narrowNumber((Number) number,
((ASTNumberLiteral) valNode).getLiteralClass());
@@ -1096,11 +1137,14 @@ public class Interpreter extends ParserV
@Override
protected Object visit(ASTSizeFunction node, Object data) {
- Object val = node.jjtGetChild(0).jjtAccept(this, data);
- if (val == null) {
- throw new JexlException(node, "size() : argument is null", null);
+ boolean isStrict = this.strictEngine;
+ try {
+ strictEngine = false;
+ Object val = node.jjtGetChild(0).jjtAccept(this, data);
+ return sizeOf(node, val);
+ } finally {
+ strictEngine = isStrict;
}
- return sizeOf(node, val);
}
@Override
@@ -1111,13 +1155,20 @@ public class Interpreter extends ParserV
@Override
protected Object visit(ASTEmptyFunction node, Object data) {
- return isEmpty(node, node.jjtGetChild(0).jjtAccept(this, data));
+ boolean isStrict = this.strictEngine;
+ try {
+ strictEngine = false;
+ Object value = node.jjtGetChild(0).jjtAccept(this, data);
+ return callEmpty(node, value);
+ } finally {
+ strictEngine = isStrict;
+ }
}
@Override
protected Object visit(ASTEmptyMethod node, Object data) {
Object val = node.jjtGetChild(0).jjtAccept(this, data);
- return isEmpty(node, val);
+ return callEmpty(node, val);
}
/**
@@ -1125,18 +1176,16 @@ public class Interpreter extends ParserV
* method.
*
* @param node the node holding the object
- * @param object the object to check the rmptyness of.
+ * @param object the object to check the emptyness of.
* @return the boolean
*/
- private Object isEmpty(JexlNode node, Object object) {
+ private Object callEmpty(JexlNode node, Object object) {
if (object == null) {
return Boolean.TRUE;
}
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.EMPTY,
object);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
+ Object opcall = callOperator(node, Operator.EMPTY, object);
+ if (opcall != JexlEngine.TRY_FAILED) {
+ return opcall;
}
if (object instanceof Number) {
return ((Number) object).intValue() == 0 ? Boolean.TRUE :
Boolean.FALSE;
@@ -1181,11 +1230,9 @@ public class Interpreter extends ParserV
if (object == null) {
return 0;
}
- if (operators != null) {
- Object result = operators.tryInvokeOperator(Operator.SIZE, object);
- if (result != JexlEngine.TRY_FAILED) {
- return result;
- }
+ Object opcall = callOperator(node, Operator.SIZE, object);
+ if (opcall != JexlEngine.TRY_FAILED) {
+ return opcall;
}
if (object instanceof Collection<?>) {
return ((Collection<?>) object).size();
@@ -1245,8 +1292,7 @@ public class Interpreter extends ParserV
&& !(node.jjtGetParent() instanceof ASTReference)
&& !context.has(name)
&& !isTernaryProtected(node)) {
- JexlException xjexl = new JexlException.Variable(node, name);
- return unknownVariable(xjexl);
+ return unsolvableVariable(node, name, true);
}
return value;
} else {
@@ -1331,6 +1377,9 @@ public class Interpreter extends ParserV
throw new JexlException.Cancel(node);
}
objectNode = node.jjtGetChild(c);
+ if (objectNode instanceof ASTMethodNode && object == null) {
+ break;
+ }
// attempt to evaluate the property within the object
object = objectNode.jjtAccept(this, object);
if (object == null && isVariable) {
@@ -1348,21 +1397,22 @@ public class Interpreter extends ParserV
// subsequent nodes must be identifier access
objectNode = node.jjtGetChild(v);
if (objectNode instanceof ASTIdentifierAccess) {
+ // variableName can *not* be null; it has been
necessarily set by the (v == 0) condition
variableName.append('.');
variableName.append(((ASTIdentifierAccess)
objectNode).getName());
} else {
break main;
}
}
+ // variableName can *not* be null; the code before this line
made sure of that
object = context.get(variableName.toString());
}
isVariable &= object == null;
}
- if (object == null && isVariable && variableName != null
- && !isTernaryProtected(node) &&
!(context.has(variableName.toString()) || isLocalVariable(node, 0))) {
- JexlException xjexl = new JexlException.Variable(node,
variableName.toString());
+ if (object == null && isVariable && variableName != null &&
!isTernaryProtected(node)) {
+ boolean undefined = !(context.has(variableName.toString()) ||
isLocalVariable(node, 0));
// variable unknown in context and not a local
- return unknownVariable(xjexl);
+ return unsolvableVariable(node, variableName.toString(),
undefined);
}
return object;
}
@@ -1384,6 +1434,10 @@ public class Interpreter extends ParserV
// check we are not assigning a symbol itself
if (last < 0) {
frame.set(symbol, right);
+ // make the closure accessible to itself, ie hoist the
currently set variable after frame creation
+ if (right instanceof Closure) {
+ ((Closure) right).setHoisted(symbol, right);
+ }
return right;
}
object = frame.get(symbol);
@@ -1627,8 +1681,10 @@ public class Interpreter extends ParserV
}
return eval;
} else {
- xjexl = new JexlException.Method(node, methodName, null);
+ return unsolvableMethod(node, methodName);
}
+ } catch(JexlException.Method xmethod) {
+ throw xmethod;
} catch (Exception xany) {
xjexl = new JexlException(node, methodName, xany);
}
@@ -1692,17 +1748,17 @@ public class Interpreter extends ParserV
}
if (ctor == null) {
String dbgStr = cobject != null ? cobject.toString() :
null;
- xjexl = new JexlException.Method(node, dbgStr, null);
+ return unsolvableMethod(node, dbgStr);
}
}
- if (xjexl == null) {
- Object instance = ctor.invoke(cobject, argv);
- // cache executor in volatile JexlNode.value
- if (cache && ctor.isCacheable()) {
- node.jjtSetValue(ctor);
- }
- return instance;
+ Object instance = ctor.invoke(cobject, argv);
+ // cache executor in volatile JexlNode.value
+ if (cache && ctor.isCacheable()) {
+ node.jjtSetValue(ctor);
}
+ return instance;
+ } catch(JexlException.Method xmethod) {
+ throw xmethod;
} catch (Exception xany) {
String dbgStr = cobject != null ? cobject.toString() : null;
xjexl = new JexlException(node, dbgStr, xany);
@@ -1759,7 +1815,7 @@ public class Interpreter extends ParserV
return value;
} catch (Exception xany) {
String attrStr = attribute != null ? attribute.toString() :
null;
- xjexl = new JexlException.Property(node, attrStr, xany);
+ return unsolvableProperty(node, attrStr, xany);
}
}
if (xjexl == null) {
@@ -1770,7 +1826,7 @@ public class Interpreter extends ParserV
throw new UnsupportedOperationException(error);
}
String attrStr = attribute != null ? attribute.toString() : null;
- xjexl = new JexlException.Property(node, attrStr, null);
+ return unsolvableProperty(node, attrStr, null);
}
if (strictEngine) {
throw xjexl;
@@ -1842,7 +1898,8 @@ public class Interpreter extends ParserV
}
}
String attrStr = attribute != null ? attribute.toString() :
null;
- xjexl = new JexlException.Property(node, attrStr, xany);
+ unsolvableProperty(node, attrStr, xany);
+ return;
}
}
if (xjexl == null) {
@@ -1854,7 +1911,8 @@ public class Interpreter extends ParserV
throw new UnsupportedOperationException(error);
}
String attrStr = attribute != null ? attribute.toString() : null;
- xjexl = new JexlException.Property(node, attrStr, null);
+ unsolvableProperty(node, attrStr, null);
+ return;
}
if (strictEngine) {
throw xjexl;
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
Wed Oct 1 08:57:12 2014
@@ -194,6 +194,23 @@ public final class Scope {
}
/**
+ * Gets the hoisted index of a given symbol, ie the target index of a
symbol in a child frame.
+ * @param symbol the symbol index
+ * @return the target symbol index or null if the symbol is not hoisted
+ */
+ public Integer getHoisted(int symbol) {
+ if (hoistedVariables != null) {
+ for (Map.Entry<Integer, Integer> hoist :
hoistedVariables.entrySet()) {
+ Integer source = hoist.getValue();
+ if (source == symbol) {
+ return hoist.getKey();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
* Gets the (maximum) number of arguments this script expects.
* @return the number of parameters
*/
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
Wed Oct 1 08:57:12 2014
@@ -210,6 +210,7 @@ public final class TemplateEngine extend
*/
abstract ExpressionType getType();
+ /** @return the info */
JexlInfo getInfo() {
return null;
}
@@ -644,6 +645,7 @@ public final class TemplateEngine extend
/**
* Creates a JxltEngine.Exception from a JexlException.
+ * @param info the source info
* @param action createExpression, prepare, evaluate
* @param expr the template expression
* @param xany the exception
@@ -686,6 +688,7 @@ public final class TemplateEngine extend
/**
* Parses a unified expression.
+ * @param info the source info
* @param expr the string expression
* @param scope the template scope
* @return the unified expression instance
@@ -878,7 +881,8 @@ public final class TemplateEngine extend
/**
* Creates a new block.
- * @param theType the type
+ * @param theType the block type
+ * @param theLine the line number
* @param theBlock the content
*/
Block(BlockType theType, int theLine, String theBlock) {
@@ -898,6 +902,11 @@ public final class TemplateEngine extend
}
}
+ /**
+ * Appends this block string representation to a builder.
+ * @param strb the string builder to append to
+ * @param prefix the line prefix (immediate or deferred)
+ */
protected void toString(StringBuilder strb, String prefix) {
if (BlockType.VERBATIM.equals(type)) {
strb.append(body);
@@ -926,6 +935,7 @@ public final class TemplateEngine extend
/**
* Creates a new template from an character input.
+ * @param info the source info
* @param directive the prefix for lines of code; can not be "$",
"${", "#" or "#{"
* since this would preclude being able to
differentiate directives and template expressions
* @param reader the input reader
@@ -978,7 +988,7 @@ public final class TemplateEngine extend
for (int b = 0; b < blocks.size(); ++b) {
Block block = blocks.get(b);
if (block.type == BlockType.VERBATIM) {
-
uexprs.add(TemplateEngine.this.parseExpression(info.at(block.line, 0),
block.body, b > codeStart ? scope : null));
+ uexprs.add(parseExpression(info.at(block.line, 0),
block.body, b > codeStart ? scope : null));
}
}
source = blocks.toArray(new Block[blocks.size()]);
@@ -1181,7 +1191,8 @@ public final class TemplateEngine extend
* <p>This will dynamically try to find the best suitable method in
the writer through uberspection.
* Subclassing Writer by adding 'print' methods should be the
preferred way to specialize output.
* </p>
- * @param arg the argument to print out
+ * @param info the source info
+ * @param arg the argument to print out
*/
private void doPrint(JexlInfo info, Object arg) {
try {
@@ -1237,7 +1248,7 @@ public final class TemplateEngine extend
throw new IllegalArgumentException("mark support in reader
required");
}
return new Iterator<CharSequence>() {
- CharSequence next = doNext();
+ private CharSequence next = doNext();
private CharSequence doNext() {
StringBuffer strb = new StringBuffer(64);
@@ -1284,7 +1295,6 @@ public final class TemplateEngine extend
/**
* Reads lines of a template grouping them by typed blocks.
- * @param info the source info
* @param prefix the directive prefix
* @param source the source reader
* @return the list of blocks
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java
Wed Oct 1 08:57:12 2014
@@ -114,11 +114,6 @@ public final class MethodExecutor extend
/**
* Reassembles arguments if the method is a vararg method.
- * @param type The vararg class type (aka component type
- * of the expected array arg)
- * @param index The index of the vararg in the method declaration
- * (This will always be one less than the number of
- * expected arguments.)
* @param actual The actual arguments being passed to this method
* @return The actual parameters adjusted for the varargs in order
* to fit the method declaration.
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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -451,6 +451,11 @@ public final class MethodKey {
*/
protected abstract Class<?>[] getParameterTypes(T app);
+ /**
+ * Whether a constructor or method handles varargs.
+ * @param app the constructor or method
+ * @return true if varargs, false otherwise
+ */
protected abstract boolean isVarArgs(T app);
// CSOFF: RedundantThrows
@@ -605,7 +610,7 @@ public final class MethodKey {
/**
* Checks whether a parameter class is a primitive.
* @param c the parameter class
- * @param possibleVararg true if this is the last parameter which can
be a primitive array (vararg call)
+ * @param possibleVarArg true if this is the last parameter which can
be a primitive array (vararg call)
* @return true if primitive, false otherwise
*/
private boolean isPrimitive(Class<?> c, boolean possibleVarArg) {
@@ -644,7 +649,7 @@ public final class MethodKey {
* argument types.
*
* @param method method that will be called
- * @param classes arguments to method
+ * @param actuals arguments signature for method
* @return true if method is applicable to arguments
*/
private boolean isApplicable(T method, Class<?>[] actuals) {
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java
Wed Oct 1 08:57:12 2014
@@ -150,12 +150,12 @@ public class PropertySetExecutor extends
* <p>This checks only one method with that name accepts an array as sole
parameter.
* @param is the introspector
* @param clazz the class to find the get method from
- * @param methodName the method name to find
+ * @param mname the method name to find
* @return the sole method that accepts an array as parameter
*/
- private static java.lang.reflect.Method lookupSetEmptyArray(Introspector
is, final Class<?> clazz, String methodName) {
+ private static java.lang.reflect.Method lookupSetEmptyArray(Introspector
is, final Class<?> clazz, String mname) {
java.lang.reflect.Method candidate = null;
- java.lang.reflect.Method[] methods = is.getMethods(clazz, methodName);
+ java.lang.reflect.Method[] methods = is.getMethods(clazz, mname);
if (methods != null) {
for (java.lang.reflect.Method method : methods) {
Class<?>[] paramTypes = method.getParameterTypes();
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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -367,50 +367,40 @@ public class Uberspect implements JexlUb
* The concrete uberspect Arithmetic class.
*/
protected class ArithmeticUberspect implements JexlArithmetic.Uberspect {
+ /** The arithmetic instance being analyzed. */
private final JexlArithmetic arithmetic;
+ /** The set of overloaded operators. */
private final EnumSet<Operator> overloads;
- private ArithmeticUberspect(JexlArithmetic arithmetic, Set<Operator>
overloads) {
- this.arithmetic = arithmetic;
- this.overloads = EnumSet.copyOf(overloads);
+ /**
+ * Creates an instance.
+ * @param theArithmetic the arithmetic instance
+ * @param theOverloads the overloaded operators
+ */
+ private ArithmeticUberspect(JexlArithmetic theArithmetic,
Set<Operator> theOverloads) {
+ this.arithmetic = theArithmetic;
+ this.overloads = EnumSet.copyOf(theOverloads);
+ // register this arithmetic class in the operator map
+ operatorMap.put(arithmetic.getClass(), overloads);
}
@Override
public JexlMethod getOperator(JexlArithmetic.Operator operator, Object
arg) {
- return overloads.contains(operator) && arg != null?
- getMethod(arithmetic, operator.getMethodName(), arg) : null;
+ return overloads.contains(operator) && arg != null
+ ? getMethod(arithmetic, operator.getMethodName(), arg)
+ : null;
}
@Override
public JexlMethod getOperator(JexlArithmetic.Operator operator, Object
lhs, Object rhs) {
- return overloads.contains(operator) && lhs != null && rhs != null?
- getMethod(arithmetic, operator.getMethodName(), lhs, rhs) :
null;
+ return overloads.contains(operator) && lhs != null && rhs != null
+ ? getMethod(arithmetic, operator.getMethodName(), lhs, rhs)
+ : null;
}
@Override
- public Object tryInvokeOperator(JexlArithmetic.Operator operator,
Object lhs, Object rhs) {
- JexlMethod method = getOperator(operator, lhs, rhs);
- if (method != null) {
- try {
- return method.invoke(arithmetic, lhs, rhs);
- } catch(Exception xany) {
- throw new ArithmeticException(xany.getMessage());
- }
- }
- return JexlEngine.TRY_FAILED;
- }
-
- @Override
- public Object tryInvokeOperator(JexlArithmetic.Operator operator,
Object arg) {
- JexlMethod method = getOperator(operator, arg);
- if (method != null) {
- try {
- return method.invoke(arithmetic, arg);
- } catch(Exception xany) {
- throw new ArithmeticException(xany.getMessage());
- }
- }
- return JexlEngine.TRY_FAILED;
+ public boolean overloads(Operator operator) {
+ return overloads.contains(operator);
}
}
@@ -429,6 +419,7 @@ public class Uberspect implements JexlUb
if (parms.length != op.getArity()) {
continue;
}
+ // eliminate method(Object) and method(Object,
Object)
boolean root = true;
for (int p = 0; root && p < parms.length; ++p) {
if (!Object.class.equals(parms[p])) {
@@ -441,7 +432,6 @@ public class Uberspect implements JexlUb
}
}
}
- operatorMap.put(arithmetic.getClass(), ops);
}
if (!ops.isEmpty()) {
jau = new ArithmeticUberspect(arithmetic, ops);
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
Wed Oct 1 08:57:12 2014
@@ -18,6 +18,9 @@ package org.apache.commons.jexl3.parser;
import org.apache.commons.jexl3.internal.Debugger;
+/**
+ * An array literal.
+ */
public final class ASTArrayLiteral extends JexlNode {
/** Whether this array is constant or not. */
private boolean constant = false;
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
Wed Oct 1 08:57:12 2014
@@ -30,12 +30,16 @@ public final class ASTJexlLambda extends
super(p, id);
}
+ /**
+ * @return true if outermost script.
+ */
public boolean isTopLevel() {
return parent == null;
}
/**
* Creates an array of arguments by copying values up to the number of
parameters.
+ * @param frame the calling frame
* @param values the argument values
* @return the arguments array
*/
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
Wed Oct 1 08:57:12 2014
@@ -74,7 +74,7 @@ public class ASTJexlScript extends JexlN
}
/**
- * Gets this script scope.
+ * @return this script scope
*/
public Scope getScope() {
return scope;
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=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Wed Oct 1 08:57:12 2014
@@ -26,6 +26,18 @@
</properties>
<body>
<release version="3.0.1" date="unreleased">
+ <action dev="henrib" type="fix" issue="JEXL-146" due-to="David
Maplesden">
+ Performance problem in Interpreter.unknownVariable mechanism
+ </action>
+ <action dev="henrib" type="fix">
+ Functions assigned to local variables can not perform
recursive calls
+ </action>
+ <action dev="henrib" type="fix">
+ Improved error reporting on undefined or null variables
+ </action>
+ <action dev="henrib" type="fix">
+ Improved operator overloading logic in JexlArithmeric (caching)
+ </action>
<action dev="henrib" type="fix" issue="JEXL-145" due-to="Ian
Connor">
Sandbox calling wrong check (classname vs class)
</action>
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=1628650&r1=1628649&r2=1628650&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
Wed Oct 1 08:57:12 2014
@@ -83,7 +83,6 @@ public class ArithmeticTest extends Jexl
public void testNullOperand() throws Exception {
asserter.setVariable("right", null);
asserter.failExpression("~right", ".*null.*");
- asserter.failExpression("-right", ".*arithmetic.*");
}
public void testBigDecimal() throws Exception {
@@ -411,4 +410,189 @@ public class ArithmeticTest extends Jexl
assertEquals("failed on " + stext, expected, result);
}
}
+
+ public static class Var {
+ final int value;
+ Var(int v) {
+ value = v;
+ }
+ }
+
+ // an arithmetic that know how to subtract strings
+ public static class ArithmeticPlus extends JexlArithmetic {
+ public ArithmeticPlus(boolean strict) {
+ super(strict);
+ }
+ public boolean equals(Var lhs, Var rhs) {
+ return lhs.value == rhs.value;
+ }
+ public boolean lessThan(Var lhs, Var rhs) {
+ return lhs.value < rhs.value;
+ }
+ public boolean lessThanOrEqual(Var lhs, Var rhs) {
+ return lhs.value <= rhs.value;
+ }
+ public boolean greaterThan(Var lhs, Var rhs) {
+ return lhs.value > rhs.value;
+ }
+ public boolean greaterThanOrEqual(Var lhs, Var rhs) {
+ return lhs.value >= rhs.value;
+ }
+ public Var add(Var lhs, Var rhs) {
+ return new Var(lhs.value + rhs.value);
+ }
+ public Var subtract(Var lhs, Var rhs) {
+ return new Var(lhs.value - rhs.value);
+ }
+ public Var divide(Var lhs, Var rhs) {
+ return new Var(lhs.value / rhs.value);
+ }
+ public Var multiply(Var lhs, Var rhs) {
+ return new Var(lhs.value * rhs.value);
+ }
+ public Var mod(Var lhs, Var rhs) {
+ return new Var(lhs.value / rhs.value);
+ }
+ public Var negate(Var arg) {
+ return new Var(-arg.value);
+ }
+ public Var bitwiseAnd(Var lhs, Var rhs) {
+ return new Var(lhs.value & rhs.value);
+ }
+ public Var bitwiseOr(Var lhs, Var rhs) {
+ return new Var(lhs.value | rhs.value);
+ }
+ public Var bitwiseXor(Var lhs, Var rhs) {
+ return new Var(lhs.value ^ rhs.value);
+ }
+ public Var bitwiseComplement(Var arg) {
+ return new Var(~arg.value);
+ }
+
+ public Object subtract(String x, String y) {
+ int ix = x.indexOf(y);
+ if (ix < 0) {
+ return x;
+ }
+ StringBuilder strb = new StringBuilder(x.substring(0, ix));
+ strb.append(x.substring(ix + y.length()));
+ return strb.toString();
+ }
+
+ public Object negate(final String str) {
+ final int length = str.length();
+ StringBuilder strb = new StringBuilder(str.length());
+ for(int c = length - 1; c >= 0; --c) {
+ strb.append(str.charAt(c));
+ }
+ return strb.toString();
+ }
+ }
+
+ public void testArithmeticPlus() throws Exception {
+ JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new
ArithmeticPlus(false)).create();
+ JexlContext jc = new EmptyTestContext();
+ runOverload(jexl, jc);
+ }
+
+ public void testArithmeticPlusNoCache() throws Exception {
+ JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new
ArithmeticPlus(false)).create();
+ JexlContext jc = new EmptyTestContext();
+ runOverload(jexl, jc);
+ }
+
+ protected void runOverload(JexlEngine jexl,JexlContext jc) {
+ JexlScript script;
+ Object result;
+
+ script = jexl.createScript("(x, y)->{ x < y }");
+ result = script.execute(jc, 42, 43);
+ assertEquals(true, result);
+ result = script.execute(jc, new Var(42), new Var(43));
+ assertEquals(true, result);
+ result = script.execute(jc, new Var(42), new Var(43));
+ assertEquals(true, result);
+ result = script.execute(jc, 43, 42);
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(43), new Var(42));
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(43), new Var(42));
+ assertEquals(false, result);
+
+ script = jexl.createScript("(x, y)->{ x <= y }");
+ result = script.execute(jc, 42, 43);
+ assertEquals(true, result);
+ result = script.execute(jc, new Var(42), new Var(43));
+ assertEquals(true, result);
+ result = script.execute(jc, new Var(41), new Var(44));
+ assertEquals(true, result);
+ result = script.execute(jc, 43, 42);
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(45), new Var(40));
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(46), new Var(39));
+ assertEquals(false, result);
+
+ script = jexl.createScript("(x, y)->{ x == y }");
+ result = script.execute(jc, 42, 43);
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(42), new Var(43));
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(41), new Var(44));
+ assertEquals(false, result);
+ result = script.execute(jc, 43, 42);
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(45), new Var(40));
+ assertEquals(false, result);
+ result = script.execute(jc, new Var(46), new Var(39));
+ assertEquals(false, result);
+
+ script = jexl.createScript("(x, y)->{ x % y }");
+ result = script.execute(jc, 4242, 100);
+ assertEquals(42, result);
+ result = script.execute(jc, new Var(4242), new Var(100));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, new Var(4242), new Var(100));
+ assertEquals(42, ((Var) result).value);
+
+ script = jexl.createScript("(x, y)->{ x * y }");
+ result = script.execute(jc, 6, 7);
+ assertEquals(42, result);
+ result = script.execute(jc, new Var(6), new Var(7));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, new Var(6), new Var(7));
+ assertEquals(42, ((Var) result).value);
+
+ script = jexl.createScript("(x, y)->{ x + y }");
+ result = script.execute(jc, 35, 7);
+ assertEquals(42, result);
+ result = script.execute(jc, new Var(35), new Var(7));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, new Var(35), new Var(7));
+ assertEquals(42, ((Var) result).value);
+
+ script = jexl.createScript("(x, y)->{ x - y }");
+ result = script.execute(jc, 49, 7);
+ assertEquals(42, result);
+ result = script.execute(jc, "foobarquux", "bar");
+ assertEquals("fooquux", result);
+ result = script.execute(jc, 50, 8);
+ assertEquals(42, result);
+ result = script.execute(jc, new Var(50), new Var(8));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, new Var(50), new Var(8));
+ assertEquals(42, ((Var) result).value);
+
+ script = jexl.createScript("(x)->{ -x }");
+ result = script.execute(jc, -42);
+ assertEquals(42, result);
+ result = script.execute(jc, new Var(-42));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, new Var(-42));
+ assertEquals(42, ((Var) result).value);
+ result = script.execute(jc, "pizza");
+ assertEquals("azzip", result);
+ result = script.execute(jc, -142);
+ assertEquals(142, result);
+ }
}
\ No newline at end of file
Modified:
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java
(original)
+++
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java
Wed Oct 1 08:57:12 2014
@@ -22,6 +22,12 @@ import java.io.FileWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Arrays;
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
/**
* Helper class to test GC / reference interactions.
@@ -36,10 +42,11 @@ public class ClassCreator {
private String className = null;
private String sourceName = null;
private ClassLoader loader = null;
- public static final boolean canRun = comSunToolsJavacMain();
+ public static final boolean canRun = true;//comSunToolsJavacMain();
static final String GEN_PATH = "/org/apache/commons/jexl3/generated";
- static final String GEN_CLASS = "org.apache.commons.jexl3.generated.";
+ static final String GEN_PACKAGE = "org.apache.commons.jexl3.generated";
+ static final String GEN_CLASS = GEN_PACKAGE + ".";
/**
* Check if we can invoke Sun's java compiler.
* @return true if it is possible, false otherwise
@@ -109,7 +116,9 @@ public class ClassCreator {
void generate() throws Exception {
FileWriter aWriter = new FileWriter(new File(packageDir, sourceName),
false);
- aWriter.write("package org.apache.commons.jexl3.generated;");
+ aWriter.write("package ");
+ aWriter.write(GEN_PACKAGE);
+ aWriter.write(";\n");
aWriter.write("public class " + className + "{\n");
aWriter.write("private int value =");
aWriter.write(Integer.toString(seed));
@@ -125,7 +134,7 @@ public class ClassCreator {
aWriter.close();
}
- Class<?> compile() throws Exception {
+ Class<?> compile0() throws Exception {
String source = packageDir.getPath() + "/" + sourceName;
Class<?> javac =
getClassLoader().loadClass("com.sun.tools.javac.Main");
if (javac == null) {
@@ -135,18 +144,36 @@ public class ClassCreator {
try {
r = (Integer) jexl.invokeMethod(javac, "compile", source);
if (r.intValue() >= 0) {
- return
getClassLoader().loadClass("org.apache.commons.jexl3.generated." + className);
+ return getClassLoader().loadClass(GEN_CLASS + className);
}
} catch (JexlException xignore) {
// ignore
}
r = (Integer) jexl.invokeMethod(javac, "compile", (Object) new
String[]{source});
if (r.intValue() >= 0) {
- return
getClassLoader().loadClass("org.apache.commons.jexl3.generated." + className);
+ return getClassLoader().loadClass(GEN_CLASS + className);
}
return null;
}
+ Class<?> compile() throws Exception {
+ String source = packageDir.getPath() + "/" + sourceName;
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ DiagnosticCollector<JavaFileObject> diagnostics = new
DiagnosticCollector<JavaFileObject>();
+ StandardJavaFileManager fileManager =
compiler.getStandardFileManager(diagnostics, null, null);
+ Iterable<? extends JavaFileObject> compilationUnits = fileManager
+ .getJavaFileObjectsFromStrings(Arrays.asList(source));
+ JavaCompiler.CompilationTask task = compiler.getTask(null,
fileManager, diagnostics, null,
+ null, compilationUnits);
+ boolean success = task.call();
+ fileManager.close();
+ if (success) {
+ return getClassLoader().loadClass(GEN_CLASS + className);
+ } else {
+ return null;
+ }
+ }
+
Object validate(Class<?> clazz) throws Exception {
Class<?> params[] = {};
Object paramsObj[] = {};
Modified:
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java?rev=1628650&r1=1628649&r2=1628650&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java
(original)
+++
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java
Wed Oct 1 08:57:12 2014
@@ -165,7 +165,7 @@ public class ClassCreatorTest extends Je
// attempt to force GC:
// while we still have a MB free, create & store big objects
- for (int b = 0; b < 64 && Runtime.getRuntime().freeMemory() >
MEGA; ++b) {
+ for (int b = 0; b < 1024 && Runtime.getRuntime().freeMemory()
> MEGA; ++b) {
BigObject big = new BigObject(b);
stuff.add(new InstanceReference(big, queue));
}