Skip to content

Commit 3b0159d

Browse files
authored
Merge pull request tree-sitter#2788 from tree-sitter/subtree-compare-stack-overflow
Avoid using recursion in `subtree_compare`
2 parents 0ff2834 + 5e2456c commit 3b0159d

File tree

4 files changed

+26
-47
lines changed

4 files changed

+26
-47
lines changed

cli/src/tests/language_test.rs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,3 @@ fn test_lookahead_iterator_modifiable_only_by_mut() {
6262
let mut names = lookahead.iter_names();
6363
let _ = names.next();
6464
}
65-
66-
/// It doesn't allowed to use lookahead iterator by shared ref:
67-
/// error[E0596]: cannot borrow `lookahead` as mutable, as it is not declared as mutable
68-
/// ```compile_fail
69-
/// use tree_sitter::{Parser, Language};
70-
/// let mut parser = Parser::new();
71-
/// let language = unsafe { Language::from_raw(std::ptr::null()) };
72-
/// let tree = parser.parse("", None).unwrap();
73-
/// let mut cursor = tree.walk();
74-
/// let next_state = cursor.node().next_parse_state();
75-
/// let lookahead = language.lookahead_iterator(next_state).unwrap();
76-
/// let _ = lookahead.next();
77-
/// ```
78-
79-
/// It doesn't allowed to use lookahead names iterator by shared ref:
80-
/// error[E0596]: cannot borrow `names` as mutable, as it is not declared as mutable
81-
/// ```compile_fail
82-
/// use tree_sitter::{Parser, Language};
83-
/// let mut parser = Parser::new();
84-
/// let language = unsafe { Language::from_raw(std::ptr::null()) };
85-
/// let tree = parser.parse("", None).unwrap();
86-
/// let mut cursor = tree.walk();
87-
/// let next_state = cursor.node().next_parse_state();
88-
/// if let Some(mut lookahead) = language.lookahead_iterator(next_state) {
89-
/// let _ = lookahead.next();
90-
/// let names = lookahead.iter_names();
91-
/// let _ = names.next();
92-
/// }
93-
/// ```
94-
95-
fn _dummy() {}

lib/src/parser.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ static bool ts_parser__select_tree(TSParser *self, Subtree left, Subtree right)
747747

748748
if (ts_subtree_error_cost(left) > 0) return true;
749749

750-
int comparison = ts_subtree_compare(left, right);
750+
int comparison = ts_subtree_compare(left, right, &self->tree_pool);
751751
switch (comparison) {
752752
case -1:
753753
LOG("select_earlier symbol:%s, over_symbol:%s", TREE_NAME(left), TREE_NAME(right));

lib/src/subtree.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#include <assert.h>
22
#include <ctype.h>
3-
#include <limits.h>
3+
#include <stdint.h>
44
#include <stdbool.h>
55
#include <string.h>
66
#include <stdio.h>
77
#include "./alloc.h"
8+
#include "./array.h"
89
#include "./atomic.h"
910
#include "./subtree.h"
1011
#include "./length.h"
@@ -618,21 +619,30 @@ void ts_subtree_release(SubtreePool *pool, Subtree self) {
618619
}
619620
}
620621

621-
int ts_subtree_compare(Subtree left, Subtree right) {
622-
if (ts_subtree_symbol(left) < ts_subtree_symbol(right)) return -1;
623-
if (ts_subtree_symbol(right) < ts_subtree_symbol(left)) return 1;
624-
if (ts_subtree_child_count(left) < ts_subtree_child_count(right)) return -1;
625-
if (ts_subtree_child_count(right) < ts_subtree_child_count(left)) return 1;
626-
for (uint32_t i = 0, n = ts_subtree_child_count(left); i < n; i++) {
627-
Subtree left_child = ts_subtree_children(left)[i];
628-
Subtree right_child = ts_subtree_children(right)[i];
629-
switch (ts_subtree_compare(left_child, right_child)) {
630-
case -1: return -1;
631-
case 1: return 1;
632-
default: break;
622+
int ts_subtree_compare(Subtree left, Subtree right, SubtreePool *pool) {
623+
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(left));
624+
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(right));
625+
626+
int result = 0;
627+
while (result == 0 && pool->tree_stack.size > 0) {
628+
right = ts_subtree_from_mut(array_pop(&pool->tree_stack));
629+
left = ts_subtree_from_mut(array_pop(&pool->tree_stack));
630+
631+
if (ts_subtree_symbol(left) < ts_subtree_symbol(right)) result = -1;
632+
if (ts_subtree_symbol(right) < ts_subtree_symbol(left)) result = 1;
633+
if (ts_subtree_child_count(left) < ts_subtree_child_count(right)) result = -1;
634+
if (ts_subtree_child_count(right) < ts_subtree_child_count(left)) result = 1;
635+
636+
for (uint32_t i = ts_subtree_child_count(left); i > 0; i--) {
637+
Subtree left_child = ts_subtree_children(left)[i - 1];
638+
Subtree right_child = ts_subtree_children(right)[i - 1];
639+
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(left_child));
640+
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(right_child));
633641
}
634642
}
635-
return 0;
643+
644+
array_clear(&pool->tree_stack);
645+
return result;
636646
}
637647

638648
static inline void ts_subtree_set_has_changes(MutableSubtree *self) {

lib/src/subtree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ Subtree ts_subtree_new_missing_leaf(SubtreePool *, TSSymbol, Length, uint32_t, c
200200
MutableSubtree ts_subtree_make_mut(SubtreePool *, Subtree);
201201
void ts_subtree_retain(Subtree);
202202
void ts_subtree_release(SubtreePool *, Subtree);
203-
int ts_subtree_compare(Subtree, Subtree);
203+
int ts_subtree_compare(Subtree, Subtree, SubtreePool *);
204204
void ts_subtree_set_symbol(MutableSubtree *, TSSymbol, const TSLanguage *);
205205
void ts_subtree_summarize(MutableSubtree, const Subtree *, uint32_t, const TSLanguage *);
206206
void ts_subtree_summarize_children(MutableSubtree, const TSLanguage *);

0 commit comments

Comments
 (0)