You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2018/09/10 08:47:41 UTC
[commons-jexl] branch master updated: JEXL-270,
JEXL-271: fix hoisting resolution and use thread-local current
interpreter to capture env while currying, fix script re-stringification,
added tests
This is an automated email from the ASF dual-hosted git repository.
henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
The following commit(s) were added to refs/heads/master by this push:
new cb4f54a JEXL-270, JEXL-271: fix hoisting resolution and use thread-local current interpreter to capture env while currying, fix script re-stringification, added tests
cb4f54a is described below
commit cb4f54a0e3468e5b1f5336a47ea98308d163d605
Author: henrib <he...@apache.org>
AuthorDate: Mon Sep 10 10:46:19 2018 +0200
JEXL-270, JEXL-271: fix hoisting resolution and use thread-local current interpreter to capture env while currying, fix script re-stringification, added tests
---
.../org/apache/commons/jexl3/JexlOperator.java | 13 ++++++---
.../apache/commons/jexl3/internal/Interpreter.java | 30 +++++++++++++++++--
.../org/apache/commons/jexl3/internal/Scope.java | 2 +-
.../org/apache/commons/jexl3/internal/Script.java | 31 ++++++++++----------
.../apache/commons/jexl3/parser/ASTJexlLambda.java | 18 ------------
.../apache/commons/jexl3/parser/ASTJexlScript.java | 16 ++++++++--
.../org/apache/commons/jexl3/Issues200Test.java | 34 ++++++++++++++++++++++
7 files changed, 101 insertions(+), 43 deletions(-)
diff --git a/src/main/java/org/apache/commons/jexl3/JexlOperator.java b/src/main/java/org/apache/commons/jexl3/JexlOperator.java
index 1332d1b..5bc448e 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlOperator.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlOperator.java
@@ -26,10 +26,15 @@ package org.apache.commons.jexl3;
* For instance, '+' is associated to 'T add(L x, R y)'.</p>
*
* <p>The default JexlArithmetic implements generic versions of these methods using Object as arguments.
- * You can use your own derived JexlArithmetic that override and/or overload those operator methods; these methods
- * must be public,
- * must respect the return type when primitive
- * and may be overloaded multiple times with different signatures.</p>
+ * You can use your own derived JexlArithmetic that override and/or overload those operator methods.
+ * Note that these are overloads by convention, not actual Java overloads.
+ * The following rules apply to operator methods:</p>
+ * <ul>
+ * <li>Operator methods should be public</li>
+ * <li>Operators return type should be respected when primitive (int, boolean,...)</li>
+ * <li>Operators may be overloaded multiple times with different signatures</li>
+ * <li>Operators may return JexlEngine.TRY_AGAIN to fallback on default JEXL implementation</li>
+ * </ul>
*
* @since 3.0
*/
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index 46d692b..89db12a 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -24,12 +24,10 @@ import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlOperator;
import org.apache.commons.jexl3.JexlScript;
-
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlPropertyGet;
import org.apache.commons.jexl3.introspection.JexlPropertySet;
import org.apache.commons.jexl3.introspection.JexlUberspect.PropertyResolver;
-
import org.apache.commons.jexl3.parser.ASTAddNode;
import org.apache.commons.jexl3.parser.ASTAndNode;
import org.apache.commons.jexl3.parser.ASTAnnotatedStatement;
@@ -135,6 +133,12 @@ public class Interpreter extends InterpreterBase {
protected Map<String, Object> functors;
/**
+ * The thread local interpreter.
+ */
+ protected static final java.lang.ThreadLocal<Interpreter> INTER =
+ new java.lang.ThreadLocal<Interpreter>();
+
+ /**
* Creates an interpreter.
* @param engine the engine creating this interpreter
* @param aContext the context to evaluate expression
@@ -168,6 +172,25 @@ public class Interpreter extends InterpreterBase {
functions = ii.functions;
functors = ii.functors;
}
+
+ /**
+ * @return the current interpreter frame
+ */
+ static Scope.Frame getCurrentFrame() {
+ Interpreter inter = INTER.get();
+ return inter != null? inter.frame : null;
+ }
+
+ /**
+ * Swaps the current thread local interpreter.
+ * @param inter the interpreter or null
+ * @return the previous thread local interpreter
+ */
+ protected Interpreter putThreadInterpreter(Interpreter inter) {
+ Interpreter pinter = INTER.get();
+ INTER.set(inter);
+ return pinter;
+ }
/**
* Interpret the given script/expression.
@@ -181,8 +204,10 @@ public class Interpreter extends InterpreterBase {
public Object interpret(JexlNode node) {
JexlContext.ThreadLocal tcontext = null;
JexlEngine tjexl = null;
+ Interpreter tinter = null;
try {
cancelCheck(node);
+ tinter = putThreadInterpreter(this);
if (context instanceof JexlContext.ThreadLocal) {
tcontext = jexl.putThreadLocal((JexlContext.ThreadLocal) context);
}
@@ -218,6 +243,7 @@ public class Interpreter extends InterpreterBase {
if (context instanceof JexlContext.ThreadLocal) {
jexl.putThreadLocal(tcontext);
}
+ putThreadInterpreter(tinter);
}
return null;
}
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Scope.java b/src/main/java/org/apache/commons/jexl3/internal/Scope.java
index f5bef11..0625daf 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Scope.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Scope.java
@@ -109,7 +109,7 @@ public final class Scope {
private Integer getSymbol(String name, boolean hoist) {
Integer register = namedVariables != null ? namedVariables.get(name) : null;
if (register == null && hoist && parent != null) {
- Integer pr = parent.getSymbol(name, false);
+ Integer pr = parent.getSymbol(name, true);
if (pr != null) {
if (hoistedVariables == null) {
hoistedVariables = new LinkedHashMap<Integer, Integer>();
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Script.java b/src/main/java/org/apache/commons/jexl3/internal/Script.java
index eeb727f..9cf4343 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Script.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Script.java
@@ -124,16 +124,27 @@ public class Script implements JexlScript, JexlExpression {
public String getParsedText() {
return getParsedText(2);
}
-
+
@Override
public String getParsedText(int indent) {
Debugger debug = new Debugger();
debug.setIndentation(indent);
- debug.debug(script);
+ debug.debug(script, false);
return debug.toString();
}
@Override
+ public String toString() {
+ CharSequence src = source;
+ if (src == null) {
+ Debugger debug = new Debugger();
+ debug.debug(script, false);
+ src = debug.toString();
+ }
+ return src.toString();
+ }
+
+ @Override
public int hashCode() {
// CSOFF: Magic number
int hash = 17;
@@ -162,17 +173,6 @@ public class Script implements JexlScript, JexlExpression {
}
@Override
- public String toString() {
- CharSequence src = source;
- if (src == null) {
- Debugger debug = new Debugger();
- debug.debug(script);
- src = debug.toString();
- }
- return src.toString();
- }
-
- @Override
public Object evaluate(JexlContext context) {
return execute(context);
}
@@ -211,10 +211,11 @@ public class Script implements JexlScript, JexlExpression {
if (sf != null) {
frame = sf.assign(args);
} else {
- frame = script.createFrame(args);
+ sf = Interpreter.getCurrentFrame();
+ frame = script.createFrame(sf, args);
}
}
-
+
@Override
protected Scope.Frame createFrame(Object[] args) {
return frame != null? frame.assign(args) : super.createFrame(args);
diff --git a/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java b/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
index c668853..e57f586 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
@@ -16,8 +16,6 @@
*/
package org.apache.commons.jexl3.parser;
-import org.apache.commons.jexl3.internal.Scope;
-
/**
* Lambda (function).
*/
@@ -36,20 +34,4 @@ public final class ASTJexlLambda extends ASTJexlScript {
public boolean isTopLevel() {
return jjtGetParent() == null;
}
-
- /**
- * Creates an array of arguments by copying values up to the number of parameters.
- * @param frame the calling frame
- * @param values the argument values
- * @return the arguments array
- */
- public Scope.Frame createFrame(Scope.Frame frame, Object... values) {
- if (getScope() != null) {
- Scope.Frame cframe = getScope().createFrame(frame);
- if (cframe != null) {
- return cframe.assign(values);
- }
- }
- return null;
- }
}
diff --git a/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java b/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
index 8dd8947..74c7bbc 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
@@ -59,7 +59,7 @@ public class ASTJexlScript extends JexlNode {
}
/**
* Sets this script pragmas.
- * @param pragmas the pragmas
+ * @param thePragmas the pragmas
*/
public void setPragmas(Map<String, Object> thePragmas) {
this.pragmas = thePragmas;
@@ -104,18 +104,28 @@ public class ASTJexlScript extends JexlNode {
/**
* Creates an array of arguments by copying values up to the number of parameters.
+ * @param caller the calling frame
* @param values the argument values
* @return the arguments array
*/
- public Scope.Frame createFrame(Object... values) {
+ public Scope.Frame createFrame(Scope.Frame caller, Object... values) {
if (scope != null) {
- Scope.Frame frame = scope.createFrame(null);
+ Scope.Frame frame = scope.createFrame(caller);
if (frame != null) {
return frame.assign(values);
}
}
return null;
}
+
+ /**
+ * Creates an array of arguments by copying values up to the number of parameters.
+ * @param values the argument values
+ * @return the arguments array
+ */
+ public Scope.Frame createFrame(Object... values) {
+ return createFrame(null, values);
+ }
/**
* Gets the (maximum) number of arguments this script expects.
diff --git a/src/test/java/org/apache/commons/jexl3/Issues200Test.java b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
index 31fb8f8..7d4d47f 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues200Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues200Test.java
@@ -652,5 +652,39 @@ public class Issues200Test extends JexlTestCase {
result = script.execute(ctxt);
Assert.assertTrue(result instanceof JexlScript);
}
+
+ @Test
+ public void test270() throws Exception {
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlScript base = jexl.createScript("(x, y, z)->{ x + y + z }");
+ String text = base.toString();
+ JexlScript script = base.curry(5, 15);
+ Assert.assertEquals(text, script.toString());
+
+ JexlEvalContext ctxt = new JexlEvalContext();
+ ctxt.set("s", base);
+ script = jexl.createScript("return s");
+ Object result = script.execute(ctxt);
+ Assert.assertEquals(text, result.toString());
+
+ script = jexl.createScript("return s.curry(1)");
+ result = script.execute(ctxt);
+ Assert.assertEquals(text, result.toString());
+ }
+ @Test
+ public void test271a() throws Exception {
+ JexlEngine jexl = new JexlBuilder().strict(false).create();
+ JexlScript base = jexl.createScript("var base = 1; var x = (a)->{ var y = (b) -> {base + b}; return base + y(a)}; x(40)");
+ Object result = base.execute(null);
+ Assert.assertEquals(42, result);
+ }
+
+ @Test
+ public void test271b() throws Exception {
+ JexlEngine jexl = new JexlBuilder().strict(false).create();
+ JexlScript base = jexl.createScript("var base = 2; var sum = (x, y, z)->{ base + x + y + z }; var y = sum.curry(1); y(2,3)");
+ Object result = base.execute(null);
+ Assert.assertEquals(8, result);
+ }
}