pub trait ParseListener: Send {
// Required method
fn enter_every_rule(
&mut self,
event: &EnterRuleEvent<'_>,
) -> Result<(), AntlrError>;
// Provided method
fn exit_every_rule(&mut self, rule_index: usize) { ... }
}Expand description
Receives committed rule enter/exit events during recognition, matching
ANTLR’s addParseListener contract (Parser::add_parse_listener,
also inherent on BaseParser and generated parsers).
Events fire on the generated recursive-descent path as rules are entered
and exited, with left-recursive operator loops following upstream’s
timing exactly: each loop pass first exits the outgoing iteration
(recRuleSetPrevCtx) and then enters the new expansion
(pushNewRecursionContext firing triggerEnterRuleEvent), so live
listener depth never accumulates across a flat operator chain —
a + a + … + a peaks at depth 2 like every ANTLR target. On expansion
events, EnterRuleEvent::current anchors at the operator-side
lookahead (the token the expansion starts at), whereas Java’s
ctx.start reaches back to the whole expression’s first token — anchor
diagnostics accordingly. Enter events fire in registration order and
exit events in reverse registration order, matching upstream. Enter/exit
calls balance on every completed path, including error recovery and
aborts inside operator loops — with one exception shared with Java: an
ordinary rule’s enter that returns Err receives no matching exit
(upstream calls enterRule outside the generated try/finally, so a
throwing listener skips exitRule the same way). Listener state shared
across parses via Arc should be reset after an abort (the unmatched
ordinary-rule enter leaves counters one high).
Divergence from Java to know about: upstream generated rule methods run only on the committed parse, while this runtime may re-enter a rule while recovering from a syntax error — such retries deliver additional balanced enter/exit pairs. Depth counters and resource bounds (the primary use case) are unaffected; exact once-per-node collectors should prefer the post-parse tree walker.
enter_every_rule is fallible: returning Err aborts the parse with
that error. The abort is sticky through rule-level recovery — the parse
fails even when recovery could have produced a tree, mirroring how a
thrown exception escapes ANTLR’s triggerEnterRuleEvent. Rules the
generator emitted no body for (interpreter-only fallback) do not fire
events; when any parse listener is registered, generated dispatch routes
ATN-preferred rules through their generated bodies so real grammars
observe every rule.
Cost: with no listener registered, dispatch pays one emptiness check per
rule boundary (benchmarked at baseline). With one registered, dispatch
itself is a few percent; on grammars where the generator classified rules
ATN-preferred, the dominant cost is the routing override above — the same
one Parser::set_max_rule_depth takes — which trades that fast path
for observability. Grammars without ATN-preferred rules (most small DSLs)
pay only the dispatch.
Required Methods§
Sourcefn enter_every_rule(
&mut self,
event: &EnterRuleEvent<'_>,
) -> Result<(), AntlrError>
fn enter_every_rule( &mut self, event: &EnterRuleEvent<'_>, ) -> Result<(), AntlrError>
Called when a generated rule is entered, before its body runs, and once per left-recursive operator expansion.
Returning Err aborts the parse with the given error.
Provided Methods§
Sourcefn exit_every_rule(&mut self, rule_index: usize)
fn exit_every_rule(&mut self, rule_index: usize)
Called when a generated rule exits, after its body (and any rule-level error recovery) finished, and once per left-recursive operator expansion as the rule unrolls.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl<T: ParseListener + ?Sized> ParseListener for Box<T>
Boxed listeners forward to their inner implementation, so the boxes
returned by Parser::remove_parse_listeners can be re-registered
through Parser::add_parse_listener unchanged.
impl<T: ParseListener + ?Sized> ParseListener for Box<T>
Boxed listeners forward to their inner implementation, so the boxes
returned by Parser::remove_parse_listeners can be re-registered
through Parser::add_parse_listener unchanged.