1use std::{
2 collections::{HashMap, HashSet},
3 error::Error,
4 fmt,
5 str::FromStr,
6};
7
8use indexmap::{IndexMap, IndexSet};
9
10use super::{
11 Precedence, YaccGrammarError, YaccGrammarErrorKind, YaccGrammarWarning, YaccGrammarWarningKind,
12 YaccKind, parser::YaccParser,
13};
14
15use crate::{
16 Span,
17 header::{GrmtoolsSectionParser, HeaderError, HeaderErrorKind, HeaderValue},
18};
19
20#[derive(Debug, PartialEq, Eq, Clone)]
22pub struct ASTModificationError {
23 kind: YaccGrammarErrorKind,
24}
25
26impl Error for ASTModificationError {}
27
28impl fmt::Display for ASTModificationError {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 write!(f, "{}", self.kind)
31 }
32}
33
34#[derive(Debug, Clone)]
37#[cfg_attr(test, derive(PartialEq))]
38pub struct ASTWithValidityInfo {
39 yacc_kind: YaccKind,
40 ast: GrammarAST,
41 errs: Vec<YaccGrammarError>,
42}
43
44impl ASTWithValidityInfo {
45 pub fn new(yacc_kind: YaccKind, s: &str) -> Self {
53 let mut errs = Vec::new();
54 let ast = {
55 let mut yp = YaccParser::new(yacc_kind, s);
56 yp.parse().map_err(|e| errs.extend(e)).ok();
57 let mut ast = yp.build();
58 ast.complete_and_validate().map_err(|e| errs.push(e)).ok();
59 ast
60 };
61 ASTWithValidityInfo {
62 ast,
63 errs,
64 yacc_kind,
65 }
66 }
67
68 pub fn ast(&self) -> &GrammarAST {
73 &self.ast
74 }
75
76 pub fn is_valid(&self) -> bool {
79 self.errors().is_empty()
80 }
81
82 pub fn yacc_kind(&self) -> YaccKind {
84 self.yacc_kind
85 }
86
87 pub fn errors(&self) -> &[YaccGrammarError] {
89 self.errs.as_slice()
90 }
91
92 pub fn clone_and_change_start_rule(&self, rule: Rule) -> Result<Self, ASTModificationError> {
93 if self.ast.get_rule(&rule.name.0).is_some() {
94 let mut ret = self.clone();
95 ret.ast.start = Some(rule.name);
101 Ok(ret)
102 } else {
103 Err(ASTModificationError {
104 kind: YaccGrammarErrorKind::InvalidStartRule(rule.name.0),
105 })
106 }
107 }
108}
109
110impl FromStr for ASTWithValidityInfo {
111 type Err = Vec<YaccGrammarError>;
112 fn from_str(src: &str) -> Result<Self, Vec<YaccGrammarError>> {
114 let mut errs = Vec::new();
115 let (header, _) = GrmtoolsSectionParser::new(src, true)
116 .parse()
117 .map_err(|mut errs| errs.drain(..).map(|e| e.into()).collect::<Vec<_>>())?;
118 if let Some(HeaderValue(_, yk_val)) = header.get("yacckind") {
119 let yacc_kind = YaccKind::try_from(yk_val).map_err(|e| vec![e.into()])?;
120 let ast = {
121 let mut yp = YaccParser::new(yacc_kind, src);
123 yp.parse().map_err(|e| errs.extend(e)).ok();
124 let mut ast = yp.build();
125 ast.complete_and_validate().map_err(|e| errs.push(e)).ok();
126 ast
127 };
128 Ok(ASTWithValidityInfo {
129 ast,
130 errs,
131 yacc_kind,
132 })
133 } else {
134 Err(vec![
135 HeaderError {
136 kind: HeaderErrorKind::InvalidEntry("yacckind"),
137 locations: vec![Span::new(0, 0)],
138 }
139 .into(),
140 ])
141 }
142 }
143}
144
145#[derive(Debug, Clone)]
149#[cfg_attr(test, derive(PartialEq))]
150#[non_exhaustive]
151pub struct GrammarAST {
152 pub start: Option<(String, Span)>,
153 pub rules: IndexMap<String, Rule>,
155 pub prods: Vec<Production>,
156 pub token_directives: HashSet<usize>,
161 pub tokens: IndexSet<String>,
162 pub spans: Vec<Span>,
163 pub precs: HashMap<String, (Precedence, Span)>,
164 pub avoid_insert: Option<HashMap<String, Span>>,
165 pub implicit_tokens: Option<HashMap<String, Span>>,
166 pub epp: HashMap<String, (Span, (String, Span))>,
170 pub expect: Option<(usize, Span)>,
171 pub expectrr: Option<(usize, Span)>,
172 pub parse_param: Option<(String, String)>,
173 pub programs: Option<String>,
174 pub expect_unused: Vec<Symbol>,
177}
178
179#[derive(Debug, Clone)]
180#[cfg_attr(test, derive(Eq, PartialEq))]
181pub struct Rule {
182 pub name: (String, Span),
183 pub pidxs: Vec<usize>, pub actiont: Option<String>,
185}
186
187#[derive(Debug, Clone)]
188#[cfg_attr(test, derive(Eq, PartialEq))]
189pub struct Production {
190 pub symbols: Vec<Symbol>,
191 pub precedence: Option<String>,
192 pub action: Option<String>,
193 pub prod_span: Span,
194}
195
196#[derive(Clone, Debug)]
197#[cfg_attr(test, derive(Eq, PartialEq))]
198pub enum Symbol {
199 Rule(String, Span),
200 Token(String, Span),
201}
202
203#[derive(Eq, PartialEq, Debug, Copy, Clone)]
206pub(crate) enum SymbolIdx {
207 Rule(usize),
208 Token(usize),
209}
210
211impl SymbolIdx {
212 pub(crate) fn symbol(self, ast: &GrammarAST) -> Symbol {
213 match self {
214 SymbolIdx::Rule(idx) => {
215 let (rule_name, rule_span) = &ast.rules[idx].name;
216 Symbol::Rule(rule_name.clone(), *rule_span)
217 }
218 SymbolIdx::Token(idx) => {
219 let tok = &ast.tokens[idx];
220 Symbol::Token(tok.clone(), ast.spans[idx])
221 }
222 }
223 }
224}
225impl fmt::Display for Symbol {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 match *self {
228 Symbol::Rule(ref s, _) => write!(f, "{}", s),
229 Symbol::Token(ref s, _) => write!(f, "{}", s),
230 }
231 }
232}
233
234impl GrammarAST {
235 pub(crate) fn new() -> GrammarAST {
236 GrammarAST {
237 start: None,
238 rules: IndexMap::new(), prods: Vec::new(),
241 spans: Vec::new(),
242 tokens: IndexSet::new(),
243 token_directives: HashSet::new(),
244 precs: HashMap::new(),
245 avoid_insert: None,
246 implicit_tokens: None,
247 epp: HashMap::new(),
248 expect: None,
249 expectrr: None,
250 parse_param: None,
251 programs: None,
252 expect_unused: Vec::new(),
253 }
254 }
255
256 pub fn add_rule(&mut self, (name, name_span): (String, Span), actiont: Option<String>) {
257 self.rules.insert(
258 name.clone(),
259 Rule {
260 name: (name, name_span),
261 pidxs: Vec::new(),
262 actiont,
263 },
264 );
265 }
266
267 pub fn add_prod(
268 &mut self,
269 rule_name: String,
270 symbols: Vec<Symbol>,
271 precedence: Option<String>,
272 action: Option<String>,
273 prod_span: Span,
274 ) {
275 self.rules[&rule_name].pidxs.push(self.prods.len());
276 self.prods.push(Production {
277 symbols,
278 precedence,
279 action,
280 prod_span,
281 });
282 }
283
284 #[deprecated(since = "0.10.2", note = "Please use set_programs instead")]
285 pub fn add_programs(&mut self, s: String) {
286 self.set_programs(s);
287 }
288
289 pub fn set_programs(&mut self, s: String) {
290 self.programs = Some(s)
291 }
292
293 pub fn get_rule(&self, key: &str) -> Option<&Rule> {
294 self.rules.get(key)
295 }
296
297 pub fn has_token(&self, s: &str) -> bool {
298 self.tokens.contains(s)
299 }
300
301 pub(crate) fn complete_and_validate(&mut self) -> Result<(), YaccGrammarError> {
311 match self.start {
312 None => {
313 return Err(YaccGrammarError {
314 kind: YaccGrammarErrorKind::NoStartRule,
315 spans: vec![Span::new(0, 0)],
316 });
317 }
318 Some((ref s, span)) => {
319 if !self.rules.contains_key(s) {
320 return Err(YaccGrammarError {
321 kind: YaccGrammarErrorKind::InvalidStartRule(s.clone()),
322 spans: vec![span],
323 });
324 }
325 }
326 }
327 for rule in self.rules.values() {
328 for &pidx in &rule.pidxs {
329 let prod = &self.prods[pidx];
330 if let Some(ref n) = prod.precedence {
331 if !self.tokens.contains(n) {
332 return Err(YaccGrammarError {
333 kind: YaccGrammarErrorKind::UnknownToken(n.clone()),
334 spans: vec![Span::new(0, 0)],
335 });
336 }
337 if !self.precs.contains_key(n) {
338 return Err(YaccGrammarError {
339 kind: YaccGrammarErrorKind::NoPrecForToken(n.clone()),
340 spans: vec![Span::new(0, 0)],
341 });
342 }
343 }
344 for sym in &prod.symbols {
345 match *sym {
346 Symbol::Rule(ref name, span) => {
347 if !self.rules.contains_key(name) {
348 return Err(YaccGrammarError {
349 kind: YaccGrammarErrorKind::UnknownRuleRef(name.clone()),
350 spans: vec![span],
351 });
352 }
353 }
354 Symbol::Token(ref name, span) => {
355 if !self.tokens.contains(name) {
356 return Err(YaccGrammarError {
357 kind: YaccGrammarErrorKind::UnknownToken(name.clone()),
358 spans: vec![span],
359 });
360 }
361 }
362 }
363 }
364 }
365 }
366
367 for (k, (sp, _)) in self.epp.iter() {
368 if self.tokens.contains(k) {
369 continue;
370 }
371 if let Some(ref it) = self.implicit_tokens {
372 if it.contains_key(k) {
373 continue;
374 }
375 }
376 return Err(YaccGrammarError {
377 kind: YaccGrammarErrorKind::UnknownEPP(k.clone()),
378 spans: vec![*sp],
379 });
380 }
381
382 for sym in &self.expect_unused {
383 match sym {
384 Symbol::Rule(sym_name, sym_span) => {
385 if self.get_rule(sym_name).is_none() {
386 return Err(YaccGrammarError {
387 kind: YaccGrammarErrorKind::UnknownRuleRef(sym_name.clone()),
388 spans: vec![*sym_span],
389 });
390 }
391 }
392 Symbol::Token(sym_name, sym_span) => {
393 if !self.has_token(sym_name) {
394 return Err(YaccGrammarError {
395 kind: YaccGrammarErrorKind::UnknownToken(sym_name.clone()),
396 spans: vec![*sym_span],
397 });
398 }
399 }
400 }
401 }
402 Ok(())
403 }
404
405 pub fn warnings(&self) -> Vec<YaccGrammarWarning> {
406 self.unused_symbols()
407 .map(|symidx| {
408 let (kind, span) = match symidx.symbol(self) {
409 Symbol::Rule(_, span) => (YaccGrammarWarningKind::UnusedRule, span),
410 Symbol::Token(_, span) => (YaccGrammarWarningKind::UnusedToken, span),
411 };
412 YaccGrammarWarning {
413 kind,
414 spans: vec![span],
415 }
416 })
417 .collect()
418 }
419
420 pub(crate) fn unused_symbols(&self) -> impl Iterator<Item = SymbolIdx> + '_ {
423 let start_rule_name = self.start.as_ref().map(|(name, _)| name.clone());
424 let start_rule = self
425 .rules
426 .iter()
427 .find(|(rule_name, _)| start_rule_name.as_ref() == Some(rule_name));
428 let mut seen_rules = HashSet::new();
429 let mut seen_tokens = HashSet::new();
430 let mut expected_unused_tokens = HashSet::new();
431 let mut expected_unused_rules = HashSet::new();
432 for sym in &self.expect_unused {
433 match sym {
434 Symbol::Rule(sym_name, _) => {
435 expected_unused_rules.insert(sym_name);
436 }
437 Symbol::Token(sym_name, _) => {
438 expected_unused_tokens.insert(sym_name);
439 }
440 }
441 }
442 if let Some(implicit_tokens) = self.implicit_tokens.as_ref() {
443 expected_unused_tokens.extend(implicit_tokens.keys())
444 }
445 if let Some((start_name, start_rule)) = start_rule {
446 let mut todo = Vec::new();
447 todo.extend(start_rule.pidxs.iter().copied());
448 seen_rules.insert(start_name);
449
450 while let Some(pidx) = todo.pop() {
451 let prod = &self.prods[pidx];
452 for sym in &prod.symbols {
453 match sym {
454 Symbol::Rule(name, _) => {
455 if seen_rules.insert(name) {
456 if let Some(rule) = self.rules.get(name) {
457 todo.extend(&rule.pidxs);
458 }
459 }
460 }
461 Symbol::Token(name, _) => {
462 seen_tokens.insert(name);
463 }
464 };
465 }
466 }
467 }
468 self.rules
469 .iter()
470 .enumerate()
471 .filter_map(move |(rule_id, (rule_name, _))| {
472 if expected_unused_rules.contains(rule_name) || seen_rules.contains(rule_name) {
473 None
474 } else {
475 Some(SymbolIdx::Rule(rule_id))
476 }
477 })
478 .chain(
479 self.tokens
480 .iter()
481 .enumerate()
482 .filter_map(move |(tok_idx, tok)| {
483 if expected_unused_tokens.contains(tok) || seen_tokens.contains(tok) {
484 None
485 } else {
486 Some(SymbolIdx::Token(tok_idx))
487 }
488 }),
489 )
490 }
491}
492
493#[cfg(test)]
494mod test {
495 use super::{
496 super::{AssocKind, Precedence},
497 GrammarAST, Span, Symbol, YaccGrammarError, YaccGrammarErrorKind,
498 };
499
500 fn rule(n: &str) -> Symbol {
501 Symbol::Rule(n.to_string(), Span::new(0, 0))
502 }
503
504 fn token(n: &str) -> Symbol {
505 Symbol::Token(n.to_string(), Span::new(0, 0))
506 }
507
508 #[test]
509 fn test_empty_grammar() {
510 let mut grm = GrammarAST::new();
511 match grm.complete_and_validate() {
512 Err(YaccGrammarError {
513 kind: YaccGrammarErrorKind::NoStartRule,
514 ..
515 }) => (),
516 _ => panic!("Validation error"),
517 }
518 }
519
520 #[test]
521 fn test_invalid_start_rule() {
522 let mut grm = GrammarAST::new();
523 let empty_span = Span::new(0, 0);
524 grm.start = Some(("A".to_string(), empty_span));
525 grm.add_rule(("B".to_string(), empty_span), None);
526 grm.add_prod("B".to_string(), vec![], None, None, empty_span);
527 match grm.complete_and_validate() {
528 Err(YaccGrammarError {
529 kind: YaccGrammarErrorKind::InvalidStartRule(_),
530 ..
531 }) => (),
532 _ => panic!("Validation error"),
533 }
534 }
535
536 #[test]
537 fn test_valid_start_rule() {
538 let mut grm = GrammarAST::new();
539 let empty_span = Span::new(0, 0);
540 grm.start = Some(("A".to_string(), empty_span));
541 grm.add_rule(("A".to_string(), empty_span), None);
542 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
543 assert!(grm.complete_and_validate().is_ok());
544 }
545
546 #[test]
547 fn test_valid_rule_ref() {
548 let mut grm = GrammarAST::new();
549 let empty_span = Span::new(0, 0);
550 grm.start = Some(("A".to_string(), empty_span));
551 grm.add_rule(("A".to_string(), empty_span), None);
552 grm.add_rule(("B".to_string(), empty_span), None);
553 grm.add_prod("A".to_string(), vec![rule("B")], None, None, empty_span);
554 grm.add_prod("B".to_string(), vec![], None, None, empty_span);
555 assert!(grm.complete_and_validate().is_ok());
556 }
557
558 #[test]
559 fn test_invalid_rule_ref() {
560 let mut grm = GrammarAST::new();
561 let empty_span = Span::new(0, 0);
562 grm.start = Some(("A".to_string(), empty_span));
563 grm.add_rule(("A".to_string(), empty_span), None);
564 grm.add_prod("A".to_string(), vec![rule("B")], None, None, empty_span);
565 match grm.complete_and_validate() {
566 Err(YaccGrammarError {
567 kind: YaccGrammarErrorKind::UnknownRuleRef(_),
568 ..
569 }) => (),
570 _ => panic!("Validation error"),
571 }
572 }
573
574 #[test]
575 fn test_valid_token_ref() {
576 let mut grm = GrammarAST::new();
577 let empty_span = Span::new(0, 0);
578 grm.tokens.insert("b".to_string());
579 grm.start = Some(("A".to_string(), empty_span));
580 grm.add_rule(("A".to_string(), empty_span), None);
581 grm.add_prod("A".to_string(), vec![token("b")], None, None, empty_span);
582 assert!(grm.complete_and_validate().is_ok());
583 }
584
585 #[test]
586 fn test_redefine_rules_as_tokens() {
587 let mut grm = GrammarAST::new();
590 let empty_span = Span::new(0, 0);
591 grm.tokens.insert("b".to_string());
592 grm.start = Some(("A".to_string(), empty_span));
593 grm.add_rule(("A".to_string(), empty_span), None);
594 grm.add_prod("A".to_string(), vec![rule("b")], None, None, empty_span);
595 assert!(grm.complete_and_validate().is_err());
596 }
597
598 #[test]
599 fn test_invalid_token_ref() {
600 let mut grm = GrammarAST::new();
601 let empty_span = Span::new(0, 0);
602 grm.start = Some(("A".to_string(), empty_span));
603 grm.add_rule(("A".to_string(), empty_span), None);
604 grm.add_prod("A".to_string(), vec![token("b")], None, None, empty_span);
605 match grm.complete_and_validate() {
606 Err(YaccGrammarError {
607 kind: YaccGrammarErrorKind::UnknownToken(_),
608 ..
609 }) => (),
610 _ => panic!("Validation error"),
611 }
612 }
613
614 #[test]
615 fn test_invalid_rule_forgotten_token() {
616 let mut grm = GrammarAST::new();
617 let empty_span = Span::new(0, 0);
618 grm.start = Some(("A".to_string(), empty_span));
619 grm.add_rule(("A".to_string(), empty_span), None);
620 grm.add_prod(
621 "A".to_string(),
622 vec![rule("b"), token("b")],
623 None,
624 None,
625 Span::new(0, 2),
626 );
627 match grm.complete_and_validate() {
628 Err(YaccGrammarError {
629 kind: YaccGrammarErrorKind::UnknownRuleRef(_),
630 ..
631 }) => (),
632 _ => panic!("Validation error"),
633 }
634 }
635
636 #[test]
637 fn test_invalid_epp() {
638 let mut grm = GrammarAST::new();
639 let empty_span = Span::new(2, 3);
640 grm.start = Some(("A".to_string(), empty_span));
641 grm.add_rule(("A".to_string(), empty_span), None);
642 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
643 grm.epp
644 .insert("k".to_owned(), (empty_span, ("v".to_owned(), empty_span)));
645 match grm.complete_and_validate() {
646 Err(YaccGrammarError {
647 kind: YaccGrammarErrorKind::UnknownEPP(_),
648 spans,
649 }) if spans.len() == 1 && spans[0] == Span::new(2, 3) => (),
650 _ => panic!("Validation error"),
651 }
652 }
653
654 #[test]
655 fn test_precedence_override() {
656 let mut grm = GrammarAST::new();
657 let empty_span = Span::new(0, 0);
658 grm.precs.insert(
659 "b".to_string(),
660 (
661 Precedence {
662 level: 1,
663 kind: AssocKind::Left,
664 },
665 Span::new(0, 0),
666 ),
667 );
668 grm.start = Some(("A".to_string(), empty_span));
669 grm.tokens.insert("b".to_string());
670 grm.add_rule(("A".to_string(), empty_span), None);
671 grm.add_prod(
672 "A".to_string(),
673 vec![token("b")],
674 Some("b".to_string()),
675 None,
676 empty_span,
677 );
678 assert!(grm.complete_and_validate().is_ok());
679 }
680
681 #[test]
682 fn test_invalid_precedence_override() {
683 let mut grm = GrammarAST::new();
684 let empty_span = Span::new(0, 0);
685 grm.start = Some(("A".to_string(), empty_span));
686 grm.add_rule(("A".to_string(), empty_span), None);
687 grm.add_prod(
688 "A".to_string(),
689 vec![token("b")],
690 Some("b".to_string()),
691 None,
692 empty_span,
693 );
694 match grm.complete_and_validate() {
695 Err(YaccGrammarError {
696 kind: YaccGrammarErrorKind::UnknownToken(_),
697 ..
698 }) => (),
699 _ => panic!("Validation error"),
700 }
701 grm.tokens.insert("b".to_string());
702 match grm.complete_and_validate() {
703 Err(YaccGrammarError {
704 kind: YaccGrammarErrorKind::NoPrecForToken(_),
705 ..
706 }) => (),
707 _ => panic!("Validation error"),
708 }
709 }
710
711 #[test]
712 fn test_ast_unused_symbols() {
713 let mut grm = GrammarAST::new();
714 let empty_span = Span::new(0, 0);
715 grm.start = Some(("A".to_string(), empty_span));
716 grm.add_rule(("A".to_string(), empty_span), None);
717 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
718 grm.tokens.insert("b".to_string());
719 grm.spans.push(Span::new(4, 5));
720 grm.add_rule(("B".to_string(), Span::new(1, 2)), None);
721 grm.add_prod("B".to_string(), vec![token("b")], None, None, empty_span);
722
723 assert_eq!(
724 grm.unused_symbols()
725 .map(|sym_idx| sym_idx.symbol(&grm))
726 .collect::<Vec<Symbol>>()
727 .as_slice(),
728 &[
729 Symbol::Rule("B".to_string(), Span::new(1, 2)),
730 Symbol::Token("b".to_string(), Span::new(4, 5))
731 ]
732 )
733 }
734
735 #[test]
736 fn token_rule_confusion_issue_557() {
737 use super::*;
738 use crate::yacc::*;
739 let ast_validity = ASTWithValidityInfo::new(
740 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
741 r#"
742 %start start
743 %%
744 start: "a" a;
745 a: "c";"#,
746 );
747 assert!(
748 ast_validity.ast().prods[0]
749 .symbols
750 .contains(&Symbol::Rule("a".to_string(), Span::new(64, 65)))
751 );
752 let ast_validity = ASTWithValidityInfo::new(
753 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
754 r#"
755 %start start
756 %%
757 start: "a" x;
758 x: "c";"#,
759 );
760 assert!(
761 ast_validity.ast().prods[0]
762 .symbols
763 .contains(&Symbol::Rule("x".to_string(), Span::new(64, 65)))
764 );
765 let ast_validity = ASTWithValidityInfo::new(
766 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
767 r#"
768 %start start
769 %token a
770 %%
771 start: "a" a;
772 "#,
773 );
774 assert_eq!(
775 ast_validity.ast().prods[0].symbols,
776 [
777 Symbol::Token("a".to_string(), Span::new(66, 67)),
778 Symbol::Token("a".to_string(), Span::new(69, 70))
779 ]
780 );
781 }
782
783 #[test]
784 fn test_token_directives() {
785 use super::*;
786 use crate::yacc::*;
787
788 let ast_validity = ASTWithValidityInfo::new(
790 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
791 r#"
792 %left "a"
793 %token a
794 %start start
795 %%
796 start: "a" a "b";
797 "#,
798 );
799 assert!(
800 ast_validity
801 .ast()
802 .token_directives
803 .contains(&ast_validity.ast().tokens.get_index_of("a").unwrap())
804 );
805 assert!(
806 !ast_validity
807 .ast()
808 .token_directives
809 .contains(&ast_validity.ast().tokens.get_index_of("b").unwrap())
810 );
811 }
812
813 #[test]
814 fn clone_ast_changing_start_rule() {
815 use super::*;
816 use crate::yacc::*;
817 let y_src = r#"
818 %start AStart
819 %token A B C
820 %%
821 AStart: A ':' BStart ';';
822 BStart: B ',' C | C ',' B;
823 "#;
824
825 let astart_ast_validity =
826 ASTWithValidityInfo::new(YaccKind::Original(YaccOriginalActionKind::NoAction), &y_src);
827 let bstart_rule = astart_ast_validity.ast().get_rule("BStart").unwrap();
828 let bstart_ast_validity = astart_ast_validity
829 .clone_and_change_start_rule(bstart_rule.clone())
830 .unwrap();
831 assert!(astart_ast_validity.is_valid());
832 assert!(bstart_ast_validity.is_valid());
833 assert_eq!(
834 bstart_ast_validity.ast().start.as_ref(),
835 Some(&bstart_rule.name)
836 );
837 }
838}