Skip to main content

antlr4_runtime/
lexer.rs

1use std::cell::RefCell;
2use std::collections::{BTreeSet, HashMap, VecDeque};
3use std::hash::BuildHasherDefault;
4use std::rc::Rc;
5
6use crate::atn::LexerAtn;
7use crate::char_stream::{CharStream, TextInterval};
8use crate::int_stream::EOF;
9use crate::prediction::PredictionFxHasher;
10use crate::recognizer::{Recognizer, RecognizerData};
11use crate::token::{
12    DEFAULT_CHANNEL, INVALID_TOKEN_TYPE, TokenId, TokenSink, TokenSourceError, TokenSpec,
13    TokenStoreError,
14};
15
16#[allow(clippy::disallowed_types)]
17type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PredictionFxHasher>>;
18
19pub const SKIP: i32 = -3;
20pub const MORE: i32 = -2;
21pub const DEFAULT_MODE: i32 = 0;
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct LexerMode(pub i32);
25
26/// Grammar-specific lexer action reached on the accepted ATN path.
27///
28/// ANTLR serializes embedded lexer actions as `(rule_index, action_index)`
29/// pairs. The runtime also records the input position where the action was
30/// reached so generated code can evaluate templates such as `Text()` at the
31/// same point as a generated ANTLR lexer, not only at the token end.
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct LexerCustomAction {
34    rule_index: i32,
35    action_index: i32,
36    position: usize,
37}
38
39impl LexerCustomAction {
40    /// Creates a custom lexer action event from serialized ATN metadata.
41    pub const fn new(rule_index: i32, action_index: i32, position: usize) -> Self {
42        Self {
43            rule_index,
44            action_index,
45            position,
46        }
47    }
48
49    /// Lexer rule index that owns the embedded action.
50    pub const fn rule_index(self) -> i32 {
51        self.rule_index
52    }
53
54    /// Per-rule action index assigned by ANTLR serialization.
55    pub const fn action_index(self) -> i32 {
56        self.action_index
57    }
58
59    /// Character-stream position at which the action transition was reached.
60    pub const fn position(self) -> usize {
61        self.position
62    }
63}
64
65/// Grammar-specific lexer predicate reached while exploring an ATN path.
66#[derive(Clone, Copy, Debug, Eq, PartialEq)]
67pub struct LexerPredicate {
68    rule_index: usize,
69    pred_index: usize,
70    position: usize,
71}
72
73impl LexerPredicate {
74    /// Creates a lexer predicate event from serialized ATN metadata.
75    pub const fn new(rule_index: usize, pred_index: usize, position: usize) -> Self {
76        Self {
77            rule_index,
78            pred_index,
79            position,
80        }
81    }
82
83    /// Lexer rule index that owns the predicate transition.
84    pub const fn rule_index(self) -> usize {
85        self.rule_index
86    }
87
88    /// Per-rule predicate index assigned by ANTLR serialization.
89    pub const fn pred_index(self) -> usize {
90        self.pred_index
91    }
92
93    /// Character-stream position at which the predicate is evaluated.
94    pub const fn position(self) -> usize {
95        self.position
96    }
97}
98
99/// Lexer reference held by [`LexerSemCtx`]. A semantic *predicate* is evaluated
100/// speculatively and gets a shared borrow; a *custom action* runs on the
101/// committed path and gets a mutable borrow so a hook can change lexer state
102/// and pending token emission, matching the closure-based `custom_action` API.
103#[derive(Debug)]
104enum LexerRef<'a, I>
105where
106    I: CharStream,
107{
108    Shared(&'a BaseLexer<I>),
109    Mut(&'a mut BaseLexer<I>),
110}
111
112impl<I> LexerRef<'_, I>
113where
114    I: CharStream,
115{
116    const fn get(&self) -> &BaseLexer<I> {
117        match self {
118            LexerRef::Shared(lexer) => lexer,
119            LexerRef::Mut(lexer) => lexer,
120        }
121    }
122}
123
124/// Runtime view passed to lexer semantic hooks.
125#[derive(Debug)]
126pub struct LexerSemCtx<'a, I>
127where
128    I: CharStream,
129{
130    lexer: LexerRef<'a, I>,
131    rule_index: usize,
132    coordinate_index: usize,
133    position: usize,
134}
135
136impl<'a, I> LexerSemCtx<'a, I>
137where
138    I: CharStream,
139{
140    pub(crate) const fn new(
141        lexer: &'a BaseLexer<I>,
142        rule_index: usize,
143        coordinate_index: usize,
144        position: usize,
145    ) -> Self {
146        Self {
147            lexer: LexerRef::Shared(lexer),
148            rule_index,
149            coordinate_index,
150            position,
151        }
152    }
153
154    /// Builds a context with a mutable lexer borrow, for a custom-action hook
155    /// that may change lexer and pending-token state.
156    pub(crate) const fn new_mut(
157        lexer: &'a mut BaseLexer<I>,
158        rule_index: usize,
159        coordinate_index: usize,
160        position: usize,
161    ) -> Self {
162        Self {
163            lexer: LexerRef::Mut(lexer),
164            rule_index,
165            coordinate_index,
166            position,
167        }
168    }
169
170    /// Lexer rule index that owns the predicate/action coordinate.
171    #[must_use]
172    pub const fn rule_index(&self) -> usize {
173        self.rule_index
174    }
175
176    /// Predicate/action index inside the owning lexer rule.
177    #[must_use]
178    pub const fn coordinate_index(&self) -> usize {
179        self.coordinate_index
180    }
181
182    /// Absolute input position where the predicate/action transition fired.
183    #[must_use]
184    pub const fn position(&self) -> usize {
185        self.position
186    }
187
188    /// Lexer mode at this coordinate.
189    #[must_use]
190    pub fn mode(&self) -> i32 {
191        self.lexer.get().mode()
192    }
193
194    /// Current source column.
195    #[must_use]
196    pub const fn column(&self) -> usize {
197        self.lexer.get().column()
198    }
199
200    /// Source column at [`Self::position`].
201    #[must_use]
202    pub fn position_column(&self) -> usize {
203        self.lexer.get().column_at(self.position)
204    }
205
206    /// Column captured at the current token start.
207    #[must_use]
208    pub const fn token_start_column(&self) -> usize {
209        self.lexer.get().token_start_column()
210    }
211
212    /// Text matched from token start to this coordinate.
213    #[must_use]
214    pub fn text_so_far(&self) -> String {
215        self.lexer.get().token_text_until(self.position)
216    }
217
218    /// Character at a one-based lookahead/lookbehind offset.
219    ///
220    /// Predicates read relative to their speculative ATN coordinate. Actions
221    /// read relative to the committed input cursor, including characters
222    /// consumed by an earlier action.
223    pub fn la(&mut self, offset: isize) -> i32 {
224        match &mut self.lexer {
225            LexerRef::Shared(lexer) => lexer.lookahead_at(self.position, offset),
226            LexerRef::Mut(lexer) => lexer.input_mut().la(offset),
227        }
228    }
229
230    /// Absolute source index where the current token begins.
231    #[must_use]
232    pub const fn token_start(&self) -> usize {
233        self.lexer.get().token_start()
234    }
235
236    /// Pending type of the token being matched.
237    #[must_use]
238    pub const fn token_type(&self) -> i32 {
239        self.lexer.get().token_type()
240    }
241
242    /// Pending channel of the token being matched.
243    #[must_use]
244    pub const fn channel(&self) -> i32 {
245        self.lexer.get().channel()
246    }
247
248    /// Sets the pending emitted token type. Action context only; see
249    /// [`Self::set_mode`] for the return value.
250    pub const fn set_type(&mut self, token_type: i32) -> bool {
251        match &mut self.lexer {
252            LexerRef::Mut(lexer) => {
253                lexer.set_type(token_type);
254                true
255            }
256            LexerRef::Shared(_) => false,
257        }
258    }
259
260    /// Sets the pending emitted token channel. Action context only; see
261    /// [`Self::set_mode`] for the return value.
262    pub const fn set_channel(&mut self, channel: i32) -> bool {
263        match &mut self.lexer {
264            LexerRef::Mut(lexer) => {
265                lexer.set_channel(channel);
266                true
267            }
268            LexerRef::Shared(_) => false,
269        }
270    }
271
272    /// Consumes one input character and updates source position tracking.
273    /// Action context only; returns whether the operation was available.
274    pub fn consume(&mut self) -> bool {
275        match &mut self.lexer {
276            LexerRef::Mut(lexer) => {
277                lexer.consume_char();
278                true
279            }
280            LexerRef::Shared(_) => false,
281        }
282    }
283
284    /// Marks the current match as skipped. Action context only.
285    pub const fn skip(&mut self) -> bool {
286        self.set_type(SKIP)
287    }
288
289    /// Extends the current token with another lexer-rule match. Action context
290    /// only.
291    pub const fn more(&mut self) -> bool {
292        self.set_type(MORE)
293    }
294
295    /// Repositions the committed accept cursor. Action context only.
296    pub fn reset_accept_position(&mut self, index: usize) -> bool {
297        match &mut self.lexer {
298            LexerRef::Mut(lexer) => {
299                lexer.reset_accept_position(index);
300                true
301            }
302            LexerRef::Shared(_) => false,
303        }
304    }
305
306    /// Moves the current token start forward within the committed match.
307    ///
308    /// This is used after queueing a prefix token so automatic emission covers
309    /// only the remaining suffix. Returns `false` for predicate contexts or an
310    /// index outside the current token span.
311    pub fn set_token_start(&mut self, index: usize) -> bool {
312        match &mut self.lexer {
313            LexerRef::Mut(lexer) => lexer.set_token_start(index),
314            LexerRef::Shared(_) => false,
315        }
316    }
317
318    /// Queues an additional token on the current channel.
319    ///
320    /// The queued token spans the current token start through `stop`
321    /// (inclusive) and is returned before the match's automatically emitted
322    /// token. Action context only.
323    pub fn enqueue_token(&mut self, token_type: i32, stop: usize) -> bool {
324        let channel = self.channel();
325        self.enqueue_token_with_channel(token_type, channel, stop)
326    }
327
328    /// Queues an additional token on an explicit channel. See
329    /// [`Self::enqueue_token`].
330    pub fn enqueue_token_with_channel(
331        &mut self,
332        token_type: i32,
333        channel: i32,
334        stop: usize,
335    ) -> bool {
336        match &mut self.lexer {
337            LexerRef::Mut(lexer) => {
338                lexer.enqueue_token(token_type, channel, stop, None);
339                true
340            }
341            LexerRef::Shared(_) => false,
342        }
343    }
344
345    /// Sets the current lexer mode. Available only from a custom-action hook
346    /// (the mutable-borrow context); a no-op with a warning path for the
347    /// speculative predicate context, where mutating lexer state is invalid.
348    ///
349    /// Returns `true` if the mutation was applied (action context), `false` if
350    /// it was ignored (predicate context).
351    pub fn set_mode(&mut self, mode: i32) -> bool {
352        match &mut self.lexer {
353            LexerRef::Mut(lexer) => {
354                lexer.set_mode(mode);
355                true
356            }
357            LexerRef::Shared(_) => false,
358        }
359    }
360
361    /// Pushes the current mode and switches to `mode`. Action context only; see
362    /// [`Self::set_mode`] for the return value.
363    pub fn push_mode(&mut self, mode: i32) -> bool {
364        match &mut self.lexer {
365            LexerRef::Mut(lexer) => {
366                lexer.push_mode(mode);
367                true
368            }
369            LexerRef::Shared(_) => false,
370        }
371    }
372
373    /// Pops the mode stack, restoring the previous mode. Action context only;
374    /// returns the popped mode (`None` if the stack was empty or this is a
375    /// predicate context).
376    pub fn pop_mode(&mut self) -> Option<i32> {
377        match &mut self.lexer {
378            LexerRef::Mut(lexer) => lexer.pop_mode(),
379            LexerRef::Shared(_) => None,
380        }
381    }
382}
383
384/// Mutable lexer state exposed at lifecycle boundaries that have no ATN
385/// semantic coordinate.
386///
387/// The context is used before a token request starts matching, after an
388/// accepted path has applied its actions but before emission, and while a
389/// lexer is reset for reuse. [`Self::accept_position`] is present only at the
390/// post-accept boundary.
391#[derive(Debug)]
392pub struct LexerLifecycleCtx<'a, I>
393where
394    I: CharStream,
395{
396    lexer: &'a mut BaseLexer<I>,
397    accept_position: Option<usize>,
398}
399
400impl<'a, I> LexerLifecycleCtx<'a, I>
401where
402    I: CharStream,
403{
404    pub(crate) const fn new(lexer: &'a mut BaseLexer<I>, accept_position: Option<usize>) -> Self {
405        Self {
406            lexer,
407            accept_position,
408        }
409    }
410
411    /// Original input boundary selected by the accepted ATN path.
412    ///
413    /// A post-accept hook may move the committed cursor away from this
414    /// boundary with [`Self::reset_accept_position`].
415    #[must_use]
416    pub const fn accept_position(&self) -> Option<usize> {
417        self.accept_position
418    }
419
420    /// Current committed input position.
421    #[must_use]
422    pub fn input_position(&self) -> usize {
423        self.lexer.input().index()
424    }
425
426    /// Current lexer mode.
427    #[must_use]
428    pub const fn mode(&self) -> i32 {
429        self.lexer.mode
430    }
431
432    /// Current source line.
433    #[must_use]
434    pub const fn line(&self) -> usize {
435        self.lexer.line()
436    }
437
438    /// Current source column.
439    #[must_use]
440    pub const fn column(&self) -> usize {
441        self.lexer.column()
442    }
443
444    /// Absolute source index where the current token begins.
445    #[must_use]
446    pub const fn token_start(&self) -> usize {
447        self.lexer.token_start()
448    }
449
450    /// Source line captured at the current token start.
451    #[must_use]
452    pub const fn token_start_line(&self) -> usize {
453        self.lexer.token_start_line()
454    }
455
456    /// Source column captured at the current token start.
457    #[must_use]
458    pub const fn token_start_column(&self) -> usize {
459        self.lexer.token_start_column()
460    }
461
462    /// Pending type of the token being matched.
463    #[must_use]
464    pub const fn token_type(&self) -> i32 {
465        self.lexer.token_type()
466    }
467
468    /// Pending channel of the token being matched.
469    #[must_use]
470    pub const fn channel(&self) -> i32 {
471        self.lexer.channel()
472    }
473
474    /// Number of tokens waiting to be returned before another ATN match.
475    #[must_use]
476    pub fn pending_token_count(&self) -> usize {
477        self.lexer.pending_tokens.len()
478    }
479
480    /// Text from the current token start through the committed input cursor.
481    #[must_use]
482    pub fn token_text(&self) -> String {
483        self.lexer.token_text()
484    }
485
486    /// Text selected by the original accepted ATN path.
487    ///
488    /// Returns `None` outside the post-accept callback.
489    #[must_use]
490    pub fn accepted_text(&self) -> Option<String> {
491        self.accept_position
492            .map(|position| self.lexer.token_text_until(position))
493    }
494
495    /// Character at a one-based lookahead/lookbehind offset from the
496    /// committed input cursor.
497    pub fn la(&mut self, offset: isize) -> i32 {
498        self.lexer.la(offset)
499    }
500
501    /// Consumes one input character and updates source position tracking.
502    pub fn consume(&mut self) {
503        self.lexer.consume_char();
504    }
505
506    /// Overrides the pending emitted token type.
507    pub const fn set_type(&mut self, token_type: i32) {
508        self.lexer.set_type(token_type);
509    }
510
511    /// Overrides the pending emitted token channel.
512    pub const fn set_channel(&mut self, channel: i32) {
513        self.lexer.set_channel(channel);
514    }
515
516    /// Marks the current match as skipped.
517    pub const fn skip(&mut self) {
518        self.lexer.skip();
519    }
520
521    /// Extends the current token with another lexer-rule match.
522    pub const fn more(&mut self) {
523        self.lexer.more();
524    }
525
526    /// Repositions the committed accept cursor.
527    pub fn reset_accept_position(&mut self, index: usize) {
528        self.lexer.reset_accept_position(index);
529    }
530
531    /// Moves the current token start forward within the committed match.
532    pub fn set_token_start(&mut self, index: usize) -> bool {
533        self.lexer.set_token_start(index)
534    }
535
536    /// Queues an additional token on the current channel.
537    pub fn enqueue_token(&mut self, token_type: i32, stop: usize) {
538        self.enqueue_token_with_channel(token_type, self.channel(), stop);
539    }
540
541    /// Queues an additional token on an explicit channel.
542    pub fn enqueue_token_with_channel(&mut self, token_type: i32, channel: i32, stop: usize) {
543        self.lexer.enqueue_token(token_type, channel, stop, None);
544    }
545
546    /// Sets the current lexer mode.
547    pub fn set_mode(&mut self, mode: i32) {
548        self.lexer.set_mode(mode);
549    }
550
551    /// Pushes the current mode and switches to `mode`.
552    pub fn push_mode(&mut self, mode: i32) {
553        self.lexer.push_mode(mode);
554    }
555
556    /// Pops the mode stack, restoring the previous mode.
557    pub fn pop_mode(&mut self) -> Option<i32> {
558        self.lexer.pop_mode()
559    }
560}
561
562pub trait Lexer: Recognizer {
563    fn mode(&self) -> i32;
564    fn set_mode(&mut self, mode: i32);
565    fn push_mode(&mut self, mode: i32);
566    fn pop_mode(&mut self) -> Option<i32>;
567}
568
569#[derive(Clone, Debug)]
570pub struct BaseLexer<I> {
571    input: I,
572    data: RecognizerData,
573    has_source_text: bool,
574    mode: i32,
575    mode_stack: Vec<i32>,
576    token_type: i32,
577    channel: i32,
578    token_start: usize,
579    token_start_line: usize,
580    token_start_column: usize,
581    line: usize,
582    column: usize,
583    hit_eof: bool,
584    force_interpreted: bool,
585    errors: RefCell<Vec<TokenSourceError>>,
586    semantic_error_coordinates: RefCell<BTreeSet<(u8, usize, usize, usize)>>,
587    pending_tokens: VecDeque<TokenSpec>,
588    dfa_cache: Rc<RefCell<LexerDfaCache>>,
589}
590
591/// Learned lexer DFA: the input-independent state/transition tables built up
592/// by ATN simulation.
593///
594/// Semantic-predicate-dependent states are stored flagged and every consumer
595/// re-simulates them instead of trusting their cached data, so the cache can
596/// be shared across lexer instances (and inputs) for the same ATN — see
597/// [`BaseLexer::with_shared_dfa`].
598#[derive(Clone, Debug, Default)]
599struct LexerDfaCache {
600    state_numbers: FxHashMap<LexerDfaKey, usize>,
601    accept_predictions: FxHashMap<usize, i32>,
602    /// `showDFA` edge trace. Lives with the tables it describes, so a lexer
603    /// on a shared cache reports the accumulated DFA — matching the reference
604    /// runtimes, whose static shared DFA is what `showDFA` prints.
605    edges: BTreeSet<LexerDfaEdge>,
606    /// Dense by DFA state number (states are numbered contiguously from 0).
607    cached_states: Vec<Option<Rc<LexerDfaCachedState>>>,
608    /// Per-source-state edge rows for symbols in `0..DENSE_EDGE_SYMBOLS`,
609    /// allocated lazily on the first cached transition out of a state. The
610    /// per-character lookup is then one bounds check and an array index —
611    /// the same scheme as Go's `edges[t-MinDFAEdge]`.
612    dense_edges: Vec<Option<Box<DenseEdgeRow>>>,
613    /// Transitions on symbols outside the dense range (supplementary planes).
614    sparse_edges: FxHashMap<(usize, i32), LexerDfaCachedTransition>,
615    mode_starts: FxHashMap<i32, usize>,
616}
617
618/// Dense-row width: ASCII, matching the reference runtimes' DFA edge arrays.
619const DENSE_EDGE_SYMBOLS: usize = 128;
620
621type DenseEdgeRow = [LexerDfaCachedTransition; DENSE_EDGE_SYMBOLS];
622
623/// Sentinel for an empty dense-row slot; no real transition targets it
624/// because DFA state numbers are assigned contiguously from 0.
625const EMPTY_DENSE_EDGE: LexerDfaCachedTransition = LexerDfaCachedTransition {
626    target_state: usize::MAX,
627    position_delta: 0,
628};
629
630thread_local! {
631    /// Learned lexer DFAs shared across lexer instances, keyed by a generated
632    /// lexer's static ATN identity (mirrors the parser's shared decision DFAs).
633    static SHARED_LEXER_DFA_CACHES: RefCell<HashMap<usize, Rc<RefCell<LexerDfaCache>>>> =
634        RefCell::new(HashMap::new());
635}
636
637/// Normalized lexer ATN config-set identity used for observed DFA traces.
638#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
639pub(crate) struct LexerDfaKey {
640    configs: Vec<LexerDfaConfigKey>,
641}
642
643impl LexerDfaKey {
644    pub(crate) fn new(mut configs: Vec<LexerDfaConfigKey>) -> Self {
645        configs.sort_unstable();
646        Self { configs }
647    }
648}
649
650/// One lexer ATN config identity with the absolute input position removed.
651#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
652pub(crate) struct LexerDfaConfigKey {
653    pub(crate) state: usize,
654    pub(crate) alt_rule_index: Option<usize>,
655    pub(crate) consumed_eof: bool,
656    pub(crate) passed_non_greedy: bool,
657    pub(crate) stack: Vec<usize>,
658    pub(crate) actions: Vec<LexerDfaActionKey>,
659}
660
661#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
662pub(crate) struct LexerDfaActionKey {
663    pub(crate) action_index: usize,
664    pub(crate) position_delta: usize,
665    pub(crate) rule_index: usize,
666}
667
668impl LexerDfaConfigKey {
669    pub(crate) const fn new(
670        state: usize,
671        alt_rule_index: Option<usize>,
672        consumed_eof: bool,
673        passed_non_greedy: bool,
674        stack: Vec<usize>,
675        actions: Vec<LexerDfaActionKey>,
676    ) -> Self {
677        Self {
678            state,
679            alt_rule_index,
680            consumed_eof,
681            passed_non_greedy,
682            stack,
683            actions,
684        }
685    }
686}
687
688#[derive(Clone, Copy, Debug)]
689pub(crate) struct LexerDfaCachedTransition {
690    pub(crate) target_state: usize,
691    pub(crate) position_delta: usize,
692}
693
694#[derive(Clone, Debug)]
695pub(crate) struct LexerDfaCachedAccept {
696    pub(crate) position_delta: usize,
697    pub(crate) rule_index: usize,
698    pub(crate) consumed_eof: bool,
699    pub(crate) actions: Vec<LexerDfaActionKey>,
700}
701
702#[derive(Clone, Debug)]
703pub(crate) struct LexerDfaCachedState {
704    pub(crate) has_semantic_context: bool,
705    pub(crate) configs: Vec<LexerDfaConfigKey>,
706    pub(crate) accept: Option<LexerDfaCachedAccept>,
707}
708
709/// One printable lexer DFA edge keyed so repeated matches keep deterministic
710/// output order.
711#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
712struct LexerDfaEdge {
713    from: usize,
714    symbol: i32,
715    to: usize,
716}
717
718impl<I> BaseLexer<I>
719where
720    I: CharStream,
721{
722    pub fn new(input: I, data: RecognizerData) -> Self {
723        let has_source_text = input.source_text().is_some();
724        Self {
725            input,
726            data,
727            has_source_text,
728            mode: DEFAULT_MODE,
729            mode_stack: Vec::new(),
730            token_type: INVALID_TOKEN_TYPE,
731            channel: DEFAULT_CHANNEL,
732            token_start: 0,
733            token_start_line: 1,
734            token_start_column: 0,
735            line: 1,
736            column: 0,
737            hit_eof: false,
738            force_interpreted: false,
739            errors: RefCell::new(Vec::new()),
740            semantic_error_coordinates: RefCell::new(BTreeSet::new()),
741            pending_tokens: VecDeque::new(),
742            dfa_cache: Rc::new(RefCell::new(LexerDfaCache::default())),
743        }
744    }
745
746    /// Resets runtime-owned lexer state so this instance can consume its input
747    /// again from the beginning.
748    ///
749    /// Learned DFA tables and configuration such as forced interpretation are
750    /// retained. Token-production state, diagnostics, pending tokens, modes,
751    /// and source position are cleared.
752    pub fn reset(&mut self) {
753        self.input.seek(0);
754        self.mode = DEFAULT_MODE;
755        self.mode_stack.clear();
756        self.token_type = INVALID_TOKEN_TYPE;
757        self.channel = DEFAULT_CHANNEL;
758        self.token_start = 0;
759        self.token_start_line = 1;
760        self.token_start_column = 0;
761        self.line = 1;
762        self.column = 0;
763        self.hit_eof = false;
764        self.errors.get_mut().clear();
765        self.semantic_error_coordinates.get_mut().clear();
766        self.pending_tokens.clear();
767    }
768
769    /// Replaces the character stream and fully resets lexer state for reuse.
770    ///
771    /// Learned DFA tables and configuration such as forced interpretation are
772    /// retained. The new stream is always rewound to its beginning.
773    pub fn set_input_stream(&mut self, input: I) {
774        self.input = input;
775        self.has_source_text = self.input.source_text().is_some();
776        self.reset();
777    }
778
779    /// Switches this lexer to the thread-shared learned DFA for `atn`.
780    ///
781    /// Generated lexers create a fresh instance per parse; without sharing,
782    /// every instance relearns the same DFA through ATN simulation. The shared
783    /// cache is keyed by the generated lexer's `&'static LexerAtn` identity and
784    /// holds only input-independent data, so it stays valid across inputs.
785    /// The `showDFA` edge trace lives in the cache too, so it reports the
786    /// accumulated DFA — the same view the reference runtimes print from
787    /// their static shared DFA.
788    #[must_use]
789    pub fn with_shared_dfa(mut self, atn: &'static LexerAtn) -> Self {
790        let ptr: *const LexerAtn = atn;
791        let key = ptr as usize;
792        self.dfa_cache = SHARED_LEXER_DFA_CACHES
793            .with(|caches| Rc::clone(caches.borrow_mut().entry(key).or_insert_with(Rc::default)));
794        self
795    }
796
797    /// Clears the learned lexer DFA shared by recognizers for this grammar.
798    ///
799    /// Ahead-of-time compiled DFA tables are immutable generated data and are
800    /// unaffected. Any path that falls back to ATN interpretation relearns its
801    /// dynamic DFA from an empty cache after this call.
802    pub fn clear_dfa(&self) {
803        *self.dfa_cache.borrow_mut() = LexerDfaCache::default();
804    }
805
806    pub const fn input(&self) -> &I {
807        &self.input
808    }
809
810    pub const fn input_mut(&mut self) -> &mut I {
811        &mut self.input
812    }
813
814    /// Captures the input index and source position for the token currently
815    /// being matched.
816    pub fn begin_token(&mut self) {
817        self.semantic_error_coordinates.get_mut().clear();
818        self.token_type = INVALID_TOKEN_TYPE;
819        self.channel = DEFAULT_CHANNEL;
820        self.token_start = self.input.index();
821        self.token_start_line = self.line;
822        self.token_start_column = self.column;
823    }
824
825    /// Returns the absolute character index where the current token began.
826    pub const fn token_start(&self) -> usize {
827        self.token_start
828    }
829
830    /// Returns the source line captured at the start of the current token.
831    pub const fn token_start_line(&self) -> usize {
832        self.token_start_line
833    }
834
835    /// Returns the source column captured at the start of the current token.
836    pub const fn token_start_column(&self) -> usize {
837        self.token_start_column
838    }
839
840    /// Returns the pending type of the token being matched.
841    pub const fn token_type(&self) -> i32 {
842        self.token_type
843    }
844
845    /// Overrides the pending type of the token being matched.
846    pub const fn set_type(&mut self, token_type: i32) {
847        self.token_type = token_type;
848    }
849
850    /// Returns the pending channel of the token being matched.
851    pub const fn channel(&self) -> i32 {
852        self.channel
853    }
854
855    /// Overrides the pending channel of the token being matched.
856    pub const fn set_channel(&mut self, channel: i32) {
857        self.channel = channel;
858    }
859
860    /// Marks the current match as skipped.
861    pub const fn skip(&mut self) {
862        self.set_type(SKIP);
863    }
864
865    /// Extends the current token with another lexer-rule match.
866    pub const fn more(&mut self) {
867        self.set_type(MORE);
868    }
869
870    /// Reads a character at a one-based lookahead/lookbehind offset from the
871    /// committed input cursor without moving it.
872    pub fn la(&mut self, offset: isize) -> i32 {
873        self.input.la(offset)
874    }
875
876    fn lookahead_at(&self, position: usize, offset: isize) -> i32 {
877        if offset == 0 {
878            return 0;
879        }
880        let absolute = if offset > 0 {
881            position.checked_add((offset - 1).cast_unsigned())
882        } else {
883            offset
884                .checked_neg()
885                .and_then(|distance| usize::try_from(distance).ok())
886                .and_then(|distance| position.checked_sub(distance))
887        };
888        let Some(index) = absolute.filter(|index| *index < self.input.size()) else {
889            return EOF;
890        };
891        if let Some(symbol) = self.input.symbol_at(index) {
892            return symbol;
893        }
894        self.input
895            .text(TextInterval::new(index, index))
896            .chars()
897            .next()
898            .map_or(EOF, |ch| u32::from(ch).cast_signed())
899    }
900
901    /// Consumes one character from the input stream and updates lexer line and
902    /// column counters.
903    ///
904    /// The input stream is indexed by Unicode scalar values. Newline handling
905    /// follows ANTLR's default convention of incrementing the line and resetting
906    /// the column after `\n`.
907    pub fn consume_char(&mut self) {
908        let la = self.input.la(1);
909        if la == EOF {
910            return;
911        }
912        self.input.consume();
913        if char::from_u32(la.cast_unsigned()) == Some('\n') {
914            self.line += 1;
915            self.column = 0;
916        } else {
917            self.column += 1;
918        }
919    }
920
921    /// Commits a predicted input span while keeping the current line and column
922    /// as the coordinates at `start`.
923    pub(crate) fn commit_position(&mut self, start: usize, target: usize) {
924        self.reposition_from(start, self.line, self.column, target);
925    }
926
927    fn reposition_from(&mut self, start: usize, line: usize, column: usize, target: usize) {
928        let start = start.min(self.input.size());
929        let target = target.max(start).min(self.input.size());
930        if let Some(summary) = self.input.position_summary(start, target) {
931            self.input.seek(target);
932            (self.line, self.column) = summary.apply(line, column);
933            #[cfg(feature = "perf-counters")]
934            crate::perf::record_lexer_bulk_commit(target - start);
935            return;
936        }
937
938        self.input.seek(start);
939        self.line = line;
940        self.column = column;
941        #[cfg(feature = "perf-counters")]
942        let before = self.input.index();
943        while self.input.index() < target && self.input.la(1) != EOF {
944            self.consume_char();
945        }
946        #[cfg(feature = "perf-counters")]
947        crate::perf::record_lexer_scalar_replay(self.input.index().saturating_sub(before));
948    }
949
950    /// Rewinds or advances the input cursor to a token accept boundary.
951    ///
952    /// Some generated lexers intentionally accept a longer path to disambiguate
953    /// a token, then emit only the prefix and leave the suffix for the next
954    /// token. Recomputing line/column from `token_start` keeps the visible lexer
955    /// position consistent after moving the cursor backwards.
956    pub fn reset_accept_position(&mut self, index: usize) {
957        let target = index.max(self.token_start);
958        self.reposition_from(
959            self.token_start,
960            self.token_start_line,
961            self.token_start_column,
962            target,
963        );
964    }
965
966    /// Moves the current token start forward within the consumed input span.
967    ///
968    /// Source line and column are advanced with the start, so a subsequently
969    /// emitted suffix token carries the same coordinates it would have had if
970    /// lexed independently.
971    pub fn set_token_start(&mut self, index: usize) -> bool {
972        if index < self.token_start || index > self.input.index() {
973            return false;
974        }
975        let (line, column) = self.position_at(index);
976        self.token_start = index;
977        self.token_start_line = line;
978        self.token_start_column = column;
979        true
980    }
981
982    /// Builds a token spanning from the current token start to the character
983    /// before the input cursor.
984    ///
985    /// When generated or interpreted lexer code does not supply explicit text,
986    /// the base lexer captures the matched source interval so downstream token
987    /// streams and parse trees can render token text without retaining a source
988    /// pair object.
989    pub fn emit(
990        &self,
991        sink: &mut TokenSink<'_>,
992        token_type: i32,
993        channel: i32,
994        text: Option<String>,
995    ) -> Result<TokenId, TokenStoreError> {
996        let stop = self.input.index().checked_sub(1).unwrap_or(usize::MAX);
997        self.emit_with_stop(sink, token_type, channel, stop, text)
998    }
999
1000    /// Builds a token with an explicit stop index.
1001    ///
1002    /// EOF-matching lexer rules do not consume a Unicode scalar value, so their
1003    /// stop index can be one before the current input index. The caller passes
1004    /// `usize::MAX` to represent ANTLR's `-1` stop index at empty input.
1005    pub fn emit_with_stop(
1006        &self,
1007        sink: &mut TokenSink<'_>,
1008        token_type: i32,
1009        channel: i32,
1010        stop: usize,
1011        text: Option<String>,
1012    ) -> Result<TokenId, TokenStoreError> {
1013        sink.push(self.token_spec_with_stop(token_type, channel, stop, text))
1014    }
1015
1016    fn token_spec_with_stop(
1017        &self,
1018        token_type: i32,
1019        channel: i32,
1020        stop: usize,
1021        text: Option<String>,
1022    ) -> TokenSpec {
1023        let text = text.or_else(|| {
1024            if stop == usize::MAX {
1025                Some("<EOF>".to_owned())
1026            } else {
1027                None
1028            }
1029        });
1030        let source_interval = if self.has_source_text
1031            && text.is_none()
1032            && stop != usize::MAX
1033            && self.token_start <= stop
1034        {
1035            self.input
1036                .byte_interval(TextInterval::new(self.token_start, stop))
1037        } else {
1038            None
1039        };
1040        let text = text.or_else(|| {
1041            source_interval
1042                .is_none()
1043                .then(|| self.input.text(TextInterval::new(self.token_start, stop)))
1044        });
1045        let (start_byte, stop_byte) = source_interval
1046            .or_else(|| self.token_byte_span(stop))
1047            .unwrap_or((self.token_start, self.token_start));
1048        TokenSpec {
1049            token_type,
1050            channel,
1051            start: self.token_start,
1052            stop,
1053            start_byte,
1054            stop_byte,
1055            line: self.token_start_line,
1056            column: self.token_start_column,
1057            text,
1058            source_backed: source_interval.is_some(),
1059        }
1060    }
1061
1062    /// Queues an additional token to be returned before the current match's
1063    /// automatic token.
1064    ///
1065    /// The token spans the current token start through `stop` (inclusive).
1066    /// `text = None` keeps the token source-backed when the input supports it.
1067    pub fn enqueue_token(
1068        &mut self,
1069        token_type: i32,
1070        channel: i32,
1071        stop: usize,
1072        text: Option<String>,
1073    ) {
1074        let token = self.token_spec_with_stop(token_type, channel, stop, text);
1075        self.pending_tokens.push_back(token);
1076    }
1077
1078    pub(crate) fn emit_pending_token(
1079        &mut self,
1080        sink: &mut TokenSink<'_>,
1081    ) -> Result<Option<TokenId>, TokenStoreError> {
1082        self.pending_tokens
1083            .pop_front()
1084            .map(|token| sink.push(token))
1085            .transpose()
1086    }
1087
1088    pub(crate) fn emit_or_enqueue_with_stop(
1089        &mut self,
1090        sink: &mut TokenSink<'_>,
1091        stop: usize,
1092        text: Option<String>,
1093    ) -> Result<TokenId, TokenStoreError> {
1094        let token = self.token_spec_with_stop(self.token_type, self.channel, stop, text);
1095        self.emit_or_enqueue(sink, token)
1096    }
1097
1098    fn emit_or_enqueue(
1099        &mut self,
1100        sink: &mut TokenSink<'_>,
1101        token: TokenSpec,
1102    ) -> Result<TokenId, TokenStoreError> {
1103        if self.pending_tokens.is_empty() {
1104            return sink.push(token);
1105        }
1106        self.pending_tokens.push_back(token);
1107        self.emit_pending_token(sink)?
1108            .ok_or_else(|| unreachable!("the pending-token queue was just populated"))
1109    }
1110
1111    /// Returns the current token text from the token start through the input
1112    /// cursor.
1113    pub fn token_text(&self) -> String {
1114        self.token_text_until(self.input.index())
1115    }
1116
1117    /// Returns the current token text from the token start through
1118    /// `stop_exclusive`.
1119    ///
1120    /// Lexer custom actions can occur before the accepted token is complete.
1121    /// The action event records the position where the transition fired, and
1122    /// generated action code uses this helper to render ANTLR's `Text()`
1123    /// template at that exact point.
1124    pub fn token_text_until(&self, stop_exclusive: usize) -> String {
1125        if stop_exclusive <= self.token_start {
1126            return String::new();
1127        }
1128        self.input
1129            .text(TextInterval::new(self.token_start, stop_exclusive - 1))
1130    }
1131
1132    /// Computes the zero-based source column at an absolute input position
1133    /// reached during prediction of the current token.
1134    pub fn column_at(&self, position: usize) -> usize {
1135        self.position_at(position).1
1136    }
1137
1138    fn position_at(&self, position: usize) -> (usize, usize) {
1139        let mut line = self.token_start_line;
1140        let mut column = self.token_start_column;
1141        if position <= self.token_start {
1142            return (line, column);
1143        }
1144        if let Some(summary) = self.input.position_summary(self.token_start, position) {
1145            return summary.apply(line, column);
1146        }
1147        for ch in self
1148            .input
1149            .text(TextInterval::new(self.token_start, position - 1))
1150            .chars()
1151        {
1152            if ch == '\n' {
1153                line += 1;
1154                column = 0;
1155            } else {
1156                column += 1;
1157            }
1158        }
1159        (line, column)
1160    }
1161
1162    /// Builds the synthetic EOF token at the current input cursor.
1163    pub fn eof_token(&self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
1164        sink.push(self.eof_token_spec())
1165    }
1166
1167    pub(crate) fn emit_eof_or_pending(
1168        &mut self,
1169        sink: &mut TokenSink<'_>,
1170    ) -> Result<TokenId, TokenStoreError> {
1171        let token = self.eof_token_spec();
1172        self.emit_or_enqueue(sink, token)
1173    }
1174
1175    fn eof_token_spec(&self) -> TokenSpec {
1176        let byte_offset = self.eof_byte_offset().unwrap_or_else(|| self.input.index());
1177        TokenSpec::eof(self.input.index(), byte_offset, self.line, self.column)
1178    }
1179
1180    fn eof_byte_offset(&self) -> Option<usize> {
1181        self.byte_offset_at(self.input.index())
1182    }
1183
1184    fn token_byte_span(&self, stop: usize) -> Option<(usize, usize)> {
1185        if stop != usize::MAX && self.token_start <= stop {
1186            let (start_byte, stop_byte) = self
1187                .input
1188                .byte_interval(TextInterval::new(self.token_start, stop))?;
1189            return Some((start_byte, stop_byte));
1190        }
1191        let byte_offset = self.byte_offset_at(self.token_start)?;
1192        Some((byte_offset, byte_offset))
1193    }
1194
1195    fn byte_offset_at(&self, index: usize) -> Option<usize> {
1196        let byte_offset = if index == 0 {
1197            0
1198        } else {
1199            let previous = TextInterval::new(index - 1, index - 1);
1200            self.input.byte_interval(previous)?.1
1201        };
1202        Some(byte_offset)
1203    }
1204}
1205
1206impl<I> Recognizer for BaseLexer<I>
1207where
1208    I: CharStream,
1209{
1210    fn data(&self) -> &RecognizerData {
1211        &self.data
1212    }
1213
1214    fn data_mut(&mut self) -> &mut RecognizerData {
1215        &mut self.data
1216    }
1217}
1218
1219impl<I> Lexer for BaseLexer<I>
1220where
1221    I: CharStream,
1222{
1223    fn mode(&self) -> i32 {
1224        self.mode
1225    }
1226
1227    fn set_mode(&mut self, mode: i32) {
1228        self.mode = mode;
1229    }
1230
1231    fn push_mode(&mut self, mode: i32) {
1232        self.mode_stack.push(self.mode);
1233        self.mode = mode;
1234    }
1235
1236    fn pop_mode(&mut self) -> Option<i32> {
1237        let mode = self.mode_stack.pop()?;
1238        self.mode = mode;
1239        Some(mode)
1240    }
1241}
1242
1243impl<I> BaseLexer<I>
1244where
1245    I: CharStream,
1246{
1247    pub const fn line(&self) -> usize {
1248        self.line
1249    }
1250
1251    pub const fn column(&self) -> usize {
1252        self.column
1253    }
1254
1255    pub fn source_name(&self) -> &str {
1256        self.input.source_name()
1257    }
1258
1259    pub fn source_text(&self) -> Option<Rc<str>> {
1260        self.input.source_text()
1261    }
1262
1263    pub const fn hit_eof(&self) -> bool {
1264        self.hit_eof
1265    }
1266
1267    pub const fn set_hit_eof(&mut self, hit_eof: bool) {
1268        self.hit_eof = hit_eof;
1269    }
1270
1271    /// Routes every token through ATN interpretation even when the generated
1272    /// lexer carries an ahead-of-time compiled DFA.
1273    ///
1274    /// Interpretation is what learns the replayable DFA that
1275    /// [`Self::lexer_dfa_string`] reports, so harnesses asserting on the
1276    /// observed-DFA trace (ANTLR's `showDFA` descriptors) enable this before
1277    /// lexing.
1278    pub const fn set_force_interpreted(&mut self, force_interpreted: bool) {
1279        self.force_interpreted = force_interpreted;
1280    }
1281
1282    /// Whether compiled-DFA entry points must fall back to interpretation.
1283    pub const fn force_interpreted(&self) -> bool {
1284        self.force_interpreted
1285    }
1286
1287    /// Buffers a lexer diagnostic until the token stream consumer is ready to
1288    /// emit errors in parser-compatible order.
1289    pub fn record_error(&self, line: usize, column: usize, message: impl Into<String>) {
1290        self.errors
1291            .borrow_mut()
1292            .push(TokenSourceError::new(line, column, message));
1293    }
1294
1295    /// Records one fail-loud semantic-hook miss per coordinate and token start.
1296    pub fn record_semantic_error(&self, action: bool, rule_index: usize, coordinate_index: usize) {
1297        let kind = u8::from(action);
1298        if !self.semantic_error_coordinates.borrow_mut().insert((
1299            kind,
1300            rule_index,
1301            coordinate_index,
1302            self.token_start,
1303        )) {
1304            return;
1305        }
1306        let label = if action { "action" } else { "predicate" };
1307        self.record_error(
1308            self.token_start_line,
1309            self.token_start_column,
1310            format!("unhandled lexer semantic {label}: rule={rule_index} index={coordinate_index}"),
1311        );
1312    }
1313
1314    /// Returns and clears lexer diagnostics produced while fetching tokens.
1315    pub fn drain_errors(&mut self) -> Vec<TokenSourceError> {
1316        std::mem::take(self.errors.get_mut())
1317    }
1318
1319    /// Returns the stable state number for a normalized lexer DFA config set,
1320    /// creating one if this input path has not reached it before.
1321    pub(crate) fn lexer_dfa_state(
1322        &self,
1323        key: LexerDfaKey,
1324        accept_prediction: Option<i32>,
1325    ) -> usize {
1326        let mut cache = self.dfa_cache.borrow_mut();
1327        let next = cache.state_numbers.len();
1328        let state = *cache.state_numbers.entry(key).or_insert(next);
1329        if let Some(prediction) = accept_prediction {
1330            cache.accept_predictions.insert(state, prediction);
1331        }
1332        state
1333    }
1334
1335    /// Records a visible lexer DFA edge unless it was already observed.
1336    pub fn record_lexer_dfa_edge(&self, from: usize, symbol: i32, to: usize) {
1337        self.dfa_cache
1338            .borrow_mut()
1339            .edges
1340            .insert(LexerDfaEdge { from, symbol, to });
1341    }
1342
1343    pub(crate) fn cached_lexer_dfa_transition(
1344        &self,
1345        state: usize,
1346        symbol: i32,
1347    ) -> Option<LexerDfaCachedTransition> {
1348        let cache = self.dfa_cache.borrow();
1349        if let Ok(sym) = usize::try_from(symbol)
1350            && sym < DENSE_EDGE_SYMBOLS
1351        {
1352            let transition = cache.dense_edges.get(state)?.as_ref()?[sym];
1353            return (transition.target_state != usize::MAX).then_some(transition);
1354        }
1355        cache.sparse_edges.get(&(state, symbol)).copied()
1356    }
1357
1358    pub(crate) fn cache_lexer_dfa_transition(
1359        &self,
1360        state: usize,
1361        symbol: i32,
1362        transition: LexerDfaCachedTransition,
1363    ) {
1364        let mut cache = self.dfa_cache.borrow_mut();
1365        if let Ok(sym) = usize::try_from(symbol)
1366            && sym < DENSE_EDGE_SYMBOLS
1367        {
1368            if cache.dense_edges.len() <= state {
1369                cache.dense_edges.resize_with(state + 1, || None);
1370            }
1371            let row = cache.dense_edges[state]
1372                .get_or_insert_with(|| Box::new([EMPTY_DENSE_EDGE; DENSE_EDGE_SYMBOLS]));
1373            // First write wins, matching the previous map `entry().or_insert`.
1374            if row[sym].target_state == usize::MAX {
1375                row[sym] = transition;
1376            }
1377            return;
1378        }
1379        cache
1380            .sparse_edges
1381            .entry((state, symbol))
1382            .or_insert(transition);
1383    }
1384
1385    pub(crate) fn cached_lexer_dfa_state(&self, state: usize) -> Option<Rc<LexerDfaCachedState>> {
1386        self.dfa_cache
1387            .borrow()
1388            .cached_states
1389            .get(state)
1390            .cloned()
1391            .flatten()
1392    }
1393
1394    pub(crate) fn cache_lexer_dfa_state(&self, state: usize, cached_state: LexerDfaCachedState) {
1395        let mut cache = self.dfa_cache.borrow_mut();
1396        if cache.cached_states.len() <= state {
1397            cache.cached_states.resize_with(state + 1, || None);
1398        }
1399        cache.cached_states[state].get_or_insert_with(|| Rc::new(cached_state));
1400    }
1401
1402    pub(crate) fn cached_lexer_mode_start(&self, mode: i32) -> Option<usize> {
1403        self.dfa_cache.borrow().mode_starts.get(&mode).copied()
1404    }
1405
1406    pub(crate) fn cache_lexer_mode_start(&self, mode: i32, state: usize) {
1407        self.dfa_cache
1408            .borrow_mut()
1409            .mode_starts
1410            .entry(mode)
1411            .or_insert(state);
1412    }
1413
1414    /// Serializes the observed default-mode lexer DFA in ANTLR's text shape.
1415    pub fn lexer_dfa_string(&self) -> String {
1416        let mut out = String::new();
1417        let cache = self.dfa_cache.borrow();
1418        for edge in &cache.edges {
1419            let Some(label) = lexer_dfa_edge_label(edge.symbol) else {
1420                continue;
1421            };
1422            out.push_str(&self.lexer_dfa_state_string(edge.from));
1423            out.push('-');
1424            out.push_str(&label);
1425            out.push_str("->");
1426            out.push_str(&self.lexer_dfa_state_string(edge.to));
1427            out.push('\n');
1428        }
1429        out
1430    }
1431
1432    fn lexer_dfa_state_string(&self, state: usize) -> String {
1433        self.dfa_cache
1434            .borrow()
1435            .accept_predictions
1436            .get(&state)
1437            .map_or_else(
1438                || format!("s{state}"),
1439                |prediction| format!(":s{state}=>{prediction}"),
1440            )
1441    }
1442}
1443
1444fn lexer_dfa_edge_label(symbol: i32) -> Option<String> {
1445    char::from_u32(symbol.cast_unsigned()).map(|ch| format!("'{ch}'"))
1446}
1447
1448#[cfg(test)]
1449mod tests {
1450    use super::*;
1451    use crate::char_stream::InputStream;
1452    use crate::int_stream::IntStream;
1453    use crate::recognizer::RecognizerData;
1454    use crate::token::{DEFAULT_CHANNEL, Token, TokenStore};
1455    use crate::vocabulary::Vocabulary;
1456
1457    #[derive(Clone, Debug)]
1458    struct UnsharedInput(InputStream);
1459
1460    impl IntStream for UnsharedInput {
1461        fn consume(&mut self) {
1462            self.0.consume();
1463        }
1464
1465        fn la(&mut self, offset: isize) -> i32 {
1466            self.0.la(offset)
1467        }
1468
1469        fn index(&self) -> usize {
1470            self.0.index()
1471        }
1472
1473        fn seek(&mut self, index: usize) {
1474            self.0.seek(index);
1475        }
1476
1477        fn size(&self) -> usize {
1478            self.0.size()
1479        }
1480
1481        fn source_name(&self) -> &str {
1482            self.0.source_name()
1483        }
1484    }
1485
1486    impl CharStream for UnsharedInput {
1487        fn text(&self, interval: TextInterval) -> String {
1488            self.0.text(interval)
1489        }
1490
1491        fn byte_interval(&self, interval: TextInterval) -> Option<(usize, usize)> {
1492            self.0.byte_interval(interval)
1493        }
1494    }
1495
1496    #[test]
1497    fn eof_token_uses_utf8_byte_offset_after_non_ascii_input() {
1498        let data = RecognizerData::new(
1499            "T",
1500            Vocabulary::new(
1501                std::iter::empty::<Option<&str>>(),
1502                std::iter::empty::<Option<&str>>(),
1503                std::iter::empty::<Option<&str>>(),
1504            ),
1505        );
1506        let mut lexer = BaseLexer::new(InputStream::new("β"), data);
1507        lexer.consume_char();
1508
1509        let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1510        let mut sink = TokenSink::new(&mut store);
1511        let id = lexer.eof_token(&mut sink).expect("test token should fit");
1512        let token = sink.view(id).expect("emitted token should exist");
1513
1514        assert_eq!(token.start(), 1);
1515        assert_eq!(token.stop(), 0);
1516        assert_eq!(token.text(), "<EOF>");
1517        assert_eq!(token.byte_span(), 2..2);
1518    }
1519
1520    #[test]
1521    fn eof_rule_token_uses_utf8_byte_offset_after_non_ascii_input() {
1522        let data = RecognizerData::new(
1523            "T",
1524            Vocabulary::new(
1525                std::iter::empty::<Option<&str>>(),
1526                std::iter::empty::<Option<&str>>(),
1527                std::iter::empty::<Option<&str>>(),
1528            ),
1529        );
1530        let mut lexer = BaseLexer::new(InputStream::new("β"), data);
1531        lexer.consume_char();
1532        lexer.begin_token();
1533
1534        let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1535        let mut sink = TokenSink::new(&mut store);
1536        let id = lexer
1537            .emit_with_stop(&mut sink, 1, DEFAULT_CHANNEL, 0, Some("<EOF>".to_owned()))
1538            .expect("test token should fit");
1539        let token = sink.view(id).expect("emitted token should exist");
1540
1541        assert_eq!(token.start(), 1);
1542        assert_eq!(token.stop(), 0);
1543        assert_eq!(token.text(), "<EOF>");
1544        assert_eq!(token.byte_span(), 2..2);
1545    }
1546
1547    #[test]
1548    fn emit_implicit_text_uses_utf8_byte_span_for_non_ascii_input() {
1549        let data = RecognizerData::new(
1550            "T",
1551            Vocabulary::new(
1552                std::iter::empty::<Option<&str>>(),
1553                std::iter::empty::<Option<&str>>(),
1554                std::iter::empty::<Option<&str>>(),
1555            ),
1556        );
1557        let mut lexer = BaseLexer::new(InputStream::new("β"), data);
1558        lexer.begin_token();
1559        lexer.consume_char();
1560
1561        let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1562        let mut sink = TokenSink::new(&mut store);
1563        let id = lexer
1564            .emit(&mut sink, 1, DEFAULT_CHANNEL, None)
1565            .expect("test token should fit");
1566        let token = sink.view(id).expect("emitted token should exist");
1567
1568        assert_eq!(token.start(), 0);
1569        assert_eq!(token.stop(), 0);
1570        assert_eq!(token.text(), "β");
1571        assert_eq!(token.byte_span(), 0..2);
1572    }
1573
1574    #[test]
1575    fn emit_falls_back_to_explicit_text_without_shareable_source() {
1576        let data = RecognizerData::new(
1577            "T",
1578            Vocabulary::new(
1579                std::iter::empty::<Option<&str>>(),
1580                std::iter::empty::<Option<&str>>(),
1581                std::iter::empty::<Option<&str>>(),
1582            ),
1583        );
1584        let mut lexer = BaseLexer::new(UnsharedInput(InputStream::new("β")), data);
1585        lexer.begin_token();
1586        lexer.consume_char();
1587
1588        let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1589        let mut sink = TokenSink::new(&mut store);
1590        let id = lexer
1591            .emit(&mut sink, 1, DEFAULT_CHANNEL, None)
1592            .expect("unshared input should emit explicit token text");
1593        let token = sink.view(id).expect("emitted token should exist");
1594
1595        assert_eq!(token.text(), "β");
1596        assert_eq!(token.byte_span(), 0..2);
1597    }
1598
1599    #[test]
1600    fn position_commits_and_rewinds_preserve_line_and_column() {
1601        let data = RecognizerData::new(
1602            "T",
1603            Vocabulary::new(
1604                std::iter::empty::<Option<&str>>(),
1605                std::iter::empty::<Option<&str>>(),
1606                std::iter::empty::<Option<&str>>(),
1607            ),
1608        );
1609        let mut lexer = BaseLexer::new(InputStream::new("ab\nγd"), data);
1610        lexer.begin_token();
1611
1612        lexer.commit_position(0, 5);
1613        assert_eq!(lexer.input().index(), 5);
1614        assert_eq!((lexer.line(), lexer.column()), (2, 2));
1615        assert_eq!(lexer.column_at(2), 2);
1616        assert_eq!(lexer.column_at(4), 1);
1617
1618        lexer.reset_accept_position(3);
1619        assert_eq!(lexer.input().index(), 3);
1620        assert_eq!((lexer.line(), lexer.column()), (2, 0));
1621    }
1622
1623    #[test]
1624    fn custom_stream_position_commit_replays_without_fast_path_methods() {
1625        let data = RecognizerData::new(
1626            "T",
1627            Vocabulary::new(
1628                std::iter::empty::<Option<&str>>(),
1629                std::iter::empty::<Option<&str>>(),
1630                std::iter::empty::<Option<&str>>(),
1631            ),
1632        );
1633        let mut lexer = BaseLexer::new(UnsharedInput(InputStream::new("a\nb")), data);
1634        lexer.begin_token();
1635
1636        lexer.commit_position(0, 3);
1637        assert_eq!(lexer.input().index(), 3);
1638        assert_eq!((lexer.line(), lexer.column()), (2, 1));
1639    }
1640
1641    #[test]
1642    fn semantic_hook_errors_are_deduplicated_per_token_coordinate() {
1643        let data = RecognizerData::new(
1644            "T",
1645            Vocabulary::new(
1646                std::iter::empty::<Option<&str>>(),
1647                std::iter::empty::<Option<&str>>(),
1648                std::iter::empty::<Option<&str>>(),
1649            ),
1650        );
1651        let mut lexer = BaseLexer::new(InputStream::new("a"), data);
1652        lexer.begin_token();
1653        lexer.record_semantic_error(false, 3, 7);
1654        lexer.record_semantic_error(false, 3, 7);
1655
1656        let errors = lexer.drain_errors();
1657        assert_eq!(errors.len(), 1);
1658        assert_eq!(
1659            errors[0].message,
1660            "unhandled lexer semantic predicate: rule=3 index=7"
1661        );
1662
1663        lexer.begin_token();
1664        lexer.record_semantic_error(false, 3, 7);
1665        assert_eq!(
1666            lexer.drain_errors().len(),
1667            1,
1668            "deduplication resets at every token boundary, even after rewinding"
1669        );
1670    }
1671
1672    #[test]
1673    fn set_input_stream_replaces_input_and_resets_transient_state() {
1674        let data = RecognizerData::new(
1675            "T",
1676            Vocabulary::new(
1677                std::iter::empty::<Option<&str>>(),
1678                std::iter::empty::<Option<&str>>(),
1679                std::iter::empty::<Option<&str>>(),
1680            ),
1681        );
1682        let mut lexer = BaseLexer::new(InputStream::new("old"), data);
1683        lexer.consume_char();
1684        lexer.set_mode(7);
1685        lexer.push_mode(9);
1686        lexer.set_type(3);
1687        lexer.record_error(1, 0, "stale");
1688
1689        lexer.set_input_stream(InputStream::with_source_name("new", "replacement"));
1690
1691        assert_eq!(lexer.input().index(), 0);
1692        assert_eq!(lexer.input().size(), 3);
1693        assert_eq!(lexer.source_name(), "replacement");
1694        assert_eq!(lexer.source_text().as_deref(), Some("new"));
1695        assert_eq!(lexer.mode(), DEFAULT_MODE);
1696        assert_eq!(lexer.token_type(), INVALID_TOKEN_TYPE);
1697        assert_eq!((lexer.line(), lexer.column()), (1, 0));
1698        assert!(!lexer.hit_eof());
1699        assert!(lexer.drain_errors().is_empty());
1700        assert!(lexer.pop_mode().is_none());
1701    }
1702
1703    #[test]
1704    fn clear_dfa_invalidates_all_lexers_sharing_the_cache() {
1705        let atn = Box::leak(Box::new(LexerAtn::new(1)));
1706        let data = || {
1707            RecognizerData::new(
1708                "T",
1709                Vocabulary::new(
1710                    std::iter::empty::<Option<&str>>(),
1711                    std::iter::empty::<Option<&str>>(),
1712                    std::iter::empty::<Option<&str>>(),
1713                ),
1714            )
1715        };
1716        let first = BaseLexer::new(InputStream::new("a"), data()).with_shared_dfa(atn);
1717        let second = BaseLexer::new(InputStream::new("a"), data()).with_shared_dfa(atn);
1718        let state = first.lexer_dfa_state(LexerDfaKey::new(Vec::new()), Some(1));
1719        first.record_lexer_dfa_edge(state, i32::from(b'a'), state);
1720
1721        assert!(!second.lexer_dfa_string().is_empty());
1722        first.clear_dfa();
1723        assert!(first.lexer_dfa_string().is_empty());
1724        assert!(second.lexer_dfa_string().is_empty());
1725    }
1726}