query: Avoid early-returning captures due to predicates

This commit is contained in:
Max Brunsfeld 2020-08-18 13:01:45 -07:00
parent 604f9e8148
commit bd42729a41
2 changed files with 70 additions and 17 deletions

View file

@ -2414,6 +2414,22 @@ fn test_query_is_definite() {
("[", true),
],
},
Row {
language: get_language("javascript"),
pattern: r#"
(subscript_expression
object: (member_expression
object: (identifier) @obj
property: (property_identifier) @prop)
"["
(#match? @prop "foo"))
"#,
results_by_symbol: &[
("identifier", false),
("property_identifier", false),
("[", true),
],
},
];
allocations::record(|| {
@ -2431,7 +2447,10 @@ fn test_query_is_definite() {
query.pattern_is_definite(0, symbol, 0),
*is_definite,
"Pattern: {:?}, symbol: {}, expected is_definite to be {}",
row.pattern,
row.pattern
.split_ascii_whitespace()
.collect::<Vec<_>>()
.join(" "),
symbol_name,
is_definite,
)

View file

@ -91,9 +91,9 @@ typedef struct {
} PatternEntry;
typedef struct {
Slice steps;
Slice predicate_steps;
uint32_t start_byte;
uint32_t start_step;
} QueryPattern;
/*
@ -1146,7 +1146,7 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *impossible_index
unsigned exists;
array_search_sorted_by(
&self->patterns, 0,
.start_step, parent_step_index,
.steps.offset, parent_step_index,
impossible_index, &exists
);
result = false;
@ -1156,12 +1156,45 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *impossible_index
// In order for a step to be definite, all of its child steps must be definite,
// and all of its later sibling steps must be definite. Propagate any indefiniteness
// upward and backward through the pattern trees.
bool all_later_children_definite = true;
for (unsigned i = self->steps.size - 1; i + 1 > 0; i--) {
QueryStep *step = &self->steps.contents[i];
if (step->depth == PATTERN_DONE_MARKER) {
all_later_children_definite = true;
} else {
Array(uint16_t) predicate_capture_ids = array_new();
for (unsigned i = 0; i < self->patterns.size; i++) {
QueryPattern *pattern = &self->patterns.contents[i];
// Gather all of the captures that are used in predicates for this pattern.
array_clear(&predicate_capture_ids);
for (
unsigned start = pattern->predicate_steps.offset,
end = start + pattern->predicate_steps.length,
j = start; j < end; j++
) {
TSQueryPredicateStep *step = &self->predicate_steps.contents[j];
if (step->type == TSQueryPredicateStepTypeCapture) {
array_insert_sorted_by(&predicate_capture_ids, 0, , step->value_id);
}
}
bool all_later_children_definite = true;
for (
unsigned start = pattern->steps.offset,
end = start + pattern->steps.length,
j = end - 1; j + 1 > start; j--
) {
QueryStep *step = &self->steps.contents[j];
// If this step has a capture that is used in a predicate,
// then it is not definite.
for (unsigned k = 0; k < MAX_STEP_CAPTURE_COUNT; k++) {
uint16_t capture_id = step->capture_ids[k];
if (capture_id == NONE) break;
unsigned index, exists;
array_search_sorted_by(&predicate_capture_ids, 0, , capture_id, &index, &exists);
if (exists) {
step->is_definite = false;
break;
}
}
// If a step is not definite, then none of its predecessors can be definite.
if (!all_later_children_definite) step->is_definite = false;
if (!step->is_definite) all_later_children_definite = false;
}
@ -1197,6 +1230,7 @@ static bool ts_query__analyze_patterns(TSQuery *self, unsigned *impossible_index
array_delete(&next_states);
array_delete(&final_step_indices);
array_delete(&parent_step_indices);
array_delete(&predicate_capture_ids);
state_predecessor_map_delete(&predecessor_map);
return result;
@ -1238,7 +1272,6 @@ static TSQueryError ts_query__parse_predicate(
predicate_name,
length
);
array_back(&self->patterns)->predicate_steps.length++;
array_push(&self->predicate_steps, ((TSQueryPredicateStep) {
.type = TSQueryPredicateStepTypeString,
.value_id = id,
@ -1249,7 +1282,6 @@ static TSQueryError ts_query__parse_predicate(
if (stream->next == ')') {
stream_advance(stream);
stream_skip_whitespace(stream);
array_back(&self->patterns)->predicate_steps.length++;
array_push(&self->predicate_steps, ((TSQueryPredicateStep) {
.type = TSQueryPredicateStepTypeDone,
.value_id = 0,
@ -1278,7 +1310,6 @@ static TSQueryError ts_query__parse_predicate(
return TSQueryErrorCapture;
}
array_back(&self->patterns)->predicate_steps.length++;
array_push(&self->predicate_steps, ((TSQueryPredicateStep) {
.type = TSQueryPredicateStepTypeCapture,
.value_id = capture_id,
@ -1318,7 +1349,6 @@ static TSQueryError ts_query__parse_predicate(
string_content,
length
);
array_back(&self->patterns)->predicate_steps.length++;
array_push(&self->predicate_steps, ((TSQueryPredicateStep) {
.type = TSQueryPredicateStepTypeString,
.value_id = id,
@ -1338,7 +1368,6 @@ static TSQueryError ts_query__parse_predicate(
symbol_start,
length
);
array_back(&self->patterns)->predicate_steps.length++;
array_push(&self->predicate_steps, ((TSQueryPredicateStep) {
.type = TSQueryPredicateStepTypeString,
.value_id = id,
@ -1778,14 +1807,19 @@ TSQuery *ts_query_new(
while (stream.input < stream.end) {
uint32_t pattern_index = self->patterns.size;
uint32_t start_step_index = self->steps.size;
uint32_t start_predicate_step_index = self->predicate_steps.size;
array_push(&self->patterns, ((QueryPattern) {
.predicate_steps = (Slice) {.offset = self->predicate_steps.size, .length = 0},
.steps = (Slice) {.offset = start_step_index},
.predicate_steps = (Slice) {.offset = start_predicate_step_index},
.start_byte = stream.input - source,
.start_step = self->steps.size,
}));
*error_type = ts_query__parse_pattern(self, &stream, 0, false);
array_push(&self->steps, query_step__new(0, PATTERN_DONE_MARKER, false));
QueryPattern *pattern = array_back(&self->patterns);
pattern->steps.length = self->steps.size - start_step_index;
pattern->predicate_steps.length = self->predicate_steps.size - start_predicate_step_index;
// If any pattern could not be parsed, then report the error information
// and terminate.
if (*error_type) {
@ -1903,7 +1937,7 @@ bool ts_query_pattern_is_definite(
TSSymbol symbol,
uint32_t index
) {
uint32_t step_index = self->patterns.contents[pattern_index].start_step;
uint32_t step_index = self->patterns.contents[pattern_index].steps.offset;
QueryStep *step = &self->steps.contents[step_index];
for (; step->depth != PATTERN_DONE_MARKER; step++) {
bool does_match = symbol ?