diff --git a/cli/src/tests/parser_test.rs b/cli/src/tests/parser_test.rs index 392d1a9d..b2b2560e 100644 --- a/cli/src/tests/parser_test.rs +++ b/cli/src/tests/parser_test.rs @@ -395,6 +395,18 @@ fn test_parsing_after_editing_end_of_code() { assert_eq!(recorder.strings_read(), vec![" * ", "abc.d)",]); } +#[test] +fn test_parsing_empty_file_with_reused_tree() { + let mut parser = Parser::new(); + parser.set_language(get_language("rust")).unwrap(); + + let tree = parser.parse("", None); + parser.parse("", tree.as_ref()); + + let tree = parser.parse("\n ", None); + parser.parse("\n ", tree.as_ref()); +} + // Thread safety #[test] diff --git a/lib/src/reusable_node.h b/lib/src/reusable_node.h index 9cba9519..e5ccaa2a 100644 --- a/lib/src/reusable_node.h +++ b/lib/src/reusable_node.h @@ -20,15 +20,6 @@ static inline void reusable_node_clear(ReusableNode *self) { self->last_external_token = NULL_SUBTREE; } -static inline void reusable_node_reset(ReusableNode *self, Subtree tree) { - reusable_node_clear(self); - array_push(&self->stack, ((StackEntry) { - .tree = tree, - .child_index = 0, - .byte_offset = 0, - })); -} - static inline Subtree reusable_node_tree(ReusableNode *self) { return self->stack.size > 0 ? self->stack.contents[self->stack.size - 1].tree @@ -86,3 +77,19 @@ static inline void reusable_node_advance_past_leaf(ReusableNode *self) { while (reusable_node_descend(self)) {} reusable_node_advance(self); } + +static inline void reusable_node_reset(ReusableNode *self, Subtree tree) { + reusable_node_clear(self); + array_push(&self->stack, ((StackEntry) { + .tree = tree, + .child_index = 0, + .byte_offset = 0, + })); + + // Never reuse the root node, because it has a non-standard internal structure + // due to transformations that are applied when it is accepted: adding the EOF + // child and any extra children. + if (!reusable_node_descend(self)) { + reusable_node_clear(self); + } +}