You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ra...@apache.org on 2009/08/01 02:36:52 UTC
svn commit: r799779 [1/3] - in
/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl: ./
context/ parser/ scripting/ util/ util/introspection/
Author: rahul
Date: Sat Aug 1 00:36:51 2009
New Revision: 799779
URL: http://svn.apache.org/viewvc?rev=799779&view=rev
Log:
JEXL-60
Step 2 of 4
Refactor two packages:
- org.apache.commons.jexl.util
- org.apache.commons.jexl.util.introspection
Changes include:
* A more complete set of specialized executors for property, map, list, duck setters and getters etc.
* Support for the new() function which allows calling constructors
* Added two missing package.html files
* New DebugInfo interface for use with Uberspects
* Separated out MethodKey class
* Type safety and Javadoc changes
Based on patch by Henri Biestro <hbiestro at gmail dot com> with minor changes.
Added:
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/BooleanGetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/DuckGetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/DuckSetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/ListGetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/ListSetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapSetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MethodExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertyGetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/PropertySetExecutor.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/DebugInfo.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodKey.java (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/package.html (with props)
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/package.html (with props)
Modified:
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Debugger.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ExpressionImpl.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Interpreter.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlContext.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlHelper.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/context/HashMapContext.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/scripting/JexlScriptEngine.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/AbstractExecutor.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/ArrayIterator.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/ArrayListWrapper.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/EnumerationIterator.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/Introspector.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/MapGetExecutor.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Info.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Debugger.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Debugger.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Debugger.java Sat Aug 1 00:36:51 2009
@@ -25,6 +25,7 @@
import org.apache.commons.jexl.parser.ASTBitwiseOrNode;
import org.apache.commons.jexl.parser.ASTBitwiseXorNode;
import org.apache.commons.jexl.parser.ASTBlock;
+import org.apache.commons.jexl.parser.ASTConstructorNode;
import org.apache.commons.jexl.parser.ASTDivNode;
import org.apache.commons.jexl.parser.ASTEQNode;
import org.apache.commons.jexl.parser.ASTEmptyFunction;
@@ -62,7 +63,7 @@
import org.apache.commons.jexl.parser.ASTTrueNode;
import org.apache.commons.jexl.parser.ASTUnaryMinusNode;
import org.apache.commons.jexl.parser.ASTWhileStatement;
-import org.apache.commons.jexl.parser.Node;
+import org.apache.commons.jexl.parser.JexlNode;
import org.apache.commons.jexl.parser.SimpleNode;
import org.apache.commons.jexl.parser.ParserVisitor;
@@ -78,7 +79,7 @@
/** The builder to compose messages. */
private StringBuilder builder;
/** The cause of the issue to debug. */
- private Node cause;
+ private JexlNode cause;
/** The starting character location offset of the cause in the builder. */
private int start;
/** The ending character location offset of the cause in the builder. */
@@ -99,14 +100,14 @@
* @param node the node to debug
* @return true if the cause was located, false otherwise
*/
- public boolean debug(Node node) {
+ public boolean debug(JexlNode node) {
start = 0;
end = 0;
if (node != null) {
builder = new StringBuilder();
this.cause = node;
// make arg cause become the root cause
- Node root = node;
+ JexlNode root = node;
while (root.jjtGetParent() != null) {
root = root.jjtGetParent();
}
@@ -143,7 +144,7 @@
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object accept(Node node, Object data) {
+ private Object accept(JexlNode node, Object data) {
if (node == cause) {
start = builder.length();
}
@@ -162,7 +163,7 @@
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object check(Node node, String image, Object data) {
+ private Object check(JexlNode node, String image, Object data) {
if (node == cause) {
start = builder.length();
}
@@ -185,7 +186,7 @@
* @param data visitor pattern argument
* @return visitor pattern value
*/
- private Object infixChildren(Node node, String infix, Object data) {
+ private Object infixChildren(JexlNode node, String infix, Object data) {
int num = node.jjtGetNumChildren();
for (int i = 0; i < num; ++i) {
if (i > 0) {
@@ -389,6 +390,22 @@
}
/** {@inheritDoc} */
+ public Object visit(ASTConstructorNode node, Object data) {
+ int num = node.jjtGetNumChildren();
+ builder.append("new ");
+ accept(node.jjtGetChild(0), data);
+ builder.append("(");
+ for (int i = 1; i < num; ++i) {
+ if (i > 1) {
+ builder.append(", ");
+ }
+ accept(node.jjtGetChild(i), data);
+ }
+ builder.append(")");
+ return data;
+ }
+
+ /** {@inheritDoc} */
public Object visit(ASTFunctionNode node, Object data) {
int num = node.jjtGetNumChildren();
accept(node.jjtGetChild(0), data);
@@ -553,10 +570,6 @@
/** {@inheritDoc} */
public Object visit(SimpleNode node, Object data) {
- int num = node.jjtGetNumChildren();
- for (int i = 0; i < num; ++i) {
- accept(node.jjtGetChild(i), data);
- }
- return data;
+ throw new UnsupportedOperationException("unexpected type of node");
}
}
\ No newline at end of file
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ExpressionImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ExpressionImpl.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ExpressionImpl.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/ExpressionImpl.java Sat Aug 1 00:36:51 2009
@@ -17,7 +17,7 @@
package org.apache.commons.jexl;
-import org.apache.commons.jexl.parser.SimpleNode;
+import org.apache.commons.jexl.parser.JexlNode;
/**
* Instances of ExpressionImpl are created by the {@link JexlEngine},
@@ -39,7 +39,7 @@
/**
* The resulting AST we can interpret.
*/
- protected final SimpleNode node;
+ protected final JexlNode node;
/**
@@ -49,7 +49,7 @@
* @param expr the expression.
* @param ref the parsed expression.
*/
- ExpressionImpl(JexlEngine engine, String expr, SimpleNode ref) {
+ ExpressionImpl(JexlEngine engine, String expr, JexlNode ref) {
expression = expr;
node = ref;
jexl = engine;
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Interpreter.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Interpreter.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/Interpreter.java Sat Aug 1 00:36:51 2009
@@ -16,6 +16,7 @@
*/
package org.apache.commons.jexl;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
@@ -23,11 +24,12 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
+import org.apache.commons.jexl.parser.SimpleNode;
import org.apache.commons.logging.Log;
+import org.apache.commons.jexl.parser.JexlNode;
import org.apache.commons.jexl.parser.ASTAddNode;
import org.apache.commons.jexl.parser.ASTAndNode;
import org.apache.commons.jexl.parser.ASTArrayAccess;
@@ -37,6 +39,7 @@
import org.apache.commons.jexl.parser.ASTBitwiseOrNode;
import org.apache.commons.jexl.parser.ASTBitwiseXorNode;
import org.apache.commons.jexl.parser.ASTBlock;
+import org.apache.commons.jexl.parser.ASTConstructorNode;
import org.apache.commons.jexl.parser.ASTDivNode;
import org.apache.commons.jexl.parser.ASTEQNode;
import org.apache.commons.jexl.parser.ASTEmptyFunction;
@@ -75,10 +78,10 @@
import org.apache.commons.jexl.parser.ASTUnaryMinusNode;
import org.apache.commons.jexl.parser.ASTWhileStatement;
import org.apache.commons.jexl.parser.Node;
-import org.apache.commons.jexl.parser.SimpleNode;
import org.apache.commons.jexl.parser.ParserVisitor;
-import org.apache.commons.jexl.util.introspection.Info;
+import org.apache.commons.jexl.util.AbstractExecutor;
+import org.apache.commons.jexl.util.introspection.DebugInfo;
import org.apache.commons.jexl.util.introspection.Uberspect;
import org.apache.commons.jexl.util.introspection.VelMethod;
import org.apache.commons.jexl.util.introspection.VelPropertyGet;
@@ -95,7 +98,7 @@
/** The uberspect. */
protected final Uberspect uberspect;
/** The arithmetic handler. */
- protected final Arithmetic arithmetic;
+ protected final JexlArithmetic arithmetic;
/** The map of registered functions. */
protected final Map<String, Object> functions;
/** The context to store/retrieve variables. */
@@ -104,10 +107,10 @@
protected final boolean strict;
/** Silent intepreter flag. */
protected boolean silent;
+ /** Cache executors. */
+ protected final boolean cache;
/** Registers made of 2 pairs of {register-name, value}. */
protected Object[] registers = null;
- /** Dummy velocity info. */
- protected static final Info DUMMY = new Info("", 1, 1);
/** Empty parameters for method matching. */
protected static final Object[] EMPTY_PARAMS = new Object[0];
@@ -123,6 +126,7 @@
this.functions = jexl.functions;
this.strict = !this.arithmetic.isLenient();
this.silent = jexl.silent;
+ this.cache = jexl.cache != null;
this.context = aContext;
}
@@ -152,7 +156,7 @@
* @return the result of the interpretation.
* @throws JexlException if any error occurs during interpretation.
*/
- public Object interpret(SimpleNode node) {
+ public Object interpret(JexlNode node) {
try {
return node.jjtAccept(this, null);
} catch (JexlException xjexl) {
@@ -188,7 +192,7 @@
* @param right the right argument
* @return the left, right or parent node
*/
- protected Node findNullOperand(RuntimeException xrt, Node node, Object left, Object right) {
+ protected JexlNode findNullOperand(RuntimeException xrt, JexlNode node, Object left, Object right) {
if (xrt instanceof NullPointerException
&& JexlException.NULL_OPERAND == xrt.getMessage()) {
if (left == null) {
@@ -202,16 +206,6 @@
}
/** {@inheritDoc} */
- public Object visit(SimpleNode node, Object data) {
- int numChildren = node.jjtGetNumChildren();
- Object result = null;
- for (int i = 0; i < numChildren; i++) {
- result = node.jjtGetChild(i).jjtAccept(this, data);
- }
- return result;
- }
-
- /** {@inheritDoc} */
public Object visit(ASTAddNode node, Object data) {
/**
* The pattern for exception mgmt is to let the child*.jjtAccept
@@ -225,7 +219,7 @@
try {
return arithmetic.add(left, right);
} catch (RuntimeException xrt) {
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "add error", xrt);
}
}
@@ -261,7 +255,7 @@
// reference
int numChildren = node.jjtGetNumChildren();
for (int i = 1; i < numChildren; i++) {
- Node nindex = node.jjtGetChild(i);
+ JexlNode nindex = node.jjtGetChild(i);
Object index = nindex.jjtAccept(this, null);
object = getAttribute(object, index, nindex);
}
@@ -272,7 +266,7 @@
/** {@inheritDoc} */
public Object visit(ASTAssignment node, Object data) {
// left contains the reference to assign to
- Node left = node.jjtGetChild(0);
+ JexlNode left = node.jjtGetChild(0);
if (!(left instanceof ASTReference)) {
throw new JexlException(left, "illegal assignment form");
}
@@ -280,9 +274,9 @@
Object right = node.jjtGetChild(1).jjtAccept(this, data);
// determine initial object & property:
- Node objectNode = null;
+ JexlNode objectNode = null;
Object object = null;
- Node propertyNode = null;
+ JexlNode propertyNode = null;
Object property = null;
boolean isVariable = true;
StringBuilder variableName = null;
@@ -327,7 +321,7 @@
variableName.append(property);
property = variableName.toString();
}
- context.getVars().put(property, right);
+ context.getVars().put(String.valueOf(property), right);
return right;
}
} else if (propertyNode instanceof ASTArrayAccess) {
@@ -375,7 +369,7 @@
long l = arithmetic.toLong(left);
n = 1;
long r = arithmetic.toLong(right);
- return new Long(l & r);
+ return l & r;
} catch (RuntimeException xrt) {
throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt);
}
@@ -386,7 +380,7 @@
Object left = node.jjtGetChild(0).jjtAccept(this, data);
try {
long l = arithmetic.toLong(left);
- return new Long(~l);
+ return ~l;
} catch (RuntimeException xrt) {
throw new JexlException(node.jjtGetChild(0), "long coercion error", xrt);
}
@@ -402,7 +396,7 @@
long l = arithmetic.toLong(left);
n = 1;
long r = arithmetic.toLong(right);
- return new Long(l | r);
+ return l | r;
} catch (RuntimeException xrt) {
throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt);
}
@@ -418,7 +412,7 @@
long l = arithmetic.toLong(left);
n = 1;
long r = arithmetic.toLong(right);
- return new Long(l ^ r);
+ return l ^ r;
} catch (RuntimeException xrt) {
throw new JexlException(node.jjtGetChild(n), "long coercion error", xrt);
}
@@ -444,7 +438,7 @@
if (!strict && xrt instanceof ArithmeticException) {
return 0.0;
}
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "divide error", xrt);
}
}
@@ -494,14 +488,17 @@
/** {@inheritDoc} */
public Object visit(ASTFalseNode node, Object data) {
-
return Boolean.FALSE;
}
/** {@inheritDoc} */
public Object visit(ASTFloatLiteral node, Object data) {
-
- return Float.valueOf(node.image);
+ Float value = (Float) node.jjtGetValue();
+ if (value == null) {
+ value = Float.valueOf(node.image);
+ node.jjtSetValue(value);
+ }
+ return value;
}
/** {@inheritDoc} */
@@ -515,10 +512,10 @@
// make sure there is a value to iterate on and a statement to execute
if (iterableValue != null && node.jjtGetNumChildren() >= 3) {
/* third objectNode is the statement to execute */
- SimpleNode statement = (SimpleNode) node.jjtGetChild(2);
+ JexlNode statement = (JexlNode) node.jjtGetChild(2);
// get an iterator for the collection/array etc via the
// introspector.
- Iterator<?> itemsIterator = getUberspect().getIterator(iterableValue, DUMMY);
+ Iterator<?> itemsIterator = getUberspect().getIterator(iterableValue, node);
while (itemsIterator.hasNext()) {
// set loopVariable to value of iterator
Object value = itemsIterator.next();
@@ -611,8 +608,16 @@
/** {@inheritDoc} */
public Object visit(ASTIntegerLiteral node, Object data) {
- Integer value = Integer.valueOf(node.image);
- return (data == null) ? value : getAttribute(data, value);
+ if (data != null) {
+ Integer value = Integer.valueOf(node.image);
+ return getAttribute(data, value, node);
+ }
+ Integer value = (Integer) node.jjtGetValue();
+ if (value == null) {
+ value = Integer.valueOf(node.image);
+ node.jjtSetValue(value);
+ }
+ return value;
}
/** {@inheritDoc} */
@@ -620,7 +625,7 @@
int numChildren = node.jjtGetNumChildren();
Object result = null;
for (int i = 0; i < numChildren; i++) {
- Node child = node.jjtGetChild(i);
+ JexlNode child = node.jjtGetChild(i);
result = child.jjtAccept(this, data);
}
return result;
@@ -668,6 +673,19 @@
return map;
}
+ /**
+ * Replace all numbers in an arguments array with the smallest type that will fit.
+ * @param args the argument array
+ */
+ protected final void narrowArguments(Object[] args) {
+ for (int a = 0; a < args.length; a++) {
+ Object arg = args[a];
+ if (arg instanceof Number) {
+ args[a] = arithmetic.narrow((Number) arg);
+ }
+ }
+ }
+
/** {@inheritDoc} */
public Object visit(ASTMethodNode node, Object data) {
// the object to invoke the method on should be in the data argument
@@ -686,34 +704,42 @@
// objectNode 0 is the identifier (method name), the others are parameters.
String methodName = ((ASTIdentifier) node.jjtGetChild(0)).image;
- // get our params
- int paramCount = node.jjtGetNumChildren() - 1;
- Object[] params = new Object[paramCount];
- for (int i = 0; i < paramCount; i++) {
- params[i] = node.jjtGetChild(i + 1).jjtAccept(this, null);
+ // get our arguments
+ int argc = node.jjtGetNumChildren() - 1;
+ Object[] argv = new Object[argc];
+ for (int i = 0; i < argc; i++) {
+ argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, null);
}
JexlException xjexl = null;
try {
- VelMethod vm = getUberspect().getMethod(data, methodName, params, DUMMY);
- // DG: If we can't find an exact match, narrow the parameters and
- // try again!
- if (vm == null) {
-
- // replace all numbers with the smallest type that will fit
- for (int i = 0; i < params.length; i++) {
- Object param = params[i];
- if (param instanceof Number) {
- params[i] = arithmetic.narrow((Number) param);
+ // attempt to reuse last executor cached in volatile JexlNode.value
+ if (node != null && cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof AbstractExecutor.Method) {
+ AbstractExecutor.Method me = (AbstractExecutor.Method) cached;
+ Object eval = me.tryExecute(methodName, data, argv);
+ if (eval != AbstractExecutor.TRY_FAILED) {
+ return eval;
}
}
- vm = getUberspect().getMethod(data, methodName, params, DUMMY);
+ }
+ VelMethod vm = uberspect.getMethod(data, methodName, argv, node);
+ // DG: If we can't find an exact match, narrow the parameters and try again!
+ if (vm == null) {
+ narrowArguments(argv);
+ vm = uberspect.getMethod(data, methodName, argv, node);
if (vm == null) {
- xjexl = new JexlException(node, "unknown method", null);
+ xjexl = new JexlException(node, "unknown or ambiguous method", null);
}
}
if (xjexl == null) {
- return vm.invoke(data, params);
+ Object eval = vm.invoke(data, argv);
+ // cache executor in volatile JexlNode.value
+ if (node != null && cache) {
+ node.jjtSetValue(vm);
+ }
+ return eval;
}
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
@@ -734,44 +760,99 @@
}
/** {@inheritDoc} */
+ public Object visit(ASTConstructorNode node, Object data) {
+ // first child is class or class name
+ Object cobject = node.jjtGetChild(0).jjtAccept(this, data);
+ // get the ctor args
+ int argc = node.jjtGetNumChildren() - 1;
+ Object[] argv = new Object[argc];
+ for (int i = 0; i < argc; i++) {
+ argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, null);
+ }
+
+ JexlException xjexl = null;
+ try {
+ Constructor<?> ctor = uberspect.getConstructor(cobject, argv, node);
+ // DG: If we can't find an exact match, narrow the parameters and
+ // try again!
+ if (ctor == null) {
+ // replace all numbers with the smallest type that will fit
+ narrowArguments(argv);
+ ctor = uberspect.getConstructor(cobject, argv, node);
+ if (ctor == null) {
+ xjexl = new JexlException(node, "unknown constructor", null);
+ }
+ }
+ if (xjexl == null) {
+ return ctor.newInstance(argv);
+ }
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ if (!(t instanceof Exception)) {
+ t = e;
+ }
+ xjexl = new JexlException(node, "constructor invocation error", t);
+ } catch (Exception e) {
+ xjexl = new JexlException(node, "constructor error", e);
+ }
+ if (xjexl != null) {
+ if (strict) {
+ throw xjexl;
+ }
+ logger.warn(xjexl.getMessage(), xjexl.getCause());
+ }
+ return null;
+ }
+
+ /** {@inheritDoc} */
public Object visit(ASTFunctionNode node, Object data) {
// objectNode 0 is the prefix
String prefix = ((ASTIdentifier) node.jjtGetChild(0)).image;
- Object functor = functions.get(prefix);
- if (functor == null) {
+ Object namespace = functions.get(prefix);
+ if (namespace == null) {
throw new JexlException(node, "no such function namespace " + prefix);
}
// objectNode 1 is the identifier , the others are parameters.
- String methodName = ((ASTIdentifier) node.jjtGetChild(1)).image;
+ String function = ((ASTIdentifier) node.jjtGetChild(1)).image;
- // get our params
- int paramCount = node.jjtGetNumChildren() - 2;
- Object[] params = new Object[paramCount];
- for (int i = 0; i < paramCount; i++) {
- params[i] = node.jjtGetChild(i + 2).jjtAccept(this, null);
+ // get our args
+ int argc = node.jjtGetNumChildren() - 2;
+ Object[] argv = new Object[argc];
+ for (int i = 0; i < argc; i++) {
+ argv[i] = node.jjtGetChild(i + 2).jjtAccept(this, null);
}
JexlException xjexl = null;
try {
- VelMethod vm = getUberspect().getMethod(functor, methodName, params, DUMMY);
+ // attempt to reuse last executor cached in volatile JexlNode.value
+ if (node != null && cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof AbstractExecutor.Method) {
+ AbstractExecutor.Method me = (AbstractExecutor.Method) cached;
+ Object eval = me.tryExecute(function, namespace, argv);
+ if (eval != AbstractExecutor.TRY_FAILED) {
+ return eval;
+ }
+ }
+ }
+ VelMethod vm = uberspect.getMethod(namespace, function, argv, node);
// DG: If we can't find an exact match, narrow the parameters and
// try again!
if (vm == null) {
-
// replace all numbers with the smallest type that will fit
- for (int i = 0; i < params.length; i++) {
- Object param = params[i];
- if (param instanceof Number) {
- params[i] = arithmetic.narrow((Number) param);
- }
- }
- vm = getUberspect().getMethod(functor, methodName, params, DUMMY);
+ narrowArguments(argv);
+ vm = uberspect.getMethod(namespace, function, argv, node);
if (vm == null) {
xjexl = new JexlException(node, "unknown function", null);
}
}
if (xjexl == null) {
- return vm.invoke(functor, params);
+ Object eval = vm.invoke(namespace, argv);
+ // cache executor in volatile JexlNode.value
+ if (node != null && cache) {
+ node.jjtSetValue(vm);
+ }
+ return eval;
}
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
@@ -801,7 +882,7 @@
if (!strict && xrt instanceof ArithmeticException) {
return 0.0;
}
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "% error", xrt);
}
}
@@ -813,7 +894,7 @@
try {
return arithmetic.multiply(left, right);
} catch (RuntimeException xrt) {
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "* error", xrt);
}
}
@@ -825,7 +906,7 @@
try {
return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE;
} catch (RuntimeException xrt) {
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "!= error", xrt);
}
}
@@ -875,10 +956,10 @@
// pass first piece of data in and loop through children
Object result = null;
StringBuilder variableName = null;
- Map<?, ?> vars = context.getVars();
+ Map<String, ?> vars = context.getVars();
boolean isVariable = true;
for (int i = 0; i < numChildren; i++) {
- Node theNode = node.jjtGetChild(i);
+ JexlNode theNode = node.jjtGetChild(i);
isVariable &= (theNode instanceof ASTIdentifier);
result = theNode.jjtAccept(this, result);
// if we get null back a result, check for an ant variable
@@ -920,12 +1001,12 @@
throw new JexlException(node, "size() : argument is null", null);
}
- return new Integer(sizeOf(node, val));
+ return sizeOf(node, val);
}
/** {@inheritDoc} */
public Object visit(ASTSizeMethod node, Object data) {
- return new Integer(sizeOf(node, data));
+ return sizeOf(node, data);
}
/** {@inheritDoc} */
@@ -945,7 +1026,7 @@
try {
return arithmetic.subtract(left, right);
} catch (RuntimeException xrt) {
- Node xnode = findNullOperand(xrt, node, left, right);
+ JexlNode xnode = findNullOperand(xrt, node, left, right);
throw new JexlException(xnode, "- error", xrt);
}
}
@@ -974,7 +1055,7 @@
/** {@inheritDoc} */
public Object visit(ASTUnaryMinusNode node, Object data) {
- Node valNode = node.jjtGetChild(0);
+ JexlNode valNode = node.jjtGetChild(0);
Object val = valNode.jjtAccept(this, data);
if (val instanceof Byte) {
byte valueAsByte = ((Byte) val).byteValue();
@@ -984,16 +1065,16 @@
return Short.valueOf((short) -valueAsShort);
} else if (val instanceof Integer) {
int valueAsInt = ((Integer) val).intValue();
- return new Integer(-valueAsInt);
+ return Integer.valueOf(-valueAsInt);
} else if (val instanceof Long) {
long valueAsLong = ((Long) val).longValue();
- return new Long(-valueAsLong);
+ return Long.valueOf(-valueAsLong);
} else if (val instanceof Float) {
float valueAsFloat = ((Float) val).floatValue();
- return new Float(-valueAsFloat);
+ return Float.valueOf(-valueAsFloat);
} else if (val instanceof Double) {
double valueAsDouble = ((Double) val).doubleValue();
- return new Double(-valueAsDouble);
+ return Double.valueOf(-valueAsDouble);
} else if (val instanceof BigDecimal) {
BigDecimal valueAsBigD = (BigDecimal) val;
return valueAsBigD.negate();
@@ -1024,7 +1105,7 @@
* @param val the object to get the size of.
* @return the size of val
*/
- private int sizeOf(Node node, Object val) {
+ private int sizeOf(JexlNode node, Object val) {
if (val instanceof Collection<?>) {
return ((Collection<?>) val).size();
} else if (val.getClass().isArray()) {
@@ -1037,7 +1118,7 @@
// check if there is a size method on the object that returns an
// integer and if so, just use it
Object[] params = new Object[0];
- VelMethod vm = uberspect.getMethod(val, "size", EMPTY_PARAMS, DUMMY);
+ VelMethod vm = uberspect.getMethod(val, "size", EMPTY_PARAMS, (DebugInfo) node);
if (vm != null && vm.getReturnType() == Integer.TYPE) {
Integer result;
try {
@@ -1072,42 +1153,30 @@
* @param node the node that evaluated as the object
* @return the attribute value
*/
- protected Object getAttribute(Object object, Object attribute, Node node) {
+ protected Object getAttribute(Object object, Object attribute, JexlNode node) {
if (object == null) {
throw new JexlException(node, "object is null");
}
- // maps do accept null keys; check attribute null status after trying
- if (object instanceof Map<?, ?>) {
- try {
- return ((Map<Object, Object>) object).get(attribute);
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "get map element error", xrt);
- }
- }
- if (attribute == null) {
- throw new JexlException(node, "object property is null");
- }
- if (object instanceof List<?>) {
- try {
- int idx = arithmetic.toInteger(attribute);
- return ((List<?>) object).get(idx);
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "get list element error", xrt);
- }
- }
- if (object.getClass().isArray()) {
- try {
- int idx = arithmetic.toInteger(attribute);
- return Array.get(object, idx);
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "get array element error", xrt);
+ // attempt to reuse last executor cached in volatile JexlNode.value
+ if (node != null && cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof AbstractExecutor.Get) {
+ AbstractExecutor.Get vg = (AbstractExecutor.Get) cached;
+ Object value = vg.tryExecute(object, attribute);
+ if (value != AbstractExecutor.TRY_FAILED) {
+ return value;
+ }
}
}
- // look up bean property of data and return
- VelPropertyGet vg = getUberspect().getPropertyGet(object, attribute.toString(), DUMMY);
+ VelPropertyGet vg = uberspect.getPropertyGet(object, attribute.toString(), node);
if (vg != null) {
try {
- return vg.invoke(object);
+ Object value = vg.invoke(object);
+ // cache executor in volatile JexlNode.value
+ if (node != null && cache) {
+ node.jjtSetValue(vg);
+ }
+ return value;
} catch (Exception xany) {
if (node == null) {
throw new RuntimeException(xany);
@@ -1141,50 +1210,27 @@
* @param value the value to assign to the object's attribute
* @param node the node that evaluated as the object
*/
- protected void setAttribute(Object object, Object attribute, Object value, Node node) {
- if (object instanceof JexlContext) {
- ((JexlContext) object).getVars().put(attribute, value);
- return;
- }
-
- if (object instanceof Map<?, ?>) {
- try {
- ((Map<Object, Object>) object).put(attribute, value);
- return;
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "set map element error", xrt);
- }
- }
- if (object instanceof List<?>) {
- try {
- int idx = arithmetic.toInteger(attribute);
- ((List<Object>) object).set(idx, value);
- return;
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "set list element error", xrt);
- }
- }
-
- if (object == null) {
- throw new JexlException(node, "object is null");
- }
-
- if (object.getClass().isArray()) {
- try {
- int idx = arithmetic.toInteger(attribute);
- Array.set(object, idx, value);
- return;
- } catch (RuntimeException xrt) {
- throw node == null ? xrt : new JexlException(node, "set array element error", xrt);
+ protected void setAttribute(Object object, Object attribute, Object value, JexlNode node) {
+ String s = attribute.toString();
+ // attempt to reuse last executor cached in volatile JexlNode.value
+ if (node != null && cache) {
+ Object cached = node.jjtGetValue();
+ if (cached instanceof AbstractExecutor.Set) {
+ AbstractExecutor.Set setter = (AbstractExecutor.Set) cached;
+ Object eval = setter.tryExecute(object, attribute, value);
+ if (eval != AbstractExecutor.TRY_FAILED) {
+ return;
+ }
}
}
-
- // "Otherwise (a JavaBean object)..." huh? :)
- String s = attribute.toString();
- VelPropertySet vs = getUberspect().getPropertySet(object, s, value, DUMMY);
+ VelPropertySet vs = uberspect.getPropertySet(object, s, value, node);
if (vs != null) {
try {
+ // cache executor in volatile JexlNode.value
vs.invoke(object, value);
+ if (node != null && cache) {
+ node.jjtSetValue(vs);
+ }
} catch (RuntimeException xrt) {
throw node == null ? xrt : new JexlException(node, "set object property error", xrt);
} catch (Exception xany) {
@@ -1196,10 +1242,22 @@
}
return;
}
+ String error = "unable to set object property"
+ + ", class: " + object.getClass().getName()
+ + ", property: " + attribute;
if (node == null) {
- throw new UnsupportedOperationException("unable to set object property, "
- + "object:" + object + ", property: " + attribute);
+ throw new UnsupportedOperationException(error);
}
- throw new JexlException(node, "unable to set bean property", null);
+ throw new JexlException(node, error, null);
+ }
+
+ /**
+ * Unused, satisfy PArserVisitor interface.
+ * @param node a node
+ * @param data the date
+ * @return does not return,
+ */
+ public Object visit(SimpleNode node, Object data) {
+ throw new UnsupportedOperationException("Not supported yet.");
}
}
\ No newline at end of file
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlArithmetic.java Sat Aug 1 00:36:51 2009
@@ -23,27 +23,39 @@
* Perform arithmetic.
* @since 2.0
*/
-class JexlArithmetic implements Arithmetic {
- /** Whether this Arithmetic instance behaves in strict or lenient mode. */
+public class JexlArithmetic {
+ /** Integer.MAX_VALUE as BigDecimal. */
+ private static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
+ /** Integer.MIN_VALUE as BigDecimal. */
+ private static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(-Double.MAX_VALUE);
+ /** Long.MAX_VALUE as BigInteger. */
+ private static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
+ /** Long.MIN_VALUE as BigInteger. */
+ private static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
+ /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */
protected boolean strict;
/**
* Creates a JexlArithmetic.
* @param lenient whether this arithmetic is lenient or strict
*/
- JexlArithmetic(boolean lenient) {
+ public JexlArithmetic(boolean lenient) {
this.strict = !lenient;
}
/**
- * {@inheritDoc}
+ * Sets whether this JexlArithmetic instance triggers errors during evaluation when
+ * null is used as an operand.
+ * @param lenient true means no JexlException will occur, false allows them
*/
public void setLenient(boolean lenient) {
this.strict = !lenient;
}
/**
- * {@inheritDoc}
+ * Checks whether this JexlArithmetic instance triggers errors during evaluation
+ * when null is used as an operand.
+ * @return true if lenient, false if strict
*/
public boolean isLenient() {
return !this.strict;
@@ -89,7 +101,7 @@
if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
double l = toDouble(left);
double r = toDouble(right);
- return new Double(l + r);
+ return l + r;
}
// if both are bigintegers use that type
@@ -110,9 +122,9 @@
BigInteger l = toBigInteger(left);
BigInteger r = toBigInteger(right);
BigInteger result = l.add(r);
- BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
- if (result.compareTo(maxLong) <= 0) {
- return new Long(result.longValue());
+ if (result.compareTo(BIGI_LONG_MAX_VALUE) <= 0
+ && result.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
+ return result.longValue();
}
return result;
} catch (java.lang.NumberFormatException nfe) {
@@ -204,9 +216,9 @@
BigInteger l = toBigInteger(left);
BigInteger r = toBigInteger(right);
BigInteger result = l.mod(r);
- BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
- if (result.compareTo(maxLong) <= 0) {
- return new Long(result.longValue());
+ if (result.compareTo(BIGI_LONG_MAX_VALUE) <= 0
+ && result.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
+ return result.longValue();
}
return result;
}
@@ -233,7 +245,7 @@
if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
double l = toDouble(left);
double r = toDouble(right);
- return new Double(l * r);
+ return l * r;
}
// if both are bigintegers use that type
@@ -254,9 +266,9 @@
BigInteger l = toBigInteger(left);
BigInteger r = toBigInteger(right);
BigInteger result = l.multiply(r);
- BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
- if (result.compareTo(maxLong) <= 0) {
- return new Long(result.longValue());
+ if (result.compareTo(BIGI_LONG_MAX_VALUE) <= 0
+ && result.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
+ return result.longValue();
}
return result;
}
@@ -283,7 +295,7 @@
if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
double l = toDouble(left);
double r = toDouble(right);
- return new Double(l - r);
+ return l - r;
}
// if both are bigintegers use that type
@@ -304,9 +316,9 @@
BigInteger l = toBigInteger(left);
BigInteger r = toBigInteger(right);
BigInteger result = l.subtract(r);
- BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE);
- if (result.compareTo(maxLong) <= 0) {
- return new Long(result.longValue());
+ if (result.compareTo(BIGI_LONG_MAX_VALUE) <= 0
+ && result.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
+ return result.longValue();
}
return result;
}
@@ -677,21 +689,21 @@
if (original instanceof BigDecimal) {
BigDecimal bigd = (BigDecimal) original;
// if it's bigger than a double it can't be narrowed
- if (bigd.compareTo(new BigDecimal(Double.MAX_VALUE)) > 0) {
+ if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0) {
return original;
}
}
if (original instanceof Double || original instanceof Float || original instanceof BigDecimal) {
double value = original.doubleValue();
if (value <= Float.MAX_VALUE && value >= Float.MIN_VALUE) {
- result = new Float(result.floatValue());
+ result = Float.valueOf(result.floatValue());
}
// else it fits in a double only
} else {
if (original instanceof BigInteger) {
BigInteger bigi = (BigInteger) original;
// if it's bigger than a Long it can't be narrowed
- if (bigi.compareTo(new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) {
+ if (bigi.compareTo(BIGI_LONG_MAX_VALUE) > 0) {
return original;
}
}
@@ -702,7 +714,7 @@
} else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
result = Short.valueOf((short) value);
} else if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) {
- result = new Integer((int) value);
+ result = Integer.valueOf((int) value);
}
// else it fits in a long
}
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlContext.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlContext.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlContext.java Sat Aug 1 00:36:51 2009
@@ -35,7 +35,7 @@
* @param vars Contents of vars will be replaced with the content
* of this Map
*/
- void setVars(Map vars);
+ void setVars(Map<String,Object> vars);
/**
* Retrives the Map of variables associated with this JexlContext. The
@@ -44,5 +44,5 @@
*
* @return A reference to the variable Map associated with this JexlContext.
*/
- Map getVars();
+ Map<String,Object> getVars();
}
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlEngine.java Sat Aug 1 00:36:51 2009
@@ -32,11 +32,12 @@
import org.apache.commons.jexl.parser.ParseException;
import org.apache.commons.jexl.parser.Parser;
-import org.apache.commons.jexl.parser.SimpleNode;
+import org.apache.commons.jexl.parser.JexlNode;
import org.apache.commons.jexl.parser.TokenMgrError;
import org.apache.commons.jexl.parser.ASTJexlScript;
import org.apache.commons.jexl.util.Introspector;
import org.apache.commons.jexl.util.introspection.Uberspect;
+import org.apache.commons.jexl.util.introspection.Info;
/**
* <p>
@@ -44,7 +45,7 @@
* Determines the behavior of Expressions & Scripts during their evaluation with respect to:
* <ul>
* <li>Introspection, see {@link Uberspect}</li>
- * <li>Arithmetic & comparison, see {@link Arithmetic}</li>
+ * <li>Arithmetic & comparison, see {@link JexlArithmetic}</li>
* <li>Error reporting</li>
* <li>Logging</li>
* </ul>
@@ -87,9 +88,9 @@
*/
protected final Uberspect uberspect;
/**
- * The Arithmetic instance.
+ * The JexlArithmetic instance.
*/
- protected final Arithmetic arithmetic;
+ protected final JexlArithmetic arithmetic;
/**
* The Log to which all JexlEngine messages will be logged.
*/
@@ -106,13 +107,17 @@
*/
protected boolean silent = false;
/**
+ * Wheter error messages will carry debugging information.
+ */
+ protected boolean debug = true;
+ /**
* The map of 'prefix:function' to object implementing the function.
*/
protected Map<String, Object> functions = Collections.EMPTY_MAP;
/**
* The expression cache.
*/
- protected Map<String, SimpleNode> cache = null;
+ protected Map<String, JexlNode> cache = null;
/**
* An empty/static/non-mutable JexlContext used instead of null context.
*/
@@ -139,18 +144,14 @@
}
/**
- * Creates a JEXL engine using the provided {@link Uberspect}, (@link Arithmetic) and logger.
+ * Creates a JEXL engine using the provided {@link Uberspect}, (@link JexlArithmetic),
+ * a function map and logger.
* @param anUberspect to allow different introspection behaviour
* @param anArithmetic to allow different arithmetic behaviour
- * @param theFunctions an optional map of functions (@see setFunctions)
+ * @param theFunctions an optional map of functions (@link setFunctions)
* @param log the logger for various messages
*/
- public JexlEngine(Uberspect anUberspect, Arithmetic anArithmetic, Map<String, Object> theFunctions, Log log) {
- this.uberspect = anUberspect == null ? Introspector.getUberspect() : anUberspect;
- this.arithmetic = anArithmetic == null ? new JexlArithmetic(true) : anArithmetic;
- if (theFunctions != null) {
- this.functions = theFunctions;
- }
+ public JexlEngine(Uberspect anUberspect, JexlArithmetic anArithmetic, Map<String, Object> theFunctions, Log log) {
if (log == null) {
log = LogFactory.getLog(JexlEngine.class);
}
@@ -158,6 +159,27 @@
throw new NullPointerException("logger can not be null");
}
this.logger = log;
+ this.uberspect = anUberspect == null ? Introspector.getUberspect(log) : anUberspect;
+ this.arithmetic = anArithmetic == null ? new JexlArithmetic(true) : anArithmetic;
+ if (theFunctions != null) {
+ this.functions = theFunctions;
+ }
+ }
+
+ /**
+ * Sets whether this engine reports debugging information when error occurs.
+ * @param flag true implies debug is on, false implies debug is off.
+ */
+ public void setDebug(boolean flag) {
+ this.debug = flag;
+ }
+
+ /**
+ * Checks whether this engine is in debug mode.
+ * @return true if debug is on, false otherwise
+ */
+ public boolean isDebug() {
+ return this.debug;
}
/**
@@ -258,14 +280,30 @@
* expression or a reference.
*/
public Expression createExpression(String expression)
+ throws ParseException {
+ return createExpression(expression, null);
+ }
+
+ /**
+ * Creates an Expression from a String containing valid
+ * JEXL syntax. This method parses the expression which
+ * must contain either a reference or an expression.
+ * @param expression A String containing valid JEXL syntax
+ * @return An Expression object which can be evaluated with a JexlContext
+ * @param info An info structure to carry debugging information if needed
+ * @throws ParseException An exception can be thrown if there is a problem
+ * parsing this expression, or if the expression is neither an
+ * expression or a reference.
+ */
+ public Expression createExpression(String expression, Info info)
throws ParseException {
// Parse the expression
- SimpleNode tree = parse(expression);
+ JexlNode tree = parse(expression, info);
if (tree.jjtGetNumChildren() > 1) {
logger.warn("The JEXL Expression created will be a reference"
+ " to the first expression from the supplied script: \"" + expression + "\" ");
}
- SimpleNode node = (SimpleNode) tree.jjtGetChild(0);
+ JexlNode node = tree.jjtGetChild(0);
return new ExpressionImpl(this, expression, node);
}
@@ -278,10 +316,23 @@
* @throws ParseException if there is a problem parsing the script.
*/
public Script createScript(String scriptText) throws ParseException {
+ return createScript(scriptText, null);
+ }
+
+ /**
+ * Creates a Script from a String containing valid JEXL syntax.
+ * This method parses the script which validates the syntax.
+ *
+ * @param scriptText A String containing valid JEXL syntax
+ * @param info An info structure to carry debugging information if needed
+ * @return A {@link Script} which can be executed using a {@link JexlContext}.
+ * @throws ParseException if there is a problem parsing the script.
+ */
+ public Script createScript(String scriptText, Info info) throws ParseException {
if (scriptText == null) {
throw new NullPointerException("scriptText is null");
}
- SimpleNode script = parse(scriptText);
+ JexlNode script = parse(scriptText, info);
if (script instanceof ASTJexlScript) {
return new ScriptImpl(this, scriptText, (ASTJexlScript) script);
} else {
@@ -308,7 +359,11 @@
throw new IOException("Can't read scriptFile (" + scriptFile.getCanonicalPath() + ")");
}
BufferedReader reader = new BufferedReader(new FileReader(scriptFile));
- return createScript(readerToString(reader));
+ Info info = null;
+ if (debug) {
+ info = new Info(scriptFile.getName(), 0, 0);
+ }
+ return createScript(readerToString(reader), info);
}
@@ -331,7 +386,11 @@
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
- return createScript(readerToString(reader));
+ Info info = null;
+ if (debug) {
+ info = new Info(scriptUrl.toString(), 0, 0);
+ }
+ return createScript(readerToString(reader), info);
}
/**
@@ -375,8 +434,8 @@
}
expr = r0 + (expr.charAt(0) == '[' ? "" : ".") + expr + ";";
try {
- SimpleNode tree = parse(expr);
- SimpleNode node = (SimpleNode) tree.jjtGetChild(0).jjtGetChild(0);
+ JexlNode tree = parse(expr, null);
+ JexlNode node = tree.jjtGetChild(0).jjtGetChild(0);
Interpreter interpreter = createInterpreter(context);
// ensure 4 objects in register array
Object[] r = {r0, bean, r0, bean};
@@ -442,8 +501,8 @@
// synthetize expr
expr = r0 + (expr.charAt(0) == '[' ? "" : ".") + expr + "=" + r1 + ";";
try {
- SimpleNode tree = parse(expr);
- SimpleNode node = (SimpleNode) tree.jjtGetChild(0).jjtGetChild(0);
+ JexlNode tree = parse(expr, null);
+ JexlNode node = tree.jjtGetChild(0).jjtGetChild(0);
Interpreter interpreter = createInterpreter(context);
// set the registers
Object[] r = {r0, bean, r1, value};
@@ -481,10 +540,10 @@
* @param cacheSize the cache size, must be > 0
* @return a Map usable as a cache bounded to the given size
*/
- protected Map<String, SimpleNode> createCache(final int cacheSize) {
- return new java.util.LinkedHashMap<String, SimpleNode>(cacheSize, LOAD_FACTOR, true) {
+ protected Map<String, JexlNode> createCache(final int cacheSize) {
+ return new java.util.LinkedHashMap<String, JexlNode>(cacheSize, LOAD_FACTOR, true) {
@Override
- protected boolean removeEldestEntry(Map.Entry<String, SimpleNode> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<String, JexlNode> eldest) {
return size() > cacheSize;
}
};
@@ -493,12 +552,13 @@
/**
* Parses an expression.
* @param expression the expression to parse
+ * @param info debug information structure
* @return the parsed tree
* @throws ParseException if any error occured during parsing
*/
- protected SimpleNode parse(CharSequence expression) throws ParseException {
+ protected JexlNode parse(CharSequence expression, Info info) throws ParseException {
String expr = cleanExpression(expression);
- SimpleNode tree = null;
+ JexlNode tree = null;
synchronized (parser) {
logger.debug("Parsing expression: " + expression);
if (cache != null) {
@@ -509,7 +569,29 @@
}
try {
Reader reader = expr.endsWith(";") ? new StringReader(expr) : new StringReader(expr + ";");
- tree = parser.parse(reader);
+ // use first calling method of JexlEngine as debug info
+ if (info == null && debug) {
+ Throwable xinfo = new Throwable();
+ xinfo.fillInStackTrace();
+ StackTraceElement[] stack = xinfo.getStackTrace();
+ StackTraceElement se = null;
+ Class<?> clazz = getClass();
+ for(int s = 0; s < stack.length; ++s, se = null) {
+ se = stack[s];
+ if (!se.getClassName().equals(clazz.getName())) {
+ // go deeper if called from UnifiedJEXL
+ if (se.getClassName().equals(UnifiedJEXL.class.getName())) {
+ clazz = UnifiedJEXL.class;
+ } else {
+ break;
+ }
+ }
+ }
+ if (se != null) {
+ info = new Info(se.getClassName()+"."+se.getMethodName(), se.getLineNumber(), 0);
+ }
+ }
+ tree = parser.parse(reader, info);
if (cache != null) {
cache.put(expr, tree);
}
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlException.java Sat Aug 1 00:36:51 2009
@@ -16,14 +16,14 @@
*/
package org.apache.commons.jexl;
-import org.apache.commons.jexl.parser.Node;
+import org.apache.commons.jexl.parser.JexlNode;
/**
* Wraps any error that might occur during interpretation of a script or expression.
*/
public class JexlException extends RuntimeException {
/** The point of origin for this exception. */
- protected Node mark;
+ protected JexlNode mark;
/** A marker to use in NPEs stating a null operand error. */
public static final String NULL_OPERAND = "jexl.null";
/**
@@ -31,7 +31,7 @@
* @param node the node causing the error
* @param msg the error message
*/
- public JexlException(Node node, String msg) {
+ public JexlException(JexlNode node, String msg) {
super(msg);
mark = node;
}
@@ -41,7 +41,7 @@
* @param msg the error message
* @param cause the exception causing the error
*/
- public JexlException(Node node, String msg, Throwable cause) {
+ public JexlException(JexlNode node, String msg, Throwable cause) {
super(msg, cause);
mark = node;
}
@@ -70,7 +70,8 @@
/**
* Detailed info message about this error.
- * Format is "@[begin,end]: string \n msg" where:
+ * Format is "debug![begin,end]: string \n msg" where:
+ * - debug is the debugging information if it exists (@link JexlEngine.setDebug)
* - begin, end are character offsets in the string for the precise location of the error
* - string is the string representation of the offending expression
* - msg is the actual explanation message for this error
@@ -81,7 +82,8 @@
Debugger dbg = new Debugger();
StringBuilder msg = new StringBuilder();
if (dbg.debug(mark)) {
- msg.append("@[");
+ msg.append(mark.debugString());
+ msg.append("![");
msg.append(dbg.start());
msg.append(",");
msg.append(dbg.end());
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlHelper.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlHelper.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlHelper.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/JexlHelper.java Sat Aug 1 00:36:51 2009
@@ -31,11 +31,11 @@
*/
public class JexlHelper {
/** singleton instance. */
- protected static JexlHelper helper = new JexlHelper();
+ protected static final JexlHelper HELPER = new JexlHelper();
/** @return the single instance. */
protected static JexlHelper getInstance() {
- return helper;
+ return HELPER;
}
/**
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java Sat Aug 1 00:36:51 2009
@@ -19,9 +19,10 @@
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.ArrayList;
-import org.apache.commons.jexl.parser.SimpleNode;
+import org.apache.commons.jexl.parser.JexlNode;
import org.apache.commons.jexl.parser.ParseException;
import org.apache.commons.jexl.parser.StringParser;
+import org.apache.commons.jexl.util.introspection.Info;
/**
* An evaluator similar to the unified EL evaluator used in JSP/JSF based on JEXL.
@@ -213,7 +214,7 @@
/**
* The sole type of (runtime) exception the UnifiedJEXL can throw.
*/
- public class Exception extends RuntimeException {
+ public static class Exception extends RuntimeException {
/**
* Creates a UnifiedJEXL.Exception.
* @param msg the exception message
@@ -228,7 +229,7 @@
* The abstract base class for all expressions, immediate '${...}' and deferred '#{...}'.
*/
public abstract class Expression {
- /** The source of this expression (see {@link Expression#prepare}) */
+ /** The source of this expression (see {@link Expression#prepare}). */
protected final Expression source;
/**
* Creates an expression.
@@ -238,6 +239,11 @@
this.source = src != null ? src : this;
}
+ /**
+ * Formats this expression, adding its source string representation in
+ * comments if available: 'expression /*= source *\/'' .
+ * @return the formatted expression string
+ */
@Override
public String toString() {
StringBuilder strb = new StringBuilder();
@@ -343,7 +349,7 @@
* Intreprets a sub-expression.
* @param interpreter a JEXL interpreter
* @return the result of interpretation
- * @throws ParseException (only for nested & composite)
+ * @throws org.apache.commons.jexl.parser.ParseException (only for nested & composite)
*/
abstract Object evaluate(Interpreter interpreter) throws ParseException;
}
@@ -373,6 +379,7 @@
this.value = val;
}
+ /** {@inheritDoc} */
@Override
public String asString() {
StringBuilder strb = new StringBuilder();
@@ -382,11 +389,13 @@
return strb.toString();
}
+ /** {@inheritDoc} */
@Override
ExpressionType getType() {
return ExpressionType.CONSTANT;
}
+ /** {@inheritDoc} */
@Override
void asString(StringBuilder strb) {
String str = value.toString();
@@ -403,21 +412,25 @@
}
}
+ /** {@inheritDoc} */
@Override
public Expression prepare(JexlContext context) {
return this;
}
+ /** {@inheritDoc} */
@Override
Expression prepare(Interpreter interpreter) throws ParseException {
return this;
}
+ /** {@inheritDoc} */
@Override
public Object evaluate(JexlContext context) {
return value;
}
+ /** {@inheritDoc} */
@Override
Object evaluate(Interpreter interpreter) throws ParseException {
return value;
@@ -430,19 +443,20 @@
/** The JEXL string for this expression. */
protected final CharSequence expr;
/** The JEXL node for this expression. */
- protected final SimpleNode node;
+ protected final JexlNode node;
/**
* Creates a JEXL interpretable expression.
- * @param expr the expression as a string
- * @param node the expression as an AST
- * @param source the source expression if any
+ * @param theExpr the expression as a string
+ * @param theNode the expression as an AST
+ * @param theSource the source expression if any
*/
- protected JexlBasedExpression(CharSequence expr, SimpleNode node, Expression source) {
- super(source);
- this.expr = expr;
- this.node = node;
+ protected JexlBasedExpression(CharSequence theExpr, JexlNode theNode, Expression theSource) {
+ super(theSource);
+ this.expr = theExpr;
+ this.node = theNode;
}
+ /** {@inheritDoc} */
@Override
public String toString() {
StringBuilder strb = new StringBuilder(expr.length() + 3);
@@ -460,6 +474,7 @@
return strb.toString();
}
+ /** {@inheritDoc} */
@Override
public void asString(StringBuilder strb) {
strb.append(isImmediate() ? '$' : '#');
@@ -468,21 +483,25 @@
strb.append("}");
}
+ /** {@inheritDoc} */
@Override
public Expression prepare(JexlContext context) {
return this;
}
+ /** {@inheritDoc} */
@Override
Expression prepare(Interpreter interpreter) throws ParseException {
return this;
}
+ /** {@inheritDoc} */
@Override
public Object evaluate(JexlContext context) {
return UnifiedJEXL.this.evaluate(context, this);
}
+ /** {@inheritDoc} */
@Override
Object evaluate(Interpreter interpreter) throws ParseException {
return interpreter.interpret(node);
@@ -498,15 +517,17 @@
* @param node the expression as an AST
* @param source the source expression if any
*/
- ImmediateExpression(CharSequence expr, SimpleNode node, Expression source) {
+ ImmediateExpression(CharSequence expr, JexlNode node, Expression source) {
super(expr, node, source);
}
+ /** {@inheritDoc} */
@Override
ExpressionType getType() {
return ExpressionType.IMMEDIATE;
}
+ /** {@inheritDoc} */
@Override
public boolean isImmediate() {
return true;
@@ -521,15 +542,17 @@
* @param node the expression as an AST
* @param source the source expression if any
*/
- DeferredExpression(CharSequence expr, SimpleNode node, Expression source) {
+ DeferredExpression(CharSequence expr, JexlNode node, Expression source) {
super(expr, node, source);
}
+ /** {@inheritDoc} */
@Override
ExpressionType getType() {
return ExpressionType.DEFERRED;
}
+ /** {@inheritDoc} */
@Override
public boolean isImmediate() {
return false;
@@ -548,35 +571,40 @@
* @param node the expression as an AST
* @param source the source expression if any
*/
- NestedExpression(CharSequence expr, SimpleNode node, Expression source) {
+ NestedExpression(CharSequence expr, JexlNode node, Expression source) {
super(expr, node, source);
if (this.source != this) {
throw new IllegalArgumentException("Nested expression can not have a source");
}
}
+ /** {@inheritDoc} */
@Override
ExpressionType getType() {
return ExpressionType.NESTED;
}
+ /** {@inheritDoc} */
@Override
public String toString() {
return expr.toString();
}
+ /** {@inheritDoc} */
@Override
public Expression prepare(JexlContext context) {
return UnifiedJEXL.this.prepare(context, this);
}
+ /** {@inheritDoc} */
@Override
public Expression prepare(Interpreter interpreter) throws ParseException {
String value = interpreter.interpret(node).toString();
- SimpleNode dnode = toNode(value);
+ JexlNode dnode = toNode(value, jexl.isDebug()? node.getInfo() : null);
return new DeferredExpression(value, dnode, this);
}
+ /** {@inheritDoc} */
@Override
public Object evaluate(Interpreter interpreter) throws ParseException {
return prepare(interpreter).evaluate(interpreter);
@@ -592,7 +620,7 @@
private final Expression[] exprs;
/**
* Creates a composite expression.
- * @param counter counters of expression per type
+ * @param counters counters of expression per type
* @param list the sub-expressions
* @param src the source for this expresion if any
*/
@@ -603,17 +631,20 @@
| (counters[ExpressionType.IMMEDIATE.index] > 0 ? 1 : 0);
}
+ /** {@inheritDoc} */
@Override
ExpressionType getType() {
return ExpressionType.COMPOSITE;
}
+ /** {@inheritDoc} */
@Override
public boolean isImmediate() {
// immediate if no deferred
return (meta & 2) == 0;
}
+ /** {@inheritDoc} */
@Override
void asString(StringBuilder strb) {
for (Expression e : exprs) {
@@ -621,11 +652,13 @@
}
}
+ /** {@inheritDoc} */
@Override
public Expression prepare(JexlContext context) {
return UnifiedJEXL.this.prepare(context, this);
}
+ /** {@inheritDoc} */
@Override
Expression prepare(Interpreter interpreter) throws ParseException {
// if this composite is not its own source, it is already prepared
@@ -658,11 +691,13 @@
return ready;
}
+ /** {@inheritDoc} */
@Override
public Object evaluate(JexlContext context) {
return UnifiedJEXL.this.evaluate(context, this);
}
+ /** {@inheritDoc} */
@Override
Object evaluate(Interpreter interpreter) throws ParseException {
final int size = exprs.length;
@@ -783,8 +818,18 @@
* @param expression the expression to parse
* @return the AST
*/
- private SimpleNode toNode(CharSequence expression) throws ParseException {
- return (SimpleNode) jexl.parse(expression).jjtGetChild(0);
+ private JexlNode toNode(CharSequence expression) throws ParseException {
+ return jexl.parse(expression, null).jjtGetChild(0);
+ }
+
+ /**
+ * Use the JEXL parser to create the AST for an expression.
+ * @param expression the expression to parse
+ * @param info debug information
+ * @return the AST
+ */
+ private JexlNode toNode(CharSequence expression, Info info) throws ParseException {
+ return jexl.parse(expression, info).jjtGetChild(0);
}
/**
@@ -832,7 +877,7 @@
* Parses a unified expression.
* @param expr the string expression
* @return the expression instance
- * @throws Exception
+ * @throws org.apache.commons.jexl.parser.ParseException if an error occur during parsing
*/
private Expression parseExpression(String expr) throws ParseException {
final int size = expr.length();
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/context/HashMapContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/context/HashMapContext.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/context/HashMapContext.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/context/HashMapContext.java Sat Aug 1 00:36:51 2009
@@ -29,13 +29,13 @@
* @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
* @version $Id$
*/
-public class HashMapContext extends HashMap implements JexlContext {
+public class HashMapContext extends HashMap<String,Object> implements JexlContext {
/** serialization version id jdk13 generated. */
static final long serialVersionUID = 5715964743204418854L;
/**
* {@inheritDoc}
*/
- public void setVars(Map vars) {
+ public void setVars(Map<String,Object> vars) {
clear();
putAll(vars);
}
@@ -43,7 +43,7 @@
/**
* {@inheritDoc}
*/
- public Map getVars() {
+ public Map<String,Object> getVars() {
return this;
}
}
Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java?rev=799779&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java (added)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java Sat Aug 1 00:36:51 2009
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl.parser;
+
+import org.apache.commons.jexl.util.introspection.Info;
+import org.apache.commons.jexl.util.introspection.DebugInfo;
+
+/**
+ * Base class for parser nodes - holds an 'image' of the token for later use.
+ *
+ * @since 2.0
+ */
+public abstract class JexlNode extends SimpleNode implements DebugInfo {
+ /** token value. */
+ public String image;
+
+ public JexlNode(int id) {
+ super(id);
+ }
+
+ public JexlNode(Parser p, int id) {
+ super(p, id);
+ }
+
+ public Info getInfo() {
+ JexlNode node = this;
+ while (node != null) {
+ if (node.value instanceof Info) {
+ return (Info) node.value;
+ }
+ node = node.jjtGetParent();
+ }
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public String debugString() {
+ Info info = getInfo();
+ return info != null? info.debugString() : "";
+ }
+}
Propchange: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/JexlNode.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt Sat Aug 1 00:36:51 2009
@@ -29,7 +29,7 @@
MULTI=true;
STATIC=false;
VISITOR=true;
- NODE_EXTENDS="JEXLNode";
+ NODE_CLASS="JexlNode";
NODE_USES_PARSER=true;
UNICODE_INPUT=true;
}
@@ -39,22 +39,24 @@
package org.apache.commons.jexl.parser;
import java.io.Reader;
-import java.io.ByteArrayInputStream;
+import org.apache.commons.jexl.util.introspection.Info;
public class Parser extends StringParser
{
+ /** Base debug information. */
+ protected Info debug = null;
- public SimpleNode parse(Reader reader)
+ public JexlNode parse(Reader reader, Info info)
throws ParseException
{
ReInit(reader);
-
/*
* lets do the 'Unique Init' in here to be
* safe - it's a pain to remember
*/
- SimpleNode tree = JexlScript();
+ JexlNode tree = JexlScript();
+ tree.value = info;
return tree;
}
}
@@ -85,7 +87,7 @@
* Program structuring syntax follows.
*/
-SimpleNode JexlScript() :
+JexlNode JexlScript() :
{
String name;
}
@@ -442,6 +444,12 @@
LOOKAHEAD(Identifier() "(") Method()
}
+void Constructor() # ConstructorNode() : {}
+{
+
+ "new" "("[ Parameter() ( "," Parameter() )* ] ")"
+}
+
void SizeMethod() : {}
{
"size" "(" ")"
@@ -449,7 +457,8 @@
void Reference() : {}
{
- (LOOKAHEAD(Identifier() "[" ( Expression() | IntegerLiteral() | Reference()) "]") ArrayAccess() |
+ (LOOKAHEAD("new") Constructor() |
+ LOOKAHEAD(Identifier() "[" ( Expression() | IntegerLiteral() | Reference()) "]") ArrayAccess() |
LOOKAHEAD(Identifier() ":" Identifier() "(") Function() |
LOOKAHEAD(Identifier() "(") Method() |
Identifier() |
Added: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java?rev=799779&view=auto
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java (added)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java Sat Aug 1 00:36:51 2009
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.jexl.parser;
+
+/**
+ * A class originally generated by JJTree:
+ * /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= *\/
+ * Worksaround issue https://javacc.dev.java.net/issues/show_bug.cgi?id=227
+ * As soon as this issue if fixed and the maven plugin uses the correct version of Javacc, this
+ * class can go away.
+ *
+ * The technical goal is to ensure every reference made in the parser was to a JexlNode; unfortunately,
+ * as in javacc 4.1, it still uses a SimpleNode reference in the generated ParserVisitor.
+ * Besides, there is no need to keep the parser around in the node.
+ *
+ * The functional goal is to a allow a <em>volatile</em> value in the node
+ * so it can serve as a last evaluation cache even in multi-threaded executions.
+ */
+public class SimpleNode implements Node {
+ protected JexlNode parent;
+ protected JexlNode[] children;
+ protected int id;
+ /** volatile value so it can be used as a last evaluation cache. */
+ protected volatile Object value;
+
+ public SimpleNode(int i) {
+ id = i;
+ }
+
+ public SimpleNode(Parser p, int i) {
+ this(i);
+ }
+
+ public void jjtOpen() {
+ }
+
+ public void jjtClose() {
+ }
+
+ public void jjtSetParent(Node n) {
+ parent = (JexlNode) n;
+ }
+
+ public JexlNode jjtGetParent() {
+ return parent;
+ }
+
+ public void jjtAddChild(Node n, int i) {
+ if (children == null) {
+ children = new JexlNode[i + 1];
+ } else if (i >= children.length) {
+ JexlNode c[] = new JexlNode[i + 1];
+ System.arraycopy(children, 0, c, 0, children.length);
+ children = c;
+ }
+ children[i] = (JexlNode) n;
+ }
+
+ public JexlNode jjtGetChild(int i) {
+ return children[i];
+ }
+
+ public int jjtGetNumChildren() {
+ return (children == null) ? 0 : children.length;
+ }
+
+ public void jjtSetValue(Object value) {
+ this.value = value;
+ }
+
+ public Object jjtGetValue() {
+ return value;
+ }
+
+ /** Accept the visitor. **/
+ public Object jjtAccept(ParserVisitor visitor, Object data) {
+ return visitor.visit(this, data);
+ }
+
+ /** Accept the visitor. **/
+ public Object childrenAccept(ParserVisitor visitor, Object data) {
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ children[i].jjtAccept(visitor, data);
+ }
+ }
+ return data;
+ }
+
+ /* You can override these two methods in subclasses of SimpleNode to
+ customize the way the JexlNode appears when the tree is dumped. If
+ your output uses more than one line you should override
+ toString(String), otherwise overriding toString() is probably all
+ you need to do. */
+
+ public String toString() { return ParserTreeConstants.jjtNodeName[id]; }
+ public String toString(String prefix) { return prefix + toString(); }
+
+ /* Override this method if you want to customize how the JexlNode dumps
+ out its children. */
+
+ public void dump(String prefix) {
+ System.out.println(toString(prefix));
+ if (children != null) {
+ for (int i = 0; i < children.length; ++i) {
+ SimpleNode n = (SimpleNode)children[i];
+ if (n != null) {
+ n.dump(prefix + " ");
+ }
+ }
+ }
+ }
+}
+
+/* JavaCC - OriginalChecksum=7dff880883d088a37c1e3197e4b455a0 (do not edit this line) */
Propchange: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/SimpleNode.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java?rev=799779&r1=799778&r2=799779&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/VisitorAdapter.java Sat Aug 1 00:36:51 2009
@@ -74,6 +74,12 @@
}
/** {@inheritDoc} */
+ public Object visit(ASTConstructorNode node, Object data) {
+ node.dump(" ");
+ return node.childrenAccept(this, data);
+ }
+
+ /** {@inheritDoc} */
public Object visit(ASTBlock node, Object data) {
node.dump(" ");
return node.childrenAccept(this, data);
@@ -301,7 +307,19 @@
return node.childrenAccept(this, data);
}
- /** {@inheritDoc} */
+ /** Sink, should not be used.
+ * @param node the node
+ * @param data some data
+ */
+ public Object visit(JexlNode node, Object data) {
+ node.dump(" ");
+ return node.childrenAccept(this, data);
+ }
+
+ /** Unused, required for generated interface compliance.
+ * @param node the node
+ * @param data some data
+ */
public Object visit(SimpleNode node, Object data) {
node.dump(" ");
return node.childrenAccept(this, data);