Ensure that duplicate captures are ordered by pattern index

This commit is contained in:
Max Brunsfeld 2019-09-17 16:27:16 -07:00
parent 82955759c0
commit 374a7ac81e
2 changed files with 64 additions and 12 deletions

View file

@ -555,16 +555,16 @@ fn test_query_captures_with_text_conditions() {
let query = Query::new(
language,
r#"
(identifier) @variable
((identifier) @constant
(match? @constant "^[A-Z]{2,}$"))
((identifier) @constructor
(match? @constructor "^[A-Z]"))
((identifier) @function.builtin
(eq? @function.builtin "require"))
((identifier) @constructor
(match? @constructor "^[A-Z]"))
((identifier) @constant
(match? @constant "^[A-Z]{2,}$"))
(identifier) @variable
"#,
)
.unwrap();
@ -584,13 +584,49 @@ fn test_query_captures_with_text_conditions() {
collect_captures(captures, &query, source),
&[
("variable", "ab"),
("variable", "require"),
("function.builtin", "require"),
("variable", "Cd"),
("variable", "require"),
("constructor", "Cd"),
("variable", "EF"),
("constructor", "EF"),
("variable", "Cd"),
("constant", "EF"),
("constructor", "EF"),
("variable", "EF"),
],
);
});
}
#[test]
fn test_query_captures_with_duplicates() {
allocations::record(|| {
let language = get_language("javascript");
let query = Query::new(
language,
r#"
(variable_declarator
name: (identifier) @function
value: (function))
(identifier) @variable
"#,
)
.unwrap();
let source = "
var x = function() {};
";
let mut parser = Parser::new();
parser.set_language(language).unwrap();
let tree = parser.parse(&source, None).unwrap();
let mut cursor = QueryCursor::new();
let captures = cursor.captures(&query, tree.root_node(), to_callback(source));
assert_eq!(
collect_captures(captures, &query, source),
&[
("function", "x"),
("variable", "x"),
],
);
});

View file

@ -1197,6 +1197,7 @@ bool ts_query_cursor_next_capture(
// match. For a finished capture to be returned, it must be *before*
// this position.
uint32_t first_unfinished_capture_byte = UINT32_MAX;
uint32_t first_unfinished_pattern_index = UINT32_MAX;
for (unsigned i = 0; i < self->states.size; i++) {
const QueryState *state = &self->states.contents[i];
if (state->capture_count > 0) {
@ -1205,8 +1206,15 @@ bool ts_query_cursor_next_capture(
state->capture_list_id
);
uint32_t capture_byte = ts_node_start_byte(captures[0].node);
if (capture_byte < first_unfinished_capture_byte) {
if (
capture_byte < first_unfinished_capture_byte ||
(
capture_byte == first_unfinished_capture_byte &&
state->pattern_index < first_unfinished_pattern_index
)
) {
first_unfinished_capture_byte = capture_byte;
first_unfinished_pattern_index = state->pattern_index;
}
}
}
@ -1214,6 +1222,7 @@ bool ts_query_cursor_next_capture(
// Find the earliest capture in a finished match.
int first_finished_state_index = -1;
uint32_t first_finished_capture_byte = first_unfinished_capture_byte;
uint32_t first_finished_pattern_index = first_unfinished_pattern_index;
for (unsigned i = 0; i < self->finished_states.size; i++) {
const QueryState *state = &self->finished_states.contents[i];
if (state->capture_count > state->consumed_capture_count) {
@ -1224,9 +1233,16 @@ bool ts_query_cursor_next_capture(
uint32_t capture_byte = ts_node_start_byte(
captures[state->consumed_capture_count].node
);
if (capture_byte <= first_finished_capture_byte) {
if (
capture_byte < first_finished_capture_byte ||
(
capture_byte == first_finished_capture_byte &&
state->pattern_index < first_finished_pattern_index
)
) {
first_finished_state_index = i;
first_finished_capture_byte = capture_byte;
first_finished_pattern_index = state->pattern_index;
}
} else {
capture_list_pool_release(