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/08/30 17:07:32 UTC

[commons-jexl] branch master updated: JEXL-369: Blind fix for elusive lexical scope cleaning pb;

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 fe04b47c JEXL-369: Blind fix for elusive lexical scope cleaning pb;
fe04b47c is described below

commit fe04b47c981d59fc6d175ecd4b1006af5bf55759
Author: henrib <he...@apache.org>
AuthorDate: Tue Aug 30 19:07:26 2022 +0200

    JEXL-369: Blind fix for elusive lexical scope cleaning pb;
---
 .../commons/jexl3/internal/LexicalScope.java       | 36 +++++++++++++++-------
 .../java/org/apache/commons/jexl3/LexicalTest.java |  8 +++++
 2 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/internal/LexicalScope.java b/src/main/java/org/apache/commons/jexl3/internal/LexicalScope.java
index 2f983e01..7a89d373 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/LexicalScope.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/LexicalScope.java
@@ -21,8 +21,8 @@ import java.util.BitSet;
 /**
  * The set of symbols declared in a lexical scope.
  * <p>The symbol identifiers are determined by the functional scope.</p>
- * <p>We use 2 bits per symbol; bit 0 sets the actual symbol as lexical (let), bit 1 as a const.
- * There are actually only 4 used states: 0, 1, 3</p>
+ * <p>We use 2 bits per symbol s; bit (s*2)+0 sets the actual symbol as lexical (let), bit (s*2)+1 as a const.
+ * There are actually only 2 used states: 1 and 3</p>
  */
 public class LexicalScope {
     /**
@@ -31,14 +31,19 @@ public class LexicalScope {
     protected static final int LONGBITS = 64;
     /**
      * Bits per symbol.
-     * Declared, const, defined.
+     * let (b + 0) + const (b + 1).
      */
     protected static final int BITS_PER_SYMBOL = 2;
+    /**
+     * Bits per symbol.
+     * Declared, const, defined.
+     */
+    protected static final int SYMBOL_SHIFT = 1;
     /**
      * Bitmask for symbols.
      * Declared, const, defined.
      */
-    protected static final long SYMBOL_MASK = (1L << BITS_PER_SYMBOL) - 1; // 3, as 1+2, 2 bits
+    protected static final long SYMBOL_MASK = (1L << (BITS_PER_SYMBOL - 1)) - 1; // 3, as 1+2, 2 bits
     /**
      * Number of symbols.
      */
@@ -122,7 +127,7 @@ public class LexicalScope {
      * @return true if declared, false otherwise
      */
     public boolean hasSymbol(final int symbol) {
-        final int bit = symbol << BITS_PER_SYMBOL;
+        final int bit = symbol << SYMBOL_SHIFT;
         return isSet(bit);
     }
 
@@ -133,7 +138,7 @@ public class LexicalScope {
      * @return true if declared as constant, false otherwise
      */
     public boolean isConstant(final int symbol) {
-        final int bit = (symbol << BITS_PER_SYMBOL) | 1;
+        final int bit = (symbol << SYMBOL_SHIFT) | 1;
         return isSet(bit);
     }
 
@@ -144,7 +149,7 @@ public class LexicalScope {
      * @return true if registered, false if symbol was already registered
      */
     public boolean addSymbol(final int symbol) {
-        final int bit = (symbol << BITS_PER_SYMBOL) ;
+        final int bit = (symbol << SYMBOL_SHIFT) ;
         if (set(bit)) {
             count += 1;
             return true;
@@ -159,7 +164,11 @@ public class LexicalScope {
      * @return true if registered, false if symbol was already registered
      */
     public boolean addConstant(final int symbol) {
-        final int bit = (symbol << BITS_PER_SYMBOL) | 1;
+        final int letb = (symbol << SYMBOL_SHIFT) ;
+        if (!isSet(letb)) {
+            throw new IllegalStateException("symbol not declared before const " + symbol);
+        }
+        final int bit = (symbol << SYMBOL_SHIFT) | 1;
         return set(bit);
     }
 
@@ -176,15 +185,20 @@ public class LexicalScope {
                 final int s = Long.numberOfTrailingZeros(clean);
                 // call clean for symbol definition (3 as a mask for 2 bits,1+2)
                 clean &= ~(SYMBOL_MASK << s);
-                cleanSymbol.accept(s >> BITS_PER_SYMBOL);
+                cleanSymbol.accept(s >> SYMBOL_SHIFT);
             }
         }
         symbols = 0L;
         if (moreSymbols != null) {
             if (cleanSymbol != null) {
                 // step by bits per symbol
-                for (int s = moreSymbols.nextSetBit(0); s != -1; s = moreSymbols.nextSetBit(s + BITS_PER_SYMBOL)) {
-                    cleanSymbol.accept(s + LONGBITS);
+                for (int s = moreSymbols.nextSetBit(0);
+                     s != -1;
+                     s = moreSymbols.nextSetBit(s + BITS_PER_SYMBOL)) {
+                    // skip const bit indicator
+                    if ((s & 1) == 0) {
+                        cleanSymbol.accept((s >> SYMBOL_SHIFT) + LONGBITS);
+                    }
                 }
             }
             moreSymbols.clear();
diff --git a/src/test/java/org/apache/commons/jexl3/LexicalTest.java b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
index 43d0fd9f..ad6f5a7b 100644
--- a/src/test/java/org/apache/commons/jexl3/LexicalTest.java
+++ b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
@@ -401,6 +401,14 @@ public class LexicalTest {
             Assert.assertTrue(scope.hasSymbol(i));
             Assert.assertFalse(scope.hasSymbol(i + 1));
         }
+        for(int i = 0; i < 128; i += 2) {
+            Assert.assertTrue(scope.addConstant(i));
+            Assert.assertFalse(scope.addConstant(i));
+        }
+        for(int i = 0; i < 128; i += 2) {
+            Assert.assertTrue(scope.hasSymbol(i));
+            Assert.assertFalse(scope.hasSymbol(i + 1));
+        }
     }
 
     @Test