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

sunlan pushed a commit to branch GROOVY-11904
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 69805779695689c9bddc23a307609269e045b22f
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Apr 5 02:14:05 2026 +0900

    GROOVY-11904: O(1) Lookup table instead of O(log n) binary search modifiers
---
 .../groovy/parser/antlr4/SemanticPredicates.java   | 23 +++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git 
a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java 
b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
index e25d40f2b4..d2dfab925c 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
@@ -24,8 +24,8 @@ import org.antlr.v4.runtime.TokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ModifierNode;
+import org.codehaus.groovy.runtime.ArrayGroovyMethods;
 
-import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -151,9 +151,6 @@ public class SemanticPredicates {
                 && LPAREN == (ts.LT(2).getType());
     }
 
-    private static final int[] MODIFIER_ARRAY =
-            ModifierNode.MODIFIER_OPCODE_MAP.keySet().stream()
-                    .mapToInt(Integer::intValue).sorted().toArray();
     /**
      * Distinguish between local variable declaration and method call, e.g. `a 
b`
      */
@@ -188,7 +185,7 @@ public class SemanticPredicates {
         int nextCodePoint = token.getText().codePointAt(0);
 
         return // VOID == tokenType ||
-                !(BuiltInPrimitiveType == tokenType || 
Arrays.binarySearch(MODIFIER_ARRAY, tokenType) >= 0)
+                !(BuiltInPrimitiveType == tokenType || isModifier(tokenType))
                         && !Character.isUpperCase(nextCodePoint)
                         && nextCodePoint != '@'
                         && !(ASSIGN == tokenType3 || (LT == tokenType2 || 
LBRACK == tokenType2))
@@ -196,6 +193,22 @@ public class SemanticPredicates {
 
     }
 
+    private static final boolean[] MODIFIER_LOOKUP_TABLE;
+    static {
+        int[] modifierArray = 
ModifierNode.MODIFIER_OPCODE_MAP.keySet().stream().mapToInt(Integer::intValue).toArray();
+        int max = ArrayGroovyMethods.max(modifierArray);
+        boolean[] table = new boolean[max + 1];
+        for (int t : modifierArray) {
+            if (t >= 0) { // skip special values like ANNOTATION_TYPE (-999)
+                table[t] = true;
+            }
+        }
+        MODIFIER_LOOKUP_TABLE = table;
+    }
+    private static boolean isModifier(int tokenType) {
+        return tokenType >= 0 && tokenType < MODIFIER_LOOKUP_TABLE.length && 
MODIFIER_LOOKUP_TABLE[tokenType];
+    }
+
     /**
      * When the input starts with one or more annotations, scan past them and 
check whether
      * the first non-annotation token is a loop keyword ({@code for}, {@code 
while}, {@code do}).

Reply via email to