1use std::cell::{RefCell, RefMut};
4use std::collections::{BTreeSet, HashMap, VecDeque};
5use std::hash::BuildHasherDefault;
6use std::mem::size_of;
7use std::ops::Range;
8use std::rc::Rc;
9use std::sync::Arc;
10
11use crate::atn::LexerAtn;
12use crate::char_stream::{CharStream, TextInterval};
13use crate::int_stream::EOF;
14use crate::prediction::{
15 ContextArena, ContextId, EMPTY_CONTEXT, PredictionFxHasher, PredictionWorkspace,
16};
17use crate::recognizer::{Recognizer, RecognizerData};
18use crate::semir::MemberEnv;
19use crate::token::{
20 DEFAULT_CHANNEL, INVALID_TOKEN_TYPE, TokenId, TokenSink, TokenSourceError, TokenSpec,
21 TokenStoreError,
22};
23
24#[allow(clippy::disallowed_types)]
25type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PredictionFxHasher>>;
26
27pub const SKIP: i32 = -3;
28pub const MORE: i32 = -2;
29pub const DEFAULT_MODE: i32 = 0;
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub struct LexerMode(pub i32);
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub struct LexerCustomAction {
42 rule_index: i32,
43 action_index: i32,
44 position: usize,
45}
46
47impl LexerCustomAction {
48 pub const fn new(rule_index: i32, action_index: i32, position: usize) -> Self {
50 Self {
51 rule_index,
52 action_index,
53 position,
54 }
55 }
56
57 pub const fn rule_index(self) -> i32 {
59 self.rule_index
60 }
61
62 pub const fn action_index(self) -> i32 {
64 self.action_index
65 }
66
67 pub const fn position(self) -> usize {
69 self.position
70 }
71}
72
73#[derive(Clone, Copy, Debug, Eq, PartialEq)]
75pub struct LexerPredicate {
76 rule_index: usize,
77 pred_index: usize,
78 position: usize,
79}
80
81impl LexerPredicate {
82 pub const fn new(rule_index: usize, pred_index: usize, position: usize) -> Self {
84 Self {
85 rule_index,
86 pred_index,
87 position,
88 }
89 }
90
91 pub const fn rule_index(self) -> usize {
93 self.rule_index
94 }
95
96 pub const fn pred_index(self) -> usize {
98 self.pred_index
99 }
100
101 pub const fn position(self) -> usize {
103 self.position
104 }
105}
106
107#[derive(Debug)]
112enum LexerRef<'a, I>
113where
114 I: CharStream,
115{
116 Shared(&'a BaseLexer<I>),
117 Mut(&'a mut BaseLexer<I>),
118}
119
120impl<I> LexerRef<'_, I>
121where
122 I: CharStream,
123{
124 const fn get(&self) -> &BaseLexer<I> {
125 match self {
126 LexerRef::Shared(lexer) => lexer,
127 LexerRef::Mut(lexer) => lexer,
128 }
129 }
130}
131
132#[derive(Debug)]
134pub struct LexerSemCtx<'a, I>
135where
136 I: CharStream,
137{
138 lexer: LexerRef<'a, I>,
139 rule_index: usize,
140 coordinate_index: usize,
141 position: usize,
142}
143
144impl<'a, I> LexerSemCtx<'a, I>
145where
146 I: CharStream,
147{
148 pub(crate) const fn new(
149 lexer: &'a BaseLexer<I>,
150 rule_index: usize,
151 coordinate_index: usize,
152 position: usize,
153 ) -> Self {
154 Self {
155 lexer: LexerRef::Shared(lexer),
156 rule_index,
157 coordinate_index,
158 position,
159 }
160 }
161
162 pub(crate) const fn new_mut(
165 lexer: &'a mut BaseLexer<I>,
166 rule_index: usize,
167 coordinate_index: usize,
168 position: usize,
169 ) -> Self {
170 Self {
171 lexer: LexerRef::Mut(lexer),
172 rule_index,
173 coordinate_index,
174 position,
175 }
176 }
177
178 #[must_use]
180 pub const fn rule_index(&self) -> usize {
181 self.rule_index
182 }
183
184 #[must_use]
186 pub const fn coordinate_index(&self) -> usize {
187 self.coordinate_index
188 }
189
190 #[must_use]
192 pub const fn position(&self) -> usize {
193 self.position
194 }
195
196 #[must_use]
198 pub fn mode(&self) -> i32 {
199 self.lexer.get().mode()
200 }
201
202 #[must_use]
204 pub const fn column(&self) -> usize {
205 self.lexer.get().column()
206 }
207
208 #[must_use]
210 pub fn position_column(&self) -> usize {
211 self.lexer.get().column_at(self.position)
212 }
213
214 #[must_use]
216 pub const fn token_start_column(&self) -> usize {
217 self.lexer.get().token_start_column()
218 }
219
220 #[must_use]
222 pub fn text_so_far(&self) -> String {
223 self.lexer.get().token_text_until(self.position)
224 }
225
226 pub fn la(&mut self, offset: isize) -> i32 {
232 match &mut self.lexer {
233 LexerRef::Shared(lexer) => lexer.lookahead_at(self.position, offset),
234 LexerRef::Mut(lexer) => lexer.input_mut().la(offset),
235 }
236 }
237
238 #[must_use]
240 pub const fn token_start(&self) -> usize {
241 self.lexer.get().token_start()
242 }
243
244 #[must_use]
246 pub const fn token_type(&self) -> i32 {
247 self.lexer.get().token_type()
248 }
249
250 #[must_use]
252 pub const fn channel(&self) -> i32 {
253 self.lexer.get().channel()
254 }
255
256 pub const fn set_type(&mut self, token_type: i32) -> bool {
259 match &mut self.lexer {
260 LexerRef::Mut(lexer) => {
261 lexer.set_type(token_type);
262 true
263 }
264 LexerRef::Shared(_) => false,
265 }
266 }
267
268 pub const fn set_channel(&mut self, channel: i32) -> bool {
271 match &mut self.lexer {
272 LexerRef::Mut(lexer) => {
273 lexer.set_channel(channel);
274 true
275 }
276 LexerRef::Shared(_) => false,
277 }
278 }
279
280 pub fn consume(&mut self) -> bool {
283 match &mut self.lexer {
284 LexerRef::Mut(lexer) => {
285 lexer.consume_char();
286 true
287 }
288 LexerRef::Shared(_) => false,
289 }
290 }
291
292 pub const fn skip(&mut self) -> bool {
294 self.set_type(SKIP)
295 }
296
297 pub const fn more(&mut self) -> bool {
300 self.set_type(MORE)
301 }
302
303 pub fn reset_accept_position(&mut self, index: usize) -> bool {
305 match &mut self.lexer {
306 LexerRef::Mut(lexer) => {
307 lexer.reset_accept_position(index);
308 true
309 }
310 LexerRef::Shared(_) => false,
311 }
312 }
313
314 pub fn set_token_start(&mut self, index: usize) -> bool {
320 match &mut self.lexer {
321 LexerRef::Mut(lexer) => lexer.set_token_start(index),
322 LexerRef::Shared(_) => false,
323 }
324 }
325
326 pub fn enqueue_token(&mut self, token_type: i32, stop: usize) -> bool {
332 let channel = self.channel();
333 self.enqueue_token_with_channel(token_type, channel, stop)
334 }
335
336 pub fn enqueue_token_with_channel(
339 &mut self,
340 token_type: i32,
341 channel: i32,
342 stop: usize,
343 ) -> bool {
344 match &mut self.lexer {
345 LexerRef::Mut(lexer) => {
346 lexer.enqueue_token(token_type, channel, stop, None);
347 true
348 }
349 LexerRef::Shared(_) => false,
350 }
351 }
352
353 pub fn set_mode(&mut self, mode: i32) -> bool {
360 match &mut self.lexer {
361 LexerRef::Mut(lexer) => {
362 lexer.set_mode(mode);
363 true
364 }
365 LexerRef::Shared(_) => false,
366 }
367 }
368
369 pub fn push_mode(&mut self, mode: i32) -> bool {
372 match &mut self.lexer {
373 LexerRef::Mut(lexer) => {
374 lexer.push_mode(mode);
375 true
376 }
377 LexerRef::Shared(_) => false,
378 }
379 }
380
381 pub fn pop_mode(&mut self) -> Option<i32> {
385 match &mut self.lexer {
386 LexerRef::Mut(lexer) => lexer.pop_mode(),
387 LexerRef::Shared(_) => None,
388 }
389 }
390
391 #[must_use]
393 pub fn member_int(&self, member: usize) -> Option<i64> {
394 self.lexer.get().members().scalar(member)
395 }
396
397 #[must_use]
400 pub fn member_stack_top(&self, member: usize) -> Option<i64> {
401 self.lexer.get().members().stack_top(member)
402 }
403
404 #[must_use]
406 pub fn member_stack_len(&self, member: usize) -> usize {
407 self.lexer.get().members().stack_len(member)
408 }
409
410 pub fn set_member_int(&mut self, member: usize, value: i64) -> bool {
413 self.with_members_mut(|members| members.set_scalar(member, value))
414 .is_some()
415 }
416
417 pub fn add_member_int(&mut self, member: usize, delta: i64) -> Option<i64> {
420 self.with_members_mut(|members| members.add_scalar(member, delta))
421 }
422
423 pub fn push_member(&mut self, member: usize, value: i64) -> bool {
426 self.with_members_mut(|members| members.push_stack(member, value))
427 .is_some()
428 }
429
430 pub fn pop_member(&mut self, member: usize) -> Option<i64> {
433 self.with_members_mut(|members| members.pop_stack(member))
434 .flatten()
435 }
436
437 fn with_members_mut<T>(&mut self, apply: impl FnOnce(&mut MemberEnv) -> T) -> Option<T> {
440 match &mut self.lexer {
441 LexerRef::Mut(lexer) => Some(apply(lexer.members_mut())),
442 LexerRef::Shared(_) => None,
443 }
444 }
445}
446
447#[derive(Clone, Copy, Debug, Eq, PartialEq)]
449pub struct LexerSemanticPredicate {
450 pub rule_index: usize,
452 pub pred_index: usize,
454 pub expr: crate::semir::ExprId,
456}
457
458#[derive(Clone, Copy, Debug, Eq, PartialEq)]
460pub struct LexerSemanticAction {
461 pub rule_index: usize,
463 pub action_index: usize,
465 pub stmt: crate::semir::StmtId,
467}
468
469#[derive(Clone, Debug, Default, Eq, PartialEq)]
475pub struct LexerSemantics {
476 pub ir: crate::semir::SemIr,
477 pub predicates: Vec<LexerSemanticPredicate>,
478 pub actions: Vec<LexerSemanticAction>,
479}
480
481impl LexerSemantics {
482 pub fn eval_predicate<I>(&self, lexer: &BaseLexer<I>, predicate: LexerPredicate) -> Option<bool>
485 where
486 I: CharStream,
487 {
488 let entry = self.predicates.iter().find(|entry| {
489 entry.rule_index == predicate.rule_index() && entry.pred_index == predicate.pred_index()
490 })?;
491 let mut ctx = LexerSemIrCtx::new(lexer, predicate);
492 Some(crate::semir::eval_pred(&self.ir, entry.expr, &mut ctx))
493 }
494
495 pub fn exec_action<I>(&self, lexer: &mut BaseLexer<I>, action: LexerCustomAction) -> bool
498 where
499 I: CharStream,
500 {
501 let Ok(rule_index) = usize::try_from(action.rule_index()) else {
502 return false;
503 };
504 let Ok(action_index) = usize::try_from(action.action_index()) else {
505 return false;
506 };
507 let Some(entry) = self
508 .actions
509 .iter()
510 .find(|entry| entry.rule_index == rule_index && entry.action_index == action_index)
511 else {
512 return false;
513 };
514 let stmt = entry.stmt;
515 let mut ctx = LexerSemIrCtx::new_mut(lexer, action);
516 crate::semir::exec_stmt(&self.ir, stmt, &mut ctx);
517 true
518 }
519}
520
521#[derive(Debug)]
529pub struct LexerSemIrCtx<'a, I>
530where
531 I: CharStream,
532{
533 ctx: LexerSemCtx<'a, I>,
534}
535
536impl<'a, I> LexerSemIrCtx<'a, I>
537where
538 I: CharStream,
539{
540 pub(crate) const fn new(lexer: &'a BaseLexer<I>, predicate: LexerPredicate) -> Self {
542 Self {
543 ctx: LexerSemCtx::new(
544 lexer,
545 predicate.rule_index(),
546 predicate.pred_index(),
547 predicate.position(),
548 ),
549 }
550 }
551
552 pub(crate) fn new_mut(lexer: &'a mut BaseLexer<I>, action: LexerCustomAction) -> Self {
554 let rule_index = usize::try_from(action.rule_index()).unwrap_or_default();
555 let action_index = usize::try_from(action.action_index()).unwrap_or_default();
556 Self {
557 ctx: LexerSemCtx::new_mut(lexer, rule_index, action_index, action.position()),
558 }
559 }
560
561 pub const fn ctx_mut(&mut self) -> &mut LexerSemCtx<'a, I> {
563 &mut self.ctx
564 }
565}
566
567impl<I> crate::semir::PredContext for LexerSemIrCtx<'_, I>
568where
569 I: CharStream,
570{
571 type TokenText<'a>
572 = String
573 where
574 Self: 'a;
575
576 fn la(&mut self, offset: isize) -> i64 {
577 i64::from(self.ctx.la(offset))
578 }
579
580 fn token_text(&mut self, _offset: isize) -> Option<Self::TokenText<'_>> {
583 None
584 }
585
586 fn token_index_adjacent(&mut self) -> bool {
587 false
588 }
589
590 fn ctx_rule_text(&self, _rule_index: usize) -> Option<String> {
591 None
592 }
593
594 fn member(&self, member: usize) -> Option<i64> {
595 Some(self.ctx.member_int(member).unwrap_or_default())
596 }
597
598 fn member_top(&self, member: usize) -> Option<i64> {
599 self.ctx.member_stack_top(member)
600 }
601
602 fn member_len(&self, member: usize) -> usize {
603 self.ctx.member_stack_len(member)
604 }
605
606 fn local_arg(&self) -> Option<i64> {
607 None
608 }
609
610 fn column(&self) -> Option<i64> {
611 Some(i64::try_from(self.ctx.position_column()).unwrap_or(i64::MAX))
612 }
613
614 fn token_start_column(&self) -> Option<i64> {
615 Some(i64::try_from(self.ctx.token_start_column()).unwrap_or(i64::MAX))
616 }
617
618 fn token_text_so_far(&self) -> Option<String> {
619 Some(self.ctx.text_so_far())
620 }
621
622 fn hook(&mut self, _hook: crate::semir::HookId) -> bool {
625 false
626 }
627}
628
629impl<I> crate::semir::ActContext for LexerSemIrCtx<'_, I>
630where
631 I: CharStream,
632{
633 fn set_member(&mut self, member: usize, value: i64) {
634 self.ctx.set_member_int(member, value);
635 }
636
637 fn push_member(&mut self, member: usize, value: i64) {
638 self.ctx.push_member(member, value);
639 }
640
641 fn pop_member(&mut self, member: usize) -> Option<i64> {
642 self.ctx.pop_member(member)
643 }
644
645 fn set_return(&mut self, _name: &str, _value: i64) {}
647
648 fn action_hook(&mut self, _hook: crate::semir::HookId) {}
649}
650
651#[derive(Debug)]
659pub struct LexerLifecycleCtx<'a, I>
660where
661 I: CharStream,
662{
663 lexer: &'a mut BaseLexer<I>,
664 accept_position: Option<usize>,
665}
666
667impl<'a, I> LexerLifecycleCtx<'a, I>
668where
669 I: CharStream,
670{
671 pub(crate) const fn new(lexer: &'a mut BaseLexer<I>, accept_position: Option<usize>) -> Self {
672 Self {
673 lexer,
674 accept_position,
675 }
676 }
677
678 #[must_use]
683 pub const fn accept_position(&self) -> Option<usize> {
684 self.accept_position
685 }
686
687 #[must_use]
689 pub fn input_position(&self) -> usize {
690 self.lexer.input().index()
691 }
692
693 #[must_use]
695 pub const fn mode(&self) -> i32 {
696 self.lexer.mode
697 }
698
699 #[must_use]
701 pub const fn line(&self) -> usize {
702 self.lexer.line()
703 }
704
705 #[must_use]
707 pub const fn column(&self) -> usize {
708 self.lexer.column()
709 }
710
711 #[must_use]
713 pub const fn token_start(&self) -> usize {
714 self.lexer.token_start()
715 }
716
717 #[must_use]
719 pub const fn token_start_line(&self) -> usize {
720 self.lexer.token_start_line()
721 }
722
723 #[must_use]
725 pub const fn token_start_column(&self) -> usize {
726 self.lexer.token_start_column()
727 }
728
729 #[must_use]
731 pub const fn token_type(&self) -> i32 {
732 self.lexer.token_type()
733 }
734
735 #[must_use]
737 pub const fn channel(&self) -> i32 {
738 self.lexer.channel()
739 }
740
741 #[must_use]
743 pub fn pending_token_count(&self) -> usize {
744 self.lexer.pending_tokens.len()
745 }
746
747 #[must_use]
749 pub fn token_text(&self) -> String {
750 self.lexer.token_text()
751 }
752
753 #[must_use]
757 pub fn accepted_text(&self) -> Option<String> {
758 self.accept_position
759 .map(|position| self.lexer.token_text_until(position))
760 }
761
762 pub fn la(&mut self, offset: isize) -> i32 {
765 self.lexer.la(offset)
766 }
767
768 pub fn consume(&mut self) {
770 self.lexer.consume_char();
771 }
772
773 pub const fn set_type(&mut self, token_type: i32) {
775 self.lexer.set_type(token_type);
776 }
777
778 pub const fn set_channel(&mut self, channel: i32) {
780 self.lexer.set_channel(channel);
781 }
782
783 pub const fn skip(&mut self) {
785 self.lexer.skip();
786 }
787
788 pub const fn more(&mut self) {
790 self.lexer.more();
791 }
792
793 pub fn reset_accept_position(&mut self, index: usize) {
795 self.lexer.reset_accept_position(index);
796 }
797
798 pub fn set_token_start(&mut self, index: usize) -> bool {
800 self.lexer.set_token_start(index)
801 }
802
803 pub fn enqueue_token(&mut self, token_type: i32, stop: usize) {
805 self.enqueue_token_with_channel(token_type, self.channel(), stop);
806 }
807
808 pub fn enqueue_token_with_channel(&mut self, token_type: i32, channel: i32, stop: usize) {
810 self.lexer.enqueue_token(token_type, channel, stop, None);
811 }
812
813 pub fn set_mode(&mut self, mode: i32) {
815 self.lexer.set_mode(mode);
816 }
817
818 pub fn push_mode(&mut self, mode: i32) {
820 self.lexer.push_mode(mode);
821 }
822
823 pub fn pop_mode(&mut self) -> Option<i32> {
825 self.lexer.pop_mode()
826 }
827}
828
829pub trait Lexer: Recognizer {
830 fn mode(&self) -> i32;
831 fn set_mode(&mut self, mode: i32);
832 fn push_mode(&mut self, mode: i32);
833 fn pop_mode(&mut self) -> Option<i32>;
834}
835
836#[derive(Clone, Debug)]
837pub struct BaseLexer<I> {
838 input: I,
839 data: RecognizerData,
840 has_source_text: bool,
841 mode: i32,
842 mode_stack: Vec<i32>,
843 token_type: i32,
844 channel: i32,
845 token_start: usize,
846 token_start_line: usize,
847 token_start_column: usize,
848 line: usize,
849 column: usize,
850 hit_eof: bool,
851 force_interpreted: bool,
852 errors: RefCell<Vec<TokenSourceError>>,
853 semantic_error_coordinates: RefCell<BTreeSet<(u8, usize, usize, usize)>>,
854 pending_tokens: VecDeque<TokenSpec>,
855 members: MemberEnv,
864 member_inits: Vec<(usize, i64)>,
868 dfa_cache: Rc<RefCell<LexerDfaCache>>,
869}
870
871#[derive(Debug, Default)]
879struct LexerDfaCache {
880 prediction: LexerPredictionStore,
881 state_numbers: FxHashMap<LexerDfaKey, usize>,
882 accept_predictions: FxHashMap<usize, i32>,
883 edges: BTreeSet<LexerDfaEdge>,
887 cached_states: Vec<Option<Rc<LexerDfaCachedState>>>,
889 dense_edges: Vec<Option<Box<DenseEdgeRow>>>,
894 sparse_edges: FxHashMap<(usize, i32), LexerDfaCachedTransition>,
896 mode_starts: FxHashMap<i32, usize>,
897}
898
899#[non_exhaustive]
901#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
902pub struct LexerDfaStats {
903 pub states: usize,
904 pub cached_states: usize,
905 pub transitions: usize,
906 pub max_configs_per_state: usize,
907 pub contexts: usize,
908 pub action_trace_sequences: usize,
909 pub action_traces: usize,
910 pub action_trace_bytes: usize,
912}
913
914#[derive(Debug, Default)]
917pub(crate) struct LexerPredictionStore {
918 pub(crate) contexts: LexerContextArena,
919 pub(crate) workspace: PredictionWorkspace,
920}
921
922#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
923pub(crate) struct LexerActionTrace {
924 pub(crate) action_index: usize,
925 pub(crate) position: usize,
926 pub(crate) rule_index: usize,
928}
929
930#[allow(clippy::rc_buffer)]
933#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
934pub(crate) struct LexerActionTraceList(Option<Arc<Vec<LexerActionTrace>>>);
935
936impl LexerActionTraceList {
937 pub(crate) fn from_vec(traces: Vec<LexerActionTrace>) -> Self {
938 if traces.is_empty() {
939 Self::default()
940 } else {
941 Self(Some(Arc::new(traces)))
942 }
943 }
944
945 pub(crate) fn as_slice(&self) -> &[LexerActionTrace] {
946 self.0.as_deref().map_or(&[], Vec::as_slice)
947 }
948
949 pub(crate) fn to_vec(&self) -> Vec<LexerActionTrace> {
950 self.as_slice().to_vec()
951 }
952
953 pub(crate) fn make_mut(&mut self) -> &mut Vec<LexerActionTrace> {
954 Arc::make_mut(self.0.get_or_insert_with(|| Arc::new(Vec::new())))
955 }
956
957 pub(crate) fn retain(&mut self, mut keep: impl FnMut(&LexerActionTrace) -> bool) {
958 let Some(traces) = self.0.as_mut() else {
959 return;
960 };
961 Arc::make_mut(traces).retain(|trace| keep(trace));
962 if traces.is_empty() {
963 self.0 = None;
964 }
965 }
966
967 pub(crate) fn len(&self) -> usize {
968 self.as_slice().len()
969 }
970}
971
972#[repr(transparent)]
974#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
975pub(crate) struct LexerContextId(u32);
976
977pub(crate) const EMPTY_LEXER_CONTEXT: LexerContextId = LexerContextId(0);
978
979#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
985pub(crate) enum LexerContextNode {
986 Empty,
987 Singleton {
988 parent: LexerContextId,
989 return_state: usize,
990 },
991 Union {
992 left: LexerContextId,
993 right: LexerContextId,
994 },
995}
996
997#[derive(Clone, Copy, Debug)]
998struct LexerContextRecord {
999 node: LexerContextNode,
1000 path_set: ContextId,
1001}
1002
1003#[derive(Debug)]
1005pub(crate) struct LexerContextArena {
1006 records: Vec<LexerContextRecord>,
1007 ids: FxHashMap<LexerContextNode, LexerContextId>,
1008 path_sets: ContextArena,
1009}
1010
1011impl LexerContextArena {
1012 pub(crate) fn new() -> Self {
1013 let mut ids = FxHashMap::default();
1014 ids.insert(LexerContextNode::Empty, EMPTY_LEXER_CONTEXT);
1015 Self {
1016 records: vec![LexerContextRecord {
1017 node: LexerContextNode::Empty,
1018 path_set: EMPTY_CONTEXT,
1019 }],
1020 ids,
1021 path_sets: ContextArena::new(),
1022 }
1023 }
1024
1025 pub(crate) fn singleton(
1026 &mut self,
1027 parent: LexerContextId,
1028 return_state: usize,
1029 ) -> LexerContextId {
1030 self.assert_valid(parent);
1031 let node = LexerContextNode::Singleton {
1032 parent,
1033 return_state,
1034 };
1035 if let Some(&context) = self.ids.get(&node) {
1036 return context;
1037 }
1038 let path_set = self
1039 .path_sets
1040 .singleton(self.record(parent).path_set, return_state);
1041 self.intern(node, path_set)
1042 }
1043
1044 pub(crate) fn merge(
1045 &mut self,
1046 left: LexerContextId,
1047 right: LexerContextId,
1048 workspace: &mut PredictionWorkspace,
1049 ) -> LexerContextId {
1050 self.assert_valid(left);
1051 self.assert_valid(right);
1052 if left == right {
1053 return left;
1054 }
1055 let left_set = self.record(left).path_set;
1056 let right_set = self.record(right).path_set;
1057 let path_set = self.path_sets.merge(left_set, right_set, false, workspace);
1058 if path_set == left_set {
1059 return left;
1060 }
1061 let node = LexerContextNode::Union { left, right };
1062 if let Some(&context) = self.ids.get(&node) {
1063 return context;
1064 }
1065 self.intern(node, path_set)
1066 }
1067
1068 pub(crate) fn node(&self, context: LexerContextId) -> LexerContextNode {
1069 self.record(context).node
1070 }
1071
1072 pub(crate) fn has_empty_path(&self, context: LexerContextId) -> bool {
1073 self.path_sets.has_empty_path(self.record(context).path_set)
1074 }
1075
1076 pub(crate) const fn len(&self) -> usize {
1077 self.records.len()
1078 }
1079
1080 fn intern(&mut self, node: LexerContextNode, path_set: ContextId) -> LexerContextId {
1081 let context = LexerContextId(
1082 u32::try_from(self.records.len()).expect("lexer context arena must fit in u32"),
1083 );
1084 self.records.push(LexerContextRecord { node, path_set });
1085 self.ids.insert(node, context);
1086 context
1087 }
1088
1089 fn record(&self, context: LexerContextId) -> &LexerContextRecord {
1090 self.assert_valid(context);
1091 &self.records[usize::try_from(context.0).expect("u32 lexer context ID fits in usize")]
1092 }
1093
1094 fn assert_valid(&self, context: LexerContextId) {
1095 assert!(
1096 usize::try_from(context.0).is_ok_and(|index| index < self.records.len()),
1097 "lexer context ID does not belong to this store"
1098 );
1099 }
1100}
1101
1102impl Default for LexerContextArena {
1103 fn default() -> Self {
1104 Self::new()
1105 }
1106}
1107
1108const DENSE_EDGE_SYMBOLS: usize = 128;
1110
1111type DenseEdgeRow = [LexerDfaCachedTransition; DENSE_EDGE_SYMBOLS];
1112
1113const EMPTY_DENSE_EDGE: LexerDfaCachedTransition = LexerDfaCachedTransition {
1116 target_state: usize::MAX,
1117 position_delta: 0,
1118};
1119
1120thread_local! {
1121 static SHARED_LEXER_DFA_CACHES: RefCell<HashMap<usize, Rc<RefCell<LexerDfaCache>>>> =
1124 RefCell::new(HashMap::new());
1125}
1126
1127#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1132pub(crate) struct LexerDfaKey {
1133 configs: Vec<LexerDfaConfigKey>,
1134}
1135
1136impl LexerDfaKey {
1137 pub(crate) const fn new(configs: Vec<LexerDfaConfigKey>) -> Self {
1138 Self { configs }
1139 }
1140}
1141
1142#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1144pub(crate) struct LexerDfaConfigKey {
1145 pub(crate) state: usize,
1146 pub(crate) alt_rule_index: Option<usize>,
1147 pub(crate) consumed_eof: bool,
1148 pub(crate) passed_non_greedy: bool,
1149 pub(crate) context: LexerContextId,
1150 pub(crate) actions: Vec<LexerDfaActionKey>,
1151}
1152
1153#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1154pub(crate) struct LexerDfaActionKey {
1155 pub(crate) action_index: usize,
1156 pub(crate) position_delta: usize,
1157 pub(crate) rule_index: usize,
1158}
1159
1160impl LexerDfaConfigKey {
1161 pub(crate) const fn new(
1162 state: usize,
1163 alt_rule_index: Option<usize>,
1164 consumed_eof: bool,
1165 passed_non_greedy: bool,
1166 context: LexerContextId,
1167 actions: Vec<LexerDfaActionKey>,
1168 ) -> Self {
1169 Self {
1170 state,
1171 alt_rule_index,
1172 consumed_eof,
1173 passed_non_greedy,
1174 context,
1175 actions,
1176 }
1177 }
1178}
1179
1180#[derive(Clone, Copy, Debug)]
1181pub(crate) struct LexerDfaCachedTransition {
1182 pub(crate) target_state: usize,
1183 pub(crate) position_delta: usize,
1184}
1185
1186#[derive(Clone, Debug)]
1187pub(crate) struct LexerDfaCachedAccept {
1188 pub(crate) position_delta: usize,
1189 pub(crate) rule_index: usize,
1190 pub(crate) consumed_eof: bool,
1191 pub(crate) actions: Vec<LexerDfaActionKey>,
1192}
1193
1194#[derive(Clone, Debug)]
1195pub(crate) struct LexerDfaCachedState {
1196 pub(crate) has_semantic_context: bool,
1197 pub(crate) configs: Vec<LexerDfaConfigKey>,
1198 pub(crate) accept: Option<LexerDfaCachedAccept>,
1199}
1200
1201#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1204struct LexerDfaEdge {
1205 from: usize,
1206 symbol: i32,
1207 to: usize,
1208}
1209
1210impl<I> BaseLexer<I>
1211where
1212 I: CharStream,
1213{
1214 pub fn new(input: I, data: RecognizerData) -> Self {
1215 let has_source_text = input.source_text().is_some();
1216 Self {
1217 input,
1218 data,
1219 has_source_text,
1220 mode: DEFAULT_MODE,
1221 mode_stack: Vec::new(),
1222 token_type: INVALID_TOKEN_TYPE,
1223 channel: DEFAULT_CHANNEL,
1224 token_start: 0,
1225 token_start_line: 1,
1226 token_start_column: 0,
1227 line: 1,
1228 column: 0,
1229 hit_eof: false,
1230 force_interpreted: false,
1231 errors: RefCell::new(Vec::new()),
1232 semantic_error_coordinates: RefCell::new(BTreeSet::new()),
1233 pending_tokens: VecDeque::new(),
1234 members: MemberEnv::new(),
1235 member_inits: Vec::new(),
1236 dfa_cache: Rc::new(RefCell::new(LexerDfaCache::default())),
1237 }
1238 }
1239
1240 #[must_use]
1247 pub fn with_initial_members(mut self, initial: impl IntoIterator<Item = (usize, i64)>) -> Self {
1248 self.member_inits = initial.into_iter().collect();
1249 self.members = MemberEnv::with_initial_scalars(self.member_inits.iter().copied());
1250 self
1251 }
1252
1253 pub fn reset(&mut self) {
1260 self.input.seek(0);
1261 self.mode = DEFAULT_MODE;
1262 self.mode_stack.clear();
1263 self.token_type = INVALID_TOKEN_TYPE;
1264 self.channel = DEFAULT_CHANNEL;
1265 self.token_start = 0;
1266 self.token_start_line = 1;
1267 self.token_start_column = 0;
1268 self.line = 1;
1269 self.column = 0;
1270 self.hit_eof = false;
1271 self.errors.get_mut().clear();
1272 self.semantic_error_coordinates.get_mut().clear();
1273 self.pending_tokens.clear();
1274 self.members
1279 .reset_to_initial(self.member_inits.iter().copied());
1280 }
1281
1282 pub fn set_input_stream(&mut self, input: I) {
1287 self.input = input;
1288 self.has_source_text = self.input.source_text().is_some();
1289 self.reset();
1290 }
1291
1292 #[must_use]
1302 pub fn with_shared_dfa(mut self, atn: &'static LexerAtn) -> Self {
1303 let ptr: *const LexerAtn = atn;
1304 let key = ptr as usize;
1305 self.dfa_cache = SHARED_LEXER_DFA_CACHES
1306 .with(|caches| Rc::clone(caches.borrow_mut().entry(key).or_insert_with(Rc::default)));
1307 self
1308 }
1309
1310 pub fn clear_dfa(&self) {
1316 let mut cache = self.dfa_cache.borrow_mut();
1317 let prediction = std::mem::take(&mut cache.prediction);
1320 *cache = LexerDfaCache {
1321 prediction,
1322 ..LexerDfaCache::default()
1323 };
1324 }
1325
1326 pub const fn input(&self) -> &I {
1327 &self.input
1328 }
1329
1330 pub const fn input_mut(&mut self) -> &mut I {
1331 &mut self.input
1332 }
1333
1334 pub fn begin_token(&mut self) {
1337 self.semantic_error_coordinates.get_mut().clear();
1338 self.token_type = INVALID_TOKEN_TYPE;
1339 self.channel = DEFAULT_CHANNEL;
1340 self.token_start = self.input.index();
1341 self.token_start_line = self.line;
1342 self.token_start_column = self.column;
1343 }
1344
1345 pub const fn token_start(&self) -> usize {
1347 self.token_start
1348 }
1349
1350 pub const fn token_start_line(&self) -> usize {
1352 self.token_start_line
1353 }
1354
1355 pub const fn token_start_column(&self) -> usize {
1357 self.token_start_column
1358 }
1359
1360 pub const fn token_type(&self) -> i32 {
1362 self.token_type
1363 }
1364
1365 pub const fn set_type(&mut self, token_type: i32) {
1367 self.token_type = token_type;
1368 }
1369
1370 pub const fn channel(&self) -> i32 {
1372 self.channel
1373 }
1374
1375 pub const fn set_channel(&mut self, channel: i32) {
1377 self.channel = channel;
1378 }
1379
1380 pub const fn skip(&mut self) {
1382 self.set_type(SKIP);
1383 }
1384
1385 pub const fn more(&mut self) {
1387 self.set_type(MORE);
1388 }
1389
1390 pub fn la(&mut self, offset: isize) -> i32 {
1393 self.input.la(offset)
1394 }
1395
1396 fn lookahead_at(&self, position: usize, offset: isize) -> i32 {
1397 if offset == 0 {
1398 return 0;
1399 }
1400 let absolute = if offset > 0 {
1401 position.checked_add((offset - 1).cast_unsigned())
1402 } else {
1403 offset
1404 .checked_neg()
1405 .and_then(|distance| usize::try_from(distance).ok())
1406 .and_then(|distance| position.checked_sub(distance))
1407 };
1408 let Some(index) = absolute.filter(|index| *index < self.input.size()) else {
1409 return EOF;
1410 };
1411 if let Some(symbol) = self.input.symbol_at(index) {
1412 return symbol;
1413 }
1414 self.input
1415 .text(TextInterval::new(index, index))
1416 .chars()
1417 .next()
1418 .map_or(EOF, |ch| u32::from(ch).cast_signed())
1419 }
1420
1421 pub fn consume_char(&mut self) {
1428 let la = self.input.la(1);
1429 if la == EOF {
1430 return;
1431 }
1432 self.input.consume();
1433 if char::from_u32(la.cast_unsigned()) == Some('\n') {
1434 self.line += 1;
1435 self.column = 0;
1436 } else {
1437 self.column += 1;
1438 }
1439 }
1440
1441 pub(crate) fn commit_position(&mut self, start: usize, target: usize) {
1444 self.reposition_from(start, self.line, self.column, target);
1445 }
1446
1447 fn reposition_from(&mut self, start: usize, line: usize, column: usize, target: usize) {
1448 let start = start.min(self.input.size());
1449 let target = target.max(start).min(self.input.size());
1450 if let Some(summary) = self.input.position_summary(start, target) {
1451 self.input.seek(target);
1452 (self.line, self.column) = summary.apply(line, column);
1453 #[cfg(feature = "perf-counters")]
1454 crate::perf::record_lexer_bulk_commit(target - start);
1455 return;
1456 }
1457
1458 self.input.seek(start);
1459 self.line = line;
1460 self.column = column;
1461 #[cfg(feature = "perf-counters")]
1462 let before = self.input.index();
1463 while self.input.index() < target && self.input.la(1) != EOF {
1464 self.consume_char();
1465 }
1466 #[cfg(feature = "perf-counters")]
1467 crate::perf::record_lexer_scalar_replay(self.input.index().saturating_sub(before));
1468 }
1469
1470 pub fn reset_accept_position(&mut self, index: usize) {
1477 let target = index.max(self.token_start);
1478 self.reposition_from(
1479 self.token_start,
1480 self.token_start_line,
1481 self.token_start_column,
1482 target,
1483 );
1484 }
1485
1486 pub fn set_token_start(&mut self, index: usize) -> bool {
1492 if index < self.token_start || index > self.input.index() {
1493 return false;
1494 }
1495 let (line, column) = self.position_at(index);
1496 self.token_start = index;
1497 self.token_start_line = line;
1498 self.token_start_column = column;
1499 true
1500 }
1501
1502 pub fn emit(
1510 &self,
1511 sink: &mut TokenSink<'_>,
1512 token_type: i32,
1513 channel: i32,
1514 text: Option<String>,
1515 ) -> Result<TokenId, TokenStoreError> {
1516 let stop = self.input.index().checked_sub(1).unwrap_or(usize::MAX);
1517 self.emit_with_stop(sink, token_type, channel, stop, text)
1518 }
1519
1520 pub fn emit_with_stop(
1526 &self,
1527 sink: &mut TokenSink<'_>,
1528 token_type: i32,
1529 channel: i32,
1530 stop: usize,
1531 text: Option<String>,
1532 ) -> Result<TokenId, TokenStoreError> {
1533 sink.push(self.token_spec_with_stop(token_type, channel, stop, text))
1534 }
1535
1536 fn token_spec_with_stop(
1537 &self,
1538 token_type: i32,
1539 channel: i32,
1540 stop: usize,
1541 text: Option<String>,
1542 ) -> TokenSpec {
1543 let text = text.or_else(|| {
1544 if stop == usize::MAX {
1545 Some("<EOF>".to_owned())
1546 } else {
1547 None
1548 }
1549 });
1550 let source_interval = if self.has_source_text
1551 && text.is_none()
1552 && stop != usize::MAX
1553 && self.token_start <= stop
1554 {
1555 self.input
1556 .byte_interval(TextInterval::new(self.token_start, stop))
1557 } else {
1558 None
1559 };
1560 let text = text.or_else(|| {
1561 source_interval
1562 .is_none()
1563 .then(|| self.input.text(TextInterval::new(self.token_start, stop)))
1564 });
1565 let (start_byte, stop_byte) = source_interval
1566 .or_else(|| self.token_byte_span(stop))
1567 .unwrap_or((usize::MAX, usize::MAX));
1568 TokenSpec {
1569 token_type,
1570 channel,
1571 start: self.token_start,
1572 stop,
1573 start_byte,
1574 stop_byte,
1575 line: self.token_start_line,
1576 column: self.token_start_column,
1577 text,
1578 source_backed: source_interval.is_some(),
1579 }
1580 }
1581
1582 pub fn enqueue_token(
1588 &mut self,
1589 token_type: i32,
1590 channel: i32,
1591 stop: usize,
1592 text: Option<String>,
1593 ) {
1594 let token = self.token_spec_with_stop(token_type, channel, stop, text);
1595 self.pending_tokens.push_back(token);
1596 }
1597
1598 pub(crate) fn emit_pending_token(
1599 &mut self,
1600 sink: &mut TokenSink<'_>,
1601 ) -> Result<Option<TokenId>, TokenStoreError> {
1602 self.pending_tokens
1603 .pop_front()
1604 .map(|token| sink.push(token))
1605 .transpose()
1606 }
1607
1608 pub(crate) fn emit_or_enqueue_with_stop(
1609 &mut self,
1610 sink: &mut TokenSink<'_>,
1611 stop: usize,
1612 text: Option<String>,
1613 ) -> Result<TokenId, TokenStoreError> {
1614 let token = self.token_spec_with_stop(self.token_type, self.channel, stop, text);
1615 self.emit_or_enqueue(sink, token)
1616 }
1617
1618 fn emit_or_enqueue(
1619 &mut self,
1620 sink: &mut TokenSink<'_>,
1621 token: TokenSpec,
1622 ) -> Result<TokenId, TokenStoreError> {
1623 if self.pending_tokens.is_empty() {
1624 return sink.push(token);
1625 }
1626 self.pending_tokens.push_back(token);
1627 self.emit_pending_token(sink)?
1628 .ok_or_else(|| unreachable!("the pending-token queue was just populated"))
1629 }
1630
1631 pub fn token_text(&self) -> String {
1634 self.token_text_until(self.input.index())
1635 }
1636
1637 pub fn token_text_until(&self, stop_exclusive: usize) -> String {
1645 if stop_exclusive <= self.token_start {
1646 return String::new();
1647 }
1648 self.input
1649 .text(TextInterval::new(self.token_start, stop_exclusive - 1))
1650 }
1651
1652 pub fn column_at(&self, position: usize) -> usize {
1655 self.position_at(position).1
1656 }
1657
1658 #[must_use]
1660 pub const fn members(&self) -> &MemberEnv {
1661 &self.members
1662 }
1663
1664 pub const fn members_mut(&mut self) -> &mut MemberEnv {
1666 &mut self.members
1667 }
1668
1669 fn position_at(&self, position: usize) -> (usize, usize) {
1670 let mut line = self.token_start_line;
1671 let mut column = self.token_start_column;
1672 if position <= self.token_start {
1673 return (line, column);
1674 }
1675 if let Some(summary) = self.input.position_summary(self.token_start, position) {
1676 return summary.apply(line, column);
1677 }
1678 for ch in self
1679 .input
1680 .text(TextInterval::new(self.token_start, position - 1))
1681 .chars()
1682 {
1683 if ch == '\n' {
1684 line += 1;
1685 column = 0;
1686 } else {
1687 column += 1;
1688 }
1689 }
1690 (line, column)
1691 }
1692
1693 pub fn eof_token(&self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
1695 sink.push(self.eof_token_spec())
1696 }
1697
1698 pub(crate) fn emit_eof_or_pending(
1699 &mut self,
1700 sink: &mut TokenSink<'_>,
1701 ) -> Result<TokenId, TokenStoreError> {
1702 let token = self.eof_token_spec();
1703 self.emit_or_enqueue(sink, token)
1704 }
1705
1706 fn eof_token_spec(&self) -> TokenSpec {
1707 let byte_offset = self.eof_byte_offset().unwrap_or(usize::MAX);
1708 TokenSpec::eof(self.input.index(), byte_offset, self.line, self.column)
1709 }
1710
1711 fn eof_byte_offset(&self) -> Option<usize> {
1712 self.byte_offset_at(self.input.index())
1713 }
1714
1715 fn token_byte_span(&self, stop: usize) -> Option<(usize, usize)> {
1716 if stop != usize::MAX && self.token_start <= stop {
1717 let (start_byte, stop_byte) = self
1718 .input
1719 .byte_interval(TextInterval::new(self.token_start, stop))?;
1720 return Some((start_byte, stop_byte));
1721 }
1722 let byte_offset = self.byte_offset_at(self.token_start)?;
1723 Some((byte_offset, byte_offset))
1724 }
1725
1726 fn byte_offset_at(&self, index: usize) -> Option<usize> {
1727 let byte_offset = if index == 0 {
1728 0
1729 } else {
1730 let previous = TextInterval::new(index - 1, index - 1);
1731 self.input.byte_interval(previous)?.1
1732 };
1733 Some(byte_offset)
1734 }
1735
1736 fn byte_span_for_scalar_range(&self, span: Range<usize>) -> Option<Range<usize>> {
1737 if span.start > span.end {
1738 return None;
1739 }
1740 if span.is_empty() {
1741 let offset = self.byte_offset_at(span.start)?;
1742 return Some(offset..offset);
1743 }
1744 let (start, end) = self
1745 .input
1746 .byte_interval(TextInterval::new(span.start, span.end - 1))?;
1747 Some(start..end)
1748 }
1749}
1750
1751impl<I> Recognizer for BaseLexer<I>
1752where
1753 I: CharStream,
1754{
1755 fn data(&self) -> &RecognizerData {
1756 &self.data
1757 }
1758
1759 fn data_mut(&mut self) -> &mut RecognizerData {
1760 &mut self.data
1761 }
1762}
1763
1764impl<I> Lexer for BaseLexer<I>
1765where
1766 I: CharStream,
1767{
1768 fn mode(&self) -> i32 {
1769 self.mode
1770 }
1771
1772 fn set_mode(&mut self, mode: i32) {
1773 self.mode = mode;
1774 }
1775
1776 fn push_mode(&mut self, mode: i32) {
1777 self.mode_stack.push(self.mode);
1778 self.mode = mode;
1779 }
1780
1781 fn pop_mode(&mut self) -> Option<i32> {
1782 let mode = self.mode_stack.pop()?;
1783 self.mode = mode;
1784 Some(mode)
1785 }
1786}
1787
1788impl<I> BaseLexer<I>
1789where
1790 I: CharStream,
1791{
1792 pub const fn line(&self) -> usize {
1793 self.line
1794 }
1795
1796 pub const fn column(&self) -> usize {
1797 self.column
1798 }
1799
1800 pub fn source_name(&self) -> &str {
1801 self.input.source_name()
1802 }
1803
1804 pub fn source_text(&self) -> Option<Rc<str>> {
1805 self.input.source_text()
1806 }
1807
1808 pub const fn hit_eof(&self) -> bool {
1809 self.hit_eof
1810 }
1811
1812 pub const fn set_hit_eof(&mut self, hit_eof: bool) {
1813 self.hit_eof = hit_eof;
1814 }
1815
1816 pub const fn set_force_interpreted(&mut self, force_interpreted: bool) {
1824 self.force_interpreted = force_interpreted;
1825 }
1826
1827 pub const fn force_interpreted(&self) -> bool {
1829 self.force_interpreted
1830 }
1831
1832 pub fn record_error(&self, line: usize, column: usize, message: impl Into<String>) {
1839 let scalar_span = self.token_start..self.input.index().max(self.token_start);
1840 self.record_error_for_scalar_span(line, column, message, scalar_span);
1841 }
1842
1843 pub fn record_error_for_scalar_span(
1849 &self,
1850 line: usize,
1851 column: usize,
1852 message: impl Into<String>,
1853 scalar_span: Range<usize>,
1854 ) {
1855 let mut error = TokenSourceError::new(line, column, message);
1856 error.span = self.byte_span_for_scalar_range(scalar_span);
1857 self.errors.borrow_mut().push(error);
1858 }
1859
1860 pub fn record_semantic_error(&self, action: bool, rule_index: usize, coordinate_index: usize) {
1862 let kind = u8::from(action);
1863 if !self.semantic_error_coordinates.borrow_mut().insert((
1864 kind,
1865 rule_index,
1866 coordinate_index,
1867 self.token_start,
1868 )) {
1869 return;
1870 }
1871 let label = if action { "action" } else { "predicate" };
1872 self.record_error(
1873 self.token_start_line,
1874 self.token_start_column,
1875 format!("unhandled lexer semantic {label}: rule={rule_index} index={coordinate_index}"),
1876 );
1877 }
1878
1879 pub fn drain_errors(&mut self) -> Vec<TokenSourceError> {
1881 std::mem::take(self.errors.get_mut())
1882 }
1883
1884 pub(crate) fn lexer_prediction_store(&self) -> RefMut<'_, LexerPredictionStore> {
1887 RefMut::map(self.dfa_cache.borrow_mut(), |cache| &mut cache.prediction)
1888 }
1889
1890 pub(crate) fn reset_lexer_prediction_workspace(&self) {
1893 self.dfa_cache.borrow_mut().prediction.workspace.reset();
1894 }
1895
1896 pub fn lexer_dfa_stats(&self) -> LexerDfaStats {
1898 let cache = self.dfa_cache.borrow();
1899 let cached_states = cache.cached_states.iter().flatten().count();
1900 let transitions = cache
1901 .dense_edges
1902 .iter()
1903 .flatten()
1904 .map(|row| {
1905 row.iter()
1906 .filter(|transition| transition.target_state != usize::MAX)
1907 .count()
1908 })
1909 .sum::<usize>()
1910 + cache.sparse_edges.len();
1911 let max_configs_per_state = cache
1912 .cached_states
1913 .iter()
1914 .flatten()
1915 .map(|state| state.configs.len())
1916 .max()
1917 .unwrap_or(0);
1918 let mut action_trace_sequences = 0;
1919 let mut action_traces = 0;
1920 let mut action_trace_bytes = 0;
1921 let mut account_actions = |actions: &Vec<LexerDfaActionKey>| {
1922 if actions.is_empty() {
1923 return;
1924 }
1925 action_trace_sequences += 1;
1926 action_traces += actions.len();
1927 action_trace_bytes += actions.capacity() * size_of::<LexerDfaActionKey>();
1928 };
1929 for key in cache.state_numbers.keys() {
1930 for config in &key.configs {
1931 account_actions(&config.actions);
1932 }
1933 }
1934 for state in cache.cached_states.iter().flatten() {
1935 for config in &state.configs {
1936 account_actions(&config.actions);
1937 }
1938 if let Some(accept) = state.accept.as_ref() {
1939 account_actions(&accept.actions);
1940 }
1941 }
1942 LexerDfaStats {
1943 states: cache.state_numbers.len(),
1944 cached_states,
1945 transitions,
1946 max_configs_per_state,
1947 contexts: cache.prediction.contexts.len(),
1948 action_trace_sequences,
1949 action_traces,
1950 action_trace_bytes,
1951 }
1952 }
1953
1954 #[cfg(test)]
1955 pub(crate) fn lexer_dfa_cache_shape(&self) -> (usize, usize, usize, usize) {
1956 let stats = self.lexer_dfa_stats();
1957 (
1958 stats.cached_states,
1959 stats.transitions,
1960 stats.max_configs_per_state,
1961 stats.contexts,
1962 )
1963 }
1964
1965 pub(crate) fn lexer_dfa_state(
1968 &self,
1969 key: LexerDfaKey,
1970 accept_prediction: Option<i32>,
1971 ) -> usize {
1972 let mut cache = self.dfa_cache.borrow_mut();
1973 let next = cache.state_numbers.len();
1974 let state = *cache.state_numbers.entry(key).or_insert(next);
1975 if let Some(prediction) = accept_prediction {
1976 cache.accept_predictions.insert(state, prediction);
1977 }
1978 state
1979 }
1980
1981 pub fn record_lexer_dfa_edge(&self, from: usize, symbol: i32, to: usize) {
1983 self.dfa_cache
1984 .borrow_mut()
1985 .edges
1986 .insert(LexerDfaEdge { from, symbol, to });
1987 }
1988
1989 pub(crate) fn cached_lexer_dfa_transition(
1990 &self,
1991 state: usize,
1992 symbol: i32,
1993 ) -> Option<LexerDfaCachedTransition> {
1994 let cache = self.dfa_cache.borrow();
1995 if let Ok(sym) = usize::try_from(symbol)
1996 && sym < DENSE_EDGE_SYMBOLS
1997 {
1998 let transition = cache.dense_edges.get(state)?.as_ref()?[sym];
1999 return (transition.target_state != usize::MAX).then_some(transition);
2000 }
2001 cache.sparse_edges.get(&(state, symbol)).copied()
2002 }
2003
2004 pub(crate) fn cache_lexer_dfa_transition(
2005 &self,
2006 state: usize,
2007 symbol: i32,
2008 transition: LexerDfaCachedTransition,
2009 ) {
2010 let mut cache = self.dfa_cache.borrow_mut();
2011 if let Ok(sym) = usize::try_from(symbol)
2012 && sym < DENSE_EDGE_SYMBOLS
2013 {
2014 if cache.dense_edges.len() <= state {
2015 cache.dense_edges.resize_with(state + 1, || None);
2016 }
2017 let row = cache.dense_edges[state]
2018 .get_or_insert_with(|| Box::new([EMPTY_DENSE_EDGE; DENSE_EDGE_SYMBOLS]));
2019 if row[sym].target_state == usize::MAX {
2021 row[sym] = transition;
2022 }
2023 return;
2024 }
2025 cache
2026 .sparse_edges
2027 .entry((state, symbol))
2028 .or_insert(transition);
2029 }
2030
2031 pub(crate) fn cached_lexer_dfa_state(&self, state: usize) -> Option<Rc<LexerDfaCachedState>> {
2032 self.dfa_cache
2033 .borrow()
2034 .cached_states
2035 .get(state)
2036 .cloned()
2037 .flatten()
2038 }
2039
2040 pub(crate) fn cache_lexer_dfa_state(&self, state: usize, cached_state: LexerDfaCachedState) {
2041 let mut cache = self.dfa_cache.borrow_mut();
2042 if cache.cached_states.len() <= state {
2043 cache.cached_states.resize_with(state + 1, || None);
2044 }
2045 cache.cached_states[state].get_or_insert_with(|| Rc::new(cached_state));
2046 }
2047
2048 pub(crate) fn cached_lexer_mode_start(&self, mode: i32) -> Option<usize> {
2049 self.dfa_cache.borrow().mode_starts.get(&mode).copied()
2050 }
2051
2052 pub(crate) fn cache_lexer_mode_start(&self, mode: i32, state: usize) {
2053 self.dfa_cache
2054 .borrow_mut()
2055 .mode_starts
2056 .entry(mode)
2057 .or_insert(state);
2058 }
2059
2060 pub fn lexer_dfa_string(&self) -> String {
2062 let mut out = String::new();
2063 let cache = self.dfa_cache.borrow();
2064 for edge in &cache.edges {
2065 let Some(label) = lexer_dfa_edge_label(edge.symbol) else {
2066 continue;
2067 };
2068 out.push_str(&self.lexer_dfa_state_string(edge.from));
2069 out.push('-');
2070 out.push_str(&label);
2071 out.push_str("->");
2072 out.push_str(&self.lexer_dfa_state_string(edge.to));
2073 out.push('\n');
2074 }
2075 out
2076 }
2077
2078 fn lexer_dfa_state_string(&self, state: usize) -> String {
2079 self.dfa_cache
2080 .borrow()
2081 .accept_predictions
2082 .get(&state)
2083 .map_or_else(
2084 || format!("s{state}"),
2085 |prediction| format!(":s{state}=>{prediction}"),
2086 )
2087 }
2088}
2089
2090fn lexer_dfa_edge_label(symbol: i32) -> Option<String> {
2091 char::from_u32(symbol.cast_unsigned()).map(|ch| format!("'{ch}'"))
2092}
2093
2094#[cfg(test)]
2095#[allow(clippy::disallowed_methods)] mod tests {
2097 use super::*;
2098 use crate::char_stream::InputStream;
2099 use crate::int_stream::IntStream;
2100 use crate::recognizer::RecognizerData;
2101 use crate::token::{DEFAULT_CHANNEL, Token, TokenStore};
2102 use crate::vocabulary::Vocabulary;
2103
2104 #[test]
2105 fn action_trace_lists_clone_on_write_without_aliasing() {
2106 let first = LexerActionTrace {
2107 action_index: 1,
2108 position: 2,
2109 rule_index: 3,
2110 };
2111 let second = LexerActionTrace {
2112 action_index: 4,
2113 position: 5,
2114 rule_index: 6,
2115 };
2116 let mut original = LexerActionTraceList::default();
2117 original.make_mut().push(first);
2118 let mut fork = original.clone();
2119 fork.make_mut().push(second);
2120
2121 assert_eq!(original.as_slice(), [first]);
2122 assert_eq!(fork.as_slice(), [first, second]);
2123 fork.retain(|_| false);
2124 assert!(fork.as_slice().is_empty());
2125
2126 fn assert_send<T: Send>() {}
2127 assert_send::<LexerActionTraceList>();
2128 }
2129
2130 #[test]
2131 fn action_trace_lists_do_not_retain_growing_prefixes() {
2132 let mut actions = LexerActionTraceList::default();
2133 for position in 0..1024 {
2134 let source = actions.clone();
2135 actions.make_mut().push(LexerActionTrace {
2136 action_index: 0,
2137 position,
2138 rule_index: 0,
2139 });
2140 drop(source);
2141 assert_eq!(
2142 Arc::strong_count(actions.0.as_ref().expect("non-empty action list")),
2143 1
2144 );
2145 }
2146 assert_eq!(actions.len(), 1024);
2147 }
2148
2149 #[derive(Clone, Debug)]
2150 struct UnsharedInput {
2151 input: InputStream,
2152 maps_bytes: bool,
2153 }
2154
2155 impl UnsharedInput {
2156 fn mapped(input: InputStream) -> Self {
2157 Self {
2158 input,
2159 maps_bytes: true,
2160 }
2161 }
2162
2163 fn scalar_only(input: InputStream) -> Self {
2164 Self {
2165 input,
2166 maps_bytes: false,
2167 }
2168 }
2169 }
2170
2171 impl IntStream for UnsharedInput {
2172 fn consume(&mut self) {
2173 self.input.consume();
2174 }
2175
2176 fn la(&mut self, offset: isize) -> i32 {
2177 self.input.la(offset)
2178 }
2179
2180 fn index(&self) -> usize {
2181 self.input.index()
2182 }
2183
2184 fn seek(&mut self, index: usize) {
2185 self.input.seek(index);
2186 }
2187
2188 fn size(&self) -> usize {
2189 self.input.size()
2190 }
2191
2192 fn source_name(&self) -> &str {
2193 self.input.source_name()
2194 }
2195 }
2196
2197 impl CharStream for UnsharedInput {
2198 fn text(&self, interval: TextInterval) -> String {
2199 self.input.text(interval)
2200 }
2201
2202 fn byte_interval(&self, interval: TextInterval) -> Option<(usize, usize)> {
2203 if self.maps_bytes {
2204 self.input.byte_interval(interval)
2205 } else {
2206 None
2207 }
2208 }
2209 }
2210
2211 #[test]
2212 fn eof_token_uses_utf8_byte_offset_after_non_ascii_input() {
2213 let data = RecognizerData::new(
2214 "T",
2215 Vocabulary::new(
2216 std::iter::empty::<Option<&str>>(),
2217 std::iter::empty::<Option<&str>>(),
2218 std::iter::empty::<Option<&str>>(),
2219 ),
2220 );
2221 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
2222 lexer.consume_char();
2223
2224 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2225 let mut sink = TokenSink::new(&mut store);
2226 let id = lexer.eof_token(&mut sink).expect("test token should fit");
2227 let token = sink.view(id).expect("emitted token should exist");
2228
2229 insta::assert_compact_debug_snapshot!(
2232 (token.start(), token.stop(), token.text(), token.byte_span()),
2233 @r#"(1, 0, Some("<EOF>"), Some(2..2))"#
2234 );
2235 }
2236
2237 #[test]
2238 fn eof_token_has_no_byte_span_without_byte_mapping() {
2239 let data = RecognizerData::new(
2240 "T",
2241 Vocabulary::new(
2242 std::iter::empty::<Option<&str>>(),
2243 std::iter::empty::<Option<&str>>(),
2244 std::iter::empty::<Option<&str>>(),
2245 ),
2246 );
2247 let mut lexer = BaseLexer::new(UnsharedInput::scalar_only(InputStream::new("β")), data);
2248 lexer.consume_char();
2249
2250 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2251 let mut sink = TokenSink::new(&mut store);
2252 let id = lexer.eof_token(&mut sink).expect("test token should fit");
2253 let token = sink.view(id).expect("emitted token should exist");
2254
2255 insta::assert_compact_debug_snapshot!(
2256 (token.start(), token.stop(), token.text(), token.byte_span()),
2257 @r#"(1, 0, Some("<EOF>"), None)"#
2258 );
2259 }
2260
2261 #[test]
2262 fn eof_rule_token_uses_utf8_byte_offset_after_non_ascii_input() {
2263 let data = RecognizerData::new(
2264 "T",
2265 Vocabulary::new(
2266 std::iter::empty::<Option<&str>>(),
2267 std::iter::empty::<Option<&str>>(),
2268 std::iter::empty::<Option<&str>>(),
2269 ),
2270 );
2271 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
2272 lexer.consume_char();
2273 lexer.begin_token();
2274
2275 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2276 let mut sink = TokenSink::new(&mut store);
2277 let id = lexer
2278 .emit_with_stop(&mut sink, 1, DEFAULT_CHANNEL, 0, Some("<EOF>".to_owned()))
2279 .expect("test token should fit");
2280 let token = sink.view(id).expect("emitted token should exist");
2281
2282 insta::assert_compact_debug_snapshot!(
2285 (token.start(), token.stop(), token.text(), token.byte_span()),
2286 @r#"(1, 0, Some("<EOF>"), Some(2..2))"#
2287 );
2288 }
2289
2290 #[test]
2291 fn emit_implicit_text_uses_utf8_byte_span_for_non_ascii_input() {
2292 let data = RecognizerData::new(
2293 "T",
2294 Vocabulary::new(
2295 std::iter::empty::<Option<&str>>(),
2296 std::iter::empty::<Option<&str>>(),
2297 std::iter::empty::<Option<&str>>(),
2298 ),
2299 );
2300 let mut lexer = BaseLexer::new(InputStream::new("β"), data);
2301 lexer.begin_token();
2302 lexer.consume_char();
2303
2304 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2305 let mut sink = TokenSink::new(&mut store);
2306 let id = lexer
2307 .emit(&mut sink, 1, DEFAULT_CHANNEL, None)
2308 .expect("test token should fit");
2309 let token = sink.view(id).expect("emitted token should exist");
2310
2311 insta::assert_compact_debug_snapshot!(
2314 (token.start(), token.stop(), token.text(), token.byte_span()),
2315 @r#"(0, 0, Some("β"), Some(0..2))"#
2316 );
2317 }
2318
2319 #[test]
2320 fn emit_falls_back_to_explicit_text_without_shareable_source() {
2321 let data = RecognizerData::new(
2322 "T",
2323 Vocabulary::new(
2324 std::iter::empty::<Option<&str>>(),
2325 std::iter::empty::<Option<&str>>(),
2326 std::iter::empty::<Option<&str>>(),
2327 ),
2328 );
2329 let mut lexer = BaseLexer::new(UnsharedInput::mapped(InputStream::new("β")), data);
2330 lexer.begin_token();
2331 lexer.consume_char();
2332
2333 let mut store = TokenStore::new(lexer.source_text(), lexer.source_name());
2334 let mut sink = TokenSink::new(&mut store);
2335 let id = lexer
2336 .emit(&mut sink, 1, DEFAULT_CHANNEL, None)
2337 .expect("unshared input should emit explicit token text");
2338 let token = sink.view(id).expect("emitted token should exist");
2339
2340 assert_eq!(token.text(), Some("β"));
2341 assert_eq!(token.byte_span(), Some(0..2));
2342 }
2343
2344 #[test]
2345 fn position_commits_and_rewinds_preserve_line_and_column() {
2346 let data = RecognizerData::new(
2347 "T",
2348 Vocabulary::new(
2349 std::iter::empty::<Option<&str>>(),
2350 std::iter::empty::<Option<&str>>(),
2351 std::iter::empty::<Option<&str>>(),
2352 ),
2353 );
2354 let mut lexer = BaseLexer::new(InputStream::new("ab\nγd"), data);
2355 lexer.begin_token();
2356
2357 lexer.commit_position(0, 5);
2358 assert_eq!(lexer.input().index(), 5);
2359 assert_eq!((lexer.line(), lexer.column()), (2, 2));
2360 assert_eq!(lexer.column_at(2), 2);
2361 assert_eq!(lexer.column_at(4), 1);
2362
2363 lexer.reset_accept_position(3);
2364 assert_eq!(lexer.input().index(), 3);
2365 assert_eq!((lexer.line(), lexer.column()), (2, 0));
2366 }
2367
2368 #[test]
2369 fn custom_stream_position_commit_replays_without_fast_path_methods() {
2370 let data = RecognizerData::new(
2371 "T",
2372 Vocabulary::new(
2373 std::iter::empty::<Option<&str>>(),
2374 std::iter::empty::<Option<&str>>(),
2375 std::iter::empty::<Option<&str>>(),
2376 ),
2377 );
2378 let mut lexer = BaseLexer::new(UnsharedInput::mapped(InputStream::new("a\nb")), data);
2379 lexer.begin_token();
2380
2381 lexer.commit_position(0, 3);
2382 assert_eq!(lexer.input().index(), 3);
2383 assert_eq!((lexer.line(), lexer.column()), (2, 1));
2384 }
2385
2386 #[test]
2387 fn semantic_hook_errors_are_deduplicated_per_token_coordinate() {
2388 let data = RecognizerData::new(
2389 "T",
2390 Vocabulary::new(
2391 std::iter::empty::<Option<&str>>(),
2392 std::iter::empty::<Option<&str>>(),
2393 std::iter::empty::<Option<&str>>(),
2394 ),
2395 );
2396 let mut lexer = BaseLexer::new(InputStream::new("a"), data);
2397 lexer.begin_token();
2398 lexer.record_semantic_error(false, 3, 7);
2399 lexer.record_semantic_error(false, 3, 7);
2400
2401 let errors = lexer.drain_errors();
2402 insta::assert_compact_debug_snapshot!(errors, @r#"[TokenSourceError { line: 1, column: 0, span: Some(0..0), message: "unhandled lexer semantic predicate: rule=3 index=7" }]"#);
2403
2404 lexer.begin_token();
2405 lexer.record_semantic_error(false, 3, 7);
2406 assert_eq!(
2407 lexer.drain_errors().len(),
2408 1,
2409 "deduplication resets at every token boundary, even after rewinding"
2410 );
2411 }
2412
2413 #[test]
2414 fn set_input_stream_replaces_input_and_resets_transient_state() {
2415 let data = RecognizerData::new(
2416 "T",
2417 Vocabulary::new(
2418 std::iter::empty::<Option<&str>>(),
2419 std::iter::empty::<Option<&str>>(),
2420 std::iter::empty::<Option<&str>>(),
2421 ),
2422 );
2423 let mut lexer = BaseLexer::new(InputStream::new("old"), data);
2424 lexer.consume_char();
2425 lexer.set_mode(7);
2426 lexer.push_mode(9);
2427 lexer.set_type(3);
2428 lexer.record_error(1, 0, "stale");
2429
2430 lexer.set_input_stream(InputStream::with_source_name("new", "replacement"));
2431
2432 assert_eq!(lexer.input().index(), 0);
2433 assert_eq!(lexer.input().size(), 3);
2434 assert_eq!(lexer.source_name(), "replacement");
2435 assert_eq!(lexer.source_text().as_deref(), Some("new"));
2436 assert_eq!(lexer.mode(), DEFAULT_MODE);
2437 assert_eq!(lexer.token_type(), INVALID_TOKEN_TYPE);
2438 assert_eq!((lexer.line(), lexer.column()), (1, 0));
2439 assert!(!lexer.hit_eof());
2440 assert!(lexer.drain_errors().is_empty());
2441 assert!(lexer.pop_mode().is_none());
2442 }
2443
2444 #[test]
2445 fn clear_dfa_invalidates_all_lexers_sharing_the_cache() {
2446 let atn = Box::leak(Box::new(LexerAtn::new(1)));
2447 let data = || {
2448 RecognizerData::new(
2449 "T",
2450 Vocabulary::new(
2451 std::iter::empty::<Option<&str>>(),
2452 std::iter::empty::<Option<&str>>(),
2453 std::iter::empty::<Option<&str>>(),
2454 ),
2455 )
2456 };
2457 let first = BaseLexer::new(InputStream::new("a"), data()).with_shared_dfa(atn);
2458 let second = BaseLexer::new(InputStream::new("a"), data()).with_shared_dfa(atn);
2459 let state = first.lexer_dfa_state(LexerDfaKey::new(Vec::new()), Some(1));
2460 first.record_lexer_dfa_edge(state, i32::from(b'a'), state);
2461
2462 assert!(!second.lexer_dfa_string().is_empty());
2463 first.clear_dfa();
2464 assert!(first.lexer_dfa_string().is_empty());
2465 assert!(second.lexer_dfa_string().is_empty());
2466 }
2467
2468 mod member_slots {
2472 pub(super) const INTERPOLATED_STRING_LEVEL: usize = 0;
2473 pub(super) const VERBATIUM: usize = 1;
2474 pub(super) const INTERPOLATED_VERBATIUMS: usize = 0;
2475 pub(super) const CURLY_LEVELS: usize = 1;
2476 }
2477
2478 fn member_state_lexer() -> BaseLexer<InputStream> {
2479 let data = RecognizerData::new(
2480 "CSharpLexer",
2481 Vocabulary::new(
2482 std::iter::empty::<Option<&str>>(),
2483 std::iter::empty::<Option<&str>>(),
2484 std::iter::empty::<Option<&str>>(),
2485 ),
2486 );
2487 BaseLexer::new(InputStream::new("$\"{x}\""), data)
2488 }
2489
2490 #[test]
2496 fn lexer_stack_members_track_nested_interpolation_state() {
2497 use member_slots::{INTERPOLATED_STRING_LEVEL, INTERPOLATED_VERBATIUMS};
2498
2499 let mut lexer = member_state_lexer();
2500 let members = lexer.members_mut();
2501
2502 members.add_scalar(INTERPOLATED_STRING_LEVEL, 1);
2504 members.push_stack(INTERPOLATED_VERBATIUMS, 0);
2505 assert_eq!(members.stack_top(INTERPOLATED_VERBATIUMS), Some(0));
2506 assert_eq!(members.scalar(INTERPOLATED_STRING_LEVEL), Some(1));
2507
2508 members.add_scalar(INTERPOLATED_STRING_LEVEL, 1);
2510 members.push_stack(INTERPOLATED_VERBATIUMS, 1);
2511 assert_eq!(members.stack_top(INTERPOLATED_VERBATIUMS), Some(1));
2512 assert_eq!(members.stack_len(INTERPOLATED_VERBATIUMS), 2);
2513
2514 members.add_scalar(INTERPOLATED_STRING_LEVEL, -1);
2517 assert_eq!(members.pop_stack(INTERPOLATED_VERBATIUMS), Some(1));
2518 assert_eq!(members.stack_top(INTERPOLATED_VERBATIUMS), Some(0));
2519
2520 members.add_scalar(INTERPOLATED_STRING_LEVEL, -1);
2523 assert_eq!(members.pop_stack(INTERPOLATED_VERBATIUMS), Some(0));
2524 assert_eq!(members.stack_top(INTERPOLATED_VERBATIUMS), None);
2525 assert_eq!(members.scalar(INTERPOLATED_STRING_LEVEL), Some(0));
2526 }
2527
2528 #[test]
2531 fn lexer_reset_clears_member_state() {
2532 use member_slots::{CURLY_LEVELS, INTERPOLATED_STRING_LEVEL};
2533
2534 let mut lexer = member_state_lexer();
2535 lexer.members_mut().add_scalar(INTERPOLATED_STRING_LEVEL, 2);
2536 lexer.members_mut().push_stack(CURLY_LEVELS, 1);
2537 assert!(!lexer.members().is_empty());
2538
2539 lexer.reset();
2540
2541 assert!(lexer.members().is_empty(), "reset must clear member state");
2542 assert_eq!(lexer.members().scalar(INTERPOLATED_STRING_LEVEL), None);
2543 assert_eq!(lexer.members().stack_top(CURLY_LEVELS), None);
2544 }
2545
2546 #[test]
2551 fn lexer_declared_initial_members_survive_construction_and_reset() {
2552 use member_slots::{CURLY_LEVELS, INTERPOLATED_STRING_LEVEL, VERBATIUM};
2553
2554 let mut lexer = member_state_lexer().with_initial_members([(VERBATIUM, 1)]);
2555 assert_eq!(lexer.members().scalar(VERBATIUM), Some(1));
2556
2557 lexer.members_mut().set_scalar(VERBATIUM, 0);
2559 lexer.members_mut().add_scalar(INTERPOLATED_STRING_LEVEL, 3);
2560 lexer.members_mut().push_stack(CURLY_LEVELS, 1);
2561
2562 lexer.reset();
2563
2564 assert_eq!(lexer.members().scalar(VERBATIUM), Some(1));
2566 assert_eq!(lexer.members().scalar(INTERPOLATED_STRING_LEVEL), None);
2568 assert_eq!(lexer.members().stack_len(CURLY_LEVELS), 0);
2569 }
2570
2571 #[test]
2575 fn lexer_predicate_context_cannot_mutate_member_state() {
2576 use member_slots::{INTERPOLATED_VERBATIUMS, VERBATIUM};
2577
2578 let mut lexer = member_state_lexer();
2579 lexer.members_mut().set_scalar(VERBATIUM, 1);
2580 lexer.members_mut().push_stack(INTERPOLATED_VERBATIUMS, 1);
2581
2582 let mut ctx = LexerSemCtx::new(&lexer, 0, 0, 0);
2583 assert_eq!(ctx.member_int(VERBATIUM), Some(1));
2585 assert_eq!(ctx.member_stack_top(INTERPOLATED_VERBATIUMS), Some(1));
2586 assert_eq!(ctx.member_stack_len(INTERPOLATED_VERBATIUMS), 1);
2587 assert!(!ctx.set_member_int(VERBATIUM, 0));
2589 assert!(!ctx.push_member(INTERPOLATED_VERBATIUMS, 0));
2590 assert_eq!(ctx.pop_member(INTERPOLATED_VERBATIUMS), None);
2591 assert_eq!(ctx.add_member_int(VERBATIUM, 5), None);
2592
2593 assert_eq!(lexer.members().scalar(VERBATIUM), Some(1));
2594 assert_eq!(lexer.members().stack_len(INTERPOLATED_VERBATIUMS), 1);
2595 }
2596
2597 #[test]
2601 fn lexer_semantics_evaluates_stack_guards_written_by_lowered_actions() {
2602 use crate::semir::{AStmt, PExpr, SemIr};
2603 use member_slots::INTERPOLATED_VERBATIUMS;
2604
2605 let mut ir = SemIr::new();
2606 let top = ir.expr(PExpr::MemberTop(INTERPOLATED_VERBATIUMS));
2608 let not_top = ir.expr(PExpr::Not(top));
2610 let yes = ir.expr(PExpr::Bool(true));
2612 let push_verbatim = ir.stmt(AStmt::PushMember(INTERPOLATED_VERBATIUMS, yes));
2613 let pop = ir.stmt(AStmt::PopMember(INTERPOLATED_VERBATIUMS));
2614
2615 let semantics = LexerSemantics {
2616 ir,
2617 predicates: vec![
2618 LexerSemanticPredicate {
2619 rule_index: 1,
2620 pred_index: 0,
2621 expr: top,
2622 },
2623 LexerSemanticPredicate {
2624 rule_index: 2,
2625 pred_index: 0,
2626 expr: not_top,
2627 },
2628 ],
2629 actions: vec![
2630 LexerSemanticAction {
2631 rule_index: 0,
2632 action_index: 0,
2633 stmt: push_verbatim,
2634 },
2635 LexerSemanticAction {
2636 rule_index: 3,
2637 action_index: 0,
2638 stmt: pop,
2639 },
2640 ],
2641 };
2642
2643 let verbatim_guard = LexerPredicate::new(1, 0, 0);
2644 let regular_guard = LexerPredicate::new(2, 0, 0);
2645 let mut lexer = member_state_lexer();
2646
2647 assert_eq!(
2650 semantics.eval_predicate(&lexer, verbatim_guard),
2651 Some(false)
2652 );
2653 assert_eq!(semantics.eval_predicate(&lexer, regular_guard), Some(true));
2654
2655 assert!(semantics.exec_action(&mut lexer, LexerCustomAction::new(0, 0, 0)));
2657 assert_eq!(semantics.eval_predicate(&lexer, verbatim_guard), Some(true));
2658 assert_eq!(semantics.eval_predicate(&lexer, regular_guard), Some(false));
2659
2660 assert!(semantics.exec_action(&mut lexer, LexerCustomAction::new(3, 0, 0)));
2662 assert_eq!(
2663 semantics.eval_predicate(&lexer, verbatim_guard),
2664 Some(false)
2665 );
2666 assert_eq!(semantics.eval_predicate(&lexer, regular_guard), Some(true));
2667
2668 assert_eq!(
2671 semantics.eval_predicate(&lexer, LexerPredicate::new(9, 9, 0)),
2672 None
2673 );
2674 assert!(!semantics.exec_action(&mut lexer, LexerCustomAction::new(9, 9, 0)));
2675 }
2676}