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 2022/12/23 16:11:58 UTC

[commons-jexl] branch JEXL-390 updated: JEXL-390: added pragma-anywhere feature that controls if pragmas can only be used before any statement;

This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch JEXL-390
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


The following commit(s) were added to refs/heads/JEXL-390 by this push:
     new 0891da10 JEXL-390: added pragma-anywhere feature that controls if pragmas can only be used before any statement;
0891da10 is described below

commit 0891da10d235fd2320ee0cf450633f0b0c44145b
Author: henrib <he...@apache.org>
AuthorDate: Fri Dec 23 17:11:51 2022 +0100

    JEXL-390: added pragma-anywhere feature that controls if pragmas can only be used before any statement;
---
 .../org/apache/commons/jexl3/JexlFeatures.java     | 39 ++++++++++++++++++++--
 .../commons/jexl3/parser/FeatureController.java    |  2 +-
 .../apache/commons/jexl3/parser/JexlParser.java    | 19 ++++++++---
 .../org/apache/commons/jexl3/parser/Parser.jjt     |  4 +--
 .../org/apache/commons/jexl3/FeaturesTest.java     |  8 +++++
 5 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
index 35a80276..d8895add 100644
--- a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
+++ b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java
@@ -41,8 +41,16 @@ import java.util.function.Predicate;
  * <li>Method calls: calling methods (obj.method(...) or obj['method'](...)); when disabled, leaves function calls
  * - including namespace prefixes - available
  * <li>Structured literals: arrays, lists, maps, sets, ranges
- * <li>Pragmas: #pragma x y
+ * <li>Pragma: pragma construct as in <code>#pragma x y</code>
  * <li>Annotation: @annotation statement;
+ * <li>Thin-arrow: use the thin-arrow, ie <code>-&gt;</code> for lambdas as in <code>x -&gt; x + x</code>
+ * <li>Fat-arrow: use the  fat-arrow, ie <code>=&gt;</code> for lambdas as in <code>x =&gt; x + x</code>
+ * <li>Namespace pragma: whether the <code>#pragma jexl.namespace.ns namespace</code> syntax is allowed</li>
+ * <li>Import pragma: whether the <code>#pragma jexl.import fully.qualified.class.name</code> syntax is allowed</li>
+ * <li>Comparator names: whether the comparator operator names can be used (as in <code>gt</code> for &gt;,
+ * <code>lt</code> for &lt;, ...)</li>
+ * <li>Pragma anywhere: whether pragma, that are <em>not</em> statements and handled before execution begins,
+ * can appear anywhere in the source or before any statements - ie at the beginning of a script.</li>
  * </ul>
  * @since 3.2
  */
@@ -60,7 +68,7 @@ public final class JexlFeatures {
         "register", "reserved variable", "local variable", "assign/modify",
         "global assign/modify", "array reference", "create instance", "loop", "function",
         "method call", "set/map/array literal", "pragma", "annotation", "script", "lexical", "lexicalShade",
-        "thin-arrow", "fat-arrow", "namespace pragma", "import pragma", "comparator names"
+        "thin-arrow", "fat-arrow", "namespace pragma", "import pragma", "comparator names", "pragma anywhere"
     };
     /** Registers feature ordinal. */
     private static final int REGISTER = 0;
