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