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 yacc::YaccOriginalActionKind,
19};
20
21#[derive(Debug, PartialEq, Eq, Clone)]
23pub struct ASTModificationError {
24 kind: YaccGrammarErrorKind,
25}
26
27impl Error for ASTModificationError {}
28
29impl fmt::Display for ASTModificationError {
30 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31 write!(f, "{}", self.kind)
32 }
33}
34
35#[derive(Debug, Clone)]
38#[cfg_attr(test, derive(PartialEq))]
39pub struct ASTWithValidityInfo {
40 yacc_kind: YaccKind,
41 ast: GrammarAST,
42 errs: Vec<YaccGrammarError>,
43}
44
45impl ASTWithValidityInfo {
46 pub fn new(yacc_kind: YaccKind, s: &str) -> Self {
54 let mut errs = Vec::new();
55 let ast = {
56 let mut yp = YaccParser::new(yacc_kind, s);
57 yp.parse().map_err(|e| errs.extend(e)).ok();
58 let mut ast = yp.build();
59 ast.complete_and_validate(Some(yacc_kind))
60 .map_err(|e| errs.push(e))
61 .ok();
62 ast
63 };
64 ASTWithValidityInfo {
65 ast,
66 errs,
67 yacc_kind,
68 }
69 }
70
71 pub fn ast(&self) -> &GrammarAST {
76 &self.ast
77 }
78
79 pub fn is_valid(&self) -> bool {
82 self.errors().is_empty()
83 }
84
85 pub fn yacc_kind(&self) -> YaccKind {
87 self.yacc_kind
88 }
89
90 pub fn errors(&self) -> &[YaccGrammarError] {
92 self.errs.as_slice()
93 }
94
95 pub fn clone_and_change_start_rule(&self, rule: Rule) -> Result<Self, ASTModificationError> {
96 if self.ast.get_rule(&rule.name.0).is_some() {
97 let mut ret = self.clone();
98 ret.ast.start = Some(rule.name);
104 Ok(ret)
105 } else {
106 Err(ASTModificationError {
107 kind: YaccGrammarErrorKind::InvalidStartRule(rule.name.0),
108 })
109 }
110 }
111}
112
113impl FromStr for ASTWithValidityInfo {
114 type Err = Vec<YaccGrammarError>;
115 fn from_str(src: &str) -> Result<Self, Vec<YaccGrammarError>> {
117 let mut errs = Vec::new();
118 let (header, _) = GrmtoolsSectionParser::new(src, true)
119 .parse()
120 .map_err(|mut errs| errs.drain(..).map(|e| e.into()).collect::<Vec<_>>())?;
121 if let Some(HeaderValue(_, yk_val)) = header.get("yacckind") {
122 let yacc_kind = YaccKind::try_from(yk_val).map_err(|e| vec![e.into()])?;
123 let ast = {
124 let mut yp = YaccParser::new(yacc_kind, src);
126 yp.parse().map_err(|e| errs.extend(e)).ok();
127 let mut ast = yp.build();
128 ast.complete_and_validate(Some(yacc_kind))
129 .map_err(|e| errs.push(e))
130 .ok();
131 ast
132 };
133 Ok(ASTWithValidityInfo {
134 ast,
135 errs,
136 yacc_kind,
137 })
138 } else {
139 Err(vec![
140 HeaderError {
141 kind: HeaderErrorKind::InvalidEntry("yacckind"),
142 locations: vec![Span::new(0, 0)],
143 }
144 .into(),
145 ])
146 }
147 }
148}
149
150#[derive(Debug, Clone)]
152#[cfg_attr(test, derive(PartialEq))]
153#[non_exhaustive]
154pub struct GrammarAST {
155 pub start: Option<(String, Span)>,
156 pub rules: IndexMap<String, Rule>,
158 pub prods: Vec<Production>,
159 pub token_directives: HashSet<usize>,
164 pub tokens: IndexSet<String>,
165 pub spans: Vec<Span>,
166 pub precs: HashMap<String, (Precedence, Span)>,
167 pub avoid_insert: Option<HashMap<String, Span>>,
168 pub implicit_tokens: Option<HashMap<String, Span>>,
169 pub epp: HashMap<String, (Span, (String, Span))>,
173 pub expect: Option<(usize, Span)>,
174 pub expectrr: Option<(usize, Span)>,
175 pub parse_param: Option<(String, String)>,
176 pub parse_generics: Option<String>,
177 pub programs: Option<String>,
178 pub expect_unused: Vec<Symbol>,
181}
182
183#[derive(Debug, Clone)]
184#[cfg_attr(test, derive(Eq, PartialEq))]
185pub struct Rule {
186 pub name: (String, Span),
187 pub pidxs: Vec<usize>, pub actiont: Option<String>,
189}
190
191#[derive(Debug, Clone)]
192#[cfg_attr(test, derive(Eq, PartialEq))]
193pub struct Production {
194 pub symbols: Vec<Symbol>,
195 pub precedence: Option<String>,
196 pub action: Option<(String, Span)>,
197 pub prod_span: Span,
198}
199
200#[derive(Clone, Debug)]
201#[cfg_attr(test, derive(Eq, PartialEq))]
202pub enum Symbol {
203 Rule(String, Span),
204 Token(String, Span),
205}
206
207#[derive(Eq, PartialEq, Debug, Copy, Clone)]
210pub(crate) enum SymbolIdx {
211 Rule(usize),
212 Token(usize),
213}
214
215impl SymbolIdx {
216 pub(crate) fn symbol(self, ast: &GrammarAST) -> Symbol {
217 match self {
218 SymbolIdx::Rule(idx) => {
219 let (rule_name, rule_span) = &ast.rules[idx].name;
220 Symbol::Rule(rule_name.clone(), *rule_span)
221 }
222 SymbolIdx::Token(idx) => {
223 let tok = &ast.tokens[idx];
224 Symbol::Token(tok.clone(), ast.spans[idx])
225 }
226 }
227 }
228}
229impl fmt::Display for Symbol {
230 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231 match *self {
232 Symbol::Rule(ref s, _) => write!(f, "{}", s),
233 Symbol::Token(ref s, _) => write!(f, "{}", s),
234 }
235 }
236}
237
238impl GrammarAST {
239 pub(crate) fn new() -> GrammarAST {
240 GrammarAST {
241 start: None,
242 rules: IndexMap::new(), prods: Vec::new(),
245 spans: Vec::new(),
246 tokens: IndexSet::new(),
247 token_directives: HashSet::new(),
248 precs: HashMap::new(),
249 avoid_insert: None,
250 implicit_tokens: None,
251 epp: HashMap::new(),
252 expect: None,
253 expectrr: None,
254 parse_param: None,
255 parse_generics: None,
256 programs: None,
257 expect_unused: Vec::new(),
258 }
259 }
260
261 pub fn add_rule(&mut self, (name, name_span): (String, Span), actiont: Option<String>) {
262 self.rules.insert(
263 name.clone(),
264 Rule {
265 name: (name, name_span),
266 pidxs: Vec::new(),
267 actiont,
268 },
269 );
270 }
271
272 pub fn add_prod(
273 &mut self,
274 rule_name: String,
275 symbols: Vec<Symbol>,
276 precedence: Option<String>,
277 action: Option<(String, Span)>,
278 prod_span: Span,
279 ) {
280 self.rules[&rule_name].pidxs.push(self.prods.len());
281 self.prods.push(Production {
282 symbols,
283 precedence,
284 action,
285 prod_span,
286 });
287 }
288
289 #[deprecated(since = "0.10.2", note = "Please use set_programs instead")]
290 pub fn add_programs(&mut self, s: String) {
291 self.set_programs(s);
292 }
293
294 pub fn set_programs(&mut self, s: String) {
295 self.programs = Some(s)
296 }
297
298 pub fn get_rule(&self, key: &str) -> Option<&Rule> {
299 self.rules.get(key)
300 }
301
302 pub fn has_token(&self, s: &str) -> bool {
303 self.tokens.contains(s)
304 }
305
306 pub(crate) fn complete_and_validate(
318 &mut self,
319 yacc_kind: Option<YaccKind>,
320 ) -> Result<(), YaccGrammarError> {
321 let kind_requires_action_checks = matches!(
322 yacc_kind,
323 Some(YaccKind::Original(YaccOriginalActionKind::UserAction)) | Some(YaccKind::Grmtools)
324 );
325
326 match self.start {
327 None => {
328 return Err(YaccGrammarError {
329 kind: YaccGrammarErrorKind::NoStartRule,
330 spans: vec![Span::new(0, 0)],
331 });
332 }
333 Some((ref s, span)) => {
334 if !self.rules.contains_key(s) {
335 return Err(YaccGrammarError {
336 kind: YaccGrammarErrorKind::InvalidStartRule(s.clone()),
337 spans: vec![span],
338 });
339 }
340 }
341 }
342 for rule in self.rules.values() {
343 if kind_requires_action_checks && rule.actiont.is_none() {
344 return Err(YaccGrammarError {
345 kind: YaccGrammarErrorKind::MissingActionType,
346 spans: vec![rule.name.1],
347 });
348 }
349 for &pidx in &rule.pidxs {
350 let prod = &self.prods[pidx];
351 if kind_requires_action_checks {
352 if let Some((action_code, action_span)) = prod.action.as_ref() {
353 let mut last = 0;
354 while let Some(off) = action_code[last..].find('$') {
355 if !(action_code[last + off..].starts_with("$$")
356 || action_code[last + off..].starts_with("$lexer")
357 || action_code[last + off..].starts_with("$span")
358 || (last + off + 1 < action_code.len()
359 && action_code[last + off + 1..]
360 .starts_with(|c: char| c.is_numeric())))
361 {
362 let m = crate::yacc::parser::RE_NAME
364 .find(&action_code[last + off + 1..]);
365 let var_start_pos = action_span.start() + last + off;
366 let var_end_pos = m
367 .map(|m| var_start_pos + 1 + m.end())
368 .unwrap_or(var_start_pos + 1);
369 return Err(YaccGrammarError {
370 kind: YaccGrammarErrorKind::UnrecognisedActionVariable,
371 spans: vec![Span::new(var_start_pos, var_end_pos)],
372 });
373 } else {
374 last = last + off + 2;
375 }
376 }
377 } else {
378 return Err(YaccGrammarError {
379 kind: YaccGrammarErrorKind::MissingActionCode,
380 spans: vec![prod.prod_span],
381 });
382 }
383 }
384
385 if let Some(ref n) = prod.precedence {
386 if !self.tokens.contains(n) {
387 return Err(YaccGrammarError {
388 kind: YaccGrammarErrorKind::UnknownToken(n.clone()),
389 spans: vec![Span::new(0, 0)],
390 });
391 }
392 if !self.precs.contains_key(n) {
393 return Err(YaccGrammarError {
394 kind: YaccGrammarErrorKind::NoPrecForToken(n.clone()),
395 spans: vec![Span::new(0, 0)],
396 });
397 }
398 }
399 for sym in &prod.symbols {
400 match *sym {
401 Symbol::Rule(ref name, span) => {
402 if !self.rules.contains_key(name) {
403 return Err(YaccGrammarError {
404 kind: YaccGrammarErrorKind::UnknownRuleRef(name.clone()),
405 spans: vec![span],
406 });
407 }
408 }
409 Symbol::Token(ref name, span) => {
410 if !self.tokens.contains(name) {
411 return Err(YaccGrammarError {
412 kind: YaccGrammarErrorKind::UnknownToken(name.clone()),
413 spans: vec![span],
414 });
415 }
416 }
417 }
418 }
419 }
420 }
421
422 for (k, (sp, _)) in self.epp.iter() {
423 if self.tokens.contains(k) {
424 continue;
425 }
426 if let Some(ref it) = self.implicit_tokens
427 && it.contains_key(k)
428 {
429 continue;
430 }
431 return Err(YaccGrammarError {
432 kind: YaccGrammarErrorKind::UnknownEPP(k.clone()),
433 spans: vec![*sp],
434 });
435 }
436
437 for sym in &self.expect_unused {
438 match sym {
439 Symbol::Rule(sym_name, sym_span) => {
440 if self.get_rule(sym_name).is_none() {
441 return Err(YaccGrammarError {
442 kind: YaccGrammarErrorKind::UnknownRuleRef(sym_name.clone()),
443 spans: vec![*sym_span],
444 });
445 }
446 }
447 Symbol::Token(sym_name, sym_span) => {
448 if !self.has_token(sym_name) {
449 return Err(YaccGrammarError {
450 kind: YaccGrammarErrorKind::UnknownToken(sym_name.clone()),
451 spans: vec![*sym_span],
452 });
453 }
454 }
455 }
456 }
457 Ok(())
458 }
459
460 pub fn warnings(&self) -> Vec<YaccGrammarWarning> {
461 self.unused_symbols()
462 .map(|symidx| {
463 let (kind, span) = match symidx.symbol(self) {
464 Symbol::Rule(_, span) => (YaccGrammarWarningKind::UnusedRule, span),
465 Symbol::Token(_, span) => (YaccGrammarWarningKind::UnusedToken, span),
466 };
467 YaccGrammarWarning {
468 kind,
469 spans: vec![span],
470 }
471 })
472 .collect()
473 }
474
475 pub(crate) fn unused_symbols(&self) -> impl Iterator<Item = SymbolIdx> + '_ {
478 let start_rule_name = self.start.as_ref().map(|(name, _)| name.clone());
479 let start_rule = self
480 .rules
481 .iter()
482 .find(|(rule_name, _)| start_rule_name.as_ref() == Some(rule_name));
483 let mut seen_rules = HashSet::new();
484 let mut seen_tokens = HashSet::new();
485 let mut expected_unused_tokens = HashSet::new();
486 let mut expected_unused_rules = HashSet::new();
487 for sym in &self.expect_unused {
488 match sym {
489 Symbol::Rule(sym_name, _) => {
490 expected_unused_rules.insert(sym_name);
491 }
492 Symbol::Token(sym_name, _) => {
493 expected_unused_tokens.insert(sym_name);
494 }
495 }
496 }
497 if let Some(implicit_tokens) = self.implicit_tokens.as_ref() {
498 expected_unused_tokens.extend(implicit_tokens.keys())
499 }
500 if let Some((start_name, start_rule)) = start_rule {
501 let mut todo = Vec::new();
502 todo.extend(start_rule.pidxs.iter().copied());
503 seen_rules.insert(start_name);
504
505 while let Some(pidx) = todo.pop() {
506 let prod = &self.prods[pidx];
507 for sym in &prod.symbols {
508 match sym {
509 Symbol::Rule(name, _) => {
510 if seen_rules.insert(name)
511 && let Some(rule) = self.rules.get(name)
512 {
513 todo.extend(&rule.pidxs);
514 }
515 }
516 Symbol::Token(name, _) => {
517 seen_tokens.insert(name);
518 }
519 };
520 }
521 }
522 }
523 self.rules
524 .iter()
525 .enumerate()
526 .filter_map(move |(rule_id, (rule_name, _))| {
527 if expected_unused_rules.contains(rule_name) || seen_rules.contains(rule_name) {
528 None
529 } else {
530 Some(SymbolIdx::Rule(rule_id))
531 }
532 })
533 .chain(
534 self.tokens
535 .iter()
536 .enumerate()
537 .filter_map(move |(tok_idx, tok)| {
538 if expected_unused_tokens.contains(tok) || seen_tokens.contains(tok) {
539 None
540 } else {
541 Some(SymbolIdx::Token(tok_idx))
542 }
543 }),
544 )
545 }
546}
547
548#[cfg(test)]
549mod test {
550 use super::{
551 super::{AssocKind, Precedence},
552 GrammarAST, Span, Symbol, YaccGrammarError, YaccGrammarErrorKind,
553 };
554
555 fn rule(n: &str) -> Symbol {
556 Symbol::Rule(n.to_string(), Span::new(0, 0))
557 }
558
559 fn token(n: &str) -> Symbol {
560 Symbol::Token(n.to_string(), Span::new(0, 0))
561 }
562
563 #[test]
564 fn test_empty_grammar() {
565 let mut grm = GrammarAST::new();
566 match grm.complete_and_validate(None) {
567 Err(YaccGrammarError {
568 kind: YaccGrammarErrorKind::NoStartRule,
569 ..
570 }) => (),
571 _ => panic!("Validation error"),
572 }
573 }
574
575 #[test]
576 fn test_invalid_start_rule() {
577 let mut grm = GrammarAST::new();
578 let empty_span = Span::new(0, 0);
579 grm.start = Some(("A".to_string(), empty_span));
580 grm.add_rule(("B".to_string(), empty_span), None);
581 grm.add_prod("B".to_string(), vec![], None, None, empty_span);
582 match grm.complete_and_validate(None) {
583 Err(YaccGrammarError {
584 kind: YaccGrammarErrorKind::InvalidStartRule(_),
585 ..
586 }) => (),
587 _ => panic!("Validation error"),
588 }
589 }
590
591 #[test]
592 fn test_valid_start_rule() {
593 let mut grm = GrammarAST::new();
594 let empty_span = Span::new(0, 0);
595 grm.start = Some(("A".to_string(), empty_span));
596 grm.add_rule(("A".to_string(), empty_span), None);
597 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
598 assert!(grm.complete_and_validate(None).is_ok());
599 }
600
601 #[test]
602 fn test_valid_rule_ref() {
603 let mut grm = GrammarAST::new();
604 let empty_span = Span::new(0, 0);
605 grm.start = Some(("A".to_string(), empty_span));
606 grm.add_rule(("A".to_string(), empty_span), None);
607 grm.add_rule(("B".to_string(), empty_span), None);
608 grm.add_prod("A".to_string(), vec![rule("B")], None, None, empty_span);
609 grm.add_prod("B".to_string(), vec![], None, None, empty_span);
610 assert!(grm.complete_and_validate(None).is_ok());
611 }
612
613 #[test]
614 fn test_invalid_rule_ref() {
615 let mut grm = GrammarAST::new();
616 let empty_span = Span::new(0, 0);
617 grm.start = Some(("A".to_string(), empty_span));
618 grm.add_rule(("A".to_string(), empty_span), None);
619 grm.add_prod("A".to_string(), vec![rule("B")], None, None, empty_span);
620 match grm.complete_and_validate(None) {
621 Err(YaccGrammarError {
622 kind: YaccGrammarErrorKind::UnknownRuleRef(_),
623 ..
624 }) => (),
625 _ => panic!("Validation error"),
626 }
627 }
628
629 #[test]
630 fn test_valid_token_ref() {
631 let mut grm = GrammarAST::new();
632 let empty_span = Span::new(0, 0);
633 grm.tokens.insert("b".to_string());
634 grm.start = Some(("A".to_string(), empty_span));
635 grm.add_rule(("A".to_string(), empty_span), None);
636 grm.add_prod("A".to_string(), vec![token("b")], None, None, empty_span);
637 assert!(grm.complete_and_validate(None).is_ok());
638 }
639
640 #[test]
641 fn test_redefine_rules_as_tokens() {
642 let mut grm = GrammarAST::new();
645 let empty_span = Span::new(0, 0);
646 grm.tokens.insert("b".to_string());
647 grm.start = Some(("A".to_string(), empty_span));
648 grm.add_rule(("A".to_string(), empty_span), None);
649 grm.add_prod("A".to_string(), vec![rule("b")], None, None, empty_span);
650 assert!(grm.complete_and_validate(None).is_err());
651 }
652
653 #[test]
654 fn test_invalid_token_ref() {
655 let mut grm = GrammarAST::new();
656 let empty_span = Span::new(0, 0);
657 grm.start = Some(("A".to_string(), empty_span));
658 grm.add_rule(("A".to_string(), empty_span), None);
659 grm.add_prod("A".to_string(), vec![token("b")], None, None, empty_span);
660 match grm.complete_and_validate(None) {
661 Err(YaccGrammarError {
662 kind: YaccGrammarErrorKind::UnknownToken(_),
663 ..
664 }) => (),
665 _ => panic!("Validation error"),
666 }
667 }
668
669 #[test]
670 fn test_invalid_rule_forgotten_token() {
671 let mut grm = GrammarAST::new();
672 let empty_span = Span::new(0, 0);
673 grm.start = Some(("A".to_string(), empty_span));
674 grm.add_rule(("A".to_string(), empty_span), None);
675 grm.add_prod(
676 "A".to_string(),
677 vec![rule("b"), token("b")],
678 None,
679 None,
680 Span::new(0, 2),
681 );
682 match grm.complete_and_validate(None) {
683 Err(YaccGrammarError {
684 kind: YaccGrammarErrorKind::UnknownRuleRef(_),
685 ..
686 }) => (),
687 _ => panic!("Validation error"),
688 }
689 }
690
691 #[test]
692 fn test_invalid_epp() {
693 let mut grm = GrammarAST::new();
694 let empty_span = Span::new(2, 3);
695 grm.start = Some(("A".to_string(), empty_span));
696 grm.add_rule(("A".to_string(), empty_span), None);
697 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
698 grm.epp
699 .insert("k".to_owned(), (empty_span, ("v".to_owned(), empty_span)));
700 match grm.complete_and_validate(None) {
701 Err(YaccGrammarError {
702 kind: YaccGrammarErrorKind::UnknownEPP(_),
703 spans,
704 }) if spans.len() == 1 && spans[0] == Span::new(2, 3) => (),
705 _ => panic!("Validation error"),
706 }
707 }
708
709 #[test]
710 fn test_precedence_override() {
711 let mut grm = GrammarAST::new();
712 let empty_span = Span::new(0, 0);
713 grm.precs.insert(
714 "b".to_string(),
715 (
716 Precedence {
717 level: 1,
718 kind: AssocKind::Left,
719 },
720 Span::new(0, 0),
721 ),
722 );
723 grm.start = Some(("A".to_string(), empty_span));
724 grm.tokens.insert("b".to_string());
725 grm.add_rule(("A".to_string(), empty_span), None);
726 grm.add_prod(
727 "A".to_string(),
728 vec![token("b")],
729 Some("b".to_string()),
730 None,
731 empty_span,
732 );
733 assert!(grm.complete_and_validate(None).is_ok());
734 }
735
736 #[test]
737 fn test_invalid_precedence_override() {
738 let mut grm = GrammarAST::new();
739 let empty_span = Span::new(0, 0);
740 grm.start = Some(("A".to_string(), empty_span));
741 grm.add_rule(("A".to_string(), empty_span), None);
742 grm.add_prod(
743 "A".to_string(),
744 vec![token("b")],
745 Some("b".to_string()),
746 None,
747 empty_span,
748 );
749 match grm.complete_and_validate(None) {
750 Err(YaccGrammarError {
751 kind: YaccGrammarErrorKind::UnknownToken(_),
752 ..
753 }) => (),
754 _ => panic!("Validation error"),
755 }
756 grm.tokens.insert("b".to_string());
757 match grm.complete_and_validate(None) {
758 Err(YaccGrammarError {
759 kind: YaccGrammarErrorKind::NoPrecForToken(_),
760 ..
761 }) => (),
762 _ => panic!("Validation error"),
763 }
764 }
765
766 #[test]
767 fn test_ast_unused_symbols() {
768 let mut grm = GrammarAST::new();
769 let empty_span = Span::new(0, 0);
770 grm.start = Some(("A".to_string(), empty_span));
771 grm.add_rule(("A".to_string(), empty_span), None);
772 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
773 grm.tokens.insert("b".to_string());
774 grm.spans.push(Span::new(4, 5));
775 grm.add_rule(("B".to_string(), Span::new(1, 2)), None);
776 grm.add_prod("B".to_string(), vec![token("b")], None, None, empty_span);
777
778 assert_eq!(
779 grm.unused_symbols()
780 .map(|sym_idx| sym_idx.symbol(&grm))
781 .collect::<Vec<Symbol>>()
782 .as_slice(),
783 &[
784 Symbol::Rule("B".to_string(), Span::new(1, 2)),
785 Symbol::Token("b".to_string(), Span::new(4, 5))
786 ]
787 )
788 }
789
790 #[test]
791 fn token_rule_confusion_issue_557() {
792 use super::*;
793 let ast_validity = ASTWithValidityInfo::new(
794 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
795 r#"
796 %start start
797 %%
798 start: "a" a;
799 a: "c";"#,
800 );
801 assert!(
802 ast_validity.ast().prods[0]
803 .symbols
804 .contains(&Symbol::Rule("a".to_string(), Span::new(64, 65)))
805 );
806 let ast_validity = ASTWithValidityInfo::new(
807 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
808 r#"
809 %start start
810 %%
811 start: "a" x;
812 x: "c";"#,
813 );
814 assert!(
815 ast_validity.ast().prods[0]
816 .symbols
817 .contains(&Symbol::Rule("x".to_string(), Span::new(64, 65)))
818 );
819 let ast_validity = ASTWithValidityInfo::new(
820 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
821 r#"
822 %start start
823 %token a
824 %%
825 start: "a" a;
826 "#,
827 );
828 assert_eq!(
829 ast_validity.ast().prods[0].symbols,
830 [
831 Symbol::Token("a".to_string(), Span::new(66, 67)),
832 Symbol::Token("a".to_string(), Span::new(69, 70))
833 ]
834 );
835 }
836
837 #[test]
838 fn test_token_directives() {
839 use super::*;
840
841 let ast_validity = ASTWithValidityInfo::new(
843 YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
844 r#"
845 %left "a"
846 %token a
847 %start start
848 %%
849 start: "a" a "b";
850 "#,
851 );
852 assert!(
853 ast_validity
854 .ast()
855 .token_directives
856 .contains(&ast_validity.ast().tokens.get_index_of("a").unwrap())
857 );
858 assert!(
859 !ast_validity
860 .ast()
861 .token_directives
862 .contains(&ast_validity.ast().tokens.get_index_of("b").unwrap())
863 );
864 }
865
866 #[test]
867 fn clone_ast_changing_start_rule() {
868 use super::*;
869 let y_src = r#"
870 %start AStart
871 %token A B C
872 %%
873 AStart: A ':' BStart ';';
874 BStart: B ',' C | C ',' B;
875 "#;
876
877 let astart_ast_validity =
878 ASTWithValidityInfo::new(YaccKind::Original(YaccOriginalActionKind::NoAction), y_src);
879 let bstart_rule = astart_ast_validity.ast().get_rule("BStart").unwrap();
880 let bstart_ast_validity = astart_ast_validity
881 .clone_and_change_start_rule(bstart_rule.clone())
882 .unwrap();
883 assert!(astart_ast_validity.is_valid());
884 assert!(bstart_ast_validity.is_valid());
885 assert_eq!(
886 bstart_ast_validity.ast().start.as_ref(),
887 Some(&bstart_rule.name)
888 );
889 }
890
891 #[test]
892 fn test_missing_actiont() {
893 use super::*;
894 let ast_validity = ASTWithValidityInfo::new(
895 YaccKind::Original(YaccOriginalActionKind::UserAction),
896 r#"
897%token a
898%%
899start: "a";
900"#,
901 );
902 assert_eq!(
903 ast_validity.errors(),
904 vec![YaccGrammarError {
905 kind: YaccGrammarErrorKind::MissingActionType,
906 spans: vec![Span::new(13, 18)],
907 }]
908 );
909
910 let ast_validity = ASTWithValidityInfo::new(
911 YaccKind::Original(YaccOriginalActionKind::UserAction),
912 r#"
913%actiontype ()
914%token a
915%%
916start: "a" { };
917"#,
918 );
919 assert!(ast_validity.errors().is_empty());
920
921 let mut grm = GrammarAST::new();
922 let empty_span = Span::new(0, 0);
923 let rule_span = Span::new(255, 255);
924 grm.start = Some(("A".to_string(), empty_span));
925 grm.add_rule(("A".to_string(), rule_span), None);
926 grm.add_prod("A".to_string(), vec![], None, None, empty_span);
927 assert_eq!(
928 grm.complete_and_validate(Some(YaccKind::Grmtools)),
929 Err(YaccGrammarError {
930 kind: YaccGrammarErrorKind::MissingActionType,
931 spans: vec![rule_span],
932 })
933 );
934 }
935
936 #[test]
937 fn test_unrecognized_action_variable() {
938 use super::*;
939 let ast_validity = ASTWithValidityInfo::new(
940 YaccKind::Grmtools,
941 r#"
942%token a
943%%
944start -> () : "a" { $foo; };
945"#,
946 );
947 assert_eq!(
948 ast_validity.errors(),
949 vec![YaccGrammarError {
950 kind: YaccGrammarErrorKind::UnrecognisedActionVariable,
951 spans: vec![Span::new(33, 37)],
952 }]
953 );
954
955 let ast_validity = ASTWithValidityInfo::new(
956 YaccKind::Grmtools,
957 r#"
958%token a
959%%
960start -> () : "a" {$};
961"#,
962 );
963 assert_eq!(
964 ast_validity.errors(),
965 vec![YaccGrammarError {
966 kind: YaccGrammarErrorKind::UnrecognisedActionVariable,
967 spans: vec![Span::new(32, 33)],
968 }]
969 );
970
971 let ast_validity = ASTWithValidityInfo::new(
972 YaccKind::Grmtools,
973 r#"
974%token a
975%%
976start -> () : "a" {$;;;; };
977"#,
978 );
979 assert_eq!(
980 ast_validity.errors(),
981 vec![YaccGrammarError {
982 kind: YaccGrammarErrorKind::UnrecognisedActionVariable,
983 spans: vec![Span::new(32, 33)],
984 }]
985 );
986 }
987}