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 08f7be64 JEXL-380: pragma values can become sets when the same key is used for different declarations; - added debugger writePragmas method and conditional call; - added tests; 08f7be64 is described below commit 08f7be64d492b67e52d617e4fa81df1fc564d7a4 Author: henrib <hen...@apache.org> AuthorDate: Mon Aug 22 18:34:53 2022 +0200 JEXL-380: pragma values can become sets when the same key is used for different declarations; - added debugger writePragmas method and conditional call; - added tests; --- RELEASE-NOTES.txt | 1 + src/changes/changes.xml | 3 + .../apache/commons/jexl3/internal/Debugger.java | 41 ++++++++++++ .../org/apache/commons/jexl3/internal/Script.java | 3 +- .../apache/commons/jexl3/parser/JexlParser.java | 4 ++ .../java/org/apache/commons/jexl3/PragmaTest.java | 74 +++++++++++++++------- 6 files changed, 100 insertions(+), 26 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 6fca5ca7..3018aeca 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -40,6 +40,7 @@ the skill set required to write scripts. New Features in 3.3: ==================== +* JEXL-380: Multiple values per pragma key * JEXL-379: Allow new to use class identifier * JEXL-373: Add support for prefix/postfix increment/decrement operators * JEXL-372: Add support for 'standard' for loop diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 9d08d6ca..4095deb5 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -27,6 +27,9 @@ <body> <release version="3.3" date="YYYY-MM-DD"> <!-- ADD --> + <action dev="henrib" type="add" issue="JEXL-380"> + Multiple values per pragma key + </action> <action dev="henrib" type="add" issue="JEXL-379"> Allow new to use class identifier </action> diff --git a/src/main/java/org/apache/commons/jexl3/internal/Debugger.java b/src/main/java/org/apache/commons/jexl3/internal/Debugger.java index 5031607f..373abd58 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Debugger.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Debugger.java @@ -23,6 +23,9 @@ import org.apache.commons.jexl3.JexlInfo; import org.apache.commons.jexl3.JexlScript; import org.apache.commons.jexl3.parser.*; +import java.util.Collections; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -52,6 +55,8 @@ public class Debugger extends ParserVisitor implements JexlInfo.Detail { protected String arrow = "->"; /** EOL. */ protected String lf = "\n"; + /** Pragmas out. */ + protected boolean outputPragmas = false; /** * Creates a Debugger. @@ -207,6 +212,16 @@ public class Debugger extends ParserVisitor implements JexlInfo.Detail { return end; } + /** + * Lets the debugger write out pragmas if any. + * @param flag turn on or off + * @return this debugger instance + */ + public Debugger outputPragmas(boolean flag) { + this.outputPragmas = flag; + return this; + } + /** * Sets the indentation level. * @param level the number of spaces for indentation, none if less or equal to zero @@ -773,8 +788,34 @@ public class Debugger extends ParserVisitor implements JexlInfo.Detail { return lambda.jjtGetNumChildren() == 1 && !isStatement(lambda.jjtGetChild(0)); } + /** + * Stringifies the pragmas. + * @param builder where to stringify + * @param pragmas the pragmas, may be null + */ + private static void writePragmas(StringBuilder builder, Map<String, Object> pragmas) { + if (pragmas != null) { + for (Map.Entry<String, Object> pragma : pragmas.entrySet()) { + String key = pragma.getKey(); + Object value = pragma.getValue(); + Set<Object> values = value instanceof Set ? (Set) value : Collections.singleton(value); + for (Object pragmaValue : values) { + builder.append("#pragma "); + builder.append(key); + builder.append(' '); + builder.append(pragmaValue.toString()); + builder.append('\n'); + } + } + } + + } + @Override protected Object visit(final ASTJexlScript node, Object arg) { + if (outputPragmas) { + writePragmas(builder, node.getPragmas()); + } Object data = arg; boolean named = false; // if lambda, produce parameters 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 f121858b..2895c771 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Script.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Script.java @@ -141,8 +141,7 @@ public class Script implements JexlScript, JexlExpression { @Override public String getParsedText(final int indent) { final Debugger debug = new Debugger(); - debug.setIndentation(indent); - debug.debug(script, false); + debug.outputPragmas(true).indentation(indent).debug(script, false); return debug.toString(); } diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java index 5ade580d..f46f87e0 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java @@ -522,12 +522,16 @@ public abstract class JexlParser extends StringParser { if (previous != null) { Set<Object> values; if (previous instanceof Set<?>) { + // reinsert previous value which was the set values = (Set<Object>) previous; + pragmas.put(key, values); } else { + // create a new set as value values = new LinkedHashSet<Object>(); pragmas.put(key, values); values.add(previous); } + // add the new value to the set of values values.add(value); } } diff --git a/src/test/java/org/apache/commons/jexl3/PragmaTest.java b/src/test/java/org/apache/commons/jexl3/PragmaTest.java index 88908dca..c67fa067 100644 --- a/src/test/java/org/apache/commons/jexl3/PragmaTest.java +++ b/src/test/java/org/apache/commons/jexl3/PragmaTest.java @@ -20,6 +20,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import org.junit.Assert; @@ -41,8 +42,7 @@ public class PragmaTest extends JexlTestCase { */ @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testPragmas() throws Exception { - final JexlContext jc = new MapContext(); + public void testPragmas() { final JexlScript script = JEXL.createScript("#pragma one 1\n#pragma the.very.hard 'truth'\n2;"); Assert.assertNotNull(script); final Map<String, Object> pragmas = script.getPragmas(); @@ -53,8 +53,7 @@ public class PragmaTest extends JexlTestCase { @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testJxltPragmas() throws Exception { - final JexlContext jc = new MapContext(); + public void testJxltPragmas() { final JxltEngine engine = new JexlBuilder().create().createJxltEngine(); final JxltEngine.Template tscript = engine.createTemplate("$$ #pragma one 1\n$$ #pragma the.very.hard 'truth'\n2;"); Assert.assertNotNull(tscript); @@ -83,6 +82,10 @@ public class PragmaTest extends JexlTestCase { } } + /** + * Sleeps, called through scripts. + * @param ms time to sleep in ms + */ public void sleep(final long ms) { try { Thread.sleep(ms); @@ -94,7 +97,7 @@ public class PragmaTest extends JexlTestCase { @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testSafePragma() throws Exception { + public void testSafePragma() { SafeContext jc = new SafeContext(); jc.set("foo", null); final JexlScript script = JEXL.createScript("#pragma jexl.safe true\nfoo.bar;"); @@ -105,7 +108,7 @@ public class PragmaTest extends JexlTestCase { jc = new SafeContext(); jc.set("foo", null); try { - result = script.execute(jc); + script.execute(jc); Assert.fail("should have thrown"); } catch (final JexlException xvar) { // ok, expected @@ -136,10 +139,30 @@ public class PragmaTest extends JexlTestCase { } } + @Test + public void testNamespacePragmaValueSet() { + String src = + "#pragma jexl.import java.util\n"+ + "#pragma jexl.import java.io\n"+ + "#pragma jexl.import java.net\n"+ + "42"; + final JexlScript script = JEXL.createScript(src); + Map<String, Object> pragmas = script.getPragmas(); + Object importz = pragmas.get("jexl.import"); + Assert.assertTrue(importz instanceof Set<?>); + Set<String> importzz = (Set<String>) importz; + Assert.assertTrue(importzz.contains("java.util")); + Assert.assertTrue(importzz.contains("java.io")); + Assert.assertTrue(importzz.contains("java.net")); + Assert.assertEquals(3, importzz.size()); + String parsed = script.getParsedText(); + Assert.assertEquals(src, parsed); + } + @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testStaticNamespacePragma() throws Exception { - final SafeContext jc = new SafeContext(); + public void testStaticNamespacePragma() { + final JexlContext jc = new SafeContext(); final JexlScript script = JEXL.createScript( "#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n" + "sleeper:sleep(100);" @@ -150,10 +173,10 @@ public class PragmaTest extends JexlTestCase { @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testStatictNamespacePragmaCtl() throws Exception { + public void testStatictNamespacePragmaCtl() { final Map<String, Object> ns = Collections.singletonMap("sleeper", StaticSleeper.class.getName()); final JexlEngine jexl = new JexlBuilder().namespaces(ns).create(); - final SafeContext jc = new SafeContext(); + final JexlContext jc = new SafeContext(); final JexlScript script = jexl.createScript( "sleeper:sleep(100);" + "42"); @@ -163,22 +186,25 @@ public class PragmaTest extends JexlTestCase { @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testNamespacePragma() throws Exception { - final SafeContext jc = new SafeContext(); - final JexlScript script = JEXL.createScript( + public void testNamespacePragma() { + final JexlContext jc = new SafeContext(); + final String src = "#pragma jexl.namespace.sleeper " + Sleeper.class.getName() + "\n" - + "sleeper:sleep(100);" - + "42"); + + "sleeper:sleep(100);\n" + + "42;\n"; + final JexlScript script = JEXL.createScript(src); final Object result = script.execute(jc); Assert.assertEquals(42, result); + String parsed = script.getParsedText(); + Assert.assertEquals(src, parsed); } @Test @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes") - public void testNamespacePragmaCtl() throws Exception { + public void testNamespacePragmaCtl() { final Map<String, Object> ns = Collections.singletonMap("sleeper", Sleeper.class.getName()); final JexlEngine jexl = new JexlBuilder().namespaces(ns).create(); - final SafeContext jc = new SafeContext(); + final JexlContext jc = new SafeContext(); final JexlScript script = jexl.createScript( "sleeper:sleep(100);" + "42"); @@ -186,23 +212,23 @@ public class PragmaTest extends JexlTestCase { Assert.assertEquals(42, result); } - @Test public void test354() throws Exception { + @Test public void test354() { Map<String, Number> values = new TreeMap<>(); values.put("1", 1); values.put("+1", 1); values.put("-1", -1); - values.put("1l", 1l); - values.put("+1l", 1l); - values.put("-1l", -1l); + values.put("1l", 1L); + values.put("+1l", 1L); + values.put("-1l", -1L); values.put("10h", BigInteger.valueOf(10)); values.put("-11h", BigInteger.valueOf(-11)); values.put("+12h", BigInteger.valueOf(12)); values.put("0xa", 0xa); values.put("+0xa", 0xa); values.put("-0xa", -0xa); - values.put("0xacl", 0xacl); - values.put("+0xadl", 0xadl); - values.put("-0xafl", -0xafl); + values.put("0xacl", 0xacL); + values.put("+0xadl", 0xadL); + values.put("-0xafl", -0xafL); values.put("1d", 1d); values.put("-1d", -1d); values.put("+1d", 1d);