Skip to main content

ParseListener

Trait ParseListener 

Source
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§

Source

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§

Source

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.

Source§

fn enter_every_rule( &mut self, event: &EnterRuleEvent<'_>, ) -> Result<(), AntlrError>

Source§

fn exit_every_rule(&mut self, rule_index: usize)

Implementors§