Author: henrib
Date: Tue Mar 13 15:13:08 2012
New Revision: 1300178
URL: http://svn.apache.org/viewvc?rev=1300178&view=rev
Log:
JEXL-127:
Reworked grammar to properly treat parenthesized expressions and calling chains;
Added 'anonymous/closure' style syntax to functions '(x, y)-> { ... }';
Made additive operations separate nodes / classes;
Renamed occurences of 'register' to symbol (Scope/Frame);
Code shuffling in Interpreter to have all complex methods located together
(assign, call, de-reference...);
Moved JexlEvalContext to test package (only use is testing);
Renamed 'UnifiedJEXLTest' to 'JXLTTest' to properly reflect new naming;
Added / completed a few tests;
Various checkstyle / Javadoc
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifierAccess.java
- copied, changed from r1243213,
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JXLTTest.java
- copied, changed from r1243213,
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/UnifiedJEXLTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JexlEvalContext.java
- copied, changed from r1243213,
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEvalContext.java
Removed:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlEvalContext.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/UnifiedJEXLTest.java
Modified:
commons/proper/jexl/trunk/pom.xml
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/Engine.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/introspection/Permissions.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTReferenceExpression.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayAccessTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/AssignTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/CacheTest.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/IfTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/JexlTest.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/MethodTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ScriptCallableTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/VarTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/Util.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/junit/Asserter.java
Modified: commons/proper/jexl/trunk/pom.xml
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/pom.xml?rev=1300178&r1=1300177&r2=1300178&view=diff
==============================================================================
--- commons/proper/jexl/trunk/pom.xml (original)
+++ commons/proper/jexl/trunk/pom.xml Tue Mar 13 15:13:08 2012
@@ -19,7 +19,7 @@
<parent>
<groupId>org.apache.commons</groupId>
<artifactId>commons-parent</artifactId>
- <version>23</version>
+ <version>24</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.commons</groupId>
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=1300178&r1=1300177&r2=1300178&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
Tue Mar 13 15:13:08 2012
@@ -16,12 +16,12 @@
*/
package org.apache.commons.jexl3.internal;
-import java.util.regex.Pattern;
+
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.jexl3.JexlScript;
-import org.apache.commons.jexl3.parser.ASTAdditiveNode;
-import org.apache.commons.jexl3.parser.ASTAdditiveOperator;
+import org.apache.commons.jexl3.parser.ASTAddNode;
import org.apache.commons.jexl3.parser.ASTAndNode;
+import org.apache.commons.jexl3.parser.ASTArguments;
import org.apache.commons.jexl3.parser.ASTArrayAccess;
import org.apache.commons.jexl3.parser.ASTArrayLiteral;
import org.apache.commons.jexl3.parser.ASTAssignment;
@@ -35,12 +35,14 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.ASTEQNode;
import org.apache.commons.jexl3.parser.ASTERNode;
import org.apache.commons.jexl3.parser.ASTEmptyFunction;
+import org.apache.commons.jexl3.parser.ASTEmptyMethod;
import org.apache.commons.jexl3.parser.ASTFalseNode;
import org.apache.commons.jexl3.parser.ASTForeachStatement;
import org.apache.commons.jexl3.parser.ASTFunctionNode;
import org.apache.commons.jexl3.parser.ASTGENode;
import org.apache.commons.jexl3.parser.ASTGTNode;
import org.apache.commons.jexl3.parser.ASTIdentifier;
+import org.apache.commons.jexl3.parser.ASTIdentifierAccess;
import org.apache.commons.jexl3.parser.ASTIfStatement;
import org.apache.commons.jexl3.parser.ASTJexlLambda;
import org.apache.commons.jexl3.parser.ASTJexlScript;
@@ -63,23 +65,23 @@ import org.apache.commons.jexl3.parser.A
import org.apache.commons.jexl3.parser.ASTSizeFunction;
import org.apache.commons.jexl3.parser.ASTSizeMethod;
import org.apache.commons.jexl3.parser.ASTStringLiteral;
+import org.apache.commons.jexl3.parser.ASTSubNode;
import org.apache.commons.jexl3.parser.ASTTernaryNode;
import org.apache.commons.jexl3.parser.ASTTrueNode;
import org.apache.commons.jexl3.parser.ASTUnaryMinusNode;
import org.apache.commons.jexl3.parser.ASTVar;
import org.apache.commons.jexl3.parser.ASTWhileStatement;
import org.apache.commons.jexl3.parser.JexlNode;
-
import org.apache.commons.jexl3.parser.ParserVisitor;
+import java.util.regex.Pattern;
+
/**
* Helps pinpoint the cause of problems in expressions that fail during
evaluation.
* <p>
- * It rebuilds an expression string from the tree and the start/end offsets of
the cause
- * in that string.
+ * It rebuilds an expression string from the tree and the start/end offsets of
the cause in that string.
+ * This implies that exceptions during evaluation do allways carry the node
that's causing the error.
* </p>
- * This implies that exceptions during evaluation do allways carry the node
that's causing
- * the error.
* @since 2.0
*/
public final class Debugger extends ParserVisitor {
@@ -101,7 +103,7 @@ public final class Debugger extends Pars
start = 0;
end = 0;
}
-
+
/**
* Position the debugger on the root of an expression.
* @param jscript the expression
@@ -188,8 +190,7 @@ public final class Debugger extends Pars
}
/**
- * Checks if a child node is the cause to debug & adds its
representation
- * to the rebuilt expression.
+ * Checks if a child node is the cause to debug & adds its
representation to the rebuilt expression.
* @param node the child node
* @param data visitor pattern argument
* @return visitor pattern value
@@ -225,8 +226,7 @@ public final class Debugger extends Pars
}
/**
- * Checks if a terminal node is the the cause to debug & adds its
- * representation to the rebuilt expression.
+ * Checks if a terminal node is the the cause to debug & adds its
representation to the rebuilt expression.
* @param node the child node
* @param image the child node token image (may be null)
* @param data visitor pattern argument
@@ -248,8 +248,8 @@ public final class Debugger extends Pars
}
/**
- * Checks if the children of a node using infix notation is the cause to
debug,
- * adds their representation to the rebuilt expression.
+ * Checks if the children of a node using infix notation is the cause to
debug, adds their representation to the
+ * rebuilt expression.
* @param node the child node
* @param infix the child node token
* @param paren whether the child should be parenthesized
@@ -274,8 +274,8 @@ public final class Debugger extends Pars
}
/**
- * Checks if the child of a node using prefix notation is the cause to
debug,
- * adds their representation to the rebuilt expression.
+ * Checks if the child of a node using prefix notation is the cause to
debug, adds their representation to the
+ * rebuilt expression.
* @param node the node
* @param prefix the node token
* @param data visitor pattern argument
@@ -295,17 +295,34 @@ public final class Debugger extends Pars
}
@Override
- protected Object visit(ASTAdditiveNode node, Object data) {
+ protected Object visit(ASTAddNode node, Object data) {
+ return additiveNode(node, " + ", data);
+ }
+
+ @Override
+ protected Object visit(ASTSubNode node, Object data) {
+ return additiveNode(node, " - ", data);
+ }
+
+ /**
+ * Rebuilds an additive expression.
+ * @param node the node
+ * @param op the operator
+ * @param data visitor pattern argument
+ * @return visitor pattern value
+ */
+ private Object additiveNode(JexlNode node, String op, Object data) {
// need parenthesis if not in operator precedence order
boolean paren = node.jjtGetParent() instanceof ASTMulNode
|| node.jjtGetParent() instanceof ASTDivNode
|| node.jjtGetParent() instanceof ASTModNode;
- int num = node.jjtGetNumChildren(); //child.jjtGetNumChildren() > 1;
+ int num = node.jjtGetNumChildren();
if (paren) {
builder.append("(");
}
accept(node.jjtGetChild(0), data);
for (int i = 1; i < num; ++i) {
+ builder.append(op);
accept(node.jjtGetChild(i), data);
}
if (paren) {
@@ -315,23 +332,14 @@ public final class Debugger extends Pars
}
@Override
- protected Object visit(ASTAdditiveOperator node, Object data) {
- builder.append(' ');
- builder.append(node.image);
- builder.append(' ');
- return data;
- }
-
- @Override
protected Object visit(ASTAndNode node, Object data) {
return infixChildren(node, " && ", false, data);
}
@Override
protected Object visit(ASTArrayAccess node, Object data) {
- accept(node.jjtGetChild(0), data);
int num = node.jjtGetNumChildren();
- for (int i = 1; i < num; ++i) {
+ for (int i = 0; i < num; ++i) {
builder.append("[");
accept(node.jjtGetChild(i), data);
builder.append("]");
@@ -400,9 +408,15 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTEmptyFunction node, Object data) {
- builder.append("empty(");
+ builder.append("empty ");
accept(node.jjtGetChild(0), data);
- builder.append(")");
+ return data;
+ }
+
+ @Override
+ protected Object visit(ASTEmptyMethod node, Object data) {
+ accept(node.jjtGetChild(0), data);
+ check(node, ".empty()", data);
return data;
}
@@ -449,7 +463,7 @@ public final class Debugger extends Pars
private static final Pattern QUOTED_IDENTIFIER =
Pattern.compile("['\"\\s\\\\]");
/** Checks number used as identifiers. */
private static final Pattern NUMBER_IDENTIFIER = Pattern.compile("^\\d*$");
-
+
@Override
protected Object visit(ASTIdentifier node, Object data) {
String image = node.image;
@@ -461,6 +475,18 @@ public final class Debugger extends Pars
}
@Override
+ protected Object visit(ASTIdentifierAccess node, Object data) {
+ builder.append(".");
+ String image = node.image;
+ if (QUOTED_IDENTIFIER.matcher(image).find() ||
NUMBER_IDENTIFIER.matcher(image).find()) {
+ // quote it
+ image = "'" + node.image.replace("'", "\\'") + "'";
+ }
+ builder.append(image);
+ return data;
+ }
+
+ @Override
protected Object visit(ASTIfStatement node, Object data) {
builder.append("if (");
accept(node.jjtGetChild(0), data);
@@ -487,7 +513,13 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTJexlScript node, Object data) {
if (node instanceof ASTJexlLambda) {
- builder.append("function(");
+ JexlNode parent = node.jjtGetParent();
+ // use lambda syntax if not assigned
+ boolean named = parent instanceof ASTAssignment;
+ if (named) {
+ builder.append("function");
+ }
+ builder.append('(');
String[] params = node.getParameters();
if (params != null && params.length > 0) {
builder.append(params[0]);
@@ -496,7 +528,12 @@ public final class Debugger extends Pars
builder.append(params[p]);
}
}
- builder.append(") ");
+ builder.append(')');
+ if (named) {
+ builder.append(' ');
+ } else {
+ builder.append("->");
+ }
}
int num = node.jjtGetNumChildren();
for (int i = 0; i < num; ++i) {
@@ -558,30 +595,38 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTFunctionNode node, Object data) {
int num = node.jjtGetNumChildren();
- accept(node.jjtGetChild(0), data);
- builder.append(":");
- accept(node.jjtGetChild(1), data);
- builder.append("(");
- for (int i = 2; i < num; ++i) {
- if (i > 2) {
- builder.append(", ");
- }
- accept(node.jjtGetChild(i), data);
+ if (num == 3) {
+ accept(node.jjtGetChild(0), data);
+ builder.append(":");
+ accept(node.jjtGetChild(1), data);
+ accept(node.jjtGetChild(2), data);
+ } else {
+ accept(node.jjtGetChild(0), data);
+ accept(node.jjtGetChild(1), data);
}
- builder.append(")");
return data;
}
@Override
protected Object visit(ASTMethodNode node, Object data) {
int num = node.jjtGetNumChildren();
- accept(node.jjtGetChild(0), data);
+ if (num == 2) {
+ accept(node.jjtGetChild(0), data);
+ accept(node.jjtGetChild(1), data);
+ }
+ return data;
+ }
+
+ @Override
+ protected Object visit(ASTArguments node, Object data) {
+ int num = node.jjtGetNumChildren();
builder.append("(");
- for (int i = 1; i < num; ++i) {
- if (i > 1) {
+ if (num > 0) {
+ accept(node.jjtGetChild(0), data);
+ for (int i = 1; i < num; ++i) {
builder.append(", ");
+ accept(node.jjtGetChild(i), data);
}
- accept(node.jjtGetChild(i), data);
}
builder.append(")");
return data;
@@ -630,9 +675,7 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTReference node, Object data) {
int num = node.jjtGetNumChildren();
- accept(node.jjtGetChild(0), data);
- for (int i = 1; i < num; ++i) {
- builder.append(".");
+ for (int i = 0; i < num; ++i) {
accept(node.jjtGetChild(i), data);
}
return data;
@@ -662,15 +705,15 @@ public final class Debugger extends Pars
@Override
protected Object visit(ASTSizeFunction node, Object data) {
- builder.append("size(");
+ builder.append("size ");
accept(node.jjtGetChild(0), data);
- builder.append(")");
return data;
}
@Override
protected Object visit(ASTSizeMethod node, Object data) {
- check(node, "size()", data);
+ accept(node.jjtGetChild(0), data);
+ check(node, ".size()", data);
return data;
}
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
URL:
http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java?rev=1300178&r1=1300177&r2=1300178&view=diff
==============================================================================
---
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
(original)
+++
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
Tue Mar 13 15:13:08 2012
@@ -24,16 +24,17 @@ import org.apache.commons.jexl3.JexlExce
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.jexl3.JexlInfo;
import org.apache.commons.jexl3.JexlScript;
-
import org.apache.commons.jexl3.internal.introspection.SandboxUberspect;
import org.apache.commons.jexl3.internal.introspection.Uberspect;
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlSandbox;
import org.apache.commons.jexl3.introspection.JexlUberspect;
-
import org.apache.commons.jexl3.parser.ASTArrayAccess;
+import org.apache.commons.jexl3.parser.ASTFunctionNode;
import org.apache.commons.jexl3.parser.ASTIdentifier;
+import org.apache.commons.jexl3.parser.ASTIdentifierAccess;
import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.ASTMethodNode;
import org.apache.commons.jexl3.parser.ASTReference;
import org.apache.commons.jexl3.parser.JexlNode;
import org.apache.commons.jexl3.parser.ParseException;
@@ -60,7 +61,6 @@ import java.util.Map.Entry;
import java.util.Set;
import java.lang.ref.SoftReference;
-
import java.net.URL;
import java.net.URLConnection;
@@ -88,6 +88,15 @@ public class Engine extends JexlEngine {
throw new UnsupportedOperationException("Not supported in void
context.");
}
};
+ /**
+ * An empty/static/non-mutable JexlNamesapce used instead of null
namespace.
+ */
+ public static final JexlContext.NamespaceResolver EMPTY_NS = new
JexlContext.NamespaceResolver() {
+ @Override
+ public Object resolveNamespace(String name) {
+ return null;
+ }
+ };
/**
* Gets the default instance of Uberspect.
@@ -127,8 +136,8 @@ public class Engine extends JexlEngine {
*/
protected final boolean strict;
/**
- * Whether expressions evaluated by this engine will throw exceptions
(false) or
- * return null (true) on errors. Default is false.
+ * Whether expressions evaluated by this engine will throw exceptions
(false) or return null (true) on errors.
+ * Default is false.
*/
protected final boolean silent;
/**
@@ -136,7 +145,7 @@ public class Engine extends JexlEngine {
*/
protected final boolean debug;
/**
- * The map of 'prefix:function' to object implementing the namespaces.
+ * The map of 'prefix:function' to object implementing the namespaces.
*/
protected final Map<String, Object> functions;
/**
@@ -585,28 +594,41 @@ public class Engine extends JexlEngine {
* @param ref the current variable being filled
*/
protected void getVariables(JexlNode node, Set<List<String>> refs,
List<String> ref) {
- boolean array = node instanceof ASTArrayAccess;
- boolean reference = node instanceof ASTReference;
- int num = node.jjtGetNumChildren();
- if (array || reference) {
- List<String> var = ref != null ? ref : new ArrayList<String>();
- boolean varf = true;
- for (int i = 0; i < num; ++i) {
- JexlNode child = node.jjtGetChild(i);
- if (array) {
- if (child instanceof ASTReference &&
child.jjtGetNumChildren() == 1) {
- JexlNode desc = child.jjtGetChild(0);
- if (varf && desc.isConstant()) {
- String image = desc.image;
+ if (node instanceof ASTIdentifier) {
+ JexlNode parent = node.jjtGetParent();
+ if (parent instanceof ASTMethodNode || parent instanceof
ASTFunctionNode) {
+ // skip identifiers for methods and functions
+ return;
+ }
+ ASTIdentifier identifier = (ASTIdentifier) node;
+ if (identifier.getSymbol() < 0) {
+ if (ref == null) {
+ ref = new ArrayList<String>();
+ refs.add(ref);
+ }
+ ref.add(identifier.image);
+ }
+ } else {
+ int num = node.jjtGetNumChildren();
+ boolean array = node instanceof ASTArrayAccess;
+ boolean reference = node instanceof ASTReference;
+ if (array || reference) {
+ List<String> var = ref != null ? ref : new ArrayList<String>();
+ boolean varf = true;
+ for (int i = 0; i < num; ++i) {
+ JexlNode child = node.jjtGetChild(i);
+ if (array) {
+ if (varf && child.isConstant()) {
+ String image = child.image;
if (image == null) {
- var.add(new Debugger().data(desc));
+ var.add(new Debugger().data(child));
} else {
var.add(image);
}
- } else if (desc instanceof ASTIdentifier) {
- if (((ASTIdentifier) desc).getRegister() < 0) {
+ } else if (child instanceof ASTIdentifier) {
+ if (((ASTIdentifier) child).getSymbol() < 0) {
List<String> di = new ArrayList<String>(1);
- di.add(desc.image);
+ di.add(child.image);
refs.add(di);
}
var = new ArrayList<String>();
@@ -614,27 +636,25 @@ public class Engine extends JexlEngine {
}
continue;
} else if (child instanceof ASTIdentifier) {
- if (i == 0 && (((ASTIdentifier) child).getRegister() <
0)) {
+ if (i == 0 && (((ASTIdentifier) child).getSymbol() <
0)) {
var.add(child.image);
}
+ varf = false;
continue;
- }
- } else {//if (reference) {
- if (child instanceof ASTIdentifier) {
- if (((ASTIdentifier) child).getRegister() < 0) {
- var.add(child.image);
- }
+ } else if (child instanceof ASTIdentifierAccess) {
+ var.add(child.image);
+ varf = false;
continue;
}
+ getVariables(child, refs, var);
+ }
+ if (!var.isEmpty() && var != ref) {
+ refs.add(var);
+ }
+ } else {
+ for (int i = 0; i < num; ++i) {
+ getVariables(node.jjtGetChild(i), refs, null);
}
- getVariables(child, refs, var);
- }
- if (!var.isEmpty() && var != ref) {
- refs.add(var);
- }
- } else {
- for (int i = 0; i < num; ++i) {
- getVariables(node.jjtGetChild(i), refs, null);
}
}
}