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}).