@@ -104,6 +112,8 @@ public final class JexlFeatures {
     public static final int IMPORT_PRAGMA = 19;
     /** Comparator names (legacy) syntax. */
     public static final int COMPARATOR_NAMES = 20;
+    /** The pragma anywhere feature ordinal. */
+    public static final int PRAGMA_ANYWHERE = 21;
     /**
      * The default features flag mask.
      */
@@ -123,7 +133,8 @@ public final class JexlFeatures {
             | (1L << THIN_ARROW)
             | (1L << NS_PRAGMA)
             | (1L << IMPORT_PRAGMA)
-            | (1L << COMPARATOR_NAMES);
+            | (1L << COMPARATOR_NAMES)
+            | (1L << PRAGMA_ANYWHERE);
 
     /**
      * Creates an all-features-enabled instance.
@@ -543,6 +554,26 @@ public final class JexlFeatures {
         return getFeature(PRAGMA);
     }
 
+    /**
+     * Sets whether pragma constructs can appear anywhere in the code.
+     * <p>
+     * @param flag true to enable, false to disable
+     * @return this features instance
+     * @since 3.3
+     */
+    public JexlFeatures pragmaAnywhere(final boolean flag) {
+        setFeature(PRAGMA_ANYWHERE, flag);
+        return this;
+    }
+
+    /**
+     * @return true if pragma constructs can appear anywhere in the code, false otherwise
+     * @since 3.3
+     */
+    public boolean supportsPragmaAnywhere() {
+        return getFeature(PRAGMA_ANYWHERE);
+    }
+
     /**
      * Sets whether namespace pragma constructs are enabled.
      * <p>
@@ -550,6 +581,7 @@ public final class JexlFeatures {
      * (#pragma jexl.namespace....) will throw a parsing exception.
      * @param flag true to enable, false to disable
      * @return this features instance
+     * @since 3.3
      */
     public JexlFeatures namespacePragma(final boolean flag) {
         setFeature(NS_PRAGMA, flag);
@@ -558,6 +590,7 @@ public final class JexlFeatures {
 
     /**
      * @return true if namespace pragma are enabled, false otherwise
+     * @since 3.3
      */
     public boolean supportsNamespacePragma() {
         return getFeature(NS_PRAGMA);
diff --git a/src/main/java/org/apache/commons/jexl3/parser/FeatureController.java b/src/main/java/org/apache/commons/jexl3/parser/FeatureController.java
index e40d6ca9..dc11a22e 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/FeatureController.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/FeatureController.java
@@ -29,7 +29,7 @@ public class FeatureController extends ScriptVisitor {
     private JexlFeatures features;
 
     /**
-     * Creates a features controller.
+     * Creates a feature controller.
      */
     public FeatureController(final JexlFeatures features) {
         this.features = features;
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 56f65876..54141d18 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java
@@ -201,6 +201,16 @@ public abstract class JexlParser extends StringParser {
         return featureController.getFeatures();
     }
 
+    /**
+     * Disables pragma feature is pragma-anywhere feature is disabled.
+     */
+    protected void controlPragmaAnywhere() {
+        JexlFeatures features = getFeatures();
+        if (features.supportsPragma() && !features.supportsPragmaAnywhere()) {
+            featureController.setFeatures(new JexlFeatures(featureController.getFeatures()).pragma(false));
+        }
+    }
+
     /**
      * Gets the frame used by this parser.
      * <p> Since local variables create new symbols, it is important to
@@ -508,19 +518,20 @@ public abstract class JexlParser extends StringParser {
      * @param value the pragma value
      */
     protected void declarePragma(final String key, final Object value) {
-        if (!getFeatures().supportsPragma()) {
+        JexlFeatures features = getFeatures();
+        if (!features.supportsPragma()) {
             throwFeatureException(JexlFeatures.PRAGMA, getToken(0));
         }
-        if (PRAGMA_IMPORT.equals(key) && !getFeatures().supportsImportPragma()) {
+        if (PRAGMA_IMPORT.equals(key) && !features.supportsImportPragma()) {
             throwFeatureException(JexlFeatures.IMPORT_PRAGMA, getToken(0));
         }
         if (pragmas == null) {
             pragmas = new TreeMap<>();
         }
         // declaring a namespace
-        Predicate<String> ns = getFeatures().namespaceTest();
+        Predicate<String> ns = features.namespaceTest();
         if (ns != null && key.startsWith(PRAGMA_JEXLNS)) {
-            if (!getFeatures().supportsNamespacePragma()) {
+            if (!features.supportsNamespacePragma()) {
                 throwFeatureException(JexlFeatures.NS_PRAGMA, getToken(0));
             }
             // jexl.namespace.***
diff --git a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
index cd6cc868..cb522f8a 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
+++ b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
@@ -324,7 +324,7 @@ ASTJexlScript JexlScript(Scope frame) : {
    {
         pushUnit(jjtThis);
    }
-        ( LOOKAHEAD(<PRAGMA>) Pragma() | Statement() )* <EOF>
+        ( LOOKAHEAD(<PRAGMA>) Pragma() | { controlPragmaAnywhere(); } Statement() )* <EOF>
    {
         popUnit(jjtThis);
         return jjtThis.script();
@@ -338,7 +338,7 @@ ASTJexlScript JexlExpression(Scope frame) #JexlScript : {
    {
         pushUnit(jjtThis);
    }
-   ( Pragma() )* ( Expression() )? <EOF>
+   ( Pragma() )* { controlPragmaAnywhere(); } ( Expression() )? <EOF>
    {
         popUnit(jjtThis);
         return jjtThis.script();
diff --git a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
index e635291f..300a4fad 100644
--- a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
+++ b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
@@ -267,6 +267,14 @@ public class FeaturesTest extends JexlTestCase {
         };
         checkFeature(f, scripts);
     }
+    @Test
+    public void testPragmaAnywhere() throws Exception {
+        final JexlFeatures f = new JexlFeatures().pragmaAnywhere(false);
+        final String[] scripts = new String[]{
+                "var x = 3;\n#pragma foo 42",
+        };
+        checkFeature(f, scripts);
+    }
 
     @Test
     public void testMixedFeatures() throws Exception {