1use std::collections::BTreeSet;
31
32use super::AtnStateKind;
33use super::parser_atn::{
34 ParserAtn, ParserAtnBuilder, ParserAtnError, ParserIntervalSetId, ParserTransitionData,
35 ParserTransitionSpec,
36};
37
38impl ParserAtn {
39 pub fn with_bypass_alternatives(&self) -> Result<Self, ParserAtnError> {
55 BypassBuilder::new(self)?.build()
56 }
57
58 pub fn bypass_token_type(&self, rule_index: usize) -> Result<i32, ParserAtnError> {
70 imaginary_token_type(self.max_token_type(), rule_index)
71 }
72}
73
74fn imaginary_token_type(max_token_type: i32, rule: usize) -> Result<i32, ParserAtnError> {
76 let overflow = || ParserAtnError::Overflow {
77 field: "bypass imaginary token type",
78 value: rule,
79 };
80 let rule = i32::try_from(rule).map_err(|_| overflow())?;
81 max_token_type
82 .checked_add(rule)
83 .and_then(|value| value.checked_add(1))
84 .ok_or_else(overflow)
85}
86
87struct BypassBuilder {
89 max_token_type: i32,
90 kinds: Vec<AtnStateKind>,
92 rule_indices: Vec<Option<usize>>,
94 end_states: Vec<Option<usize>>,
96 loop_back_states: Vec<Option<usize>>,
98 non_greedy: Vec<bool>,
100 left_recursive: Vec<bool>,
102 out: Vec<Vec<ParserTransitionSpec>>,
104 interval_sets: Vec<Vec<(i32, i32)>>,
107 decisions: Vec<usize>,
108 rule_starts: Vec<usize>,
109 rule_stops: Vec<usize>,
110}
111
112impl BypassBuilder {
113 fn new(atn: &ParserAtn) -> Result<Self, ParserAtnError> {
115 let state_count = atn.state_count();
116 let mut kinds = Vec::with_capacity(state_count);
117 let mut rule_indices = Vec::with_capacity(state_count);
118 let mut end_states = Vec::with_capacity(state_count);
119 let mut loop_back_states = Vec::with_capacity(state_count);
120 let mut non_greedy = Vec::with_capacity(state_count);
121 let mut left_recursive = Vec::with_capacity(state_count);
122 let mut out = Vec::with_capacity(state_count);
123
124 for number in 0..state_count {
125 let state = atn
126 .state(number)
127 .expect("state index below state_count is in bounds");
128 kinds.push(state.kind());
129 rule_indices.push(state.rule_index());
130 end_states.push(state.end_state());
131 loop_back_states.push(state.loop_back_state());
132 non_greedy.push(state.non_greedy());
133 left_recursive.push(state.left_recursive_rule());
134 out.push(
135 state
136 .transitions()
137 .iter()
138 .map(|transition| data_to_spec(transition.data()))
139 .collect::<Result<Vec<_>, _>>()?,
140 );
141 }
142
143 let interval_sets = (0..atn.set_count())
144 .map(|index| {
145 atn.token_set(index)
146 .expect("set index below set_count is in bounds")
147 .ranges()
148 .collect::<Vec<_>>()
149 })
150 .collect();
151
152 let decisions = atn.decision_to_state().into_iter().collect();
153 let rule_starts = atn.rule_to_start_state().into_iter().collect();
154 let rule_stops = atn.rule_to_stop_state().into_iter().collect();
155
156 Ok(Self {
157 max_token_type: atn.max_token_type(),
158 kinds,
159 rule_indices,
160 end_states,
161 loop_back_states,
162 non_greedy,
163 left_recursive,
164 out,
165 interval_sets,
166 decisions,
167 rule_starts,
168 rule_stops,
169 })
170 }
171
172 fn build(mut self) -> Result<ParserAtn, ParserAtnError> {
174 let rule_count = self.rule_starts.len();
175 let original_state_count = self.kinds.len();
176
177 let new_state_base = original_state_count;
181 for rule in 0..rule_count {
182 let bypass_start = new_state_base + rule * 3;
183 let bypass_stop = bypass_start + 1;
184 let match_state = bypass_start + 2;
185 self.push_state(
187 AtnStateKind::BlockStart,
188 Some(rule),
189 Some(bypass_stop),
190 None,
191 );
192 self.push_state(AtnStateKind::BlockEnd, Some(rule), None, None);
193 self.push_state(AtnStateKind::Basic, None, None, None);
194 debug_assert_eq!(self.out.len(), match_state + 1);
195 }
196
197 let mut end_states: Vec<usize> = Vec::with_capacity(rule_count);
202 let mut bypass_stop_for_end: Vec<Option<usize>> = vec![None; self.kinds.len()];
203 let mut excluded: BTreeSet<(usize, usize)> = BTreeSet::new();
204 for rule in 0..rule_count {
205 let bypass_stop = new_state_base + rule * 3 + 1;
206 let (end_state, exclude) = self.rule_end_state(rule)?;
207 end_states.push(end_state);
208 bypass_stop_for_end[end_state] = Some(bypass_stop);
209 if let Some(exclude) = exclude {
210 excluded.insert(exclude);
211 }
212 }
213
214 for rule in 0..rule_count {
216 let rule_start = self.rule_starts[rule];
217 let bypass_start = new_state_base + rule * 3;
218 let moved = std::mem::take(&mut self.out[rule_start]);
219 self.out[bypass_start] = moved;
220 }
221
222 for (source, transitions) in self.out.iter_mut().enumerate() {
225 for (index, spec) in transitions.iter_mut().enumerate() {
226 if excluded.contains(&(source, index)) {
227 continue;
228 }
229 if let Some(bypass_stop) = bypass_stop_for_end[spec.target()] {
230 *spec = spec.with_target(bypass_stop);
231 }
232 }
233 }
234
235 for (rule, &end_state) in end_states.iter().enumerate() {
238 let rule_start = self.rule_starts[rule];
239 let bypass_start = new_state_base + rule * 3;
240 let bypass_stop = bypass_start + 1;
241 let match_state = bypass_start + 2;
242 let imaginary = self.imaginary_token_type(rule)?;
243
244 self.out[rule_start].push(ParserTransitionSpec::Epsilon {
245 target: bypass_start,
246 });
247 self.out[bypass_start].push(ParserTransitionSpec::Epsilon {
248 target: match_state,
249 });
250 self.out[bypass_stop].push(ParserTransitionSpec::Epsilon { target: end_state });
251 self.out[match_state].push(ParserTransitionSpec::Atom {
252 target: bypass_stop,
253 label: imaginary,
254 });
255 self.decisions.push(bypass_start);
256 }
257
258 self.emit()
259 }
260
261 fn push_state(
263 &mut self,
264 kind: AtnStateKind,
265 rule_index: Option<usize>,
266 end_state: Option<usize>,
267 loop_back_state: Option<usize>,
268 ) {
269 self.kinds.push(kind);
270 self.rule_indices.push(rule_index);
271 self.end_states.push(end_state);
272 self.loop_back_states.push(loop_back_state);
273 self.non_greedy.push(false);
274 self.left_recursive.push(false);
275 self.out.push(Vec::new());
276 }
277
278 fn rule_end_state(
287 &self,
288 rule: usize,
289 ) -> Result<(usize, Option<(usize, usize)>), ParserAtnError> {
290 let rule_start = self.rule_starts[rule];
291 if !self.left_recursive[rule_start] {
292 return Ok((self.rule_stops[rule], None));
293 }
294
295 for state in 0..self.kinds.len() {
299 if self.rule_indices[state] != Some(rule)
300 || self.kinds[state] != AtnStateKind::StarLoopEntry
301 {
302 continue;
303 }
304 let Some(last) = self.out[state].last() else {
305 continue;
306 };
307 let loop_end = last.target();
308 if self.kinds.get(loop_end).copied() != Some(AtnStateKind::LoopEnd) {
309 continue;
310 }
311 let epsilon_only = self.out[loop_end]
315 .iter()
316 .all(|edge| matches!(edge, ParserTransitionSpec::Epsilon { .. }));
317 let reaches_stop = self.out[loop_end]
318 .first()
319 .is_some_and(|edge| self.kinds.get(edge.target()) == Some(&AtnStateKind::RuleStop));
320 if !epsilon_only || !reaches_stop {
321 continue;
322 }
323 let Some(loop_back) = self.loop_back_states[loop_end] else {
324 continue;
325 };
326 if self.out[loop_back]
329 .first()
330 .is_some_and(|edge| edge.target() == state)
331 {
332 return Ok((state, Some((loop_back, 0))));
333 }
334 }
335
336 Err(ParserAtnError::InvalidData(format!(
337 "could not identify precedence prefix boundary for left-recursive rule {rule}"
338 )))
339 }
340
341 fn imaginary_token_type(&self, rule: usize) -> Result<i32, ParserAtnError> {
343 imaginary_token_type(self.max_token_type, rule)
344 }
345
346 fn emit(self) -> Result<ParserAtn, ParserAtnError> {
348 let mut builder = ParserAtnBuilder::new(self.max_token_type);
349
350 for (index, &kind) in self.kinds.iter().enumerate() {
351 builder.add_state(kind, self.rule_indices[index])?;
352 }
353 for (index, end_state) in self.end_states.iter().enumerate() {
354 if let Some(end_state) = end_state {
355 builder.set_end_state(index, *end_state)?;
356 }
357 }
358 for (index, loop_back) in self.loop_back_states.iter().enumerate() {
359 if let Some(loop_back) = loop_back {
360 builder.set_loop_back_state(index, *loop_back)?;
361 }
362 }
363 for (index, &flag) in self.non_greedy.iter().enumerate() {
364 if flag {
365 builder.set_non_greedy(index)?;
366 }
367 }
368 for (index, &flag) in self.left_recursive.iter().enumerate() {
369 if flag {
370 builder.set_left_recursive_rule(index)?;
371 }
372 }
373 for ranges in &self.interval_sets {
374 builder.add_interval_set(ranges.iter().copied())?;
375 }
376 for (source, transitions) in self.out.iter().enumerate() {
377 for spec in transitions {
378 builder.add_transition(source, *spec)?;
379 }
380 }
381 for &state in &self.decisions {
382 builder.add_decision_state(state)?;
383 }
384 builder.set_rule_to_start_state(self.rule_starts)?;
385 builder.set_rule_to_stop_state(self.rule_stops)?;
386
387 builder.finish()
388 }
389}
390
391fn data_to_spec(data: ParserTransitionData<'_>) -> Result<ParserTransitionSpec, ParserAtnError> {
394 Ok(match data {
395 ParserTransitionData::Epsilon { target } => ParserTransitionSpec::Epsilon { target },
396 ParserTransitionData::Atom { target, label } => {
397 ParserTransitionSpec::Atom { target, label }
398 }
399 ParserTransitionData::Range {
400 target,
401 start,
402 stop,
403 } => ParserTransitionSpec::Range {
404 target,
405 start,
406 stop,
407 },
408 ParserTransitionData::Set { target, set } => ParserTransitionSpec::Set {
409 target,
410 set: ParserIntervalSetId::try_from(set.index())?,
411 },
412 ParserTransitionData::NotSet { target, set } => ParserTransitionSpec::NotSet {
413 target,
414 set: ParserIntervalSetId::try_from(set.index())?,
415 },
416 ParserTransitionData::Wildcard { target } => ParserTransitionSpec::Wildcard { target },
417 ParserTransitionData::Rule {
418 target,
419 rule_index,
420 follow_state,
421 precedence,
422 } => ParserTransitionSpec::Rule {
423 target,
424 rule_index,
425 follow_state,
426 precedence,
427 },
428 ParserTransitionData::Predicate {
429 target,
430 rule_index,
431 pred_index,
432 context_dependent,
433 } => ParserTransitionSpec::Predicate {
434 target,
435 rule_index,
436 pred_index,
437 context_dependent,
438 },
439 ParserTransitionData::Action {
440 target,
441 rule_index,
442 action_index,
443 context_dependent,
444 } => ParserTransitionSpec::Action {
445 target,
446 rule_index,
447 action_index,
448 context_dependent,
449 },
450 ParserTransitionData::Precedence { target, precedence } => {
451 ParserTransitionSpec::Precedence { target, precedence }
452 }
453 })
454}
455
456#[cfg(test)]
457#[allow(clippy::disallowed_methods)] mod tests {
459 use super::*;
460 use crate::atn::parser_atn::{ParserTransition, ParserTransitionKind};
461 use crate::token::{Token, TokenId, TokenSink, TokenSource, TokenSpec, TokenStoreError};
462 use crate::{BaseParser, CommonTokenStream, NodeKind, RecognizerData, Vocabulary};
463
464 #[derive(Debug)]
467 struct ListSource {
468 specs: Vec<TokenSpec>,
469 index: usize,
470 }
471
472 impl TokenSource for ListSource {
473 fn next_token(&mut self, sink: &mut TokenSink<'_>) -> Result<TokenId, TokenStoreError> {
474 let spec = self
475 .specs
476 .get(self.index)
477 .cloned()
478 .unwrap_or_else(|| TokenSpec::eof(self.index, self.index, 1, self.index));
479 self.index += 1;
480 sink.push(spec)
481 }
482
483 fn line(&self) -> usize {
484 1
485 }
486
487 fn column(&self) -> usize {
488 self.index
489 }
490
491 fn source_name(&self) -> &'static str {
492 "bypass-test"
493 }
494 }
495
496 fn two_rule_atn() -> ParserAtn {
501 let mut atn = ParserAtnBuilder::new(2);
502 for (number, kind, rule) in [
503 (0, AtnStateKind::RuleStart, 0),
504 (1, AtnStateKind::Basic, 0),
505 (2, AtnStateKind::Basic, 0),
506 (3, AtnStateKind::RuleStop, 0),
507 (4, AtnStateKind::RuleStart, 1),
508 (5, AtnStateKind::Basic, 1),
509 (6, AtnStateKind::RuleStop, 1),
510 ] {
511 assert_eq!(
512 atn.add_state(kind, Some(rule)).expect("state").index(),
513 number
514 );
515 }
516 atn.set_rule_to_start_state(vec![0, 4]).expect("starts");
517 atn.set_rule_to_stop_state(vec![3, 6]).expect("stops");
518 atn.add_transition(
520 0,
521 ParserTransitionSpec::Atom {
522 target: 1,
523 label: 1,
524 },
525 )
526 .expect("edge");
527 atn.add_transition(
528 1,
529 ParserTransitionSpec::Rule {
530 target: 4,
531 rule_index: 1,
532 follow_state: 2,
533 precedence: 0,
534 },
535 )
536 .expect("edge");
537 atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
538 .expect("edge");
539 atn.add_transition(6, ParserTransitionSpec::Epsilon { target: 2 })
541 .expect("edge");
542 atn.add_transition(
544 4,
545 ParserTransitionSpec::Atom {
546 target: 5,
547 label: 2,
548 },
549 )
550 .expect("edge");
551 atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
552 .expect("edge");
553 atn.finish().expect("valid base ATN")
554 }
555
556 fn left_recursive_atn() -> ParserAtn {
561 let mut atn = ParserAtnBuilder::new(2);
562 for (number, kind, rule) in [
563 (0, AtnStateKind::RuleStart, 0),
564 (1, AtnStateKind::Basic, 0), (2, AtnStateKind::StarLoopEntry, 0),
566 (3, AtnStateKind::Basic, 0), (4, AtnStateKind::StarLoopBack, 0),
568 (5, AtnStateKind::LoopEnd, 0),
569 (6, AtnStateKind::RuleStop, 0),
570 ] {
571 assert_eq!(
572 atn.add_state(kind, Some(rule)).expect("state").index(),
573 number
574 );
575 }
576 atn.set_left_recursive_rule(0).expect("LR flag");
577 atn.set_rule_to_start_state(vec![0]).expect("starts");
578 atn.set_rule_to_stop_state(vec![6]).expect("stops");
579 atn.set_loop_back_state(5, 4).expect("loop back");
580 atn.add_decision_state(2).expect("decision");
581 atn.add_transition(
582 0,
583 ParserTransitionSpec::Atom {
584 target: 1,
585 label: 1,
586 },
587 )
588 .expect("edge");
589 atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
590 .expect("edge");
591 atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 3 })
592 .expect("edge");
593 atn.add_transition(2, ParserTransitionSpec::Epsilon { target: 5 })
594 .expect("edge");
595 atn.add_transition(
596 3,
597 ParserTransitionSpec::Atom {
598 target: 4,
599 label: 2,
600 },
601 )
602 .expect("edge");
603 atn.add_transition(4, ParserTransitionSpec::Epsilon { target: 2 })
605 .expect("edge");
606 atn.add_transition(5, ParserTransitionSpec::Epsilon { target: 6 })
607 .expect("edge");
608 atn.finish().expect("valid left-recursive ATN")
609 }
610
611 #[test]
615 fn bypass_wraps_left_recursive_prefix_and_preserves_loop_back() {
616 let base = left_recursive_atn();
617 let bypass = base.with_bypass_alternatives().expect("bypass ATN");
618
619 let star_loop_entry = 2;
620 let star_loop_back = 4;
621 let bypass_start = base.state_count();
622 let bypass_stop = bypass_start + 1;
623
624 let prefix_targets: Vec<_> = bypass
626 .state(1)
627 .expect("prefix state")
628 .transitions()
629 .iter()
630 .map(ParserTransition::target)
631 .collect();
632 assert_eq!(prefix_targets, vec![bypass_stop]);
633 let loop_back_targets: Vec<_> = bypass
635 .state(star_loop_back)
636 .expect("loop-back state")
637 .transitions()
638 .iter()
639 .map(ParserTransition::target)
640 .collect();
641 assert_eq!(loop_back_targets, vec![star_loop_entry]);
642 let stop_targets: Vec<_> = bypass
645 .state(bypass_stop)
646 .expect("bypass stop")
647 .transitions()
648 .iter()
649 .map(ParserTransition::target)
650 .collect();
651 assert_eq!(stop_targets, vec![star_loop_entry]);
652 }
653
654 #[test]
657 fn bypass_reports_unrecognizable_left_recursive_structure() {
658 let mut atn = ParserAtnBuilder::new(1);
659 for (number, kind) in [
660 (0, AtnStateKind::RuleStart),
661 (1, AtnStateKind::Basic),
662 (2, AtnStateKind::RuleStop),
663 ] {
664 assert_eq!(atn.add_state(kind, Some(0)).expect("state").index(), number);
665 }
666 atn.set_left_recursive_rule(0).expect("LR flag");
668 atn.set_rule_to_start_state(vec![0]).expect("starts");
669 atn.set_rule_to_stop_state(vec![2]).expect("stops");
670 atn.add_transition(
671 0,
672 ParserTransitionSpec::Atom {
673 target: 1,
674 label: 1,
675 },
676 )
677 .expect("edge");
678 atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
679 .expect("edge");
680 let base = atn.finish().expect("valid base ATN");
681
682 let error = base
683 .with_bypass_alternatives()
684 .expect_err("missing precedence prefix must be reported");
685 assert!(
686 error.to_string().contains("left-recursive rule 0"),
687 "unexpected error: {error}"
688 );
689 }
690
691 #[test]
692 fn bypass_grows_three_states_per_rule_and_keeps_max_token_type() {
693 let base = two_rule_atn();
694 let bypass = base.with_bypass_alternatives().expect("bypass ATN");
695
696 assert_eq!(
698 bypass.state_count(),
699 base.state_count() + 3 * base.rule_count()
700 );
701 assert_eq!(bypass.max_token_type(), base.max_token_type());
703 }
704
705 #[test]
706 fn bypass_adds_one_imaginary_atom_per_rule() {
707 let base = two_rule_atn();
708 let bypass = base.with_bypass_alternatives().expect("bypass ATN");
709
710 let mut imaginary_atoms = Vec::new();
712 for state in 0..bypass.state_count() {
713 for transition in bypass.state(state).expect("state").transitions() {
714 if transition.kind() == ParserTransitionKind::Atom {
715 if let ParserTransitionData::Atom { label, .. } = transition.data() {
716 if label > base.max_token_type() {
717 imaginary_atoms.push(label);
718 }
719 }
720 }
721 }
722 }
723 imaginary_atoms.sort_unstable();
724 assert_eq!(imaginary_atoms, vec![3, 4]); }
726
727 #[test]
728 fn bypass_preserves_rule_start_and_stop_tables() {
729 let base = two_rule_atn();
730 let bypass = base.with_bypass_alternatives().expect("bypass ATN");
731
732 let base_starts: Vec<_> = base.rule_to_start_state().into_iter().collect();
733 let bypass_starts: Vec<_> = bypass.rule_to_start_state().into_iter().collect();
734 assert_eq!(base_starts, bypass_starts);
735
736 let base_stops: Vec<_> = base.rule_to_stop_state().into_iter().collect();
737 let bypass_stops: Vec<_> = bypass.rule_to_stop_state().into_iter().collect();
738 assert_eq!(base_stops, bypass_stops);
739 }
740
741 #[test]
742 fn rule_start_gains_epsilon_into_bypass_block() {
743 let base = two_rule_atn();
744 let bypass = base.with_bypass_alternatives().expect("bypass ATN");
745
746 let bypass_start_for_rule_0 = base.state_count();
749 let rule_start = bypass.state(0).expect("rule start");
750 let epsilon_targets: Vec<_> = rule_start
751 .transitions()
752 .iter()
753 .filter(|t| t.kind() == ParserTransitionKind::Epsilon)
754 .map(ParserTransition::target)
755 .collect();
756 assert!(
757 epsilon_targets.contains(&bypass_start_for_rule_0),
758 "rule start must epsilon into its bypass block; got {epsilon_targets:?}"
759 );
760 }
761
762 fn two_rule_recognizer_data() -> RecognizerData {
763 RecognizerData::new(
764 "Bypass.g4",
765 Vocabulary::new(
766 [None, Some("'x'"), Some("'y'")],
767 [None, Some("X"), Some("Y")],
768 [None::<&str>, None],
769 ),
770 )
771 .with_rule_names(["a", "b"])
772 }
773
774 #[test]
779 fn interpreter_matches_imaginary_token_as_whole_rule() {
780 let bypass = two_rule_atn()
781 .with_bypass_alternatives()
782 .expect("bypass ATN");
783 let imaginary_b = 4;
785 let source = ListSource {
786 specs: vec![
787 TokenSpec::explicit(1, "x"), TokenSpec::explicit(imaginary_b, "<b>"), ],
790 index: 0,
791 };
792 let mut parser =
793 BaseParser::new(CommonTokenStream::new(source), two_rule_recognizer_data());
794
795 let tree = parser
796 .parse_atn_rule(&bypass, 0)
797 .expect("bypass interpret of `a : X b` with imaginary b");
798
799 let root = parser.node(tree).as_rule().expect("root is rule a");
800 assert_eq!(root.rule_index(), 0);
801 let children: Vec<_> = root.node().children().collect();
802 assert_eq!(children.len(), 2, "a has children [X, b]");
803
804 let x = children[0].as_terminal().expect("first child terminal X");
806 assert_eq!(x.symbol().token_type(), 1);
807
808 let b = children[1].as_rule().expect("second child rule b");
811 assert_eq!(b.rule_index(), 1);
812 let b_children: Vec<_> = b.node().children().collect();
813 assert_eq!(b_children.len(), 1, "bypassed rule b has exactly one child");
814 assert_eq!(b_children[0].kind(), NodeKind::Terminal);
815 assert_eq!(
816 b_children[0]
817 .as_terminal()
818 .expect("b's lone child is a terminal")
819 .symbol()
820 .token_type(),
821 imaginary_b,
822 "the lone child carries the imaginary bypass token type"
823 );
824 }
825
826 #[test]
829 fn bypass_atn_still_parses_ordinary_input() {
830 let bypass = two_rule_atn()
831 .with_bypass_alternatives()
832 .expect("bypass ATN");
833 let source = ListSource {
834 specs: vec![TokenSpec::explicit(1, "x"), TokenSpec::explicit(2, "y")],
835 index: 0,
836 };
837 let mut parser =
838 BaseParser::new(CommonTokenStream::new(source), two_rule_recognizer_data());
839
840 let tree = parser
841 .parse_atn_rule(&bypass, 0)
842 .expect("bypass interpret of ordinary `X Y`");
843
844 let root = parser.node(tree).as_rule().expect("root is rule a");
845 let children: Vec<_> = root.node().children().collect();
846 assert_eq!(children.len(), 2);
847 assert_eq!(
848 children[0]
849 .as_terminal()
850 .expect("X terminal")
851 .symbol()
852 .token_type(),
853 1
854 );
855 let b = children[1].as_rule().expect("rule b");
856 let y = b
857 .node()
858 .children()
859 .next()
860 .expect("b child")
861 .as_terminal()
862 .expect("Y terminal");
863 assert_eq!(y.symbol().token_type(), 2);
864 assert_eq!(parser.number_of_syntax_errors(), 0);
865 }
866}