Merge pull request #2406 from tree-sitter/query-alternatives-after-repetitions

Fix miscompilation of queries that start with repetitions followed by alternatives
This commit is contained in:
Amaan Qureshi 2023-07-18 21:56:02 -04:00 committed by GitHub
commit 1c65ca24bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 15 deletions

View file

@ -252,16 +252,14 @@ fn test_node_parent_of_child_by_field_name() {
fn test_node_field_name_for_child() {
let mut parser = Parser::new();
parser.set_language(get_language("c")).unwrap();
let tree = parser.parse("void main() { x + y; }", None).unwrap();
let tree = parser.parse("int w = x + y;", None).unwrap();
let translation_unit_node = tree.root_node();
let binary_expression_node = translation_unit_node
.named_child(0)
let declaration_node = translation_unit_node.named_child(0).unwrap();
let binary_expression_node = declaration_node
.child_by_field_name("declarator")
.unwrap()
.named_child(2)
.unwrap()
.named_child(0)
.unwrap()
.named_child(0)
.child_by_field_name("value")
.unwrap();
assert_eq!(binary_expression_node.field_name_for_child(0), Some("left"));

View file

@ -1826,6 +1826,53 @@ fn test_query_matches_with_alternatives_and_too_many_permutations_to_track() {
});
}
#[test]
fn test_repetitions_before_with_alternatives() {
allocations::record(|| {
let language = get_language("rust");
let query = Query::new(
language,
r#"
(
(line_comment)* @comment
.
[
(struct_item name: (_) @name)
(function_item name: (_) @name)
(enum_item name: (_) @name)
(impl_item type: (_) @name)
]
)
"#,
)
.unwrap();
assert_query_matches(
language,
&query,
r#"
// a
// b
fn c() {}
// d
// e
impl F {}
"#,
&[
(
0,
vec![("comment", "// a"), ("comment", "// b"), ("name", "c")],
),
(
0,
vec![("comment", "// d"), ("comment", "// e"), ("name", "F")],
),
],
);
});
}
#[test]
fn test_query_matches_with_anonymous_tokens() {
allocations::record(|| {

View file

@ -2780,7 +2780,6 @@ TSQuery *ts_query_new(
// then add multiple entries to the pattern map.
if (step->alternative_index != NONE) {
start_step_index = step->alternative_index;
step->alternative_index = NONE;
} else if (wildcard_root_alternative_index != NONE) {
start_step_index = wildcard_root_alternative_index;
wildcard_root_alternative_index = NONE;
@ -3008,11 +3007,43 @@ void ts_query_cursor_set_match_limit(TSQueryCursor *self, uint32_t limit) {
self->capture_list_pool.max_capture_list_count = limit;
}
#ifdef DEBUG_EXECUTE_QUERY
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define LOG(...)
#endif
void ts_query_cursor_exec(
TSQueryCursor *self,
const TSQuery *query,
TSNode node
) {
if (query) {
LOG("query steps:\n");
for (unsigned i = 0; i < query->steps.size; i++) {
QueryStep *step = &query->steps.contents[i];
LOG(" %u: {", i);
if (step->depth == PATTERN_DONE_MARKER) {
LOG("DONE");
} else if (step->is_dead_end) {
LOG("dead_end");
} else if (step->is_pass_through) {
LOG("pass_through");
} else if (step->symbol != WILDCARD_SYMBOL) {
LOG("symbol: %s", query->language->symbol_names[step->symbol]);
} else {
LOG("symbol: *");
}
if (step->field) {
LOG(", field: %s", query->language->field_names[step->field]);
}
if (step->alternative_index != NONE) {
LOG(", alternative: %u", step->alternative_index);
}
LOG("},\n");
}
}
array_clear(&self->states);
array_clear(&self->finished_states);
ts_tree_cursor_reset(&self->cursor, node);
@ -3180,12 +3211,6 @@ void ts_query_cursor__compare_captures(
}
}
#ifdef DEBUG_EXECUTE_QUERY
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define LOG(...)
#endif
static void ts_query_cursor__add_state(
TSQueryCursor *self,
const PatternEntry *pattern