fix(cbm): replace O(N²) indexed loop with O(N) cursor in parse_generic_imports

ts_node_child(root, i) and ts_node_next_sibling() both call
ts_node_child_with_descendant() internally, making sibling iteration
O(N²) total on roots with many children (e.g. generated TypeScript
.d.ts files or large Perl files with 5,000–50,000 top-level nodes).

Replace with TSTreeCursor: ts_tree_cursor_goto_next_sibling() maintains
traversal state across calls and is O(1) per step, reducing total
complexity from O(N²) to O(N).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Shane McCarronandClaude Sonnet 4.6 committed 2026-03-21 13:10:51 -05:00
1 parent 75b5dcb897
commit 2af9e60738
1 file changed
+14 -4
+14 -4
View File
@@ -575,9 +575,18 @@ static void parse_lua_imports(CBMExtractCtx *ctx) {
static void parse_generic_imports(CBMExtractCtx *ctx, const char *node_type) {
CBMArena *a = ctx->arena;
uint32_t count = ts_node_child_count(ctx->root);
for (uint32_t i = 0; i < count; i++) {
TSNode node = ts_node_child(ctx->root, i);
/* Use TSTreeCursor for O(1)-per-step sibling traversal.
* ts_node_child(root, i) and ts_node_next_sibling() both call
* ts_node_child_with_descendant() internally, making naive iteration
* O(N²) on roots with thousands of children (e.g. generated .d.ts files).
* ts_tree_cursor_goto_next_sibling() maintains cursor state and is O(1). */
TSTreeCursor cursor = ts_tree_cursor_new(ctx->root);
if (!ts_tree_cursor_goto_first_child(&cursor)) {
ts_tree_cursor_delete(&cursor);
return;
}
do {
TSNode node = ts_tree_cursor_current_node(&cursor);
if (strcmp(ts_node_type(node), node_type) != 0) {
continue;
}
@@ -616,7 +625,8 @@ static void parse_generic_imports(CBMExtractCtx *ctx, const char *node_type) {
}
}
}
}
} while (ts_tree_cursor_goto_next_sibling(&cursor));
ts_tree_cursor_delete(&cursor);
}
// --- Wolfram imports ---