From 7f4828254fc4d99fd8e99a8a416de32c0f69e2ef Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 9 Mar 2020 11:30:08 -0700 Subject: [PATCH] Fix criteria for detecting when an aborted parse is resuming --- cli/src/tests/parser_test.rs | 91 ++++++++++++++++++++++-------------- lib/src/parser.c | 8 +++- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/cli/src/tests/parser_test.rs b/cli/src/tests/parser_test.rs index 9a04c70d..0384bce8 100644 --- a/cli/src/tests/parser_test.rs +++ b/cli/src/tests/parser_test.rs @@ -972,59 +972,73 @@ fn test_parsing_with_a_newly_excluded_range() { #[test] fn test_parsing_with_a_newly_included_range() { - let source_code = "
<%= foo() %>
<%= bar() %>"; - let first_code_start_index = source_code.find(" foo").unwrap(); - let first_code_end_index = first_code_start_index + 7; - let second_code_start_index = source_code.find(" bar").unwrap(); - let second_code_end_index = second_code_start_index + 7; - let ranges = [ - Range { - start_byte: first_code_start_index, - end_byte: first_code_end_index, - start_point: Point::new(0, first_code_start_index), - end_point: Point::new(0, first_code_end_index), - }, - Range { - start_byte: second_code_start_index, - end_byte: second_code_end_index, - start_point: Point::new(0, second_code_start_index), - end_point: Point::new(0, second_code_end_index), - }, - ]; + let source_code = "
<%= foo() %>
<%= bar() %><%= baz() %>"; + let range1_start = source_code.find(" foo").unwrap(); + let range2_start = source_code.find(" bar").unwrap(); + let range3_start = source_code.find(" baz").unwrap(); + let range1_end = range1_start + 7; + let range2_end = range2_start + 7; + let range3_end = range3_start + 7; // Parse only the first code directive as JavaScript let mut parser = Parser::new(); parser.set_language(get_language("javascript")).unwrap(); - parser.set_included_ranges(&ranges[0..1]).unwrap(); - let first_tree = parser.parse(source_code, None).unwrap(); + parser + .set_included_ranges(&[simple_range(range1_start, range1_end)]) + .unwrap(); + let tree = parser.parse(source_code, None).unwrap(); assert_eq!( - first_tree.root_node().to_sexp(), + tree.root_node().to_sexp(), concat!( "(program", " (expression_statement (call_expression function: (identifier) arguments: (arguments))))", ) ); - // Parse both the code directives as JavaScript, using the old tree as a reference. - parser.set_included_ranges(&ranges).unwrap(); - let tree = parser.parse(&source_code, Some(&first_tree)).unwrap(); + // Parse both the first and third code directives as JavaScript, using the old tree as a + // reference. + parser + .set_included_ranges(&[ + simple_range(range1_start, range1_end), + simple_range(range3_start, range3_end), + ]) + .unwrap(); + let tree2 = parser.parse(&source_code, Some(&tree)).unwrap(); assert_eq!( - tree.root_node().to_sexp(), + tree2.root_node().to_sexp(), concat!( "(program", " (expression_statement (call_expression function: (identifier) arguments: (arguments)))", " (expression_statement (call_expression function: (identifier) arguments: (arguments))))", ) ); - assert_eq!( - tree.changed_ranges(&first_tree).collect::>(), - vec![Range { - start_byte: first_code_end_index, - end_byte: second_code_end_index, - start_point: Point::new(0, first_code_end_index), - end_point: Point::new(0, second_code_end_index), - }] + tree2.changed_ranges(&tree).collect::>(), + &[simple_range(range1_end, range3_end)] + ); + + // Parse all three code directives as JavaScript, using the old tree as a + // reference. + parser + .set_included_ranges(&[ + simple_range(range1_start, range1_end), + simple_range(range2_start, range2_end), + simple_range(range3_start, range3_end), + ]) + .unwrap(); + let tree3 = parser.parse(&source_code, Some(&tree)).unwrap(); + assert_eq!( + tree3.root_node().to_sexp(), + concat!( + "(program", + " (expression_statement (call_expression function: (identifier) arguments: (arguments)))", + " (expression_statement (call_expression function: (identifier) arguments: (arguments)))", + " (expression_statement (call_expression function: (identifier) arguments: (arguments))))", + ) + ); + assert_eq!( + tree3.changed_ranges(&tree2).collect::>(), + &[simple_range(range2_start + 1, range2_end - 1)] ); } @@ -1088,3 +1102,12 @@ fn test_parsing_with_included_ranges_and_missing_tokens() { assert_eq!(root.start_byte(), 2); assert_eq!(root.child(3).unwrap().start_byte(), 4); } + +fn simple_range(start: usize, end: usize) -> Range { + Range { + start_byte: start, + end_byte: end, + start_point: Point::new(0, start), + end_point: Point::new(0, end), + } +} diff --git a/lib/src/parser.c b/lib/src/parser.c index 5671e724..d4b22730 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -599,6 +599,10 @@ static Subtree ts_parser__reuse_node( uint32_t byte_offset = reusable_node_byte_offset(&self->reusable_node); uint32_t end_byte_offset = byte_offset + ts_subtree_total_bytes(result); + // Do not reuse an EOF node if the included ranges array has changes + // later on in the file. + if (ts_subtree_is_eof(result)) end_byte_offset = UINT32_MAX; + if (byte_offset > position) { LOG("before_reusable_node symbol:%s", TREE_NAME(result)); break; @@ -1611,8 +1615,8 @@ static unsigned ts_parser__condense_stack(TSParser *self) { static bool ts_parser_has_outstanding_parse(TSParser *self) { return ( - self->lexer.current_position.bytes > 0 || - ts_stack_state(self->stack, 0) != 1 + ts_stack_state(self->stack, 0) != 1 || + ts_stack_node_count_since_error(self->stack, 0) != 0 ); }