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);

Reply via email to