mirror of
https://github.com/tree-sitter/tree-sitter.git
synced 2026-09-10 15:36:29 -04:00
perf(parser): use LookaheadIterator in error recovery's all-symbol scan
In `ts_parser__do_all_potential_reductions`, when `lookahead_symbol` is 0 (error recovery), the code scanned every symbol from 1 to `token_count` calling ts_language_table_entry for each with most returning empty. Replace with `LookaheadIterator` which efficiently visits only symbols with valid actions, yielding 7-20x fewer lookups for typical grammars. Error recovery throughput improves ~29% (JS) / ~39% (C). Valid-code parsing is unaffected.
This commit is contained in:
parent
cb01ffcc3f
commit
c1379718ab
|
|
@ -1098,6 +1098,35 @@ static void ts_parser__accept(
|
|||
ts_stack_halt(self->stack, version);
|
||||
}
|
||||
|
||||
static bool ts_parser__process_candidate_recovery_actions(
|
||||
TSParser *self,
|
||||
const TSParseAction *actions,
|
||||
uint32_t action_count
|
||||
) {
|
||||
bool has_shift_action = false;
|
||||
for (uint32_t i = 0; i < action_count; i++) {
|
||||
TSParseAction action = actions[i];
|
||||
switch (action.type) {
|
||||
case TSParseActionTypeShift:
|
||||
case TSParseActionTypeRecover:
|
||||
if (!action.shift.extra && !action.shift.repetition) has_shift_action = true;
|
||||
break;
|
||||
case TSParseActionTypeReduce:
|
||||
if (action.reduce.child_count > 0)
|
||||
ts_reduce_action_set_add(&self->reduce_actions, (ReduceAction) {
|
||||
.symbol = action.reduce.symbol,
|
||||
.count = action.reduce.child_count,
|
||||
.dynamic_precedence = action.reduce.dynamic_precedence,
|
||||
.production_id = action.reduce.production_id,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return has_shift_action;
|
||||
}
|
||||
|
||||
static bool ts_parser__do_all_potential_reductions(
|
||||
TSParser *self,
|
||||
StackVersion starting_version,
|
||||
|
|
@ -1124,37 +1153,17 @@ static bool ts_parser__do_all_potential_reductions(
|
|||
bool has_shift_action = false;
|
||||
array_clear(&self->reduce_actions);
|
||||
|
||||
TSSymbol first_symbol, end_symbol;
|
||||
if (lookahead_symbol != 0) {
|
||||
first_symbol = lookahead_symbol;
|
||||
end_symbol = lookahead_symbol + 1;
|
||||
} else {
|
||||
first_symbol = 1;
|
||||
end_symbol = self->language->token_count;
|
||||
}
|
||||
|
||||
for (TSSymbol symbol = first_symbol; symbol < end_symbol; symbol++) {
|
||||
TableEntry entry;
|
||||
ts_language_table_entry(self->language, state, symbol, &entry);
|
||||
for (uint32_t j = 0; j < entry.action_count; j++) {
|
||||
TSParseAction action = entry.actions[j];
|
||||
switch (action.type) {
|
||||
case TSParseActionTypeShift:
|
||||
case TSParseActionTypeRecover:
|
||||
if (!action.shift.extra && !action.shift.repetition) has_shift_action = true;
|
||||
break;
|
||||
case TSParseActionTypeReduce:
|
||||
if (action.reduce.child_count > 0)
|
||||
ts_reduce_action_set_add(&self->reduce_actions, (ReduceAction) {
|
||||
.symbol = action.reduce.symbol,
|
||||
.count = action.reduce.child_count,
|
||||
.dynamic_precedence = action.reduce.dynamic_precedence,
|
||||
.production_id = action.reduce.production_id,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ts_language_table_entry(self->language, state, lookahead_symbol, &entry);
|
||||
has_shift_action = ts_parser__process_candidate_recovery_actions(self, entry.actions, entry.action_count);
|
||||
} else {
|
||||
LookaheadIterator iter = ts_language_lookaheads(self->language, state);
|
||||
while (ts_lookahead_iterator__next(&iter)) {
|
||||
// only terminal tokens are valid lookaheads for reduction decisions
|
||||
if (iter.symbol == ts_builtin_sym_end || iter.symbol >= self->language->token_count) continue;
|
||||
if (ts_parser__process_candidate_recovery_actions(self, iter.actions, iter.action_count))
|
||||
has_shift_action = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue