From 64c6cf44732d889b8844c8f73b7b67e0383b23f4 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 18 Oct 2019 11:28:59 -0700 Subject: [PATCH] Implicitly reset parser's state if language is changed after a timeout --- cli/src/tests/parser_test.rs | 51 ++++++++++++++++++++++++++++++++++++ lib/src/parser.c | 5 ++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/cli/src/tests/parser_test.rs b/cli/src/tests/parser_test.rs index dc25e081..c9249eb8 100644 --- a/cli/src/tests/parser_test.rs +++ b/cli/src/tests/parser_test.rs @@ -1,3 +1,4 @@ +use super::helpers::allocations; use super::helpers::edits::ReadRecorder; use super::helpers::fixtures::{get_language, get_test_language}; use crate::generate::generate_parser_for_grammar; @@ -567,6 +568,56 @@ fn test_parsing_with_a_timeout_and_a_reset() { ); } +#[test] +fn test_parsing_with_a_timeout_and_implicit_reset() { + allocations::record(|| { + let mut parser = Parser::new(); + parser.set_language(get_language("javascript")).unwrap(); + + parser.set_timeout_micros(5); + let tree = parser.parse( + "[\"ok\", 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]", + None, + ); + assert!(tree.is_none()); + + // Changing the parser's language implicitly resets, discarding + // the previous partial parse. + parser.set_language(get_language("json")).unwrap(); + parser.set_timeout_micros(0); + let tree = parser.parse( + "[null, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]", + None, + ).unwrap(); + assert_eq!( + tree.root_node() + .named_child(0) + .unwrap() + .named_child(0) + .unwrap() + .kind(), + "null" + ); + }); +} + +#[test] +fn test_parsing_with_timeout_and_no_completion() { + allocations::record(|| { + let mut parser = Parser::new(); + parser.set_language(get_language("javascript")).unwrap(); + + parser.set_timeout_micros(5); + let tree = parser.parse( + "[\"ok\", 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]", + None, + ); + assert!(tree.is_none()); + + // drop the parser when it has an unfinished parse + }); +} + // Included Ranges #[test] diff --git a/lib/src/parser.c b/lib/src/parser.c index 88b20845..35772ed0 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -1655,6 +1655,7 @@ TSParser *ts_parser_new(void) { void ts_parser_delete(TSParser *self) { if (!self) return; + ts_parser_set_language(self, NULL); ts_stack_delete(self->stack); if (self->reduce_actions.contents) { array_delete(&self->reduce_actions); @@ -1670,7 +1671,6 @@ void ts_parser_delete(TSParser *self) { ts_parser__set_cached_token(self, 0, NULL_SUBTREE, NULL_SUBTREE); ts_subtree_pool_delete(&self->tree_pool); reusable_node_delete(&self->reusable_node); - ts_parser_set_language(self, NULL); ts_free(self); } @@ -1695,6 +1695,7 @@ bool ts_parser_set_language(TSParser *self, const TSLanguage *language) { } self->language = language; + ts_parser_reset(self); return true; } @@ -1747,7 +1748,7 @@ const TSRange *ts_parser_included_ranges(const TSParser *self, uint32_t *count) } void ts_parser_reset(TSParser *self) { - if (self->language->external_scanner.deserialize) { + if (self->language && self->language->external_scanner.deserialize) { self->language->external_scanner.deserialize(self->external_scanner_payload, NULL, 0); }