Fix logic for aborting failed matches

This commit is contained in:
Max Brunsfeld 2020-05-08 14:15:25 -07:00
parent b0671aea6a
commit 9c0535cea6
2 changed files with 40 additions and 8 deletions

View file

@ -595,6 +595,33 @@ fn test_query_matches_with_top_level_repetitions() {
});
}
#[test]
fn test_query_matches_with_non_terminal_repetitions_within_root() {
allocations::record(|| {
let language = get_language("javascript");
let query = Query::new(
language,
r#"
(*
(expression_statement
(identifier) @id)+)
"#,
)
.unwrap();
assert_query_matches(
language,
&query,
r#"
a;
b;
c;
"#,
&[(0, vec![("id", "a"), ("id", "b"), ("id", "c")])],
);
});
}
#[test]
fn test_query_matches_with_nested_repetitions() {
allocations::record(|| {

View file

@ -1407,7 +1407,17 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
if (self->ascending) {
LOG("leave node. type:%s\n", ts_node_type(ts_tree_cursor_current_node(&self->cursor)));
// When leaving a node, remove any states that cannot make further progress.
// Leave this node by stepping to its next sibling or to its parent.
bool did_move = true;
if (ts_tree_cursor_goto_next_sibling(&self->cursor)) {
self->ascending = false;
} else if (ts_tree_cursor_goto_parent(&self->cursor)) {
self->depth--;
} else {
did_move = false;
}
// After leaving a node, remove any states that cannot make further progress.
uint32_t deleted_count = 0;
for (unsigned i = 0, n = self->states.size; i < n; i++) {
QueryState *state = &self->states.contents[i];
@ -1416,7 +1426,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// If a state completed its pattern inside of this node, but was deferred from finishing
// in order to search for longer matches, mark it as finished.
if (step->depth == PATTERN_DONE_MARKER) {
if (state->start_depth > self->depth) {
if (state->start_depth > self->depth || !did_move) {
LOG(" finish pattern %u\n", state->pattern_index);
state->id = self->next_state_id++;
array_push(&self->finished_states, *state);
@ -1447,12 +1457,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
}
self->states.size -= deleted_count;
// Leave this node by stepping to its next sibling or to its parent.
if (ts_tree_cursor_goto_next_sibling(&self->cursor)) {
self->ascending = false;
} else if (ts_tree_cursor_goto_parent(&self->cursor)) {
self->depth--;
} else {
if (!did_move) {
return self->finished_states.size > 0;
}
} else {