1use std::collections::{BTreeSet, HashMap};
2use std::hash::BuildHasherDefault;
3use std::rc::Rc;
4
5use crate::char_stream::{CharStream, TextInterval};
6use crate::int_stream::EOF;
7use crate::prediction::PredictionFxHasher;
8use crate::recognizer::{Recognizer, RecognizerData};
9use crate::token::{CommonToken, CommonTokenFactory, TokenFactory, TokenSourceError, TokenSpec};
10
11#[allow(clippy::disallowed_types)]
12type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PredictionFxHasher>>;
13
14pub const SKIP: i32 = -3;
15pub const MORE: i32 = -2;
16pub const DEFAULT_MODE: i32 = 0;
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub struct LexerMode(pub i32);
20
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub struct LexerCustomAction {
29 rule_index: i32,
30 action_index: i32,
31 position: usize,
32}
33
34impl LexerCustomAction {
35 pub const fn new(rule_index: i32, action_index: i32, position: usize) -> Self {
37 Self {
38 rule_index,
39 action_index,
40 position,
41 }
42 }
43
44 pub const fn rule_index(self) -> i32 {
46 self.rule_index
47 }
48
49 pub const fn action_index(self) -> i32 {
51 self.action_index
52 }
53
54 pub const fn position(self) -> usize {
56 self.position
57 }
58}
59
60#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub struct LexerPredicate {
63 rule_index: usize,
64 pred_index: usize,
65 position: usize,
66}
67
68impl LexerPredicate {
69 pub const fn new(rule_index: usize, pred_index: usize, position: usize) -> Self {
71 Self {
72 rule_index,
73 pred_index,
74 position,
75 }
76 }
77
78 pub const fn rule_index(self) -> usize {
80 self.rule_index
81 }
82
83 pub const fn pred_index(self) -> usize {
85 self.pred_index
86 }
87
88 pub const fn position(self) -> usize {
90 self.position
91 }
92}
93
94pub trait Lexer: Recognizer {
95 fn mode(&self) -> i32;
96 fn set_mode(&mut self, mode: i32);
97 fn push_mode(&mut self, mode: i32);
98 fn pop_mode(&mut self) -> Option<i32>;
99}
100
101#[derive(Clone, Debug)]
102pub struct BaseLexer<I, F = CommonTokenFactory> {
103 input: I,
104 data: RecognizerData,
105 factory: F,
106 mode: i32,
107 mode_stack: Vec<i32>,
108 token_start: usize,
109 token_start_line: usize,
110 token_start_column: usize,
111 line: usize,
112 column: usize,
113 hit_eof: bool,
114 errors: Vec<TokenSourceError>,
115 lexer_dfa: LexerDfaTrace,
116}
117
118#[derive(Clone, Debug, Default)]
121struct LexerDfaTrace {
122 state_numbers: FxHashMap<LexerDfaKey, usize>,
123 accept_predictions: FxHashMap<usize, i32>,
124 edges: BTreeSet<LexerDfaEdge>,
125 cached_states: FxHashMap<usize, Rc<LexerDfaCachedState>>,
126 transitions: FxHashMap<(usize, i32), LexerDfaCachedTransition>,
127 mode_starts: FxHashMap<i32, usize>,
128}
129
130impl LexerDfaTrace {
131 fn new() -> Self {
132 Self {
133 state_numbers: FxHashMap::default(),
134 accept_predictions: FxHashMap::default(),
135 edges: BTreeSet::new(),
136 cached_states: FxHashMap::default(),
137 transitions: FxHashMap::default(),
138 mode_starts: FxHashMap::default(),
139 }
140 }
141}
142
143#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
145pub(crate) struct LexerDfaKey {
146 configs: Vec<LexerDfaConfigKey>,
147}
148
149impl LexerDfaKey {
150 pub(crate) fn new(mut configs: Vec<LexerDfaConfigKey>) -> Self {
151 configs.sort_unstable();
152 Self { configs }
153 }
154}
155
156#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
158pub(crate) struct LexerDfaConfigKey {
159 pub(crate) state: usize,
160 pub(crate) alt_rule_index: Option<usize>,
161 pub(crate) consumed_eof: bool,
162 pub(crate) passed_non_greedy: bool,
163 pub(crate) stack: Vec<usize>,
164 pub(crate) actions: Vec<LexerDfaActionKey>,
165}
166
167#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
168pub(crate) struct LexerDfaActionKey {
169 pub(crate) action_index: usize,
170 pub(crate) position_delta: usize,
171 pub(crate) rule_index: usize,
172}
173
174impl LexerDfaConfigKey {
175 pub(crate) const fn new(
176 state: usize,
177 alt_rule_index: Option<usize>,
178 consumed_eof: bool,
179 passed_non_greedy: bool,
180 stack: Vec<usize>,
181 actions: Vec<LexerDfaActionKey>,
182 ) -> Self {
183 Self {
184 state,
185 alt_rule_index,
186 consumed_eof,
187 passed_non_greedy,
188 stack,
189 actions,
190 }
191 }
192}
193
194#[derive(Clone, Debug)]
195pub(crate) struct LexerDfaCachedTransition {
196 pub(crate) target_state: usize,
197 pub(crate) position_delta: usize,
198}
199
200#[derive(Clone, Debug)]
201pub(crate) struct LexerDfaCachedAccept {
202 pub(crate) position_delta: usize,
203 pub(crate) rule_index: usize,
204 pub(crate) consumed_eof: bool,
205 pub(crate) actions: Vec<LexerDfaActionKey>,
206}
207
208#[derive(Clone, Debug)]
209pub(crate) struct LexerDfaCachedState {
210 pub(crate) has_semantic_context: bool,
211 pub(crate) configs: Vec<LexerDfaConfigKey>,
212 pub(crate) accept: Option<LexerDfaCachedAccept>,
213}
214
215#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
218struct LexerDfaEdge {
219 from: usize,
220 symbol: i32,
221 to: usize,
222}
223
224impl<I> BaseLexer<I>
225where
226 I: CharStream,
227{
228 pub fn new(input: I, data: RecognizerData) -> Self {
230 Self::with_factory(input, data, CommonTokenFactory)
231 }
232}
233
234impl<I, F> BaseLexer<I, F>
235where
236 I: CharStream,
237 F: TokenFactory,
238{
239 pub fn with_factory(input: I, data: RecognizerData, factory: F) -> Self {
241 Self {
242 input,
243 data,
244 factory,
245 mode: DEFAULT_MODE,
246 mode_stack: Vec::new(),
247 token_start: 0,
248 token_start_line: 1,
249 token_start_column: 0,
250 line: 1,
251 column: 0,
252 hit_eof: false,
253 errors: Vec::new(),
254 lexer_dfa: LexerDfaTrace::new(),
255 }
256 }
257
258 pub const fn input(&self) -> &I {
259 &self.input
260 }
261
262 pub const fn input_mut(&mut self) -> &mut I {
263 &mut self.input
264 }
265
266 pub fn begin_token(&mut self) {
269 self.token_start = self.input.index();
270 self.token_start_line = self.line;
271 self.token_start_column = self.column;
272 }
273
274 pub const fn token_start(&self) -> usize {
276 self.token_start
277 }
278
279 pub const fn token_start_line(&self) -> usize {
281 self.token_start_line
282 }
283
284 pub const fn token_start_column(&self) -> usize {
286 self.token_start_column
287 }
288
289 pub fn consume_char(&mut self) {
296 let la = self.input.la(1);
297 if la == EOF {
298 return;
299 }
300 self.input.consume();
301 if char::from_u32(la.cast_unsigned()) == Some('\n') {
302 self.line += 1;
303 self.column = 0;
304 } else {
305 self.column += 1;
306 }
307 }
308
309 pub fn reset_accept_position(&mut self, index: usize) {
316 let target = index.max(self.token_start);
317 self.input.seek(self.token_start);
318 self.line = self.token_start_line;
319 self.column = self.token_start_column;
320 while self.input.index() < target && self.input.la(1) != EOF {
321 self.consume_char();
322 }
323 }
324
325 pub fn emit(&self, token_type: i32, channel: i32, text: Option<String>) -> CommonToken {
333 let stop = self.input.index().checked_sub(1).unwrap_or(usize::MAX);
334 self.emit_with_stop(token_type, channel, stop, text)
335 }
336
337 pub fn emit_with_stop(
343 &self,
344 token_type: i32,
345 channel: i32,
346 stop: usize,
347 text: Option<String>,
348 ) -> CommonToken {
349 let text = text.or_else(|| {
350 if stop == usize::MAX {
351 Some("<EOF>".to_owned())
352 } else {
353 None
354 }
355 });
356 let source_interval = if text.is_none() && stop != usize::MAX && self.token_start <= stop {
357 self.input
358 .text_source_interval(TextInterval::new(self.token_start, stop))
359 } else {
360 None
361 };
362 let source_text = source_interval
363 .as_ref()
364 .and_then(|(input, start_byte, stop_byte)| {
365 Some(crate::token::TokenSourceText {
366 input: Rc::clone(input),
367 start_byte: u32::try_from(*start_byte).ok()?,
368 stop_byte: u32::try_from(*stop_byte).ok()?,
369 })
370 });
371 let source_byte_span = source_text
372 .as_ref()
373 .map(|source_text| (source_text.start_byte, source_text.stop_byte));
374 let text = text.or_else(|| {
375 source_text
376 .is_none()
377 .then(|| self.input.text(TextInterval::new(self.token_start, stop)))
378 });
379 let mut token = self.factory.create(TokenSpec {
380 token_type,
381 channel,
382 start: self.token_start,
383 stop,
384 line: self.token_start_line,
385 column: self.token_start_column,
386 text,
387 source_text,
388 source_name: self.input.source_name(),
389 });
390 if let Some((start_byte, stop_byte)) =
391 source_byte_span.or_else(|| self.token_byte_span(stop))
392 {
393 token = token.with_byte_span(start_byte, stop_byte);
394 }
395 token
396 }
397
398 pub fn token_text(&self) -> String {
401 self.token_text_until(self.input.index())
402 }
403
404 pub fn token_text_until(&self, stop_exclusive: usize) -> String {
412 if stop_exclusive <= self.token_start {
413 return String::new();
414 }
415 self.input
416 .text(TextInterval::new(self.token_start, stop_exclusive - 1))
417 }
418
419 pub fn column_at(&self, position: usize) -> usize {
422 let mut column = self.token_start_column;
423 if position <= self.token_start {
424 return column;
425 }
426 for ch in self
427 .input
428 .text(TextInterval::new(self.token_start, position - 1))
429 .chars()
430 {
431 if ch == '\n' {
432 column = 0;
433 } else {
434 column += 1;
435 }
436 }
437 column
438 }
439
440 pub fn eof_token(&self) -> CommonToken {
442 let token = CommonToken::eof(
443 self.input.source_name(),
444 self.input.index(),
445 self.line,
446 self.column,
447 );
448 match self.eof_byte_offset() {
449 Some(byte_offset) => token.with_byte_span(byte_offset, byte_offset),
450 None => token,
451 }
452 }
453
454 fn eof_byte_offset(&self) -> Option<u32> {
455 self.byte_offset_at(self.input.index())
456 }
457
458 fn token_byte_span(&self, stop: usize) -> Option<(u32, u32)> {
459 if stop != usize::MAX && self.token_start <= stop {
460 let (_, start_byte, stop_byte) = self
461 .input
462 .text_source_interval(TextInterval::new(self.token_start, stop))?;
463 return Some((
464 u32::try_from(start_byte).ok()?,
465 u32::try_from(stop_byte).ok()?,
466 ));
467 }
468 let byte_offset = self.byte_offset_at(self.token_start)?;
469 Some((byte_offset, byte_offset))
470 }
471
472 fn byte_offset_at(&self, index: usize) -> Option<u32> {
473 let byte_offset = if index == 0 {
474 0
475 } else {
476 let previous = TextInterval::new(index - 1, index - 1);
477 self.input.text_source_interval(previous)?.2
478 };
479 u32::try_from(byte_offset).ok()
480 }
481}
482
483impl<I, F> Recognizer for BaseLexer<I, F>
484where
485 I: CharStream,
486 F: TokenFactory,
487{
488 fn data(&self) -> &RecognizerData {
489 &self.data
490 }
491
492 fn data_mut(&mut self) -> &mut RecognizerData {
493 &mut self.data
494 }
495}
496
497impl<I, F> Lexer for BaseLexer<I, F>
498where
499 I: CharStream,
500 F: TokenFactory,
501{
502 fn mode(&self) -> i32 {
503 self.mode
504 }
505
506 fn set_mode(&mut self, mode: i32) {
507 self.mode = mode;
508 }
509
510 fn push_mode(&mut self, mode: i32) {
511 self.mode_stack.push(self.mode);
512 self.mode = mode;
513 }
514
515 fn pop_mode(&mut self) -> Option<i32> {
516 let mode = self.mode_stack.pop()?;
517 self.mode = mode;
518 Some(mode)
519 }
520}
521
522impl<I, F> BaseLexer<I, F>
523where
524 I: CharStream,
525 F: TokenFactory,
526{
527 pub const fn line(&self) -> usize {
528 self.line
529 }
530
531 pub const fn column(&self) -> usize {
532 self.column
533 }
534
535 pub fn source_name(&self) -> &str {
536 self.input.source_name()
537 }
538
539 pub const fn hit_eof(&self) -> bool {
540 self.hit_eof
541 }
542
543 pub const fn set_hit_eof(&mut self, hit_eof: bool) {
544 self.hit_eof = hit_eof;
545 }
546
547 pub fn record_error(&mut self, line: usize, column: usize, message: impl Into<String>) {
550 self.errors
551 .push(TokenSourceError::new(line, column, message));
552 }
553
554 pub fn drain_errors(&mut self) -> Vec<TokenSourceError> {
556 std::mem::take(&mut self.errors)
557 }
558
559 pub(crate) fn lexer_dfa_state(
562 &mut self,
563 key: LexerDfaKey,
564 accept_prediction: Option<i32>,
565 ) -> usize {
566 let next = self.lexer_dfa.state_numbers.len();
567 let state = *self.lexer_dfa.state_numbers.entry(key).or_insert(next);
568 if let Some(prediction) = accept_prediction {
569 self.lexer_dfa.accept_predictions.insert(state, prediction);
570 }
571 state
572 }
573
574 pub fn record_lexer_dfa_edge(&mut self, from: usize, symbol: i32, to: usize) {
576 self.lexer_dfa
577 .edges
578 .insert(LexerDfaEdge { from, symbol, to });
579 }
580
581 pub(crate) fn cached_lexer_dfa_transition(
582 &self,
583 state: usize,
584 symbol: i32,
585 ) -> Option<LexerDfaCachedTransition> {
586 self.lexer_dfa.transitions.get(&(state, symbol)).cloned()
587 }
588
589 pub(crate) fn cache_lexer_dfa_transition(
590 &mut self,
591 state: usize,
592 symbol: i32,
593 transition: LexerDfaCachedTransition,
594 ) {
595 self.lexer_dfa
596 .transitions
597 .entry((state, symbol))
598 .or_insert(transition);
599 }
600
601 pub(crate) fn cached_lexer_dfa_state(&self, state: usize) -> Option<Rc<LexerDfaCachedState>> {
602 self.lexer_dfa.cached_states.get(&state).cloned()
603 }
604
605 pub(crate) fn cache_lexer_dfa_state(
606 &mut self,
607 state: usize,
608 cached_state: LexerDfaCachedState,
609 ) {
610 self.lexer_dfa
611 .cached_states
612 .entry(state)
613 .or_insert_with(|| Rc::new(cached_state));
614 }
615
616 pub(crate) fn cached_lexer_mode_start(&self, mode: i32) -> Option<usize> {
617 self.lexer_dfa.mode_starts.get(&mode).copied()
618 }
619
620 pub(crate) fn cache_lexer_mode_start(&mut self, mode: i32, state: usize) {
621 self.lexer_dfa.mode_starts.entry(mode).or_insert(state);
622 }
623
624 pub fn lexer_dfa_string(&self) -> String {
626 let mut out = String::new();
627 for edge in &self.lexer_dfa.edges {
628 let Some(label) = lexer_dfa_edge_label(edge.symbol) else {
629 continue;
630 };
631 out.push_str(&self.lexer_dfa_state_string(edge.from));
632 out.push('-');
633 out.push_str(&label);
634 out.push_str("->");
635 out.push_str(&self.lexer_dfa_state_string(edge.to));
636 out.push('\n');
637 }
638 out
639 }
640
641 fn lexer_dfa_state_string(&self, state: usize) -> String {
642 self.lexer_dfa.accept_predictions.get(&state).map_or_else(
643 || format!("s{state}"),
644 |prediction| format!(":s{state}=>{prediction}"),
645 )
646 }
647}
648
649fn lexer_dfa_edge_label(symbol: i32) -> Option<String> {
650 char::from_u32(symbol.cast_unsigned()).map(|ch| format!("'{ch}'"))
651}
652
653#[cfg(test)]
654mod tests {
655 use super::*;
656 use crate::char_stream::InputStream;
657 use crate::recognizer::RecognizerData;
658 use crate::token::{DEFAULT_CHANNEL, Token};
659 use crate::vocabulary::Vocabulary;
660
661 #[test]
662 fn eof_token_uses_utf8_byte_offset_after_non_ascii_input() {
663 let data = RecognizerData::new(
664 "T",
665 Vocabulary::new(
666 std::iter::empty::<Option<&str>>(),
667 std::iter::empty::<Option<&str>>(),
668 std::iter::empty::<Option<&str>>(),
669 ),
670 );
671 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
672 lexer.consume_char();
673
674 let token = lexer.eof_token();
675
676 assert_eq!(token.start(), 1);
677 assert_eq!(token.stop(), 0);
678 assert_eq!(token.text(), Some("<EOF>"));
679 assert_eq!(token.byte_span(), 2..2);
680 }
681
682 #[test]
683 fn eof_rule_token_uses_utf8_byte_offset_after_non_ascii_input() {
684 let data = RecognizerData::new(
685 "T",
686 Vocabulary::new(
687 std::iter::empty::<Option<&str>>(),
688 std::iter::empty::<Option<&str>>(),
689 std::iter::empty::<Option<&str>>(),
690 ),
691 );
692 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
693 lexer.consume_char();
694 lexer.begin_token();
695
696 let token = lexer.emit_with_stop(1, DEFAULT_CHANNEL, 0, Some("<EOF>".to_owned()));
697
698 assert_eq!(token.start(), 1);
699 assert_eq!(token.stop(), 0);
700 assert_eq!(token.text(), Some("<EOF>"));
701 assert_eq!(token.byte_span(), 2..2);
702 }
703
704 #[test]
705 fn emit_implicit_text_uses_utf8_byte_span_for_non_ascii_input() {
706 let data = RecognizerData::new(
707 "T",
708 Vocabulary::new(
709 std::iter::empty::<Option<&str>>(),
710 std::iter::empty::<Option<&str>>(),
711 std::iter::empty::<Option<&str>>(),
712 ),
713 );
714 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
715 lexer.begin_token();
716 lexer.consume_char();
717
718 let token = lexer.emit(1, DEFAULT_CHANNEL, None);
719
720 assert_eq!(token.start(), 0);
721 assert_eq!(token.stop(), 0);
722 assert_eq!(token.text(), Some("β"));
723 assert_eq!(token.byte_span(), 0..2);
724 }
725}