diff --git a/.jules/bolt.md b/.jules/bolt.md index b8cd366..1fc3e0f 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -9,3 +9,7 @@ ## 2026-04-08 - [Fast Dense Integer Set Tracking] **Learning:** When keeping track of seen integer IDs that are dense and bounded (e.g. from 0 to N), using `new Set()` incurs heavy allocation and insertion overhead compared to a fixed-size byte array. **Action:** Replace `Set` with `new Uint8Array(maxIndex)` and use `array[id] = 1` to track presence, which is ~15x faster and avoids garbage collection pauses in hot paths. (Benchmark context: `N=100,000` IDs, `bun` version 1.2.14, Linux x86_64, Intel Xeon 2.30GHz, 4 cores, 8GB RAM, averaged over 100 iterations comparing `Set` addition vs `new Uint8Array(maxIndex)` indexed assignment `array[id] = 1`). + +## 2024-05-01 - Optimizing TreeSitter AST node type checking +**Learning:** In hot paths or AST traversal loops (e.g., searching for parent class declarations or extracting symbols based on node type), dynamic string manipulation (`.toLowerCase().includes('class_declaration')`) or regular expression checks (`/class_declaration|class_definition|^class$/.test(nodeType)`) create unnecessary overhead and memory allocations. +**Action:** Replace these checks with a pre-defined static `Set` of exact node names (e.g., `['class_declaration', 'class_definition', 'class']`) to perform O(1) `.has()` lookups. This eliminates redundant allocations and improves parsing latency for large source files. diff --git a/language-server/src/core/tree-sitter-parser.ts b/language-server/src/core/tree-sitter-parser.ts index 7744190..966af49 100644 --- a/language-server/src/core/tree-sitter-parser.ts +++ b/language-server/src/core/tree-sitter-parser.ts @@ -39,6 +39,14 @@ interface TreeSitterLib { } export class TreeSitterParser { + private static readonly CLASS_NODE_TYPES = new Set(['class_declaration', 'class_definition', 'class', 'struct_declaration', 'struct_definition', 'struct']); + private static readonly INTERFACE_NODE_TYPES = new Set(['interface_declaration', 'interface_definition', 'interface', 'trait_declaration', 'trait_definition', 'trait']); + private static readonly ENUM_NODE_TYPES = new Set(['enum_declaration', 'enum_definition', 'enum']); + private static readonly METHOD_NODE_TYPES = new Set(['method_declaration', 'method_definition', 'method']); + private static readonly FUNCTION_NODE_TYPES = new Set(['function_declaration', 'function_definition', 'function']); + private static readonly PROPERTY_NODE_TYPES = new Set(['property_declaration', 'property_definition']); + private static readonly VARIABLE_NODE_TYPES = new Set(['variable_declaration', 'variable_declarator']); + private isInitialized: boolean = false; private readonly languages: Map = new Map(); private ParserClass: ParserConstructor | undefined = undefined; @@ -465,13 +473,14 @@ export class TreeSitterParser { let parent = this.getParent(methodNode); while ( parent && - !parent.type.toLowerCase().includes('class_declaration') && + // ⚡ Bolt: Fast O(1) Set lookup replacing dynamic string manipulation + !TreeSitterParser.CLASS_NODE_TYPES.has(parent.type) && parent.type !== 'compilation_unit' ) { parent = this.getParent(parent); } - if (parent?.type.toLowerCase().includes('class_declaration')) { + if (parent && TreeSitterParser.CLASS_NODE_TYPES.has(parent.type)) { const results: { method: string | null; route: string | null } = { method: null, route: null, @@ -607,28 +616,23 @@ export class TreeSitterParser { } private getSearchItemType(nodeType: string, langId: string): SearchItemType | undefined { + // ⚡ Bolt: Fast O(1) Set lookups replacing RegExp checks // Classes & Types - if (/class_declaration|class_definition|^class$/.test(nodeType)) { + if (TreeSitterParser.CLASS_NODE_TYPES.has(nodeType)) { return SearchItemType.CLASS; } - if (/interface_declaration|interface_definition|^interface$/.test(nodeType)) { + if (TreeSitterParser.INTERFACE_NODE_TYPES.has(nodeType)) { return SearchItemType.INTERFACE; } - if (/enum_declaration|enum_definition|^enum$/.test(nodeType)) { + if (TreeSitterParser.ENUM_NODE_TYPES.has(nodeType)) { return SearchItemType.ENUM; } - if (/struct_declaration|struct_definition|^struct$/.test(nodeType)) { - return SearchItemType.CLASS; - } - if (/trait_declaration|trait_definition|^trait$/.test(nodeType)) { - return SearchItemType.INTERFACE; - } // Functions & Methods - if (/method_declaration|method_definition|^method$/.test(nodeType)) { + if (TreeSitterParser.METHOD_NODE_TYPES.has(nodeType)) { return SearchItemType.METHOD; } - if (/function_declaration|function_definition|^function$/.test(nodeType)) { + if (TreeSitterParser.FUNCTION_NODE_TYPES.has(nodeType)) { return SearchItemType.FUNCTION; } @@ -652,10 +656,10 @@ export class TreeSitterParser { } // Fallback for common properties and variables - if (/property_declaration|property_definition/.test(nodeType)) { + if (TreeSitterParser.PROPERTY_NODE_TYPES.has(nodeType)) { return SearchItemType.PROPERTY; } - if (/variable_declaration|variable_declarator/.test(nodeType)) { + if (TreeSitterParser.VARIABLE_NODE_TYPES.has(nodeType)) { return SearchItemType.VARIABLE; }