1use std::collections::HashMap;
23use std::hash::BuildHasherDefault;
24
25use memchr::{memchr, memchr2, memchr3};
26
27#[cfg(feature = "perf-counters")]
28use crate::atn::ascii_range::AsciiRangeClass;
29use crate::atn::ascii_range::{self, AsciiRanges};
30use crate::atn::lexer::{
31 LexerConfig, best_accept, epsilon_closure, lexer_action_belongs_to_accept, prune_after_accepts,
32 set_config_state,
33};
34use crate::atn::{LexerAtn, LexerTransition};
35use crate::int_stream::EOF;
36use crate::lexer::{
37 EMPTY_LEXER_CONTEXT, LexerContextArena, LexerContextId, LexerContextNode, LexerDfaActionKey,
38 LexerDfaConfigKey, LexerDfaKey,
39};
40use crate::prediction::{PredictionFxHasher, PredictionWorkspace};
41
42#[allow(clippy::disallowed_types)]
43type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PredictionFxHasher>>;
44
45const MIN_CHAR_VALUE: i32 = 0;
46const MAX_CHAR_VALUE: i32 = 0x0010_FFFF;
47
48pub(super) const DEAD_STATE: u16 = u16::MAX;
50
51pub(super) const ESCAPE_STATE: u16 = u16::MAX - 1;
53
54const MAX_MODE_STATES: usize = 4096;
57
58const MAX_CONTEXT_DEPTH: usize = 32;
61
62const MAX_ACTION_TRACES: usize = 16;
66
67const ASCII_EDGE_SYMBOLS: usize = 128;
69const ASCII_EDGE_LIMIT: i32 = 128;
71
72#[derive(Clone, Copy, Debug, Eq, PartialEq)]
74pub(super) enum AsciiRun {
75 None,
76 Any,
77 Until1(u8),
78 Until2(u8, u8),
79 Until3(u8, u8, u8),
80 Ranges(AsciiRanges),
81}
82
83impl AsciiRun {
84 fn classify(row: &[u16; ASCII_EDGE_SYMBOLS], state: u16) -> Self {
85 let mut exits = [0_u8; 3];
86 let mut count = 0;
87 for (symbol, &target) in row.iter().enumerate() {
88 if target == state {
89 continue;
90 }
91 if count < exits.len() {
92 exits[count] = u8::try_from(symbol).expect("symbol overflow");
93 }
94 count += 1;
95 }
96 match count {
97 0 => Self::Any,
98 1 => Self::Until1(exits[0]),
99 2 => Self::Until2(exits[0], exits[1]),
100 3 => Self::Until3(exits[0], exits[1], exits[2]),
101 _ => AsciiRanges::from_self_loops(row, state).map_or(Self::None, Self::Ranges),
102 }
103 }
104
105 fn scan(self, input: &[u8]) -> Option<AsciiRunScan> {
106 let exit = match self {
107 Self::None => return None,
108 Self::Any => None,
109 Self::Until1(a) => memchr(a, input),
110 Self::Until2(a, b) => memchr2(a, b, input),
111 Self::Until3(a, b, c) => memchr3(a, b, c, input),
112 Self::Ranges(ranges) => {
113 let bytes = ascii_range::scan_scalar(ranges, input);
114 return Some(AsciiRunScan {
115 bytes,
116 found_exit: bytes != input.len(),
117 #[cfg(any(feature = "perf-counters", test))]
118 range: Some(AsciiRangeScan { ranges }),
119 });
120 }
121 };
122 Some(AsciiRunScan {
123 bytes: exit.unwrap_or(input.len()),
124 found_exit: exit.is_some(),
125 #[cfg(any(feature = "perf-counters", test))]
126 range: None,
127 })
128 }
129
130 const fn serialized_words(self) -> usize {
131 if matches!(self, Self::Ranges(_)) {
132 3
133 } else {
134 1
135 }
136 }
137
138 fn write_serialized(self, out: &mut Vec<u32>) {
139 match self {
140 Self::None => out.push(0),
141 Self::Any => out.push(1),
142 Self::Until1(a) => out.push(2 | (u32::from(a) << 8)),
143 Self::Until2(a, b) => {
144 out.push(3 | (u32::from(a) << 8) | (u32::from(b) << 16));
145 }
146 Self::Until3(a, b, c) => {
147 out.push(4 | (u32::from(a) << 8) | (u32::from(b) << 16) | (u32::from(c) << 24));
148 }
149 Self::Ranges(ranges) => {
150 out.push(5 | (u32::from(ranges.count()) << 8));
151 out.extend(ranges.packed_words());
152 }
153 }
154 }
155
156 fn read_serialized(reader: &mut SerializedReader<'_>) -> Option<Self> {
157 let word = reader.next()?;
158 match word.to_le_bytes() {
159 [0, 0, 0, 0] => Some(Self::None),
160 [1, 0, 0, 0] => Some(Self::Any),
161 [2, a, 0, 0] if a.is_ascii() => Some(Self::Until1(a)),
162 [3, a, b, 0] if a.is_ascii() && b.is_ascii() => Some(Self::Until2(a, b)),
163 [4, a, b, c] if a.is_ascii() && b.is_ascii() && c.is_ascii() => {
164 Some(Self::Until3(a, b, c))
165 }
166 [5, count, 0, 0] => Some(Self::Ranges(AsciiRanges::from_packed(
167 count,
168 [reader.next()?, reader.next()?],
169 )?)),
170 _ => None,
171 }
172 }
173
174 #[cfg(feature = "perf-counters")]
175 fn descriptor_kind(self) -> AsciiRunDescriptorKind {
176 match self {
177 Self::None => AsciiRunDescriptorKind::None,
178 Self::Any => AsciiRunDescriptorKind::Any,
179 Self::Until1(_) | Self::Until2(..) | Self::Until3(..) => AsciiRunDescriptorKind::Until,
180 Self::Ranges(ranges) => AsciiRunDescriptorKind::Ranges {
181 count: ranges.count(),
182 class: ranges.class(),
183 },
184 }
185 }
186}
187
188#[derive(Clone, Copy, Debug, Eq, PartialEq)]
189pub(super) struct AsciiRunScan {
190 pub(super) bytes: usize,
191 pub(super) found_exit: bool,
192 #[cfg(any(feature = "perf-counters", test))]
193 pub(super) range: Option<AsciiRangeScan>,
194}
195
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197#[cfg(any(feature = "perf-counters", test))]
198pub(super) struct AsciiRangeScan {
199 ranges: AsciiRanges,
200}
201
202#[cfg(feature = "perf-counters")]
203impl AsciiRangeScan {
204 pub(super) fn class(self) -> AsciiRangeClass {
205 self.ranges.class()
206 }
207}
208
209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
210#[cfg(feature = "perf-counters")]
211pub(crate) enum AsciiRunDescriptorKind {
212 None,
213 Any,
214 Until,
215 Ranges { count: u8, class: AsciiRangeClass },
216}
217
218#[derive(Clone, Debug)]
225pub struct CompiledLexerDfa {
226 mode_starts: Vec<Option<u16>>,
227 states: Vec<CompiledLexerState>,
228 ascii_runs: Vec<AsciiRun>,
229 ascii_rows: Vec<[u16; ASCII_EDGE_SYMBOLS]>,
230 wide_rows: Vec<Box<[WideRange]>>,
231 accepts: Vec<CompiledLexerAccept>,
232 escape_rows: Vec<CompiledLexerEscapeRow>,
233 continuations: Vec<CompiledLexerContinuation>,
234}
235
236#[derive(Clone, Copy, Debug)]
239struct CompiledLexerState {
240 ascii_row: u32,
241 wide_row: u32,
242 eof_target: u16,
243 accept: u32,
245}
246
247#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
249struct WideRange {
250 low: u32,
251 high: u32,
252 target: u16,
253}
254
255#[derive(Clone, Debug)]
257struct CompiledLexerEscapeRow {
258 ranges: Box<[CompiledLexerEscapeRange]>,
259 eof: u32,
260}
261
262#[derive(Clone, Copy, Debug)]
264struct CompiledLexerEscapeRange {
265 low: u32,
266 high: u32,
267 continuation: u32,
268}
269
270#[derive(Clone, Debug)]
273pub(super) struct CompiledLexerContinuation {
274 pub(super) contexts: Vec<CompiledLexerContext>,
275 pub(super) configs: Vec<CompiledLexerConfig>,
276}
277
278#[derive(Clone, Copy, Debug)]
280pub(super) enum CompiledLexerContext {
281 Singleton { parent: u32, return_state: usize },
282 Union { left: u32, right: u32 },
283}
284
285#[derive(Clone, Debug)]
287pub(super) struct CompiledLexerConfig {
288 pub(super) state: usize,
289 pub(super) consumed_eof: bool,
290 pub(super) alt_rule_index: Option<usize>,
291 pub(super) passed_non_greedy: bool,
292 pub(super) context: u32,
293 pub(super) actions: Vec<CompiledLexerActionTrace>,
294}
295
296#[derive(Clone, Debug)]
299pub(super) struct CompiledLexerAccept {
300 pub(super) rule_index: usize,
301 pub(super) consumed_eof: bool,
302 pub(super) actions: Vec<CompiledLexerActionTrace>,
303}
304
305#[derive(Clone, Copy, Debug)]
308pub(super) struct CompiledLexerActionTrace {
309 pub(super) action_index: usize,
310 pub(super) rule_index: usize,
311 pub(super) behind: usize,
313}
314
315impl CompiledLexerDfa {
316 pub fn compile(atn: &LexerAtn) -> Self {
319 let mut dfa = Self {
320 mode_starts: Vec::new(),
321 states: Vec::new(),
322 ascii_runs: Vec::new(),
323 ascii_rows: Vec::new(),
324 wide_rows: Vec::new(),
325 accepts: Vec::new(),
326 escape_rows: Vec::new(),
327 continuations: Vec::new(),
328 };
329 let mut pools = RowPools::default();
330 for mode in 0..atn.mode_to_start_state().len() {
331 let start = build_mode(atn, mode, &mut dfa, &mut pools);
332 dfa.mode_starts.push(start);
333 }
334 #[cfg(feature = "perf-counters")]
335 dfa.record_ascii_run_descriptors();
336 dfa
337 }
338
339 pub fn has_compiled_modes(&self) -> bool {
341 self.mode_starts.iter().any(Option::is_some)
342 }
343
344 pub const fn state_count(&self) -> usize {
346 self.states.len()
347 }
348
349 pub fn compiled_mode_flags(&self) -> Vec<bool> {
351 self.mode_starts.iter().map(Option::is_some).collect()
352 }
353
354 pub fn mode_state_counts(&self) -> Vec<usize> {
356 let mut starts: Vec<usize> = self
357 .mode_starts
358 .iter()
359 .flatten()
360 .map(|&start| usize::from(start))
361 .collect();
362 starts.push(self.states.len());
363 starts.windows(2).map(|pair| pair[1] - pair[0]).collect()
364 }
365
366 pub(super) fn mode_start(&self, mode: i32) -> Option<u16> {
369 let mode = usize::try_from(mode).ok()?;
370 self.mode_starts.get(mode).copied().flatten()
371 }
372
373 pub(super) fn accept(&self, state: u16) -> Option<&CompiledLexerAccept> {
374 self.accepts
375 .get(self.states[usize::from(state)].accept as usize)
376 }
377
378 pub(super) fn ascii_target(&self, state: u16, symbol: u8) -> u16 {
380 debug_assert!(symbol.is_ascii());
381 let compiled = &self.states[usize::from(state)];
382 self.ascii_rows[compiled.ascii_row as usize][usize::from(symbol)]
383 }
384
385 pub(super) fn ascii_run(&self, state: u16) -> AsciiRun {
386 self.ascii_runs[usize::from(state)]
387 }
388
389 pub(super) fn scan_ascii_run(&self, state: u16, input: &[u8]) -> Option<AsciiRunScan> {
390 self.ascii_run(state).scan(input)
391 }
392
393 pub(super) fn char_target(&self, state: u16, symbol: i32) -> u16 {
395 let compiled = &self.states[usize::from(state)];
396 let code_point = symbol.cast_unsigned();
397 if let Ok(ascii) = usize::try_from(symbol)
398 && ascii < ASCII_EDGE_SYMBOLS
399 {
400 return self.ascii_rows[compiled.ascii_row as usize][ascii];
401 }
402 let row = &self.wide_rows[compiled.wide_row as usize];
403 match row.binary_search_by(|range| range.low.cmp(&code_point)) {
404 Ok(found) => row[found].target,
405 Err(insert) => {
406 if insert > 0 && row[insert - 1].high >= code_point {
407 row[insert - 1].target
408 } else {
409 DEAD_STATE
410 }
411 }
412 }
413 }
414
415 pub(super) fn eof_target(&self, state: u16) -> u16 {
417 self.states[usize::from(state)].eof_target
418 }
419
420 pub(super) fn char_continuation(
422 &self,
423 state: u16,
424 symbol: i32,
425 ) -> Option<&CompiledLexerContinuation> {
426 let code_point = symbol.cast_unsigned();
427 let ranges = &self.escape_rows[usize::from(state)].ranges;
428 let found = match ranges.binary_search_by(|range| range.low.cmp(&code_point)) {
429 Ok(found) => Some(found),
430 Err(insert) if insert > 0 && ranges[insert - 1].high >= code_point => Some(insert - 1),
431 Err(_) => None,
432 }?;
433 let continuation = usize::try_from(ranges[found].continuation).ok()?;
434 self.continuations.get(continuation)
435 }
436
437 pub(super) fn eof_continuation(&self, state: u16) -> Option<&CompiledLexerContinuation> {
439 let continuation = usize::try_from(self.escape_rows[usize::from(state)].eof).ok()?;
440 self.continuations.get(continuation)
441 }
442
443 pub fn serialize(&self) -> Vec<u32> {
450 let ascii_run_words: usize = self
455 .ascii_runs
456 .iter()
457 .map(|run| run.serialized_words())
458 .sum();
459 let wide_words: usize = self.wide_rows.iter().map(|row| 1 + row.len() * 3).sum();
460 let accept_words: usize = self
461 .accepts
462 .iter()
463 .map(|accept| 3 + accept.actions.len() * 3)
464 .sum();
465 let escape_row_words: usize = self
466 .escape_rows
467 .iter()
468 .map(|row| 2 + row.ranges.len() * 3)
469 .sum();
470 let continuation_words: usize = self
471 .continuations
472 .iter()
473 .map(|continuation| {
474 2 + continuation.contexts.len() * 3
475 + continuation
476 .configs
477 .iter()
478 .map(|config| 6 + config.actions.len() * 3)
479 .sum::<usize>()
480 })
481 .sum();
482 let capacity = 9
483 + self.mode_starts.len()
484 + self.states.len() * 4
485 + ascii_run_words
486 + self.ascii_rows.len() * (ASCII_EDGE_SYMBOLS / 2)
487 + wide_words
488 + accept_words
489 + escape_row_words
490 + continuation_words;
491 let mut out = Vec::with_capacity(capacity);
492 out.push(SERIALIZED_TAG);
493 out.push(self.mode_starts.len() as u32);
494 for start in &self.mode_starts {
495 out.push(start.map_or(u32::MAX, u32::from));
496 }
497 out.push(self.states.len() as u32);
498 for state in &self.states {
499 out.push(state.ascii_row);
500 out.push(state.wide_row);
501 out.push(u32::from(state.eof_target));
502 out.push(state.accept);
503 }
504 out.push(u32::try_from(self.ascii_runs.len()).expect("ascii_runs length overflow"));
505 for &run in &self.ascii_runs {
506 run.write_serialized(&mut out);
507 }
508 out.push(self.ascii_rows.len() as u32);
509 for row in &self.ascii_rows {
510 for pair in row.chunks(2) {
511 out.push(u32::from(pair[0]) | (u32::from(pair[1]) << 16));
512 }
513 }
514 out.push(self.wide_rows.len() as u32);
515 for row in &self.wide_rows {
516 out.push(row.len() as u32);
517 for range in &**row {
518 out.push(range.low);
519 out.push(range.high);
520 out.push(u32::from(range.target));
521 }
522 }
523 out.push(self.accepts.len() as u32);
524 for accept in &self.accepts {
525 out.push(accept.rule_index as u32);
526 out.push(u32::from(accept.consumed_eof));
527 out.push(accept.actions.len() as u32);
528 for action in &accept.actions {
529 out.push(action.action_index as u32);
530 out.push(action.rule_index as u32);
531 out.push(action.behind as u32);
532 }
533 }
534 out.push(self.escape_rows.len() as u32);
535 for row in &self.escape_rows {
536 out.push(row.eof);
537 out.push(row.ranges.len() as u32);
538 for range in &*row.ranges {
539 out.push(range.low);
540 out.push(range.high);
541 out.push(range.continuation);
542 }
543 }
544 out.push(self.continuations.len() as u32);
545 for continuation in &self.continuations {
546 out.push(continuation.contexts.len() as u32);
547 for context in &continuation.contexts {
548 match context {
549 CompiledLexerContext::Singleton {
550 parent,
551 return_state,
552 } => {
553 out.push(0);
554 out.push(*parent);
555 out.push(
556 u32::try_from(*return_state)
557 .expect("lexer context return state must fit in u32"),
558 );
559 }
560 CompiledLexerContext::Union { left, right } => {
561 out.push(1);
562 out.push(*left);
563 out.push(*right);
564 }
565 }
566 }
567 out.push(continuation.configs.len() as u32);
568 for config in &continuation.configs {
569 out.push(config.state as u32);
570 out.push(config.alt_rule_index.map_or(u32::MAX, |rule| rule as u32));
571 out.push(u32::from(config.consumed_eof));
572 out.push(u32::from(config.passed_non_greedy));
573 out.push(config.context);
574 out.push(config.actions.len() as u32);
575 for action in &config.actions {
576 out.push(action.action_index as u32);
577 out.push(action.rule_index as u32);
578 out.push(action.behind as u32);
579 }
580 }
581 }
582 debug_assert_eq!(
583 out.len(),
584 capacity,
585 "serialized stream fills its capacity exactly"
586 );
587 out
588 }
589
590 pub fn from_serialized(data: &[u32]) -> Option<Self> {
593 let mut reader = SerializedReader { data, position: 0 };
594 if reader.next()? != SERIALIZED_TAG {
595 return None;
596 }
597 let mode_count = reader.next_len()?;
598 let mut mode_starts = Vec::with_capacity(mode_count);
599 for _ in 0..mode_count {
600 let word = reader.next()?;
601 let start = if word == u32::MAX {
602 None
603 } else {
604 Some(u16::try_from(word).ok()?)
605 };
606 mode_starts.push(start);
607 }
608 let states = reader.read_states()?;
609 let ascii_runs = reader.read_ascii_runs()?;
610 let ascii_rows = reader.read_ascii_rows()?;
611 let wide_rows = reader.read_wide_rows()?;
612 let accepts = reader.read_accepts()?;
613 let escape_rows = reader.read_escape_rows()?;
614 let continuations = reader.read_continuations()?;
615 if reader.position != data.len() {
616 return None;
617 }
618 let dfa = Self {
619 mode_starts,
620 states,
621 ascii_runs,
622 ascii_rows,
623 wide_rows,
624 accepts,
625 escape_rows,
626 continuations,
627 };
628 if !dfa.table_indexes_are_valid() {
629 return None;
630 }
631 #[cfg(feature = "perf-counters")]
632 dfa.record_ascii_run_descriptors();
633 Some(dfa)
634 }
635
636 fn table_indexes_are_valid(&self) -> bool {
639 let state_ok =
640 |target: u16| usize::from(target) < self.states.len() || target >= ESCAPE_STATE;
641 let continuation_ok = |continuation: u32| {
642 usize::try_from(continuation)
643 .is_ok_and(|continuation| continuation < self.continuations.len())
644 };
645 self.mode_starts
646 .iter()
647 .flatten()
648 .all(|&start| usize::from(start) < self.states.len())
649 && self.states.iter().all(|state| {
650 (state.ascii_row as usize) < self.ascii_rows.len()
651 && (state.wide_row as usize) < self.wide_rows.len()
652 && state_ok(state.eof_target)
653 && (state.accept == u32::MAX || (state.accept as usize) < self.accepts.len())
654 })
655 && self.ascii_runs.len() == self.states.len()
656 && self.states.iter().zip(&self.ascii_runs).enumerate().all(
657 |(state_id, (state, &ascii_run))| {
658 u16::try_from(state_id).is_ok_and(|state_id| {
659 ascii_run
660 == AsciiRun::classify(
661 &self.ascii_rows[state.ascii_row as usize],
662 state_id,
663 )
664 })
665 },
666 )
667 && self
668 .ascii_rows
669 .iter()
670 .all(|row| row.iter().all(|&target| state_ok(target)))
671 && self.wide_rows.iter().all(|row| {
672 wide_row_is_searchable(row) && row.iter().all(|range| state_ok(range.target))
673 })
674 && self.escape_rows.len() == self.states.len()
675 && self.escape_rows.iter().all(|row| {
676 (row.eof == u32::MAX || continuation_ok(row.eof))
677 && escape_row_is_searchable(&row.ranges)
678 && row
679 .ranges
680 .iter()
681 .all(|range| continuation_ok(range.continuation))
682 })
683 && self
684 .continuations
685 .iter()
686 .all(compiled_continuation_contexts_are_valid)
687 }
688
689 #[cfg(feature = "perf-counters")]
690 fn record_ascii_run_descriptors(&self) {
691 for &run in &self.ascii_runs {
692 crate::perf::record_lexer_run_descriptor(run.descriptor_kind());
693 }
694 }
695}
696
697fn compiled_continuation_contexts_are_valid(continuation: &CompiledLexerContinuation) -> bool {
698 let contexts_valid = continuation
699 .contexts
700 .iter()
701 .enumerate()
702 .all(|(index, context)| {
703 let local_id = u32::try_from(index + 1).ok();
704 local_id.is_some_and(|local_id| match context {
705 CompiledLexerContext::Singleton { parent, .. } => *parent < local_id,
706 CompiledLexerContext::Union { left, right } => {
707 *left < local_id && *right < local_id
708 }
709 })
710 });
711 contexts_valid
712 && u32::try_from(continuation.contexts.len()).is_ok_and(|max_context| {
713 continuation
714 .configs
715 .iter()
716 .all(|config| config.context <= max_context)
717 })
718}
719
720fn wide_row_is_searchable(row: &[WideRange]) -> bool {
724 row.iter().all(|range| range.low <= range.high)
725 && row.windows(2).all(|pair| pair[0].high < pair[1].low)
726}
727
728fn escape_row_is_searchable(row: &[CompiledLexerEscapeRange]) -> bool {
729 row.iter().all(|range| range.low <= range.high)
730 && row.windows(2).all(|pair| pair[0].high < pair[1].low)
731}
732
733const SERIALIZED_TAG: u32 = 0x4C58_4407;
736
737struct SerializedReader<'a> {
739 data: &'a [u32],
740 position: usize,
741}
742
743impl SerializedReader<'_> {
744 fn next(&mut self) -> Option<u32> {
745 let value = self.data.get(self.position).copied();
746 self.position += 1;
747 value
748 }
749
750 fn next_u16(&mut self) -> Option<u16> {
751 u16::try_from(self.next()?).ok()
752 }
753
754 fn next_len(&mut self) -> Option<usize> {
755 usize::try_from(self.next()?).ok()
756 }
757
758 fn read_states(&mut self) -> Option<Vec<CompiledLexerState>> {
759 let count = self.next_len()?;
760 let mut states = Vec::with_capacity(count.min(self.data.len()));
761 for _ in 0..count {
762 states.push(CompiledLexerState {
763 ascii_row: self.next()?,
764 wide_row: self.next()?,
765 eof_target: self.next_u16()?,
766 accept: self.next()?,
767 });
768 }
769 Some(states)
770 }
771
772 fn read_ascii_runs(&mut self) -> Option<Vec<AsciiRun>> {
773 let count = self.next_len()?;
774 let mut runs = Vec::with_capacity(count.min(self.data.len()));
775 for _ in 0..count {
776 runs.push(AsciiRun::read_serialized(self)?);
777 }
778 Some(runs)
779 }
780
781 fn read_ascii_rows(&mut self) -> Option<Vec<[u16; ASCII_EDGE_SYMBOLS]>> {
782 let count = self.next_len()?;
783 let mut rows = Vec::with_capacity(count.min(self.data.len()));
784 for _ in 0..count {
785 let mut row = [DEAD_STATE; ASCII_EDGE_SYMBOLS];
786 for pair in 0..ASCII_EDGE_SYMBOLS / 2 {
787 let word = self.next()?;
788 row[pair * 2] = (word & 0xFFFF) as u16;
789 row[pair * 2 + 1] = (word >> 16) as u16;
790 }
791 rows.push(row);
792 }
793 Some(rows)
794 }
795
796 fn read_wide_rows(&mut self) -> Option<Vec<Box<[WideRange]>>> {
797 let count = self.next_len()?;
798 let mut rows = Vec::with_capacity(count.min(self.data.len()));
799 for _ in 0..count {
800 let len = self.next_len()?;
801 let mut row = Vec::with_capacity(len.min(self.data.len()));
802 for _ in 0..len {
803 row.push(WideRange {
804 low: self.next()?,
805 high: self.next()?,
806 target: self.next_u16()?,
807 });
808 }
809 rows.push(row.into());
810 }
811 Some(rows)
812 }
813
814 fn read_accepts(&mut self) -> Option<Vec<CompiledLexerAccept>> {
815 let count = self.next_len()?;
816 let mut accepts = Vec::with_capacity(count.min(self.data.len()));
817 for _ in 0..count {
818 let rule_index = self.next_len()?;
819 let consumed_eof = self.next()? != 0;
820 let action_count = self.next_len()?;
821 let mut actions = Vec::with_capacity(action_count.min(self.data.len()));
822 for _ in 0..action_count {
823 actions.push(CompiledLexerActionTrace {
824 action_index: self.next_len()?,
825 rule_index: self.next_len()?,
826 behind: self.next_len()?,
827 });
828 }
829 accepts.push(CompiledLexerAccept {
830 rule_index,
831 consumed_eof,
832 actions,
833 });
834 }
835 Some(accepts)
836 }
837
838 fn read_escape_rows(&mut self) -> Option<Vec<CompiledLexerEscapeRow>> {
839 let count = self.next_len()?;
840 let mut rows = Vec::with_capacity(count.min(self.data.len()));
841 for _ in 0..count {
842 let eof = self.next()?;
843 let len = self.next_len()?;
844 let mut ranges = Vec::with_capacity(len.min(self.data.len()));
845 for _ in 0..len {
846 ranges.push(CompiledLexerEscapeRange {
847 low: self.next()?,
848 high: self.next()?,
849 continuation: self.next()?,
850 });
851 }
852 rows.push(CompiledLexerEscapeRow {
853 ranges: ranges.into(),
854 eof,
855 });
856 }
857 Some(rows)
858 }
859
860 fn read_continuations(&mut self) -> Option<Vec<CompiledLexerContinuation>> {
861 let count = self.next_len()?;
862 let mut continuations = Vec::with_capacity(count.min(self.data.len()));
863 for _ in 0..count {
864 let context_count = self.next_len()?;
865 let mut contexts = Vec::with_capacity(context_count.min(self.data.len()));
866 for _ in 0..context_count {
867 let kind = self.next()?;
868 let first = self.next()?;
869 let second = self.next()?;
870 contexts.push(match kind {
871 0 => CompiledLexerContext::Singleton {
872 parent: first,
873 return_state: usize::try_from(second).ok()?,
874 },
875 1 => CompiledLexerContext::Union {
876 left: first,
877 right: second,
878 },
879 _ => return None,
880 });
881 }
882 let config_count = self.next_len()?;
883 let mut configs = Vec::with_capacity(config_count.min(self.data.len()));
884 for _ in 0..config_count {
885 let state = self.next_len()?;
886 let alt_rule = self.next()?;
887 let alt_rule_index = if alt_rule == u32::MAX {
888 None
889 } else {
890 Some(usize::try_from(alt_rule).ok()?)
891 };
892 let consumed_eof = self.next()? != 0;
893 let passed_non_greedy = self.next()? != 0;
894 let context = self.next()?;
895 let action_count = self.next_len()?;
896 let mut actions = Vec::with_capacity(action_count.min(self.data.len()));
897 for _ in 0..action_count {
898 actions.push(CompiledLexerActionTrace {
899 action_index: self.next_len()?,
900 rule_index: self.next_len()?,
901 behind: self.next_len()?,
902 });
903 }
904 configs.push(CompiledLexerConfig {
905 state,
906 consumed_eof,
907 alt_rule_index,
908 passed_non_greedy,
909 context,
910 actions,
911 });
912 }
913 continuations.push(CompiledLexerContinuation { contexts, configs });
914 }
915 Some(continuations)
916 }
917}
918
919#[derive(Debug, Default)]
921struct RowPools {
922 ascii_ids: FxHashMap<[u16; ASCII_EDGE_SYMBOLS], u32>,
923 wide_ids: FxHashMap<Box<[WideRange]>, u32>,
924}
925
926impl RowPools {
927 fn intern_ascii(
928 &mut self,
929 rows: &mut Vec<[u16; ASCII_EDGE_SYMBOLS]>,
930 row: [u16; ASCII_EDGE_SYMBOLS],
931 ) -> u32 {
932 *self.ascii_ids.entry(row).or_insert_with(|| {
933 rows.push(row);
934 (rows.len() - 1) as u32
935 })
936 }
937
938 fn intern_wide(&mut self, rows: &mut Vec<Box<[WideRange]>>, row: Vec<WideRange>) -> u32 {
939 let row: Box<[WideRange]> = row.into();
940 if let Some(&id) = self.wide_ids.get(&row) {
941 return id;
942 }
943 rows.push(row.clone());
944 let id = (rows.len() - 1) as u32;
945 self.wide_ids.insert(row, id);
946 id
947 }
948}
949
950struct ModeBuild {
956 base: usize,
957 continuation_base: usize,
958 contexts: LexerContextArena,
959 workspace: PredictionWorkspace,
960 ids: FxHashMap<LexerDfaKey, u16>,
961 configs: Vec<Vec<LexerConfig>>,
962 steps: Vec<usize>,
963 accepts: Vec<Option<CompiledLexerAccept>>,
964 continuations: Vec<CompiledLexerContinuation>,
965}
966
967struct StateRows {
969 segments: Vec<(i32, i32, u16)>,
971 eof_target: u16,
972 escapes: Vec<(i32, i32, u32)>,
973 eof_escape: u32,
974}
975
976#[derive(Clone, Copy)]
977struct EdgeTarget {
978 state: u16,
979 continuation: u32,
980}
981
982impl EdgeTarget {
983 const DEAD: Self = Self {
984 state: DEAD_STATE,
985 continuation: u32::MAX,
986 };
987}
988
989impl ModeBuild {
990 fn new(base: usize, continuation_base: usize) -> Self {
991 Self {
992 base,
993 continuation_base,
994 contexts: LexerContextArena::new(),
995 workspace: PredictionWorkspace::default(),
996 ids: FxHashMap::default(),
997 configs: Vec::new(),
998 steps: Vec::new(),
999 accepts: Vec::new(),
1000 continuations: Vec::new(),
1001 }
1002 }
1003
1004 const fn len(&self) -> usize {
1005 self.configs.len()
1006 }
1007
1008 fn intern(&mut self, atn: &LexerAtn, configs: Vec<LexerConfig>, step: usize) -> u16 {
1013 let key = LexerDfaKey::new(
1014 configs
1015 .iter()
1016 .map(|config| relative_config_key(config, step))
1017 .collect(),
1018 );
1019 if let Some(&id) = self.ids.get(&key) {
1020 return id;
1021 }
1022 let local = self.configs.len();
1023 let global = self.base + local;
1024 if local >= MAX_MODE_STATES || global >= usize::from(ESCAPE_STATE) {
1025 return ESCAPE_STATE;
1026 }
1027 let Ok(id) = u16::try_from(global) else {
1028 return ESCAPE_STATE;
1029 };
1030 self.ids.insert(key, id);
1031 self.accepts.push(compiled_accept(atn, &configs, step));
1032 self.configs.push(configs);
1033 self.steps.push(step);
1034 id
1035 }
1036
1037 fn add_continuation(&mut self, configs: &[LexerConfig], step: usize) -> u32 {
1038 let id = self.continuation_base + self.continuations.len();
1039 let Ok(id) = u32::try_from(id) else {
1040 return u32::MAX;
1041 };
1042 let mut context_ids = FxHashMap::default();
1043 context_ids.insert(EMPTY_LEXER_CONTEXT, 0);
1044 let mut contexts = Vec::new();
1045 let compiled_configs = configs
1046 .iter()
1047 .map(|config| CompiledLexerConfig {
1048 state: config.state,
1049 consumed_eof: config.consumed_eof,
1050 alt_rule_index: config.alt_rule_index(),
1051 passed_non_greedy: config.passed_non_greedy,
1052 context: compile_context(
1053 &self.contexts,
1054 config.context,
1055 &mut context_ids,
1056 &mut contexts,
1057 ),
1058 actions: config
1059 .actions
1060 .as_slice()
1061 .iter()
1062 .map(|action| CompiledLexerActionTrace {
1063 action_index: action.action_index,
1064 rule_index: action.rule_index,
1065 behind: step.saturating_sub(action.position),
1066 })
1067 .collect(),
1068 })
1069 .collect();
1070 self.continuations.push(CompiledLexerContinuation {
1071 contexts,
1072 configs: compiled_configs,
1073 });
1074 id
1075 }
1076}
1077
1078fn relative_config_key(config: &LexerConfig, step: usize) -> LexerDfaConfigKey {
1086 LexerDfaConfigKey::new(
1087 config.state,
1088 config.alt_rule_index(),
1089 config.consumed_eof,
1090 config.passed_non_greedy,
1091 config.context,
1092 config
1093 .actions
1094 .as_slice()
1095 .iter()
1096 .map(|action| LexerDfaActionKey {
1097 action_index: action.action_index,
1098 position_delta: step.saturating_sub(action.position),
1099 rule_index: action.rule_index,
1100 })
1101 .collect(),
1102 )
1103}
1104
1105fn compiled_accept(
1108 atn: &LexerAtn,
1109 configs: &[LexerConfig],
1110 step: usize,
1111) -> Option<CompiledLexerAccept> {
1112 let accept = best_accept(atn, configs)?;
1113 debug_assert!(
1114 accept.position == step,
1115 "every config in a lexer DFA state shares the state's input offset"
1116 );
1117 Some(CompiledLexerAccept {
1118 rule_index: accept.rule_index,
1119 consumed_eof: accept.consumed_eof,
1120 actions: accept
1121 .actions
1122 .iter()
1123 .map(|trace| CompiledLexerActionTrace {
1124 action_index: trace.action_index,
1125 rule_index: trace.rule_index,
1126 behind: accept.position.saturating_sub(trace.position),
1127 })
1128 .collect(),
1129 })
1130}
1131
1132fn build_mode(
1135 atn: &LexerAtn,
1136 mode: usize,
1137 dfa: &mut CompiledLexerDfa,
1138 pools: &mut RowPools,
1139) -> Option<u16> {
1140 let start_state = atn.mode_to_start_state().get(mode).copied()?;
1141 let mut build = ModeBuild::new(dfa.states.len(), dfa.continuations.len());
1142 let start_configs = closed_configs(
1143 atn,
1144 &mut build,
1145 vec![LexerConfig::new(start_state, 0, EMPTY_LEXER_CONTEXT)],
1146 )?;
1147 let start_id = build.intern(atn, start_configs, 0);
1148 if start_id == ESCAPE_STATE {
1149 return None;
1150 }
1151
1152 let mut rows = Vec::new();
1153 let mut cursor = 0;
1154 while cursor < build.len() {
1155 rows.push(expand_state(atn, &mut build, cursor));
1156 cursor += 1;
1157 }
1158
1159 commit_mode(dfa, pools, build, rows);
1160 Some(start_id)
1161}
1162
1163fn closed_configs(
1168 atn: &LexerAtn,
1169 build: &mut ModeBuild,
1170 moved: Vec<LexerConfig>,
1171) -> Option<Vec<LexerConfig>> {
1172 let closure = epsilon_closure(
1173 atn,
1174 moved,
1175 &mut build.contexts,
1176 &mut build.workspace,
1177 &mut |_| true,
1178 );
1179 if closure.has_semantic_context {
1180 return None;
1181 }
1182 if closure
1183 .configs
1184 .iter()
1185 .any(|config| has_recursive_context(config, &build.contexts))
1186 {
1187 return None;
1188 }
1189 let mut configs = closure.configs;
1190 for config in &mut configs {
1191 prune_dead_action_traces(atn, config);
1192 if config.actions.len() > MAX_ACTION_TRACES {
1193 return None;
1194 }
1195 }
1196 Some(prune_after_accepts(atn, configs))
1197}
1198
1199fn prune_dead_action_traces(atn: &LexerAtn, config: &mut LexerConfig) {
1208 let Some(accept_rule) = config.alt_rule_index() else {
1209 return;
1210 };
1211 config
1212 .actions
1213 .retain(|trace| lexer_action_belongs_to_accept(atn, accept_rule, trace.rule_index));
1214}
1215
1216fn compile_context(
1218 contexts: &LexerContextArena,
1219 context: LexerContextId,
1220 ids: &mut FxHashMap<LexerContextId, u32>,
1221 compiled: &mut Vec<CompiledLexerContext>,
1222) -> u32 {
1223 if let Some(&id) = ids.get(&context) {
1224 return id;
1225 }
1226
1227 enum Frame {
1228 Visit(LexerContextId),
1229 Finish(LexerContextId),
1230 }
1231
1232 let mut pending = vec![Frame::Visit(context)];
1233 while let Some(frame) = pending.pop() {
1234 match frame {
1235 Frame::Visit(current) => {
1236 if ids.contains_key(¤t) {
1237 continue;
1238 }
1239 let node = contexts.node(current);
1240 match node {
1241 LexerContextNode::Empty => {
1242 ids.insert(current, 0);
1243 }
1244 LexerContextNode::Singleton { parent, .. } => {
1245 pending.push(Frame::Finish(current));
1246 pending.push(Frame::Visit(parent));
1247 }
1248 LexerContextNode::Union { left, right } => {
1249 pending.push(Frame::Finish(current));
1250 pending.push(Frame::Visit(right));
1251 pending.push(Frame::Visit(left));
1252 }
1253 }
1254 }
1255 Frame::Finish(current) => {
1256 let node = match contexts.node(current) {
1257 LexerContextNode::Empty => unreachable!("empty contexts finish immediately"),
1258 LexerContextNode::Singleton {
1259 parent,
1260 return_state,
1261 } => CompiledLexerContext::Singleton {
1262 parent: ids[&parent],
1263 return_state,
1264 },
1265 LexerContextNode::Union { left, right } => CompiledLexerContext::Union {
1266 left: ids[&left],
1267 right: ids[&right],
1268 },
1269 };
1270 let id = u32::try_from(compiled.len() + 1)
1271 .expect("compiled lexer context table overflow");
1272 compiled.push(node);
1273 ids.insert(current, id);
1274 }
1275 }
1276 }
1277
1278 ids[&context]
1279}
1280
1281fn has_recursive_context(config: &LexerConfig, contexts: &LexerContextArena) -> bool {
1285 enum Frame {
1286 Visit(LexerContextId),
1287 LeaveRule,
1288 }
1289
1290 let mut path = Vec::with_capacity(MAX_CONTEXT_DEPTH);
1291 let mut pending = vec![Frame::Visit(config.context)];
1292 while let Some(frame) = pending.pop() {
1293 match frame {
1294 Frame::Visit(context) => match contexts.node(context) {
1295 LexerContextNode::Empty => {}
1296 LexerContextNode::Union { left, right } => {
1297 pending.push(Frame::Visit(right));
1298 pending.push(Frame::Visit(left));
1299 }
1300 LexerContextNode::Singleton {
1301 parent,
1302 return_state,
1303 } => {
1304 if path.len() >= MAX_CONTEXT_DEPTH || path.contains(&return_state) {
1305 return true;
1306 }
1307 path.push(return_state);
1308 pending.push(Frame::LeaveRule);
1309 pending.push(Frame::Visit(parent));
1310 }
1311 },
1312 Frame::LeaveRule => {
1313 path.pop().expect("leave frame must match an entered rule");
1314 }
1315 }
1316 }
1317
1318 false
1319}
1320
1321fn expand_state(atn: &LexerAtn, build: &mut ModeBuild, local: usize) -> StateRows {
1323 let configs = build.configs[local].clone();
1324 let step = build.steps[local];
1325 let entries = consuming_entries(atn, &configs);
1326 let eof_target = eof_move(atn, build, &configs, step, &entries);
1327
1328 let entry_intervals: Vec<Vec<(i32, i32)>> = entries
1329 .iter()
1330 .map(|(_, transition)| transition_char_intervals(transition))
1331 .collect();
1332 let segments = char_segments(&entry_intervals);
1333 let matrix = segment_mask_matrix(&segments, &entry_intervals, entries.len());
1334 let words = entries.len().div_ceil(64);
1335
1336 let mut rows = StateRows {
1337 segments: Vec::new(),
1338 eof_target: eof_target.state,
1339 escapes: Vec::new(),
1340 eof_escape: eof_target.continuation,
1341 };
1342 let mut mask_targets: FxHashMap<Vec<u64>, EdgeTarget> = FxHashMap::default();
1346 for (index, &(low, high)) in segments.iter().enumerate() {
1347 let mask = &matrix[index * words..(index + 1) * words];
1348 if mask.iter().all(|&word| word == 0) {
1349 continue;
1350 }
1351 let target = match mask_targets.get(mask) {
1352 Some(&target) => target,
1353 None => {
1354 let target = move_target(atn, build, &configs, step, &entries, mask);
1355 mask_targets.insert(mask.to_vec(), target);
1356 target
1357 }
1358 };
1359 if target.state != DEAD_STATE {
1360 rows.segments.push((low, high, target.state));
1361 if target.continuation != u32::MAX {
1362 rows.escapes.push((low, high, target.continuation));
1363 }
1364 }
1365 }
1366 rows
1367}
1368
1369fn consuming_entries<'a>(
1371 atn: &'a LexerAtn,
1372 configs: &[LexerConfig],
1373) -> Vec<(usize, &'a LexerTransition)> {
1374 let mut entries = Vec::new();
1375 for (config_index, config) in configs.iter().enumerate() {
1376 let Some(state) = atn.state(config.state) else {
1377 continue;
1378 };
1379 for transition in &state.transitions {
1380 if !transition.is_epsilon() {
1381 entries.push((config_index, transition));
1382 }
1383 }
1384 }
1385 entries
1386}
1387
1388fn char_segments(entry_intervals: &[Vec<(i32, i32)>]) -> Vec<(i32, i32)> {
1391 let mut cuts = Vec::new();
1392 for intervals in entry_intervals {
1393 for &(low, high) in intervals {
1394 cuts.push(low);
1395 cuts.push(high + 1);
1396 }
1397 }
1398 cuts.sort_unstable();
1399 cuts.dedup();
1400 cuts.windows(2).map(|pair| (pair[0], pair[1] - 1)).collect()
1401}
1402
1403fn segment_mask_matrix(
1407 segments: &[(i32, i32)],
1408 entry_intervals: &[Vec<(i32, i32)>],
1409 entry_count: usize,
1410) -> Vec<u64> {
1411 let words = entry_count.div_ceil(64);
1412 let mut matrix = vec![0_u64; segments.len() * words];
1413 for (bit, intervals) in entry_intervals.iter().enumerate() {
1414 for &(low, high) in intervals {
1415 let from = segments.partition_point(|&(start, _)| start < low);
1418 let to = segments.partition_point(|&(start, _)| start <= high);
1419 for segment in from..to {
1420 matrix[segment * words + bit / 64] |= 1 << (bit % 64);
1421 }
1422 }
1423 }
1424 matrix
1425}
1426
1427fn transition_char_intervals(transition: &LexerTransition) -> Vec<(i32, i32)> {
1430 let mut intervals = Vec::new();
1431 let mut push_clamped = |low: i32, high: i32| {
1432 let low = low.max(MIN_CHAR_VALUE);
1433 let high = high.min(MAX_CHAR_VALUE);
1434 if low <= high {
1435 intervals.push((low, high));
1436 }
1437 };
1438 match transition {
1439 LexerTransition::Atom { label, .. } => push_clamped(*label, *label),
1440 LexerTransition::Range { start, stop, .. } => push_clamped(*start, *stop),
1441 LexerTransition::Set { set, .. } => {
1442 for &(low, high) in set.ranges() {
1443 push_clamped(low, high);
1444 }
1445 }
1446 LexerTransition::NotSet { set, .. } => {
1447 let mut next = MIN_CHAR_VALUE;
1450 for &(low, high) in set.ranges() {
1451 if low > next {
1452 push_clamped(next, low - 1);
1453 }
1454 next = next.max(high.saturating_add(1));
1455 }
1456 push_clamped(next, MAX_CHAR_VALUE);
1457 }
1458 LexerTransition::Wildcard { .. } => push_clamped(MIN_CHAR_VALUE, MAX_CHAR_VALUE),
1459 _ => {}
1460 }
1461 intervals
1462}
1463
1464fn move_target(
1467 atn: &LexerAtn,
1468 build: &mut ModeBuild,
1469 configs: &[LexerConfig],
1470 step: usize,
1471 entries: &[(usize, &LexerTransition)],
1472 mask: &[u64],
1473) -> EdgeTarget {
1474 let mut moved = Vec::new();
1475 for (bit, (config_index, transition)) in entries.iter().enumerate() {
1476 if mask[bit / 64] & (1 << (bit % 64)) == 0 {
1477 continue;
1478 }
1479 let mut advanced = configs[*config_index].clone();
1480 set_config_state(atn, &mut advanced, transition.target());
1481 advanced.position += 1;
1482 moved.push(advanced);
1483 }
1484 let continuation_configs = moved.clone();
1485 let Some(active) = closed_configs(atn, build, moved) else {
1486 return EdgeTarget {
1487 state: ESCAPE_STATE,
1488 continuation: build.add_continuation(&continuation_configs, step + 1),
1489 };
1490 };
1491 if active.is_empty() {
1492 return EdgeTarget::DEAD;
1493 }
1494 EdgeTarget {
1495 state: build.intern(atn, active, step + 1),
1496 continuation: u32::MAX,
1497 }
1498}
1499
1500fn eof_move(
1503 atn: &LexerAtn,
1504 build: &mut ModeBuild,
1505 configs: &[LexerConfig],
1506 step: usize,
1507 entries: &[(usize, &LexerTransition)],
1508) -> EdgeTarget {
1509 let mut moved = Vec::new();
1510 for (config_index, transition) in entries {
1511 if !transition.matches(EOF, MIN_CHAR_VALUE, MAX_CHAR_VALUE) {
1512 continue;
1513 }
1514 let mut advanced = configs[*config_index].clone();
1515 set_config_state(atn, &mut advanced, transition.target());
1516 advanced.consumed_eof = true;
1517 moved.push(advanced);
1518 }
1519 if moved.is_empty() {
1520 return EdgeTarget::DEAD;
1521 }
1522 let continuation_configs = moved.clone();
1523 let Some(active) = closed_configs(atn, build, moved) else {
1524 return EdgeTarget {
1525 state: ESCAPE_STATE,
1526 continuation: build.add_continuation(&continuation_configs, step),
1527 };
1528 };
1529 if active.is_empty() {
1530 return EdgeTarget::DEAD;
1531 }
1532 EdgeTarget {
1533 state: build.intern(atn, active, step),
1534 continuation: u32::MAX,
1535 }
1536}
1537
1538fn commit_mode(
1540 dfa: &mut CompiledLexerDfa,
1541 pools: &mut RowPools,
1542 build: ModeBuild,
1543 rows: Vec<StateRows>,
1544) {
1545 let ModeBuild {
1546 accepts,
1547 continuations,
1548 ..
1549 } = build;
1550 for (accept, state_rows) in accepts.into_iter().zip(rows) {
1551 let accept_id = accept.map_or(u32::MAX, |accept| {
1552 dfa.accepts.push(accept);
1553 (dfa.accepts.len() - 1) as u32
1554 });
1555 let (ascii_row, wide_row) = split_rows(&state_rows.segments);
1556 let state_id = u16::try_from(dfa.states.len()).expect("state ID overflow");
1557 let ascii_run = AsciiRun::classify(&ascii_row, state_id);
1558 dfa.states.push(CompiledLexerState {
1559 ascii_row: pools.intern_ascii(&mut dfa.ascii_rows, ascii_row),
1560 wide_row: pools.intern_wide(&mut dfa.wide_rows, wide_row),
1561 eof_target: state_rows.eof_target,
1562 accept: accept_id,
1563 });
1564 dfa.ascii_runs.push(ascii_run);
1565 dfa.escape_rows.push(CompiledLexerEscapeRow {
1566 ranges: merge_escape_ranges(&state_rows.escapes).into(),
1567 eof: state_rows.eof_escape,
1568 });
1569 }
1570 dfa.continuations.extend(continuations);
1571}
1572
1573fn merge_escape_ranges(segments: &[(i32, i32, u32)]) -> Vec<CompiledLexerEscapeRange> {
1574 let mut ranges: Vec<CompiledLexerEscapeRange> = Vec::new();
1575 for &(low, high, continuation) in segments {
1576 let low = low.cast_unsigned();
1577 let high = high.cast_unsigned();
1578 if let Some(last) = ranges.last_mut()
1579 && last.continuation == continuation
1580 && last.high.checked_add(1) == Some(low)
1581 {
1582 last.high = high;
1583 continue;
1584 }
1585 ranges.push(CompiledLexerEscapeRange {
1586 low,
1587 high,
1588 continuation,
1589 });
1590 }
1591 ranges
1592}
1593
1594fn split_rows(segments: &[(i32, i32, u16)]) -> ([u16; ASCII_EDGE_SYMBOLS], Vec<WideRange>) {
1596 let mut ascii = [DEAD_STATE; ASCII_EDGE_SYMBOLS];
1597 let mut wide: Vec<WideRange> = Vec::new();
1598 for &(low, high, target) in segments {
1599 let ascii_high = high.min(ASCII_EDGE_LIMIT - 1);
1600 for code_point in low..=ascii_high {
1601 ascii[code_point.cast_unsigned() as usize] = target;
1602 }
1603 if high >= ASCII_EDGE_LIMIT {
1604 let low = low.max(ASCII_EDGE_LIMIT).cast_unsigned();
1605 let high = high.cast_unsigned();
1606 if let Some(last) = wide.last_mut()
1607 && last.target == target
1608 && last.high + 1 == low
1609 {
1610 last.high = high;
1611 continue;
1612 }
1613 wide.push(WideRange { low, high, target });
1614 }
1615 }
1616 (ascii, wide)
1617}
1618
1619#[cfg(test)]
1620mod tests {
1621 use super::*;
1622 use crate::atn::lexer::{
1623 next_token, next_token_compiled, next_token_compiled_with_hooks, next_token_with_hooks,
1624 };
1625 use crate::atn::serialized::{AtnDeserializer, SerializedAtn};
1626 use crate::char_stream::{CharStream, InputStream, TextInterval};
1627 use crate::int_stream::IntStream;
1628 use crate::lexer::{BaseLexer, Lexer};
1629 use crate::recognizer::RecognizerData;
1630 use crate::token::{TOKEN_EOF, Token, TokenSink, TokenStore};
1631 use crate::vocabulary::Vocabulary;
1632
1633 #[derive(Debug, Eq, PartialEq)]
1634 struct TokenSnapshot {
1635 token_type: i32,
1636 text: String,
1637 channel: i32,
1638 start: usize,
1639 stop: usize,
1640 start_byte: Option<usize>,
1641 stop_byte: Option<usize>,
1642 line: usize,
1643 column: usize,
1644 }
1645
1646 #[derive(Debug, Eq, PartialEq)]
1647 struct StreamSnapshot {
1648 tokens: Vec<TokenSnapshot>,
1649 errors: Vec<String>,
1650 final_mode: i32,
1651 popped_modes: Vec<i32>,
1652 }
1653
1654 fn compiled_token<I>(
1655 lexer: &mut BaseLexer<I>,
1656 atn: &LexerAtn,
1657 dfa: &CompiledLexerDfa,
1658 ) -> TokenSnapshot
1659 where
1660 I: CharStream,
1661 {
1662 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1663 let mut sink = TokenSink::new(&mut store);
1664 let id = next_token_compiled(lexer, &mut sink, atn, dfa).expect("test token should fit");
1665 let token = sink.view(id).expect("emitted token should exist");
1666 TokenSnapshot {
1667 token_type: token.token_type(),
1668 text: token.text_or_empty().to_owned(),
1669 channel: token.channel(),
1670 start: token.start(),
1671 stop: token.stop(),
1672 start_byte: token.start_byte(),
1673 stop_byte: token.stop_byte(),
1674 line: token.line(),
1675 column: token.column(),
1676 }
1677 }
1678
1679 fn interpreted_token(lexer: &mut BaseLexer<InputStream>, atn: &LexerAtn) -> TokenSnapshot {
1680 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
1681 let mut sink = TokenSink::new(&mut store);
1682 let id = next_token(lexer, &mut sink, atn).expect("test token should fit");
1683 let token = sink.view(id).expect("emitted token should exist");
1684 TokenSnapshot {
1685 token_type: token.token_type(),
1686 text: token.text_or_empty().to_owned(),
1687 channel: token.channel(),
1688 start: token.start(),
1689 stop: token.stop(),
1690 start_byte: token.start_byte(),
1691 stop_byte: token.stop_byte(),
1692 line: token.line(),
1693 column: token.column(),
1694 }
1695 }
1696
1697 #[derive(Clone, Debug)]
1698 struct FallbackInput(InputStream);
1699
1700 impl IntStream for FallbackInput {
1701 fn consume(&mut self) {
1702 self.0.consume();
1703 }
1704
1705 fn la(&mut self, offset: isize) -> i32 {
1706 self.0.la(offset)
1707 }
1708
1709 fn index(&self) -> usize {
1710 self.0.index()
1711 }
1712
1713 fn seek(&mut self, index: usize) {
1714 self.0.seek(index);
1715 }
1716
1717 fn size(&self) -> usize {
1718 self.0.size()
1719 }
1720
1721 fn source_name(&self) -> &str {
1722 self.0.source_name()
1723 }
1724 }
1725
1726 impl CharStream for FallbackInput {
1728 fn text(&self, interval: TextInterval) -> String {
1729 self.0.text(interval)
1730 }
1731 }
1732
1733 fn recognizer_data() -> RecognizerData {
1734 RecognizerData::new(
1735 "T",
1736 Vocabulary::new(
1737 [None, Some("'ab'"), Some("' '")],
1738 [None, Some("AB"), Some("WS")],
1739 [None::<&str>, None, None],
1740 ),
1741 )
1742 }
1743
1744 #[rustfmt::skip]
1751 fn two_rule_atn(with_predicate: bool) -> LexerAtn {
1752 let epsilon_or_predicate = if with_predicate { 4 } else { 1 };
1753 AtnDeserializer::new(&SerializedAtn::from_i32(&[
1754 4, 0, 2, 9, 6, -1, 2, 0, 1, 0, 1, 0, 7, 0, 2, 1, 1, 1, 1, 1, 7, 1, 0, 0, 2, 1, 1, 5, 2, 1, 0, 0, 8, 0, 1, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 1, 2, 5, 'a' as i32, 0, 0, 2, 3, 5, 'b' as i32, 0, 0, 3, 4, epsilon_or_predicate, 0, 0, 0, 5, 6, 5, ' ' as i32, 0, 0, 6, 7, 1, 0, 0, 0, 7, 8, 6, 1, 0, 0, 1, 0, 1, 6, 0, 0, ]))
1786 .deserialize()
1787 .expect("artificial lexer ATN should deserialize")
1788 }
1789
1790 #[rustfmt::skip]
1795 fn wide_range_atn() -> LexerAtn {
1796 AtnDeserializer::new(&SerializedAtn::from_i32(&[
1797 4, 0, 1, 5, 6, -1, 2, 0, 1, 0, 1, 0, 7, 0, 0, 0, 1, 1, 1, 1, 0, 0, 5, 0, 1, 1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 2, 3, 2, 0x100, 0x200, 0, 3, 2, 1, 0, 0, 0, 3, 4, 1, 0, 0, 0, 0, 0, ]))
1820 .deserialize()
1821 .expect("artificial wide-range lexer ATN should deserialize")
1822 }
1823
1824 #[rustfmt::skip]
1828 fn complement_loop_atn() -> LexerAtn {
1829 AtnDeserializer::new(&SerializedAtn::from_i32(&[
1830 4, 0, 1, 5, 6, -1, 2, 0, 1, 0, 1, 0, 7, 0, 0, 0, 1, 1, 1, 1, 0, 1, 3, 0, '\n' as i32, '\n' as i32,
1846 '"' as i32, '"' as i32,
1847 '\\' as i32, '\\' as i32,
1848 5, 0, 1, 1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 2, 3, 8, 0, 0, 0, 3, 2, 1, 0, 0, 0, 3, 4, 1, 0, 0, 0, 0, 0, ]))
1857 .deserialize()
1858 .expect("artificial complement-loop lexer ATN should deserialize")
1859 }
1860
1861 #[rustfmt::skip]
1866 fn range_loop_atn() -> LexerAtn {
1867 AtnDeserializer::new(&SerializedAtn::from_i32(&[
1868 4, 0, 3, 13, 6, -1, 2, 0, 1, 0, 1, 0, 7, 0, 2, 1, 1, 1, 1, 1, 7, 1, 2, 2, 1, 2, 1, 2, 7, 2, 0, 0, 3, 1, 1, 5, 2, 9, 3, 1, 0, 3, 1, 0, '0' as i32, '9' as i32,
1894 4, 0, '0' as i32, '9' as i32,
1896 'A' as i32, 'Z' as i32,
1897 '_' as i32, '_' as i32,
1898 'a' as i32, 'z' as i32,
1899 3, 0, '\t' as i32, '\n' as i32,
1901 '\r' as i32, '\r' as i32,
1902 ' ' as i32, ' ' as i32,
1903 15, 0, 1, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 2, 3, 7, 0, 0, 0, 3, 2, 1, 0, 0, 0, 3, 4, 6, 0, 0, 0, 5, 6, 1, 0, 0, 0, 6, 7, 7, 1, 0, 0, 7, 6, 1, 0, 0, 0, 7, 8, 6, 1, 1, 0, 9, 10, 1, 0, 0, 0, 10, 11, 7, 2, 0, 0, 11, 10, 1, 0, 0, 0, 11, 12, 6, 2, 2, 0, 0, 3, 0, 7, 0, 5, 0, 0, 6, 0, 0, ]))
1925 .deserialize()
1926 .expect("artificial range-loop lexer ATN should deserialize")
1927 }
1928
1929 fn compiled_stream(input: &str, atn: &LexerAtn, dfa: &CompiledLexerDfa) -> StreamSnapshot {
1930 let mut lexer = BaseLexer::new(InputStream::new(input), recognizer_data());
1931 let mut tokens = Vec::new();
1932 loop {
1933 let token = compiled_token(&mut lexer, atn, dfa);
1934 let at_eof = token.token_type == TOKEN_EOF;
1935 tokens.push(token);
1936 if at_eof {
1937 break;
1938 }
1939 }
1940 let errors = lexer
1941 .drain_errors()
1942 .into_iter()
1943 .map(|error| error.message)
1944 .collect();
1945 let final_mode = lexer.mode();
1946 let mut popped_modes = Vec::new();
1947 while let Some(mode) = lexer.pop_mode() {
1948 popped_modes.push(mode);
1949 }
1950 StreamSnapshot {
1951 tokens,
1952 errors,
1953 final_mode,
1954 popped_modes,
1955 }
1956 }
1957
1958 fn serialized_run_offset(dfa: &CompiledLexerDfa, state: usize) -> usize {
1959 4 + dfa.mode_starts.len()
1960 + dfa.states.len() * 4
1961 + dfa.ascii_runs[..state]
1962 .iter()
1963 .map(|run| run.serialized_words())
1964 .sum::<usize>()
1965 }
1966
1967 fn first_serialized_range_offset(dfa: &CompiledLexerDfa) -> usize {
1968 let state = dfa
1969 .ascii_runs
1970 .iter()
1971 .position(|run| matches!(run, AsciiRun::Ranges(_)))
1972 .expect("test DFA should contain a range descriptor");
1973 serialized_run_offset(dfa, state)
1974 }
1975
1976 #[test]
1977 fn recursive_context_detection_enforces_depth_and_cycle_backstops() {
1978 let mut contexts = LexerContextArena::new();
1979 let mut bounded = EMPTY_LEXER_CONTEXT;
1980 for return_state in 0..MAX_CONTEXT_DEPTH {
1981 bounded = contexts.singleton(bounded, return_state);
1982 }
1983 let config = |context| LexerConfig::new(0, 0, context).with_alt_rule_index(0);
1984
1985 assert!(!has_recursive_context(&config(bounded), &contexts));
1986
1987 let too_deep = contexts.singleton(bounded, MAX_CONTEXT_DEPTH);
1988 assert!(has_recursive_context(&config(too_deep), &contexts));
1989
1990 let first = contexts.singleton(EMPTY_LEXER_CONTEXT, 7);
1991 let recursive = contexts.singleton(first, 7);
1992 assert!(has_recursive_context(&config(recursive), &contexts));
1993 }
1994
1995 #[test]
1996 fn deep_union_context_operations_fit_on_a_small_native_stack() {
1997 let mut contexts = LexerContextArena::new();
1998 let mut workspace = PredictionWorkspace::default();
1999 let mut context = contexts.singleton(EMPTY_LEXER_CONTEXT, 0);
2000 for return_state in 1..2048 {
2001 let branch = contexts.singleton(EMPTY_LEXER_CONTEXT, return_state);
2002 context = contexts.merge(context, branch, &mut workspace);
2003 }
2004 let expected_contexts = contexts.len() - 1;
2005 let config = LexerConfig::new(0, 0, context).with_alt_rule_index(0);
2006
2007 std::thread::Builder::new()
2008 .stack_size(64 * 1024)
2009 .spawn(move || {
2010 assert!(!has_recursive_context(&config, &contexts));
2011
2012 let mut ids = FxHashMap::default();
2013 ids.insert(EMPTY_LEXER_CONTEXT, 0);
2014 let mut compiled = Vec::new();
2015 let compiled_context =
2016 compile_context(&contexts, config.context, &mut ids, &mut compiled);
2017 assert_eq!(compiled.len(), expected_contexts);
2018 assert_eq!(compiled_context as usize, expected_contexts);
2019 })
2020 .expect("small-stack context thread should start")
2021 .join()
2022 .expect("deep context traversal should not overflow");
2023 }
2024
2025 #[test]
2026 fn ascii_run_classifies_and_scans_only_exact_self_loops() {
2027 let state = 7;
2028 let mut row = [state; ASCII_EDGE_SYMBOLS];
2029 assert_eq!(AsciiRun::classify(&row, state), AsciiRun::Any);
2030 assert_eq!(
2031 AsciiRun::Any.scan(b"body"),
2032 Some(AsciiRunScan {
2033 bytes: 4,
2034 found_exit: false,
2035 range: None,
2036 })
2037 );
2038
2039 row[usize::from(b'\n')] = DEAD_STATE;
2040 row[usize::from(b'"')] = 3;
2041 row[usize::from(b'\\')] = ESCAPE_STATE;
2042 let run = AsciiRun::classify(&row, state);
2043 assert_eq!(run, AsciiRun::Until3(b'\n', b'"', b'\\'));
2044 assert_eq!(
2045 run.scan(b"body\\tail"),
2046 Some(AsciiRunScan {
2047 bytes: 4,
2048 found_exit: true,
2049 range: None,
2050 })
2051 );
2052
2053 row[usize::from(b'\r')] = DEAD_STATE;
2054 assert_eq!(AsciiRun::classify(&row, state), AsciiRun::None);
2055 assert_eq!(AsciiRun::None.scan(b"body"), None);
2056
2057 let mut identifier = [DEAD_STATE; ASCII_EDGE_SYMBOLS];
2058 for byte in b'0'..=b'9' {
2059 identifier[usize::from(byte)] = state;
2060 }
2061 for byte in b'A'..=b'Z' {
2062 identifier[usize::from(byte)] = state;
2063 }
2064 identifier[usize::from(b'_')] = state;
2065 for byte in b'a'..=b'z' {
2066 identifier[usize::from(byte)] = state;
2067 }
2068 let AsciiRun::Ranges(ranges) = AsciiRun::classify(&identifier, state) else {
2069 panic!("identifier row should produce a range descriptor");
2070 };
2071 assert_eq!(ranges.count(), 4);
2072 assert_eq!(
2073 AsciiRun::Ranges(ranges)
2074 .scan(b"abc_123!")
2075 .expect("range descriptor should scan")
2076 .bytes,
2077 7
2078 );
2079
2080 let mut unsupported = [DEAD_STATE; ASCII_EDGE_SYMBOLS];
2081 for byte in *b"acegi" {
2082 unsupported[usize::from(byte)] = state;
2083 }
2084 assert_eq!(AsciiRun::classify(&unsupported, state), AsciiRun::None);
2085 }
2086
2087 #[test]
2088 fn run_scans_match_scalar_compiled_walks_for_random_ascii() {
2089 let atn = complement_loop_atn();
2090 let accelerated = CompiledLexerDfa::compile(&atn);
2091 assert!(
2092 accelerated
2093 .ascii_runs
2094 .iter()
2095 .any(|run| matches!(run, AsciiRun::Until3(..)))
2096 );
2097 let mut scalar = accelerated.clone();
2098 for run in &mut scalar.ascii_runs {
2099 *run = AsciiRun::None;
2100 }
2101
2102 let mut inputs = vec![
2103 "a".repeat(512),
2104 format!(
2105 "{}\"{}\\{}\n{}",
2106 "a".repeat(64),
2107 "b".repeat(65),
2108 "c".repeat(66),
2109 "d".repeat(67)
2110 ),
2111 ];
2112 let mut random = 0xA5A5_79E3_u32;
2113 for _ in 0..128 {
2114 random = random.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
2115 let len = (random as usize) & 0xFF;
2116 let mut input = String::with_capacity(len);
2117 for _ in 0..len {
2118 random = random.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
2119 input.push(char::from((random >> 25) as u8));
2120 }
2121 inputs.push(input);
2122 }
2123
2124 for input in inputs {
2125 assert_eq!(
2126 compiled_stream(&input, &atn, &accelerated),
2127 compiled_stream(&input, &atn, &scalar),
2128 "compiled walks diverged for {input:?}"
2129 );
2130 }
2131 }
2132
2133 #[test]
2134 fn range_scans_match_scalar_compiled_token_streams() {
2135 let atn = range_loop_atn();
2136 let accelerated = CompiledLexerDfa::compile(&atn);
2137 let counts = accelerated
2138 .ascii_runs
2139 .iter()
2140 .filter_map(|run| match run {
2141 AsciiRun::Ranges(ranges) => Some(ranges.count()),
2142 _ => None,
2143 })
2144 .collect::<Vec<_>>();
2145 assert!(counts.contains(&1), "{counts:?}");
2146 assert!(counts.contains(&3), "{counts:?}");
2147 assert!(counts.contains(&4), "{counts:?}");
2148
2149 let mut scalar = accelerated.clone();
2150 for run in &mut scalar.ascii_runs {
2151 if matches!(run, AsciiRun::Ranges(_)) {
2152 *run = AsciiRun::None;
2153 }
2154 }
2155 let input = format!(
2156 "{}!\t{}\r\n{} {}",
2157 "identifier_0123456789".repeat(12),
2158 "1234567890".repeat(20),
2159 "Another_identifier_9876543210".repeat(10),
2160 "short_123"
2161 );
2162
2163 let accelerated = compiled_stream(&input, &atn, &accelerated);
2164 let scalar = compiled_stream(&input, &atn, &scalar);
2165 assert_eq!(accelerated, scalar);
2166 assert_eq!(accelerated.final_mode, 0);
2167 assert_eq!(accelerated.popped_modes, [0, 0, 0]);
2168 assert!(
2169 accelerated.tokens.iter().any(|token| token.channel == 7),
2170 "{accelerated:?}"
2171 );
2172 assert!(
2173 accelerated.tokens.iter().any(|token| token.line > 1),
2174 "{accelerated:?}"
2175 );
2176 assert_eq!(
2177 accelerated
2178 .tokens
2179 .last()
2180 .expect("stream includes EOF")
2181 .token_type,
2182 TOKEN_EOF
2183 );
2184 assert_eq!(
2185 accelerated.errors,
2186 ["token recognition error at: '!'".to_owned()]
2187 );
2188 }
2189
2190 #[test]
2191 fn compiled_dfa_matches_longest_token_and_skips() {
2192 let atn = two_rule_atn(false);
2193 let dfa = CompiledLexerDfa::compile(&atn);
2194 assert!(dfa.has_compiled_modes());
2195 assert!(dfa.mode_start(0).is_some());
2196
2197 let mut lexer = BaseLexer::new(InputStream::new(" ab"), recognizer_data());
2198 let token = compiled_token(&mut lexer, &atn, &dfa);
2199 assert_eq!(token.token_type, 1);
2200 assert_eq!(token.text, "ab");
2201 assert_eq!(compiled_token(&mut lexer, &atn, &dfa).token_type, TOKEN_EOF);
2202 }
2203
2204 #[test]
2205 fn predicate_edge_resumes_the_interpreter_for_true_and_false_outcomes() {
2206 let atn = two_rule_atn(true);
2207 let dfa = CompiledLexerDfa::compile(&atn);
2208 assert!(dfa.mode_start(0).is_some());
2211 assert!(
2212 !dfa.continuations.is_empty(),
2213 "predicate edge should preserve a narrowed continuation"
2214 );
2215
2216 let mut lexer = BaseLexer::new(InputStream::new(" ab"), recognizer_data());
2217 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2218 let mut sink = TokenSink::new(&mut store);
2219 let mut true_predicate_calls = 0;
2220 let id = next_token_compiled_with_hooks(
2221 &mut lexer,
2222 &mut sink,
2223 &atn,
2224 &dfa,
2225 |_, _| {},
2226 |_, _| {
2227 true_predicate_calls += 1;
2228 true_predicate_calls == 1
2229 },
2230 |_, _, _| {},
2231 )
2232 .expect("test token should fit");
2233 let token = sink.view(id).expect("emitted token should exist");
2234 assert_eq!(token.token_type(), 1);
2235 assert_eq!(token.text(), Some("ab"));
2236 assert_eq!(true_predicate_calls, 1);
2237
2238 let mut compiled = BaseLexer::new(InputStream::new("ab"), recognizer_data());
2239 let mut interpreted = BaseLexer::new(InputStream::new("ab"), recognizer_data());
2240 let mut compiled_store = TokenStore::new(compiled.source_text(), compiled.source_name());
2241 let mut interpreted_store =
2242 TokenStore::new(interpreted.source_text(), interpreted.source_name());
2243 let mut compiled_sink = TokenSink::new(&mut compiled_store);
2244 let mut interpreted_sink = TokenSink::new(&mut interpreted_store);
2245 let mut compiled_predicate_calls = 0;
2246 let compiled_id = next_token_compiled_with_hooks(
2247 &mut compiled,
2248 &mut compiled_sink,
2249 &atn,
2250 &dfa,
2251 |_, _| {},
2252 |_, _| {
2253 compiled_predicate_calls += 1;
2254 false
2255 },
2256 |_, _, _| {},
2257 )
2258 .expect("false predicate should recover to EOF");
2259 let mut interpreted_predicate_calls = 0;
2260 let interpreted_id = next_token_with_hooks(
2261 &mut interpreted,
2262 &mut interpreted_sink,
2263 &atn,
2264 |_, _| {},
2265 |_, _| {
2266 interpreted_predicate_calls += 1;
2267 false
2268 },
2269 |_, _, _| {},
2270 )
2271 .expect("interpreted false predicate should recover to EOF");
2272 assert_eq!(compiled_predicate_calls, interpreted_predicate_calls);
2273 assert_eq!(compiled_predicate_calls, 1);
2274 assert_eq!(
2275 compiled_sink
2276 .view(compiled_id)
2277 .expect("compiled token should exist")
2278 .token_type(),
2279 interpreted_sink
2280 .view(interpreted_id)
2281 .expect("interpreted token should exist")
2282 .token_type()
2283 );
2284 assert_eq!(
2285 compiled
2286 .drain_errors()
2287 .into_iter()
2288 .map(|error| error.message)
2289 .collect::<Vec<_>>(),
2290 interpreted
2291 .drain_errors()
2292 .into_iter()
2293 .map(|error| error.message)
2294 .collect::<Vec<_>>()
2295 );
2296 }
2297
2298 #[test]
2299 fn compiled_dfa_walks_wide_ranges() {
2300 let atn = wide_range_atn();
2301 let dfa = CompiledLexerDfa::compile(&atn);
2302 assert!(dfa.mode_start(0).is_some());
2303
2304 let mut lexer = BaseLexer::new(InputStream::new("ĀĂ"), recognizer_data());
2305 let token = compiled_token(&mut lexer, &atn, &dfa);
2306 assert_eq!(token.token_type, 1);
2307 assert_eq!(token.text, "ĀĂ");
2308 assert_eq!(compiled_token(&mut lexer, &atn, &dfa).token_type, TOKEN_EOF);
2309 }
2310
2311 #[test]
2312 fn compiled_dfa_keeps_custom_streams_on_the_compatible_fallback() {
2313 let atn = two_rule_atn(false);
2314 let dfa = CompiledLexerDfa::compile(&atn);
2315 let mut lexer = BaseLexer::new(FallbackInput(InputStream::new(" ab")), recognizer_data());
2316
2317 let token = compiled_token(&mut lexer, &atn, &dfa);
2318 assert_eq!(token.token_type, 1);
2319 assert_eq!(token.text, "ab");
2320 assert_eq!((token.line, token.column), (1, 1));
2321 assert_eq!(lexer.input().index(), 3);
2322 }
2323
2324 #[cfg(feature = "perf-counters")]
2325 #[test]
2326 fn lexer_counters_distinguish_ascii_unicode_and_replay_paths() {
2327 let ascii_atn = two_rule_atn(false);
2328 let ascii_dfa = CompiledLexerDfa::compile(&ascii_atn);
2329 crate::perf::reset();
2330 let mut ascii = BaseLexer::new(InputStream::new(" ab"), recognizer_data());
2331 let token = compiled_token(&mut ascii, &ascii_atn, &ascii_dfa);
2332 assert_eq!(token.text, "ab");
2333 let [direct, generic, replay, bulk] = crate::perf::lexer_snapshot();
2334 assert!(direct >= 3, "{direct}");
2335 assert_eq!(generic, 0);
2336 assert_eq!(replay, 0);
2337 assert_eq!(bulk, 3);
2338
2339 let unicode_atn = wide_range_atn();
2340 let unicode_dfa = CompiledLexerDfa::compile(&unicode_atn);
2341 crate::perf::reset();
2342 let mut unicode = BaseLexer::new(InputStream::new("ĀĂ"), recognizer_data());
2343 let token = compiled_token(&mut unicode, &unicode_atn, &unicode_dfa);
2344 assert_eq!(token.text, "ĀĂ");
2345 let [direct, generic, replay, bulk] = crate::perf::lexer_snapshot();
2346 assert_eq!(direct, 0);
2347 assert!(generic >= 2, "{generic}");
2348 assert_eq!(replay, 0);
2349 assert_eq!(bulk, 2);
2350
2351 crate::perf::reset();
2352 let mut fallback =
2353 BaseLexer::new(FallbackInput(InputStream::new(" ab")), recognizer_data());
2354 let token = compiled_token(&mut fallback, &ascii_atn, &ascii_dfa);
2355 assert_eq!(token.text, "ab");
2356 let [direct, generic, replay, bulk] = crate::perf::lexer_snapshot();
2357 assert_eq!(direct, 0);
2358 assert!(generic >= 3, "{generic}");
2359 assert_eq!(replay, 3);
2360 assert_eq!(bulk, 0);
2361 }
2362
2363 #[cfg(feature = "perf-counters")]
2364 #[test]
2365 fn lexer_counters_report_compiled_run_scan_coverage() {
2366 let atn = complement_loop_atn();
2367 let dfa = CompiledLexerDfa::compile(&atn);
2368 crate::perf::reset();
2369 let input = format!("{}\"", "a".repeat(512));
2370 let mut lexer = BaseLexer::new(InputStream::new(input), recognizer_data());
2371 let token = compiled_token(&mut lexer, &atn, &dfa);
2372 assert_eq!(token.text.len(), 512);
2373
2374 let [scalar, calls, bytes, exits, ends, rejected] = crate::perf::lexer_run_snapshot();
2375 assert_eq!(scalar, 10);
2376 assert_eq!(calls, 1);
2377 assert_eq!(bytes, 503);
2378 assert_eq!(exits, 1);
2379 assert_eq!(ends, 0);
2380 assert_eq!(rejected, 0);
2381 }
2382
2383 #[cfg(feature = "perf-counters")]
2384 #[test]
2385 fn lexer_counters_report_range_descriptor_and_scan_coverage() {
2386 crate::perf::reset();
2387 let before = crate::perf::lexer_range_descriptor_snapshot();
2388 let atn = range_loop_atn();
2389 let dfa = CompiledLexerDfa::compile(&atn);
2390 let descriptors = crate::perf::lexer_range_descriptor_snapshot();
2391 assert!(descriptors[3] > before[3], "{before:?} -> {descriptors:?}");
2392 assert!(descriptors[5] > before[5], "{before:?} -> {descriptors:?}");
2393 assert!(descriptors[6] > before[6], "{before:?} -> {descriptors:?}");
2394 assert!(descriptors[7] > before[7], "{before:?} -> {descriptors:?}");
2395 assert!(descriptors[8] > before[8], "{before:?} -> {descriptors:?}");
2396 assert!(descriptors[9] > before[9], "{before:?} -> {descriptors:?}");
2397
2398 crate::perf::reset();
2399 let input = format!(
2400 "{} {} {}",
2401 "long_identifier_0123456789".repeat(20),
2402 "1234567890".repeat(40),
2403 " \t\r\n".repeat(80)
2404 );
2405 let _ = compiled_stream(&input, &atn, &dfa);
2406 let scans = crate::perf::lexer_range_scan_snapshot();
2407 assert!(scans[0] > 0, "{scans:?}");
2408 assert!(scans[1] > 0, "{scans:?}");
2409 assert!(scans[2] > 0, "{scans:?}");
2410 assert!(scans[3] > 0, "{scans:?}");
2411 assert!(scans[4] > 0, "{scans:?}");
2412 }
2413
2414 #[test]
2415 fn compiled_dfa_reports_recognition_errors_like_the_interpreter() {
2416 let atn = wide_range_atn();
2417 let dfa = CompiledLexerDfa::compile(&atn);
2418
2419 let mut compiled = BaseLexer::new(InputStream::new("zĀ"), recognizer_data());
2420 let mut interpreted = BaseLexer::new(InputStream::new("zĀ"), recognizer_data());
2421 loop {
2422 let compiled_token = compiled_token(&mut compiled, &atn, &dfa);
2423 let interpreted_token = interpreted_token(&mut interpreted, &atn);
2424 assert_eq!(compiled_token, interpreted_token);
2425 if compiled_token.token_type == TOKEN_EOF {
2426 break;
2427 }
2428 }
2429 let compiled_errors: Vec<String> = compiled
2430 .drain_errors()
2431 .into_iter()
2432 .map(|error| error.message)
2433 .collect();
2434 let interpreted_errors: Vec<String> = interpreted
2435 .drain_errors()
2436 .into_iter()
2437 .map(|error| error.message)
2438 .collect();
2439 assert_eq!(compiled_errors, vec!["token recognition error at: 'z'"]);
2440 assert_eq!(compiled_errors, interpreted_errors);
2441 }
2442
2443 #[test]
2444 fn serialization_round_trips() {
2445 let atn = range_loop_atn();
2446 let dfa = CompiledLexerDfa::compile(&atn);
2447 let stream = dfa.serialize();
2448
2449 let restored =
2450 CompiledLexerDfa::from_serialized(&stream).expect("stream should deserialize");
2451 assert_eq!(restored.serialize(), stream);
2452 assert_eq!(restored.continuations.len(), dfa.continuations.len());
2453 assert_eq!(restored.ascii_runs, dfa.ascii_runs);
2454
2455 let mut lexer = BaseLexer::new(InputStream::new("identifier_123"), recognizer_data());
2456 let token = compiled_token(&mut lexer, &atn, &restored);
2457 assert_eq!(token.token_type, 2);
2458 assert_eq!(token.text, "identifier_123");
2459
2460 let mut wrong_tag = stream;
2462 wrong_tag[0] ^= 1;
2463 assert!(CompiledLexerDfa::from_serialized(&wrong_tag).is_none());
2464 }
2465
2466 #[test]
2467 fn serialized_run_descriptors_are_validated_against_ascii_rows() {
2468 let dfa = CompiledLexerDfa::compile(&complement_loop_atn());
2469 let state = dfa
2470 .ascii_runs
2471 .iter()
2472 .position(|&run| run != AsciiRun::Any)
2473 .expect("test grammar should contain a state that is not Any");
2474 let mut stream = dfa.serialize();
2475 stream[serialized_run_offset(&dfa, state)] = 1;
2476
2477 assert!(CompiledLexerDfa::from_serialized(&stream).is_none());
2478 }
2479
2480 #[test]
2481 fn malformed_serialized_range_descriptors_are_rejected() {
2482 let dfa = CompiledLexerDfa::compile(&range_loop_atn());
2483 let stream = dfa.serialize();
2484 let range = first_serialized_range_offset(&dfa);
2485 assert_eq!(stream[range].to_le_bytes()[0], 5);
2486
2487 let mut zero_ranges = stream.clone();
2488 zero_ranges[range] = 5;
2489 assert!(CompiledLexerDfa::from_serialized(&zero_ranges).is_none());
2490
2491 let mut too_many_ranges = stream.clone();
2492 too_many_ranges[range] = 5 | (5 << 8);
2493 assert!(CompiledLexerDfa::from_serialized(&too_many_ranges).is_none());
2494
2495 let mut adjacent_ranges = stream.clone();
2496 adjacent_ranges[range] = 5 | (2 << 8);
2497 adjacent_ranges[range + 1] = u32::from(b'a')
2498 | (u32::from(b'm') << 8)
2499 | (u32::from(b'n') << 16)
2500 | (u32::from(b'z') << 24);
2501 adjacent_ranges[range + 2] = 0;
2502 assert!(CompiledLexerDfa::from_serialized(&adjacent_ranges).is_none());
2503
2504 let mut non_ascii_range = stream.clone();
2505 non_ascii_range[range] = 5 | (1 << 8);
2506 non_ascii_range[range + 1] = u32::from(b'a') | (128 << 8);
2507 non_ascii_range[range + 2] = 0;
2508 assert!(CompiledLexerDfa::from_serialized(&non_ascii_range).is_none());
2509
2510 let mut nonzero_padding = stream.clone();
2511 nonzero_padding[range] = 5 | (1 << 8);
2512 nonzero_padding[range + 1] = u32::from(b'0')
2513 | (u32::from(b'9') << 8)
2514 | (u32::from(b'A') << 16)
2515 | (u32::from(b'Z') << 24);
2516 nonzero_padding[range + 2] = 0;
2517 assert!(CompiledLexerDfa::from_serialized(&nonzero_padding).is_none());
2518
2519 let mut truncated = stream;
2520 truncated.truncate(range + 2);
2521 assert!(CompiledLexerDfa::from_serialized(&truncated).is_none());
2522 }
2523
2524 #[test]
2525 fn malformed_wide_rows_are_rejected() {
2526 let atn = wide_range_atn();
2527 let stream = CompiledLexerDfa::compile(&atn).serialize();
2528
2529 let position = stream
2532 .windows(2)
2533 .position(|pair| pair == [0x100, 0x200])
2534 .expect("wide-range test grammar serializes its range bounds");
2535 let mut inverted = stream;
2536 inverted.swap(position, position + 1);
2537 assert!(CompiledLexerDfa::from_serialized(&inverted).is_none());
2538 }
2539
2540 #[test]
2541 fn malformed_escape_continuations_are_rejected() {
2542 let atn = two_rule_atn(true);
2543 let mut dfa = CompiledLexerDfa::compile(&atn);
2544 let range = dfa
2545 .escape_rows
2546 .iter_mut()
2547 .flat_map(|row| row.ranges.iter_mut())
2548 .next()
2549 .expect("predicate grammar should contain an escape range");
2550 range.continuation = u32::MAX - 1;
2551
2552 assert!(CompiledLexerDfa::from_serialized(&dfa.serialize()).is_none());
2553 }
2554
2555 #[test]
2556 fn escape_range_merging_does_not_wrap_maximum_bound() {
2557 let ranges = merge_escape_ranges(&[(-1, -1, 0), (0, 0, 0)]);
2558
2559 assert_eq!(ranges.len(), 2);
2560 assert_eq!((ranges[0].low, ranges[0].high), (u32::MAX, u32::MAX));
2561 assert_eq!((ranges[1].low, ranges[1].high), (0, 0));
2562 }
2563
2564 #[test]
2565 fn force_interpreted_bypasses_compiled_tables() {
2566 let atn = two_rule_atn(false);
2567 let dfa = CompiledLexerDfa::compile(&atn);
2568
2569 let mut lexer = BaseLexer::new(InputStream::new("ab"), recognizer_data());
2570 lexer.set_force_interpreted(true);
2571 let token = compiled_token(&mut lexer, &atn, &dfa);
2572 assert_eq!(token.token_type, 1);
2573 assert!(!lexer.lexer_dfa_string().is_empty());
2576 }
2577}