Browse Source

Use Tries to match with the keywords

Toni Helenius 8 months ago
parent
commit
d5ab75f17c

+ 43 - 43
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/lexer/GlslKeywordLibrary.java

@@ -31,6 +31,7 @@
  */
  */
 package com.jme3.gde.glsl.highlighter.lexer;
 package com.jme3.gde.glsl.highlighter.lexer;
 
 
+import com.jme3.gde.glsl.highlighter.util.Trie;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
@@ -40,18 +41,20 @@ import java.util.List;
  *
  *
  * @author grizeldi
  * @author grizeldi
  */
  */
-class GlslKeywordLibrary {
-
+final class GlslKeywordLibrary {
+    
     public enum KeywordType {
     public enum KeywordType {
         KEYWORD, BUILTIN_FUNCTION, BUILTIN_VARIABLE, BASIC_TYPE, UNFINISHED;
         KEYWORD, BUILTIN_FUNCTION, BUILTIN_VARIABLE, BASIC_TYPE, UNFINISHED;
     }
     }
-    private static final List<String> keywords = new ArrayList<>(),
-            builtinFunctions = new ArrayList<>(),
-            builtinVariables = new ArrayList<>(),
-            basicTypes = new ArrayList<>();
+    
+    private static final Trie keywordsTrie = new Trie();
+    private static final Trie builtinFunctionsTrie = new Trie();
+    private static final Trie builtinVariablesTrie = new Trie();
+    private static final Trie basicTypesTrie = new Trie();
 
 
     static {
     static {
         //keywords
         //keywords
+        List<String> keywords = new ArrayList<>();
         keywords.add("attribute");
         keywords.add("attribute");
         keywords.add("const");
         keywords.add("const");
         keywords.add("uniform");
         keywords.add("uniform");
@@ -93,6 +96,7 @@ class GlslKeywordLibrary {
         keywords.add("discard");
         keywords.add("discard");
         keywords.add("return");
         keywords.add("return");
         //primitives and other types
         //primitives and other types
+        List<String> basicTypes = new ArrayList<>();
         basicTypes.add("float");
         basicTypes.add("float");
         basicTypes.add("double");
         basicTypes.add("double");
         basicTypes.add("int");
         basicTypes.add("int");
@@ -217,6 +221,7 @@ class GlslKeywordLibrary {
         basicTypes.add("struct");
         basicTypes.add("struct");
         //builtin variables
         //builtin variables
         //compute shaders
         //compute shaders
+        List<String> builtinVariables = new ArrayList<>();
         builtinVariables.add("gl_NumWorkGroups");
         builtinVariables.add("gl_NumWorkGroups");
         builtinVariables.add("gl_WorkGroupSize");
         builtinVariables.add("gl_WorkGroupSize");
         builtinVariables.add("gl_WorkGroupID");
         builtinVariables.add("gl_WorkGroupID");
@@ -291,6 +296,7 @@ class GlslKeywordLibrary {
         builtinVariables.add("g_LightColor");
         builtinVariables.add("g_LightColor");
         builtinVariables.add("g_AmbientLightColor");
         builtinVariables.add("g_AmbientLightColor");
         //builtin functions
         //builtin functions
+        List<String> builtinFunctions = new ArrayList<>();
         builtinFunctions.add("radians");
         builtinFunctions.add("radians");
         builtinFunctions.add("degrees");
         builtinFunctions.add("degrees");
         builtinFunctions.add("sin");
         builtinFunctions.add("sin");
@@ -466,51 +472,45 @@ class GlslKeywordLibrary {
         builtinFunctions.add("memoryBarrierShared");
         builtinFunctions.add("memoryBarrierShared");
         builtinFunctions.add("memoryBarrierImage");
         builtinFunctions.add("memoryBarrierImage");
         builtinFunctions.add("groupMemoryBarrier");
         builtinFunctions.add("groupMemoryBarrier");
+        
+        // Create the search tries
+        for(String keyword : keywords) {
+            keywordsTrie.insert(keyword);
+        }
+        for(String keyword : builtinFunctions) {
+            builtinFunctionsTrie.insert(keyword);
+        }
+        for(String keyword : builtinVariables) {
+            builtinVariablesTrie.insert(keyword);
+        }
+        for(String keyword : basicTypes) {
+            basicTypesTrie.insert(keyword);
+        }
     }
     }
 
 
     public static KeywordType lookup(String s) {
     public static KeywordType lookup(String s) {
         KeywordType returnType = null;
         KeywordType returnType = null;
-        for (String primitive : basicTypes) {
-            if (primitive.startsWith(s)) {
-                if (primitive.equals(s)) {
-                    returnType = KeywordType.BASIC_TYPE;
-                    break;
-                } else {
-                    returnType = KeywordType.UNFINISHED;
-                }
-            }
+        returnType = lookup(s, returnType, KeywordType.BASIC_TYPE, basicTypesTrie);
+        returnType = lookup(s, returnType, KeywordType.BUILTIN_VARIABLE, builtinVariablesTrie);
+        if (returnType == KeywordType.UNFINISHED || returnType == null) {
+            returnType = lookup(s, returnType, KeywordType.BUILTIN_FUNCTION, builtinFunctionsTrie);
         }
         }
-        for (String var : builtinVariables) {
-            if (var.startsWith(s)) {
-                if (var.equals(s)) {
-                    returnType = KeywordType.BUILTIN_VARIABLE;
-                    break;
-                } else {
-                    returnType = KeywordType.UNFINISHED;
-                }
-            }
+        if (returnType == KeywordType.UNFINISHED || returnType == null) {
+            returnType = lookup(s, returnType, KeywordType.KEYWORD, keywordsTrie);
         }
         }
-        for (String func : builtinFunctions) {
-            if (func.startsWith(s) && (returnType == KeywordType.UNFINISHED || returnType == null)) {
-                if (func.equals(s)) {
-                    returnType = KeywordType.BUILTIN_FUNCTION;
-                    break;
-                } else {
-                    returnType = KeywordType.UNFINISHED;
-                }
-            }
+
+        return returnType;
+    }
+
+    private static KeywordType lookup(String s, KeywordType currentType, KeywordType matchType, Trie searchTrie) {
+        Trie.MatchType match = searchTrie.search(s);
+        if (match == Trie.MatchType.FULL_MATCH) {
+            return matchType;
         }
         }
-        for (String keyword : keywords) {
-            if (keyword.startsWith(s) && (returnType == KeywordType.UNFINISHED || returnType == null)) {
-                if (keyword.equals(s)) {
-                    returnType = KeywordType.KEYWORD;
-                    break;
-                } else {
-                    returnType = KeywordType.UNFINISHED;
-                }
-            }
+        if (match == Trie.MatchType.PARTIAL_MATCH) {
+            return KeywordType.UNFINISHED;
         }
         }
 
 
-        return returnType;
+        return currentType;
     }
     }
 }
 }

+ 91 - 0
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/util/Trie.java

@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.glsl.highlighter.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple and efficient text search
+ */
+public class Trie {
+
+    private static class TrieNode {
+
+        Map<Character, TrieNode> children = new HashMap<>();
+        boolean isEndOfWord = false;
+    }
+
+    public enum MatchType {
+        NO_MATCH,
+        PARTIAL_MATCH,
+        FULL_MATCH
+    }
+
+    private final TrieNode root;
+
+    public Trie() {
+        root = new TrieNode();
+    }
+
+    /**
+     * Insert word to the Trie structure
+     *
+     * @param word word to insert
+     */
+    public void insert(String word) {
+        TrieNode current = root;
+        for (char ch : word.toCharArray()) {
+            current = current.children.computeIfAbsent(ch, c -> new TrieNode());
+        }
+        current.isEndOfWord = true;
+    }
+
+    /**
+     * Searches for the string
+     *
+     * @param word word to search for
+     * @return match type
+     */
+    public MatchType search(String word) {
+        TrieNode current = root;
+        for (char ch : word.toCharArray()) {
+            if (!current.children.containsKey(ch)) {
+                return MatchType.NO_MATCH;
+            }
+            current = current.children.get(ch);
+        }
+
+        return current.isEndOfWord ? MatchType.FULL_MATCH : MatchType.PARTIAL_MATCH;
+    }
+
+}