Skip to main content

cfgrammar/yacc/
grammar.rs

1#![allow(clippy::derive_partial_eq_without_eq)]
2use std::{cell::RefCell, collections::HashMap, fmt::Write, str::FromStr};
3
4#[cfg(feature = "bincode")]
5use bincode::{Decode, Encode};
6use num_traits::{AsPrimitive, PrimInt, Unsigned};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9use vob::Vob;
10
11use super::{
12    YaccKind, ast,
13    firsts::YaccFirsts,
14    follows::YaccFollows,
15    parser::{YaccGrammarError, YaccGrammarResult},
16};
17use crate::{PIdx, RIdx, SIdx, Span, Symbol, TIdx};
18
19const START_RULE: &str = "^";
20const IMPLICIT_RULE: &str = "~";
21const IMPLICIT_START_RULE: &str = "^~";
22
23pub type PrecedenceLevel = u64;
24#[derive(Clone, Copy, Debug, PartialEq)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
27pub struct Precedence {
28    pub level: PrecedenceLevel,
29    pub kind: AssocKind,
30}
31
32#[derive(Clone, Copy, Debug, PartialEq)]
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
35pub enum AssocKind {
36    Left,
37    Right,
38    Nonassoc,
39}
40
41/// Representation of a `YaccGrammar`. See the [top-level documentation](../../index.html) for the
42/// guarantees this struct makes about rules, tokens, productions, and symbols.
43#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
44#[cfg_attr(feature = "bincode", derive(Encode))]
45pub struct YaccGrammar<StorageT = u32> {
46    /// How many rules does this grammar have?
47    rules_len: RIdx<StorageT>,
48    /// A mapping from `RIdx` -> `(Span, String)`.
49    rule_names: Box<[(String, Span)]>,
50    /// A mapping from `TIdx` -> `Option<(Span, String)>`. Every user-specified token will have a name,
51    /// but tokens inserted by cfgrammar (e.g. the EOF token) won't.
52    token_names: Box<[Option<(Span, String)>]>,
53    /// A mapping from `TIdx` -> `Option<Precedence>`
54    token_precs: Box<[Option<Precedence>]>,
55    /// A mapping from `TIdx` -> `Option<String>` for the %epp declaration, giving pretty-printed
56    /// versions of token names that can be presented to the user in case of an error. Every
57    /// user-specified token will have a name that can be presented to the user (if a token doesn't
58    /// have an %epp entry, the token name will be used in lieu), but tokens inserted by cfgrammar
59    /// (e.g. the EOF token) won't.
60    token_epp: Box<[Option<String>]>,
61    /// How many tokens does this grammar have?
62    tokens_len: TIdx<StorageT>,
63    /// The offset of the EOF token.
64    eof_token_idx: TIdx<StorageT>,
65    /// How many productions does this grammar have?
66    prods_len: PIdx<StorageT>,
67    /// Which production is the sole production of the start rule?
68    start_prod: PIdx<StorageT>,
69    /// A list of all productions.
70    prods: Box<[Box<[Symbol<StorageT>]>]>,
71    /// A mapping from rules to their productions. Note that 1) the order of rules is identical to
72    /// that of `rule_names` 2) every rule will have at least 1 production 3) productions
73    /// are not necessarily stored sequentially.
74    rules_prods: Box<[Box<[PIdx<StorageT>]>]>,
75    /// A mapping from productions to their corresponding rule indexes.
76    prods_rules: Box<[RIdx<StorageT>]>,
77    /// The precedence of each production.
78    prod_precs: Box<[Option<Precedence>]>,
79    /// The span for each production.
80    ///
81    /// In the case of an empty span this may be a zero length span.
82    prod_spans: Box<[Span]>,
83    /// The index of the rule added for implicit tokens, if they were specified; otherwise
84    /// `None`.
85    implicit_rule: Option<RIdx<StorageT>>,
86    /// User defined Rust programs which can be called within actions
87    actions: Box<[Option<String>]>,
88    /// Spans for each action.
89    action_spans: Box<[Option<Span>]>,
90    /// A `(name, type)` pair defining an extra parameter to pass to action functions.
91    parse_param: Option<(String, String)>,
92    /// Generic parameters (types and lifetimes) to pass to action functions.
93    parse_generics: Option<String>,
94    /// Lifetimes for `param_args`
95    programs: Option<String>,
96    /// The actiontypes of rules (one per rule).
97    actiontypes: Box<[Option<String>]>,
98    /// Tokens marked as %avoid_insert (if any).
99    avoid_insert: Option<Vob>,
100    /// How many shift/reduce conflicts the grammar author expected (if any).
101    expect: Option<usize>,
102    /// How many reduce/reduce conflicts the grammar author expected (if any).
103    expectrr: Option<usize>,
104}
105
106// The implementations of `Decode` and `BorrowDecode`
107// Contain a modified copy of the output of `cargo expand` of the derivation:
108// #[cfg_attr(feature = "bincode", derive(Decode))]
109//
110// The current version of bincode has bugs in it's derive macro implementation
111// https://github.com/bincode-org/bincode/issues/763
112// https://github.com/bincode-org/bincode/issues/646
113//
114// Once those are fixed, we can replace this with derive.
115
116#[cfg(feature = "bincode")]
117impl<StorageT, __Context> Decode<__Context> for YaccGrammar<StorageT>
118where
119    StorageT: Decode<__Context> + 'static,
120{
121    fn decode<__D: bincode::de::Decoder<Context = __Context>>(
122        decoder: &mut __D,
123    ) -> Result<Self, bincode::error::DecodeError> {
124        Ok(Self {
125            rules_len: Decode::decode(decoder)?,
126            rule_names: Decode::decode(decoder)?,
127            token_names: Decode::decode(decoder)?,
128            token_precs: Decode::decode(decoder)?,
129            token_epp: Decode::decode(decoder)?,
130            tokens_len: Decode::decode(decoder)?,
131            eof_token_idx: Decode::decode(decoder)?,
132            prods_len: Decode::decode(decoder)?,
133            start_prod: Decode::decode(decoder)?,
134            prods: Decode::decode(decoder)?,
135            rules_prods: Decode::decode(decoder)?,
136            prods_rules: Decode::decode(decoder)?,
137            prod_precs: Decode::decode(decoder)?,
138            prod_spans: Decode::decode(decoder)?,
139            implicit_rule: Decode::decode(decoder)?,
140            actions: Decode::decode(decoder)?,
141            action_spans: Decode::decode(decoder)?,
142            parse_param: Decode::decode(decoder)?,
143            parse_generics: Decode::decode(decoder)?,
144            programs: Decode::decode(decoder)?,
145            actiontypes: Decode::decode(decoder)?,
146            avoid_insert: Decode::decode(decoder)?,
147            expect: Decode::decode(decoder)?,
148            expectrr: Decode::decode(decoder)?,
149        })
150    }
151}
152
153// Eventually this should just be provided through:
154// #[cfg_attr(feature = "bincode", derive(Decode))]
155//
156// See comment at the corresponding bincode::Decode impl.
157#[cfg(feature = "bincode")]
158impl<'__de, StorageT, __Context> bincode::BorrowDecode<'__de, __Context> for YaccGrammar<StorageT>
159where
160    StorageT: bincode::de::BorrowDecode<'__de, __Context> + '__de,
161{
162    fn borrow_decode<__D: ::bincode::de::BorrowDecoder<'__de, Context = __Context>>(
163        decoder: &mut __D,
164    ) -> Result<Self, bincode::error::DecodeError> {
165        Ok(Self {
166            rules_len: bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
167            rule_names: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
168            token_names: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
169            token_precs: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
170            token_epp: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
171            tokens_len: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
172            eof_token_idx: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
173            prods_len: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
174            start_prod: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
175            prods: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
176            rules_prods: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
177            prods_rules: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
178            prod_precs: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
179            prod_spans: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
180            implicit_rule: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
181            actions: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
182            action_spans: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
183            parse_param: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
184            parse_generics: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
185            programs: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
186            actiontypes: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
187            avoid_insert: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
188            expect: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
189            expectrr: ::bincode::BorrowDecode::<'_, __Context>::borrow_decode(decoder)?,
190        })
191    }
192}
193
194// Internally, we assume that a grammar's start rule has a single production. Since we manually
195// create the start rule ourselves (without relying on user input), this is a safe assumption.
196
197impl YaccGrammar<u32> {
198    pub fn new(yk: YaccKind, s: &str) -> YaccGrammarResult<Self> {
199        YaccGrammar::new_with_storaget(yk, s)
200    }
201}
202
203impl<StorageT: 'static + PrimInt + Unsigned> FromStr for YaccGrammar<StorageT>
204where
205    usize: AsPrimitive<StorageT>,
206{
207    type Err = Vec<YaccGrammarError>;
208    fn from_str(s: &str) -> YaccGrammarResult<Self> {
209        let ast_validation = ast::ASTWithValidityInfo::from_str(s)?;
210        Self::new_from_ast_with_validity_info(&ast_validation)
211    }
212}
213
214impl<StorageT: 'static + PrimInt + Unsigned> YaccGrammar<StorageT>
215where
216    usize: AsPrimitive<StorageT>,
217{
218    /// Takes as input a Yacc grammar of [`YaccKind`](enum.YaccKind.html) as a `String` `s` and returns a
219    /// [`YaccGrammar`](grammar/struct.YaccGrammar.html) (or
220    /// ([`YaccGrammarError`](grammar/enum.YaccGrammarError.html) on error).
221    ///
222    /// As we're compiling the `YaccGrammar`, we add a new start rule (which we'll refer to as `^`,
223    /// though the actual name is a fresh name that is guaranteed to be unique) that references the
224    /// user defined start rule.
225    pub fn new_with_storaget(yk: YaccKind, s: &str) -> YaccGrammarResult<Self> {
226        let ast_validation = ast::ASTWithValidityInfo::new(yk, s);
227        Self::new_from_ast_with_validity_info(&ast_validation)
228    }
229
230    pub fn new_from_ast_with_validity_info(
231        ast_validation: &ast::ASTWithValidityInfo,
232    ) -> YaccGrammarResult<Self> {
233        if !ast_validation.is_valid() {
234            return Err(ast_validation.errors().to_owned());
235        }
236        let ast = ast_validation.ast();
237        // Check that StorageT is big enough to hold RIdx/PIdx/SIdx/TIdx values; after these
238        // checks we can guarantee that things like RIdx(ast.rules.len().as_()) are safe.
239        if ast.rules.len() > num_traits::cast(StorageT::max_value()).unwrap() {
240            panic!("StorageT is not big enough to store this grammar's rules.");
241        }
242        if ast.tokens.len() > num_traits::cast(StorageT::max_value()).unwrap() {
243            panic!("StorageT is not big enough to store this grammar's tokens.");
244        }
245        if ast.prods.len() > num_traits::cast(StorageT::max_value()).unwrap() {
246            panic!("StorageT is not big enough to store this grammar's productions.");
247        }
248        for p in &ast.prods {
249            if p.symbols.len() > num_traits::cast(StorageT::max_value()).unwrap() {
250                panic!(
251                    "StorageT is not big enough to store the symbols of at least one of this grammar's productions."
252                );
253            }
254        }
255
256        let mut rule_names: Vec<(String, Span)> = Vec::with_capacity(ast.rules.len() + 1);
257
258        // Generate a guaranteed unique start rule name. We simply keep making the string longer
259        // until we've hit something unique (at the very worst, this will require looping for as
260        // many times as there are rules). We use the same technique later for unique end
261        // token and whitespace names.
262        let mut start_rule = START_RULE.to_string();
263        while ast.rules.get(&start_rule).is_some() {
264            start_rule += START_RULE;
265        }
266        rule_names.push((start_rule.clone(), Span::new(0, 0)));
267
268        let implicit_rule;
269        let implicit_start_rule;
270        match ast_validation.yacc_kind() {
271            YaccKind::Original(_) | YaccKind::Grmtools => {
272                implicit_rule = None;
273                implicit_start_rule = None;
274            }
275            YaccKind::Eco => {
276                if ast.implicit_tokens.is_some() {
277                    let mut n1 = IMPLICIT_RULE.to_string();
278                    while ast.rules.get(&n1).is_some() {
279                        n1 += IMPLICIT_RULE;
280                    }
281                    rule_names.push((n1.clone(), Span::new(0, 0)));
282                    implicit_rule = Some(n1);
283                    let mut n2 = IMPLICIT_START_RULE.to_string();
284                    while ast.rules.get(&n2).is_some() {
285                        n2 += IMPLICIT_START_RULE;
286                    }
287                    rule_names.push((n2.clone(), Span::new(0, 0)));
288                    implicit_start_rule = Some(n2);
289                } else {
290                    implicit_rule = None;
291                    implicit_start_rule = None;
292                }
293            }
294        };
295
296        for (
297            k,
298            ast::Rule {
299                name: (_, name_span),
300                ..
301            },
302        ) in &ast.rules
303        {
304            rule_names.push((k.clone(), *name_span));
305        }
306        let mut rules_prods: Vec<Vec<PIdx<StorageT>>> = Vec::with_capacity(rule_names.len());
307        let mut rule_map = HashMap::<String, RIdx<StorageT>>::new();
308        for (i, (v, _)) in rule_names.iter().enumerate() {
309            rules_prods.push(Vec::new());
310            rule_map.insert(v.clone(), RIdx(i.as_()));
311        }
312
313        let mut token_names: Vec<Option<(Span, String)>> = Vec::with_capacity(ast.tokens.len() + 1);
314        let mut token_precs: Vec<Option<Precedence>> = Vec::with_capacity(ast.tokens.len() + 1);
315        let mut token_epp: Vec<Option<String>> = Vec::with_capacity(ast.tokens.len() + 1);
316        for (i, k) in ast.tokens.iter().enumerate() {
317            token_names.push(Some((ast.spans[i], k.clone())));
318            token_precs.push(ast.precs.get(k).map(|(prec, _)| prec).cloned());
319            token_epp.push(Some(
320                ast.epp.get(k).map(|(_, (s, _))| s).unwrap_or(k).clone(),
321            ));
322        }
323        let eof_token_idx = TIdx(token_names.len().as_());
324        token_names.push(None);
325        token_precs.push(None);
326        token_epp.push(None);
327        let mut token_map = HashMap::<String, TIdx<StorageT>>::new();
328        for (i, v) in token_names.iter().enumerate() {
329            if let Some((_, n)) = v.as_ref() {
330                token_map.insert(n.clone(), TIdx(i.as_()));
331            }
332        }
333
334        // In order to avoid fiddling about with production indices from the AST, we simply map
335        // tem 1:1 to grammar indices. That means that any new productions are added to the *end*
336        // of the list of productions.
337        let mut prods = vec![None; ast.prods.len()];
338        let mut prod_precs: Vec<Option<Option<Precedence>>> = vec![None; ast.prods.len()];
339        let mut prods_rules = vec![None; ast.prods.len()];
340        let mut actions = vec![None; ast.prods.len()];
341        let mut action_spans = vec![None; ast.prods.len()];
342        let mut actiontypes = vec![None; rule_names.len()];
343        let (start_name, _) = ast.start.as_ref().unwrap();
344        for (astrulename, _) in &rule_names {
345            let ridx = rule_map[astrulename];
346            if astrulename == &start_rule {
347                // Add the special start rule which has a single production which references a
348                // single rule.
349                rules_prods[usize::from(ridx)].push(PIdx(prods.len().as_()));
350                let start_prod = match implicit_start_rule {
351                    None => {
352                        // Add ^: S;
353                        vec![Symbol::Rule(rule_map[start_name])]
354                    }
355                    Some(ref s) => {
356                        // An implicit rule has been specified, so the special start rule
357                        // needs to reference the intermediate start rule required. Therefore add:
358                        //   ^: ^~;
359                        vec![Symbol::Rule(rule_map[s])]
360                    }
361                };
362                prods.push(Some(start_prod));
363                prod_precs.push(Some(None));
364                prods_rules.push(Some(ridx));
365                actions.push(None);
366                continue;
367            } else if implicit_start_rule.as_ref() == Some(astrulename) {
368                // Add the intermediate start rule (handling implicit tokens at the beginning of
369                // the file):
370                //   ^~: ~ S;
371                rules_prods[usize::from(rule_map[astrulename])].push(PIdx(prods.len().as_()));
372                prods.push(Some(vec![
373                    Symbol::Rule(rule_map[implicit_rule.as_ref().unwrap()]),
374                    Symbol::Rule(rule_map[start_name]),
375                ]));
376                prod_precs.push(Some(None));
377                prods_rules.push(Some(ridx));
378                continue;
379            } else if implicit_rule.as_ref() == Some(astrulename) {
380                // Add the implicit rule: ~: "IMPLICIT_TOKEN_1" ~ | ... | "IMPLICIT_TOKEN_N" ~ | ;
381                let implicit_prods = &mut rules_prods[usize::from(rule_map[astrulename])];
382                // Add a production for each implicit token
383                for (t, _) in ast.implicit_tokens.as_ref().unwrap().iter() {
384                    implicit_prods.push(PIdx(prods.len().as_()));
385                    prods.push(Some(vec![Symbol::Token(token_map[t]), Symbol::Rule(ridx)]));
386                    prod_precs.push(Some(None));
387                    prods_rules.push(Some(ridx));
388                }
389                // Add an empty production
390                implicit_prods.push(PIdx(prods.len().as_()));
391                prods.push(Some(vec![]));
392                prod_precs.push(Some(None));
393                prods_rules.push(Some(ridx));
394                continue;
395            } else {
396                actiontypes[usize::from(ridx)] = ast.rules[astrulename].actiont.clone();
397            }
398
399            let rule = &mut rules_prods[usize::from(ridx)];
400            for &pidx in &ast.rules[astrulename].pidxs {
401                let astprod = &ast.prods[pidx];
402                let mut prod = Vec::with_capacity(astprod.symbols.len());
403                for astsym in &astprod.symbols {
404                    match *astsym {
405                        ast::Symbol::Rule(ref n, _) => {
406                            prod.push(Symbol::Rule(rule_map[n]));
407                        }
408                        ast::Symbol::Token(ref n, _) => {
409                            prod.push(Symbol::Token(token_map[n]));
410                            if let Some(implicit_rule) = &implicit_rule {
411                                prod.push(Symbol::Rule(rule_map[implicit_rule]));
412                            }
413                        }
414                    };
415                }
416                let mut prec = None;
417                if let Some(ref n) = astprod.precedence {
418                    prec = Some(ast.precs[n]);
419                } else {
420                    for astsym in astprod.symbols.iter().rev() {
421                        if let ast::Symbol::Token(ref n, _) = *astsym {
422                            if let Some(p) = ast.precs.get(n) {
423                                prec = Some(*p);
424                            }
425                            break;
426                        }
427                    }
428                }
429                (*rule).push(PIdx(pidx.as_()));
430                prods[pidx] = Some(prod);
431                prod_precs[pidx] = Some(prec.map(|(prec, _)| prec));
432                prods_rules[pidx] = Some(ridx);
433                if let Some((s, span)) = &astprod.action {
434                    actions[pidx] = Some(s.clone());
435                    action_spans[pidx] = Some(*span);
436                }
437            }
438        }
439
440        let avoid_insert = if let Some(ai) = &ast.avoid_insert {
441            let mut aiv = Vob::from_elem(false, token_names.len());
442            for n in ai.keys() {
443                aiv.set(usize::from(token_map[n]), true);
444            }
445            Some(aiv)
446        } else {
447            None
448        };
449
450        assert!(!token_names.is_empty());
451        assert!(!rule_names.is_empty());
452        Ok(YaccGrammar {
453            rules_len: RIdx(rule_names.len().as_()),
454            rule_names: rule_names.into_boxed_slice(),
455            tokens_len: TIdx(token_names.len().as_()),
456            eof_token_idx,
457            token_names: token_names.into_boxed_slice(),
458            token_precs: token_precs.into_boxed_slice(),
459            token_epp: token_epp.into_boxed_slice(),
460            prods_len: PIdx(prods.len().as_()),
461            start_prod: rules_prods[usize::from(rule_map[&start_rule])][0],
462            rules_prods: rules_prods
463                .iter()
464                .map(|x| x.iter().copied().collect())
465                .collect(),
466            prods_rules: prods_rules.into_iter().map(Option::unwrap).collect(),
467            prods: prods
468                .into_iter()
469                .map(|x| x.unwrap().into_boxed_slice())
470                .collect(),
471            prod_precs: prod_precs.into_iter().map(Option::unwrap).collect(),
472            prod_spans: ast.prods.iter().map(|prod| prod.prod_span).collect(),
473            implicit_rule: implicit_rule.map(|x| rule_map[&x]),
474            actions: actions.into_boxed_slice(),
475            action_spans: action_spans.into_boxed_slice(),
476            parse_param: ast.parse_param.clone(),
477            parse_generics: ast.parse_generics.clone(),
478            programs: ast.programs.clone(),
479            avoid_insert,
480            actiontypes: actiontypes.into_boxed_slice(),
481            expect: ast.expect.map(|(n, _)| n),
482            expectrr: ast.expectrr.map(|(n, _)| n),
483        })
484    }
485
486    /// How many productions does this grammar have?
487    pub fn prods_len(&self) -> PIdx<StorageT> {
488        self.prods_len
489    }
490
491    /// Return an iterator which produces (in order from `0..self.prods_len()`) all this
492    /// grammar's valid `PIdx`s.
493    pub fn iter_pidxs(&self) -> impl Iterator<Item = PIdx<StorageT>> {
494        // We can use as_ safely, because we know that we're only generating integers from
495        // 0..self.rules_len() and, since rules_len() returns an RIdx<StorageT>, then by
496        // definition the integers we're creating fit within StorageT.
497        Box::new((0..usize::from(self.prods_len())).map(|x| PIdx(x.as_())))
498    }
499
500    /// Get the sequence of symbols for production `pidx`. Panics if `pidx` doesn't exist.
501    pub fn prod(&self, pidx: PIdx<StorageT>) -> &[Symbol<StorageT>] {
502        &self.prods[usize::from(pidx)]
503    }
504
505    /// How many symbols does production `pidx` have? Panics if `pidx` doesn't exist.
506    pub fn prod_len(&self, pidx: PIdx<StorageT>) -> SIdx<StorageT> {
507        // Since we've already checked that StorageT can store all the symbols for every production
508        // in the grammar, the call to as_ is safe.
509        SIdx(self.prods[usize::from(pidx)].len().as_())
510    }
511
512    /// Return the rule index of the production `pidx`. Panics if `pidx` doesn't exist.
513    pub fn prod_to_rule(&self, pidx: PIdx<StorageT>) -> RIdx<StorageT> {
514        self.prods_rules[usize::from(pidx)]
515    }
516
517    /// Return the precedence of production `pidx` (where `None` indicates "no precedence specified").
518    /// Panics if `pidx` doesn't exist.
519    pub fn prod_precedence(&self, pidx: PIdx<StorageT>) -> Option<Precedence> {
520        self.prod_precs[usize::from(pidx)]
521    }
522
523    /// Return the span for a production `pidx`
524    ///
525    /// May return a zero length span such as when there is an empty production.
526    pub fn prod_span(&self, pidx: PIdx<StorageT>) -> Span {
527        self.prod_spans[usize::from(pidx)]
528    }
529
530    /// Return the production index of the start rule's sole production (for Yacc grammars the
531    /// start rule is defined to have precisely one production).
532    pub fn start_prod(&self) -> PIdx<StorageT> {
533        self.start_prod
534    }
535
536    /// How many rules does this grammar have?
537    pub fn rules_len(&self) -> RIdx<StorageT> {
538        self.rules_len
539    }
540
541    /// Return an iterator which produces (in order from `0..self.rules_len()`) all this
542    /// grammar's valid `RIdx`s.
543    pub fn iter_rules(&self) -> impl Iterator<Item = RIdx<StorageT>> {
544        // We can use as_ safely, because we know that we're only generating integers from
545        // 0..self.rules_len() and, since rules_len() returns an RIdx<StorageT>, then by
546        // definition the integers we're creating fit within StorageT.
547        Box::new((0..usize::from(self.rules_len())).map(|x| RIdx(x.as_())))
548    }
549
550    /// Return the productions for rule `ridx`. Panics if `ridx` doesn't exist.
551    pub fn rule_to_prods(&self, ridx: RIdx<StorageT>) -> &[PIdx<StorageT>] {
552        &self.rules_prods[usize::from(ridx)]
553    }
554
555    /// Return the name of rule `ridx`. Panics if `ridx` doesn't exist.
556    #[deprecated(since = "0.13.0", note = "Please use rule_name_str instead")]
557    pub fn rule_name(&self, ridx: RIdx<StorageT>) -> &str {
558        self.rule_name_str(ridx)
559    }
560
561    /// Return the name of rule `ridx`. Panics if `ridx` doesn't exist.
562    pub fn rule_name_str(&self, ridx: RIdx<StorageT>) -> &str {
563        let (name, _) = &self.rule_names[usize::from(ridx)];
564        name.as_str()
565    }
566
567    /// Return the span of rule `ridx`. Panics if `ridx` doesn't exist.
568    pub fn rule_name_span(&self, ridx: RIdx<StorageT>) -> Span {
569        let (_, span) = self.rule_names[usize::from(ridx)];
570        span
571    }
572
573    /// Return the `RIdx` of the implict rule if it exists, or `None` otherwise.
574    pub fn implicit_rule(&self) -> Option<RIdx<StorageT>> {
575        self.implicit_rule
576    }
577
578    /// Return the index of the rule named `n` or `None` if it doesn't exist.
579    pub fn rule_idx(&self, n: &str) -> Option<RIdx<StorageT>> {
580        self.rule_names
581            .iter()
582            .position(|(x, _)| x == n)
583            // The call to as_() is safe because rule_names is guaranteed to be
584            // small enough to fit into StorageT
585            .map(|x| RIdx(x.as_()))
586    }
587
588    /// What is the index of the start rule? Note that cfgrammar will have inserted at least one
589    /// rule "above" the user's start rule.
590    pub fn start_rule_idx(&self) -> RIdx<StorageT> {
591        self.prod_to_rule(self.start_prod)
592    }
593
594    /// How many tokens does this grammar have?
595    pub fn tokens_len(&self) -> TIdx<StorageT> {
596        self.tokens_len
597    }
598
599    /// Return an iterator which produces (in order from `0..self.tokens_len()`) all this
600    /// grammar's valid `TIdx`s.
601    pub fn iter_tidxs(&self) -> impl Iterator<Item = TIdx<StorageT>> {
602        // We can use as_ safely, because we know that we're only generating integers from
603        // 0..self.rules_len() and, since rules_len() returns an TIdx<StorageT>, then by
604        // definition the integers we're creating fit within StorageT.
605        Box::new((0..usize::from(self.tokens_len())).map(|x| TIdx(x.as_())))
606    }
607
608    /// Return the index of the end token.
609    pub fn eof_token_idx(&self) -> TIdx<StorageT> {
610        self.eof_token_idx
611    }
612
613    /// Return the name of token `tidx` (where `None` indicates "the rule has no name"). Panics if
614    /// `tidx` doesn't exist.
615    pub fn token_name(&self, tidx: TIdx<StorageT>) -> Option<&str> {
616        self.token_names[usize::from(tidx)]
617            .as_ref()
618            .map(|(_, x)| x.as_str())
619    }
620
621    /// Return the precedence of token `tidx` (where `None` indicates "no precedence specified").
622    /// Panics if `tidx` doesn't exist.
623    pub fn token_precedence(&self, tidx: TIdx<StorageT>) -> Option<Precedence> {
624        self.token_precs[usize::from(tidx)]
625    }
626
627    /// Return the %epp entry for token `tidx` (where `None` indicates "the token has no
628    /// pretty-printed value"). Panics if `tidx` doesn't exist.
629    pub fn token_epp(&self, tidx: TIdx<StorageT>) -> Option<&str> {
630        self.token_epp[usize::from(tidx)].as_deref()
631    }
632
633    /// Return the span for token given by `tidx` if one exists.
634    /// If `None`, the token is either implicit and not derived from a token
635    /// in the source, otherwise the `YaccGrammar` itself may not derived from a
636    /// textual source in which case the token may be explicit but still lack spans
637    /// from its construction.
638    pub fn token_span(&self, tidx: TIdx<StorageT>) -> Option<Span> {
639        self.token_names[usize::from(tidx)]
640            .as_ref()
641            .map(|(span, _)| *span)
642    }
643
644    /// Get the action for production `pidx`. Panics if `pidx` doesn't exist.
645    pub fn action(&self, pidx: PIdx<StorageT>) -> &Option<String> {
646        &self.actions[usize::from(pidx)]
647    }
648
649    pub fn action_span(&self, pidx: PIdx<StorageT>) -> Option<Span> {
650        self.action_spans[usize::from(pidx)]
651    }
652
653    pub fn actiontype(&self, ridx: RIdx<StorageT>) -> &Option<String> {
654        &self.actiontypes[usize::from(ridx)]
655    }
656
657    pub fn parse_param(&self) -> &Option<(String, String)> {
658        &self.parse_param
659    }
660
661    pub fn parse_generics(&self) -> &Option<String> {
662        &self.parse_generics
663    }
664
665    /// Get the programs part of the grammar
666    pub fn programs(&self) -> &Option<String> {
667        &self.programs
668    }
669
670    /// Returns a map from names to `TIdx`s of all tokens that a lexer will need to generate valid
671    /// inputs from this grammar.
672    pub fn tokens_map(&self) -> HashMap<&str, TIdx<StorageT>> {
673        let mut m = HashMap::with_capacity(usize::from(self.tokens_len) - 1);
674        for tidx in self.iter_tidxs() {
675            if let Some((_, n)) = self.token_names[usize::from(tidx)].as_ref() {
676                m.insert(&**n, tidx);
677            }
678        }
679        m
680    }
681
682    /// Return the index of the token named `n` or `None` if it doesn't exist.
683    pub fn token_idx(&self, n: &str) -> Option<TIdx<StorageT>> {
684        self.token_names
685            .iter()
686            .position(|x| x.as_ref().is_some_and(|(_, x)| x == n))
687            // The call to as_() is safe because token_names is guaranteed to be small
688            // enough to fit into StorageT
689            .map(|x| TIdx(x.as_()))
690    }
691
692    /// Is the token `tidx` marked as `%avoid_insert`?
693    pub fn avoid_insert(&self, tidx: TIdx<StorageT>) -> bool {
694        if let Some(ai) = &self.avoid_insert {
695            ai.get(usize::from(tidx)).unwrap()
696        } else {
697            false
698        }
699    }
700
701    // How many shift/reduce conflicts were expected?
702    pub fn expect(&self) -> Option<usize> {
703        self.expect
704    }
705
706    // How many reduce/reduce conflicts were expected?
707    pub fn expectrr(&self) -> Option<usize> {
708        self.expectrr
709    }
710
711    /// Is there a path from the `from` rule to the `to` rule? Note that recursive rules
712    /// return `true` for a path from themselves to themselves.
713    pub fn has_path(&self, from: RIdx<StorageT>, to: RIdx<StorageT>) -> bool {
714        let mut seen = vec![];
715        seen.resize(usize::from(self.rules_len()), false);
716        let mut todo = vec![];
717        todo.resize(usize::from(self.rules_len()), false);
718        todo[usize::from(from)] = true;
719        loop {
720            let mut empty = true;
721            for ridx in self.iter_rules() {
722                if !todo[usize::from(ridx)] {
723                    continue;
724                }
725                seen[usize::from(ridx)] = true;
726                todo[usize::from(ridx)] = false;
727                empty = false;
728                for pidx in self.rule_to_prods(ridx).iter() {
729                    for sym in self.prod(*pidx) {
730                        if let Symbol::Rule(p_ridx) = *sym {
731                            if p_ridx == to {
732                                return true;
733                            }
734                            if !seen[usize::from(p_ridx)] {
735                                todo[usize::from(p_ridx)] = true;
736                            }
737                        }
738                    }
739                }
740            }
741            if empty {
742                return false;
743            }
744        }
745    }
746
747    /// Returns the string representation of a given production `pidx`.
748    pub fn pp_prod(&self, pidx: PIdx<StorageT>) -> String {
749        let mut sprod = String::new();
750        let ridx = self.prod_to_rule(pidx);
751        sprod.push_str(self.rule_name_str(ridx));
752        sprod.push(':');
753        for sym in self.prod(pidx) {
754            let s = match sym {
755                Symbol::Token(tidx) => self.token_name(*tidx).unwrap(),
756                Symbol::Rule(ridx) => self.rule_name_str(*ridx),
757            };
758            write!(sprod, " \"{}\"", s).ok();
759        }
760        sprod
761    }
762
763    /// Return a `SentenceGenerator` which can then generate minimal sentences for any rule
764    /// based on the user-defined `token_cost` function which gives the associated cost for
765    /// generating each token (where the cost must be greater than 0). Note that multiple
766    /// tokens can have the same score. The simplest cost function is thus `|_| 1`.
767    pub fn sentence_generator<F>(&self, token_cost: F) -> SentenceGenerator<'_, StorageT>
768    where
769        F: Fn(TIdx<StorageT>) -> u8,
770    {
771        SentenceGenerator::new(self, token_cost)
772    }
773
774    /// Return a `YaccFirsts` struct for this grammar.
775    pub fn firsts(&self) -> YaccFirsts<StorageT> {
776        YaccFirsts::new(self)
777    }
778
779    /// Return a `YaccFirsts` struct for this grammar.
780    pub fn follows(&self) -> YaccFollows<StorageT> {
781        YaccFollows::new(self)
782    }
783}
784
785/// A `SentenceGenerator` can generate minimal sentences for any given rule. e.g. for the
786/// grammar:
787///
788/// ```text
789/// %start A
790/// %%
791/// A: A B | ;
792/// B: C | D;
793/// C: 'x' B | 'x';
794/// D: 'y' B | 'y' 'z';
795/// ```
796///
797/// the following are valid minimal sentences:
798///
799/// ```text
800/// A: []
801/// B: [x]
802/// C: [x]
803/// D: [y, x] or [y, z]
804/// ```
805pub struct SentenceGenerator<'a, StorageT> {
806    grm: &'a YaccGrammar<StorageT>,
807    rule_min_costs: RefCell<Option<Vec<u16>>>,
808    rule_max_costs: RefCell<Option<Vec<u16>>>,
809    token_costs: Vec<u8>,
810}
811
812impl<'a, StorageT: 'static + PrimInt + Unsigned> SentenceGenerator<'a, StorageT>
813where
814    usize: AsPrimitive<StorageT>,
815{
816    fn new<F>(grm: &'a YaccGrammar<StorageT>, token_cost: F) -> Self
817    where
818        F: Fn(TIdx<StorageT>) -> u8,
819    {
820        let mut token_costs = Vec::with_capacity(usize::from(grm.tokens_len()));
821        for tidx in grm.iter_tidxs() {
822            token_costs.push(token_cost(tidx));
823        }
824        SentenceGenerator {
825            grm,
826            token_costs,
827            rule_min_costs: RefCell::new(None),
828            rule_max_costs: RefCell::new(None),
829        }
830    }
831
832    /// What is the cost of a minimal sentence for the rule `ridx`? Note that, unlike
833    /// `min_sentence`, this function does not actually *build* a sentence and it is thus much
834    /// faster.
835    pub fn min_sentence_cost(&self, ridx: RIdx<StorageT>) -> u16 {
836        self.rule_min_costs
837            .borrow_mut()
838            .get_or_insert_with(|| rule_min_costs(self.grm, &self.token_costs))[usize::from(ridx)]
839    }
840
841    /// What is the cost of a maximal sentence for the rule `ridx`? Rules which can generate
842    /// sentences of unbounded length return None; rules which can only generate maximal strings of
843    /// a finite length return a `Some(u16)`.
844    pub fn max_sentence_cost(&self, ridx: RIdx<StorageT>) -> Option<u16> {
845        let v = self
846            .rule_max_costs
847            .borrow_mut()
848            .get_or_insert_with(|| rule_max_costs(self.grm, &self.token_costs))[usize::from(ridx)];
849        if v == u16::MAX { None } else { Some(v) }
850    }
851
852    /// Non-deterministically return a minimal sentence from the set of minimal sentences for the
853    /// rule `ridx`.
854    pub fn min_sentence(&self, ridx: RIdx<StorageT>) -> Vec<TIdx<StorageT>> {
855        let cheapest_prod = |p_ridx: RIdx<StorageT>| -> PIdx<StorageT> {
856            let mut low_sc = None;
857            let mut low_idx = None;
858            for &pidx in self.grm.rule_to_prods(p_ridx).iter() {
859                let mut sc = 0;
860                for sym in self.grm.prod(pidx).iter() {
861                    sc += match *sym {
862                        Symbol::Rule(i) => self.min_sentence_cost(i),
863                        Symbol::Token(i) => u16::from(self.token_costs[usize::from(i)]),
864                    };
865                }
866                if low_sc.is_none() || Some(sc) < low_sc {
867                    low_sc = Some(sc);
868                    low_idx = Some(pidx);
869                }
870            }
871            low_idx.unwrap()
872        };
873
874        let mut s = vec![];
875        let mut st = vec![(cheapest_prod(ridx), 0)];
876        while let Some((pidx, sym_idx)) = st.pop() {
877            let prod = self.grm.prod(pidx);
878            for (sidx, sym) in prod.iter().enumerate().skip(sym_idx) {
879                match sym {
880                    Symbol::Rule(s_ridx) => {
881                        st.push((pidx, sidx + 1));
882                        st.push((cheapest_prod(*s_ridx), 0));
883                    }
884                    Symbol::Token(s_tidx) => {
885                        s.push(*s_tidx);
886                    }
887                }
888            }
889        }
890        s
891    }
892
893    /// Return (in arbitrary order) all the minimal sentences for the rule `ridx`.
894    pub fn min_sentences(&self, ridx: RIdx<StorageT>) -> Vec<Vec<TIdx<StorageT>>> {
895        let cheapest_prods = |p_ridx: RIdx<StorageT>| -> Vec<PIdx<StorageT>> {
896            let mut low_sc = None;
897            let mut low_idxs = vec![];
898            for &pidx in self.grm.rule_to_prods(p_ridx).iter() {
899                let mut sc = 0;
900                for sym in self.grm.prod(pidx).iter() {
901                    sc += match *sym {
902                        Symbol::Rule(s_ridx) => self.min_sentence_cost(s_ridx),
903                        Symbol::Token(s_tidx) => u16::from(self.token_costs[usize::from(s_tidx)]),
904                    };
905                }
906                if low_sc.is_none() || Some(sc) <= low_sc {
907                    if Some(sc) < low_sc {
908                        low_idxs.clear();
909                    }
910                    low_sc = Some(sc);
911                    low_idxs.push(pidx);
912                }
913            }
914            low_idxs
915        };
916
917        let mut sts = Vec::new(); // Output sentences
918        for pidx in cheapest_prods(ridx) {
919            let prod = self.grm.prod(pidx);
920            if prod.is_empty() {
921                sts.push(vec![]);
922                continue;
923            }
924
925            // We construct the minimal sentences in two phases.
926            //
927            // First, for each symbol in the production, we gather all the possible minimal
928            // sentences for it. If, for the grammar:
929            //   X: 'a' Y
930            //   Y: 'b' | 'c'
931            // we ask for the minimal sentences of X's only production we'll end up with a vec of
932            // vecs as follows:
933            //   [[['a']], [['b'], ['c']]]
934
935            let mut ms = Vec::with_capacity(prod.len());
936            for sym in prod {
937                match *sym {
938                    Symbol::Rule(s_ridx) => ms.push(self.min_sentences(s_ridx)),
939                    Symbol::Token(s_tidx) => ms.push(vec![vec![s_tidx]]),
940                }
941            }
942
943            // Second, we need to generate all combinations of the gathered sentences. We do this
944            // by writing our own simple numeric incrementing scheme. If we rewrite the list from
945            // above as follows:
946            //
947            //      0 1 <- call this axis "i"
948            //   0: a b
949            //   1:   c
950            //   ^
951            //   |
952            //   call this axis "todo"
953            //
954            // this hopefully becomes easier to see. Let's call the list "ms": the combinations we
955            // need to generate are thus:
956            //
957            //   ms[0][0] + ms[1][0]  (i.e. 'ab')
958            //   ms[0][0] + ms[1][1]  (i.e. 'ac')
959            //
960            // The easiest way to model this is to have a list (todo) with each entry starting at
961            // 0. After each iteration around the loop (i) we add 1 to the last todo column's
962            // entry: if that spills over the length of the corresponding ms entry, then we reset
963            // that column to zero, and try adding 1 to the previous column (as many times as
964            // needed). If the first column spills, then we're done. This is basically normal
965            // arithmetic but with each digit having an arbitrary base.
966
967            let mut todo = vec![0; prod.len()];
968            let mut cur = Vec::new();
969            'b: loop {
970                for i in 0..todo.len() {
971                    cur.extend(&ms[i][todo[i]]);
972                }
973                sts.push(std::mem::take(&mut cur));
974
975                let mut j = todo.len() - 1;
976                loop {
977                    if todo[j] + 1 == ms[j].len() {
978                        if j == 0 {
979                            break 'b;
980                        }
981                        todo[j] = 0;
982                        j -= 1;
983                    } else {
984                        todo[j] += 1;
985                        break;
986                    }
987                }
988            }
989        }
990        sts
991    }
992}
993
994/// Return the cost of a minimal string for each rule in this grammar. The cost of a
995/// token is specified by the user-defined `token_cost` function.
996#[allow(clippy::unnecessary_unwrap)]
997fn rule_min_costs<StorageT: 'static + PrimInt + Unsigned>(
998    grm: &YaccGrammar<StorageT>,
999    token_costs: &[u8],
1000) -> Vec<u16>
1001where
1002    usize: AsPrimitive<StorageT>,
1003{
1004    // We use a simple(ish) fixed-point algorithm to determine costs. We maintain two lists
1005    // "costs" and "done". An integer costs[i] starts at 0 and monotonically increments
1006    // until done[i] is true, at which point costs[i] value is fixed. We also use the done
1007    // list as a simple "todo" list: whilst there is at least one false value in done, there is
1008    // still work to do.
1009    //
1010    // On each iteration of the loop, we examine each rule in the todo list to see if
1011    // we can get a better idea of its true cost. Some are trivial:
1012    //   * A rule with an empty production immediately has a cost of 0.
1013    //   * Rules whose productions don't reference any rules (i.e. only contain tokens) can be
1014    //     immediately given a cost by calculating the lowest-cost production.
1015    // However if a rule A references another rule B, we may need to wait until
1016    // we've fully analysed B before we can cost A. This might seem to cause problems with
1017    // recursive rules, so we introduce the concept of "incomplete costs" i.e. if a production
1018    // references a rule we can work out its minimum possible cost simply by counting
1019    // the production's token costs. Since rules can have a mix of complete and
1020    // incomplete productions, this is sometimes enough to allow us to assign a final cost to
1021    // a rule (if the lowest complete production's cost is lower than or equal to all
1022    // the lowest incomplete production's cost). This allows us to make progress, since it
1023    // means that we can iteratively improve our knowledge of a token's minimum cost:
1024    // eventually we will reach a point where we can determine it definitively.
1025
1026    let mut costs = vec![0; usize::from(grm.rules_len())];
1027    let mut done = vec![false; usize::from(grm.rules_len())];
1028    loop {
1029        let mut all_done = true;
1030        for i in 0..done.len() {
1031            if done[i] {
1032                continue;
1033            }
1034            all_done = false;
1035            let mut ls_cmplt = None; // lowest completed cost
1036            let mut ls_noncmplt = None; // lowest non-completed cost
1037
1038            // The call to as_() is guaranteed safe because done.len() == grm.rules_len(), and
1039            // we guarantee that grm.rules_len() can fit in StorageT.
1040            for pidx in grm.rule_to_prods(RIdx(i.as_())).iter() {
1041                let mut c: u16 = 0; // production cost
1042                let mut cmplt = true;
1043                for sym in grm.prod(*pidx) {
1044                    let sc = match *sym {
1045                        Symbol::Token(tidx) => u16::from(token_costs[usize::from(tidx)]),
1046                        Symbol::Rule(ridx) => {
1047                            if !done[usize::from(ridx)] {
1048                                cmplt = false;
1049                            }
1050                            costs[usize::from(ridx)]
1051                        }
1052                    };
1053                    c = c
1054                        .checked_add(sc)
1055                        .expect("Overflow occurred when calculating rule costs");
1056                }
1057                if cmplt && (ls_cmplt.is_none() || Some(c) < ls_cmplt) {
1058                    ls_cmplt = Some(c);
1059                } else if !cmplt && (ls_noncmplt.is_none() || Some(c) < ls_noncmplt) {
1060                    ls_noncmplt = Some(c);
1061                }
1062            }
1063            if ls_cmplt.is_some() && (ls_noncmplt.is_none() || ls_cmplt < ls_noncmplt) {
1064                debug_assert!(ls_cmplt.unwrap() >= costs[i]);
1065                costs[i] = ls_cmplt.unwrap();
1066                done[i] = true;
1067            } else if let Some(ls_noncmplt) = ls_noncmplt {
1068                debug_assert!(ls_noncmplt >= costs[i]);
1069                costs[i] = ls_noncmplt;
1070            }
1071        }
1072        if all_done {
1073            debug_assert!(done.iter().all(|x| *x));
1074            break;
1075        }
1076    }
1077    costs
1078}
1079
1080/// Return the cost of the maximal string for each rule in this grammar (u32::max_val()
1081/// representing "this rule can generate strings of infinite length"). The cost of a
1082/// token is specified by the user-defined `token_cost` function.
1083#[allow(clippy::unnecessary_unwrap)]
1084fn rule_max_costs<StorageT: 'static + PrimInt + Unsigned>(
1085    grm: &YaccGrammar<StorageT>,
1086    token_costs: &[u8],
1087) -> Vec<u16>
1088where
1089    usize: AsPrimitive<StorageT>,
1090{
1091    let mut done = vec![false; usize::from(grm.rules_len())];
1092    let mut costs = vec![0; usize::from(grm.rules_len())];
1093
1094    // First mark all recursive rules.
1095    for ridx in grm.iter_rules() {
1096        // Calling has_path so frequently is not exactly efficient...
1097        if grm.has_path(ridx, ridx) {
1098            costs[usize::from(ridx)] = u16::MAX;
1099            done[usize::from(ridx)] = true;
1100        }
1101    }
1102
1103    loop {
1104        let mut all_done = true;
1105        for i in 0..done.len() {
1106            if done[i] {
1107                continue;
1108            }
1109            all_done = false;
1110            let mut hs_cmplt = None; // highest completed cost
1111            let mut hs_noncmplt = None; // highest non-completed cost
1112
1113            // The call to as_() is guaranteed safe because done.len() == grm.rules_len(), and
1114            // we guarantee that grm.rules_len() can fit in StorageT.
1115            'a: for pidx in grm.rule_to_prods(RIdx(i.as_())).iter() {
1116                let mut c: u16 = 0; // production cost
1117                let mut cmplt = true;
1118                for sym in grm.prod(*pidx) {
1119                    let sc = match *sym {
1120                        Symbol::Token(s_tidx) => u16::from(token_costs[usize::from(s_tidx)]),
1121                        Symbol::Rule(s_ridx) => {
1122                            if costs[usize::from(s_ridx)] == u16::MAX {
1123                                // As soon as we find reference to an infinite rule, we
1124                                // can stop looking.
1125                                hs_cmplt = Some(u16::MAX);
1126                                break 'a;
1127                            }
1128                            if !done[usize::from(s_ridx)] {
1129                                cmplt = false;
1130                            }
1131                            costs[usize::from(s_ridx)]
1132                        }
1133                    };
1134                    c = c
1135                        .checked_add(sc)
1136                        .expect("Overflow occurred when calculating rule costs");
1137                    if c == u16::MAX {
1138                        panic!("Unable to represent cost in 64 bits.");
1139                    }
1140                }
1141                if cmplt && (hs_cmplt.is_none() || Some(c) > hs_cmplt) {
1142                    hs_cmplt = Some(c);
1143                } else if !cmplt && (hs_noncmplt.is_none() || Some(c) > hs_noncmplt) {
1144                    hs_noncmplt = Some(c);
1145                }
1146            }
1147            if hs_cmplt.is_some() && (hs_noncmplt.is_none() || hs_cmplt > hs_noncmplt) {
1148                debug_assert!(hs_cmplt.unwrap() >= costs[i]);
1149                costs[i] = hs_cmplt.unwrap();
1150                done[i] = true;
1151            } else if let Some(hs_noncmplt) = hs_noncmplt {
1152                debug_assert!(hs_noncmplt >= costs[i]);
1153                costs[i] = hs_noncmplt;
1154            }
1155        }
1156        if all_done {
1157            debug_assert!(done.iter().all(|x| *x));
1158            break;
1159        }
1160    }
1161    costs
1162}
1163
1164#[cfg(test)]
1165mod test {
1166    use super::{
1167        super::{AssocKind, Precedence, YaccGrammar, YaccKind, YaccOriginalActionKind},
1168        IMPLICIT_RULE, IMPLICIT_START_RULE, rule_max_costs, rule_min_costs,
1169    };
1170    use crate::{PIdx, RIdx, Span, Symbol, TIdx};
1171    use std::collections::HashMap;
1172    use std::str::FromStr;
1173
1174    macro_rules! bslice {
1175        () => (
1176            ::Vec::new().into_boxed_slice()
1177        );
1178        ($elem:expr; $n:expr) => (
1179            ::vec::from_elem($elem, $n).into_boxed_slice()
1180        );
1181        ($($x:expr),+ $(,)?) => (
1182            <[_]>::into_vec(
1183                Box::new([$($x),+])
1184            ).into_boxed_slice()
1185        );
1186    }
1187
1188    #[test]
1189    fn test_minimal() {
1190        let grm = YaccGrammar::new(
1191            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1192            "%start R %token T %% R: 'T';",
1193        )
1194        .unwrap();
1195
1196        assert_eq!(grm.start_prod, PIdx(1));
1197        assert_eq!(grm.implicit_rule(), None);
1198        grm.rule_idx("^").unwrap();
1199        grm.rule_idx("R").unwrap();
1200        grm.token_idx("T").unwrap();
1201
1202        assert_eq!(&*grm.rules_prods, &[bslice![PIdx(1)], bslice![PIdx(0)]]);
1203        let start_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("^").unwrap())][0]);
1204        assert_eq!(*start_prod, [Symbol::Rule(grm.rule_idx("R").unwrap())]);
1205        let r_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("R").unwrap())][0]);
1206        assert_eq!(*r_prod, [Symbol::Token(grm.token_idx("T").unwrap())]);
1207        assert_eq!(&*grm.prods_rules, &[RIdx(1), RIdx(0)]);
1208
1209        assert_eq!(
1210            grm.tokens_map(),
1211            [("T", TIdx(0))]
1212                .iter()
1213                .cloned()
1214                .collect::<HashMap<&str, TIdx<_>>>()
1215        );
1216        assert_eq!(grm.iter_rules().collect::<Vec<_>>(), vec![RIdx(0), RIdx(1)]);
1217    }
1218
1219    #[test]
1220    fn test_rule_ref() {
1221        let grm = YaccGrammar::new(
1222            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1223            "%start R %token T %% R : S; S: 'T';",
1224        )
1225        .unwrap();
1226
1227        grm.rule_idx("^").unwrap();
1228        grm.rule_idx("R").unwrap();
1229        grm.rule_idx("S").unwrap();
1230        grm.token_idx("T").unwrap();
1231        assert!(grm.token_name(grm.eof_token_idx()).is_none());
1232
1233        assert_eq!(
1234            &*grm.rules_prods,
1235            &[bslice![PIdx(2)], bslice![PIdx(0)], bslice![PIdx(1)]]
1236        );
1237        let start_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("^").unwrap())][0]);
1238        assert_eq!(*start_prod, [Symbol::Rule(grm.rule_idx("R").unwrap())]);
1239        let r_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("R").unwrap())][0]);
1240        assert_eq!(r_prod.len(), 1);
1241        assert_eq!(r_prod[0], Symbol::Rule(grm.rule_idx("S").unwrap()));
1242        let s_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("S").unwrap())][0]);
1243        assert_eq!(s_prod.len(), 1);
1244        assert_eq!(s_prod[0], Symbol::Token(grm.token_idx("T").unwrap()));
1245    }
1246
1247    #[test]
1248    #[rustfmt::skip]
1249    fn test_long_prod() {
1250        let grm = YaccGrammar::new(
1251            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1252            "%start R %token T1 T2 %% R : S 'T1' S; S: 'T2';"
1253        ).unwrap();
1254
1255        grm.rule_idx("^").unwrap();
1256        grm.rule_idx("R").unwrap();
1257        grm.rule_idx("S").unwrap();
1258        grm.token_idx("T1").unwrap();
1259        grm.token_idx("T2").unwrap();
1260
1261        assert_eq!(&*grm.rules_prods, &[bslice![PIdx(2)],
1262                                         bslice![PIdx(0)],
1263                                         bslice![PIdx(1)]]);
1264        assert_eq!(&*grm.prods_rules, &[RIdx(1),
1265                                         RIdx(2),
1266                                         RIdx(0)]);
1267        let start_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("^").unwrap())][0]);
1268        assert_eq!(*start_prod, [Symbol::Rule(grm.rule_idx("R").unwrap())]);
1269        let r_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("R").unwrap())][0]);
1270        assert_eq!(r_prod.len(), 3);
1271        assert_eq!(r_prod[0], Symbol::Rule(grm.rule_idx("S").unwrap()));
1272        assert_eq!(r_prod[1], Symbol::Token(grm.token_idx("T1").unwrap()));
1273        assert_eq!(r_prod[2], Symbol::Rule(grm.rule_idx("S").unwrap()));
1274        let s_prod = grm.prod(grm.rules_prods[usize::from(grm.rule_idx("S").unwrap())][0]);
1275        assert_eq!(s_prod.len(), 1);
1276        assert_eq!(s_prod[0], Symbol::Token(grm.token_idx("T2").unwrap()));
1277    }
1278
1279    #[test]
1280    fn test_prods_rules() {
1281        let grm = YaccGrammar::new(
1282            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1283            "
1284            %start A
1285            %%
1286            A: B
1287             | C;
1288            B: 'x';
1289            C: 'y'
1290             | 'z';
1291          ",
1292        )
1293        .unwrap();
1294
1295        assert_eq!(
1296            &*grm.prods_rules,
1297            &[RIdx(1), RIdx(1), RIdx(2), RIdx(3), RIdx(3), RIdx(0)]
1298        );
1299    }
1300
1301    #[test]
1302    #[rustfmt::skip]
1303    fn test_left_right_nonassoc_precs() {
1304        let grm = YaccGrammar::new(
1305            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1306            "
1307            %start Expr
1308            %right '='
1309            %left '+' '-'
1310            %left '/'
1311            %left '*'
1312            %nonassoc '~'
1313            %%
1314            Expr : Expr '=' Expr
1315                 | Expr '+' Expr
1316                 | Expr '-' Expr
1317                 | Expr '/' Expr
1318                 | Expr '*' Expr
1319                 | Expr '~' Expr
1320                 | 'id' ;
1321          ").unwrap();
1322
1323        assert_eq!(grm.prod_precs.len(), 8);
1324        assert_eq!(grm.prod_precs[0].unwrap(), Precedence{level: 0, kind: AssocKind::Right});
1325        assert_eq!(grm.prod_precs[1].unwrap(), Precedence{level: 1, kind: AssocKind::Left});
1326        assert_eq!(grm.prod_precs[2].unwrap(), Precedence{level: 1, kind: AssocKind::Left});
1327        assert_eq!(grm.prod_precs[3].unwrap(), Precedence{level: 2, kind: AssocKind::Left});
1328        assert_eq!(grm.prod_precs[4].unwrap(), Precedence{level: 3, kind: AssocKind::Left});
1329        assert_eq!(grm.prod_precs[5].unwrap(), Precedence{level: 4, kind: AssocKind::Nonassoc});
1330        assert!(grm.prod_precs[6].is_none());
1331        assert_eq!(grm.prod_precs[7], None);
1332    }
1333
1334    #[test]
1335    #[rustfmt::skip]
1336    fn test_prec_override() {
1337        let grm = YaccGrammar::new(
1338            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1339            "
1340            %start expr
1341            %left '+' '-'
1342            %left '*' '/'
1343            %%
1344            expr : expr '+' expr
1345                 | expr '-' expr
1346                 | expr '*' expr
1347                 | expr '/' expr
1348                 | '-'  expr %prec '*'
1349                 | 'id' ;
1350        "
1351        ).unwrap();
1352        assert_eq!(grm.prod_precs.len(), 7);
1353        assert_eq!(grm.prod_precs[0].unwrap(), Precedence{level: 0, kind: AssocKind::Left});
1354        assert_eq!(grm.prod_precs[1].unwrap(), Precedence{level: 0, kind: AssocKind::Left});
1355        assert_eq!(grm.prod_precs[2].unwrap(), Precedence{level: 1, kind: AssocKind::Left});
1356        assert_eq!(grm.prod_precs[3].unwrap(), Precedence{level: 1, kind: AssocKind::Left});
1357        assert_eq!(grm.prod_precs[4].unwrap(), Precedence{level: 1, kind: AssocKind::Left});
1358        assert!(grm.prod_precs[5].is_none());
1359        assert_eq!(grm.prod_precs[6], None);
1360    }
1361
1362    #[test]
1363    #[rustfmt::skip]
1364    fn test_implicit_tokens_rewrite() {
1365        let grm = YaccGrammar::new(
1366            YaccKind::Eco,
1367            "
1368          %implicit_tokens ws1 ws2
1369          %start S
1370          %%
1371          S: 'a' | T;
1372          T: 'c' |;
1373          "
1374        ).unwrap();
1375
1376        // Check that the above grammar has been rewritten to:
1377        //   ^ : ^~;
1378        //   ^~: ~ S;
1379        //   ~ : ws1 | ws2 | ;
1380        //   S : 'a' ~ | T;
1381        //   T : 'c' ~ | ;
1382
1383        assert_eq!(grm.prod_precs.len(), 9);
1384
1385        let itfs_rule_idx = grm.rule_idx(IMPLICIT_START_RULE).unwrap();
1386        assert_eq!(grm.rules_prods[usize::from(itfs_rule_idx)].len(), 1);
1387
1388        let itfs_prod1 = &grm.prods[usize::from(grm.rules_prods[usize::from(itfs_rule_idx)][0])];
1389        assert_eq!(itfs_prod1.len(), 2);
1390        assert_eq!(itfs_prod1[0], Symbol::Rule(grm.rule_idx(IMPLICIT_RULE).unwrap()));
1391        assert_eq!(itfs_prod1[1], Symbol::Rule(grm.rule_idx("S").unwrap()));
1392
1393        let s_rule_idx = grm.rule_idx("S").unwrap();
1394        assert_eq!(grm.rules_prods[usize::from(s_rule_idx)].len(), 2);
1395
1396        let s_prod1 = &grm.prods[usize::from(grm.rules_prods[usize::from(s_rule_idx)][0])];
1397        assert_eq!(s_prod1.len(), 2);
1398        assert_eq!(s_prod1[0], Symbol::Token(grm.token_idx("a").unwrap()));
1399        assert_eq!(s_prod1[1], Symbol::Rule(grm.rule_idx(IMPLICIT_RULE).unwrap()));
1400
1401        let s_prod2 = &grm.prods[usize::from(grm.rules_prods[usize::from(s_rule_idx)][1])];
1402        assert_eq!(s_prod2.len(), 1);
1403        assert_eq!(s_prod2[0], Symbol::Rule(grm.rule_idx("T").unwrap()));
1404
1405        let t_rule_idx = grm.rule_idx("T").unwrap();
1406        assert_eq!(grm.rules_prods[usize::from(s_rule_idx)].len(), 2);
1407
1408        let t_prod1 = &grm.prods[usize::from(grm.rules_prods[usize::from(t_rule_idx)][0])];
1409        assert_eq!(t_prod1.len(), 2);
1410        assert_eq!(t_prod1[0], Symbol::Token(grm.token_idx("c").unwrap()));
1411        assert_eq!(t_prod1[1], Symbol::Rule(grm.rule_idx(IMPLICIT_RULE).unwrap()));
1412
1413        let t_prod2 = &grm.prods[usize::from(grm.rules_prods[usize::from(t_rule_idx)][1])];
1414        assert_eq!(t_prod2.len(), 0);
1415
1416        assert_eq!(Some(grm.rule_idx(IMPLICIT_RULE).unwrap()), grm.implicit_rule());
1417        let i_rule_idx = grm.rule_idx(IMPLICIT_RULE).unwrap();
1418        assert_eq!(grm.rules_prods[usize::from(i_rule_idx)].len(), 3);
1419        let i_prod1 = &grm.prods[usize::from(grm.rules_prods[usize::from(i_rule_idx)][0])];
1420        let i_prod2 = &grm.prods[usize::from(grm.rules_prods[usize::from(i_rule_idx)][1])];
1421        assert_eq!(i_prod1.len(), 2);
1422        assert_eq!(i_prod2.len(), 2);
1423        // We don't know what order the implicit rule will contain our tokens in,
1424        // hence the awkward dance below.
1425        let cnd1 = bslice![
1426            Symbol::Token(grm.token_idx("ws1").unwrap()),
1427            Symbol::Rule(grm.implicit_rule().unwrap()),
1428        ];
1429        let cnd2 = bslice![
1430            Symbol::Token(grm.token_idx("ws2").unwrap()),
1431            Symbol::Rule(grm.implicit_rule().unwrap()),
1432        ];
1433        assert!((*i_prod1 == cnd1 && *i_prod2 == cnd2) || (*i_prod1 == cnd2 && *i_prod2 == cnd1));
1434        let i_prod3 = &grm.prods[usize::from(grm.rules_prods[usize::from(i_rule_idx)][2])];
1435        assert_eq!(i_prod3.len(), 0);
1436    }
1437
1438    #[test]
1439    #[rustfmt::skip]
1440    fn test_has_path() {
1441        let grm = YaccGrammar::new(
1442            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1443            "
1444            %start A
1445            %%
1446            A: B;
1447            B: B 'x' | C;
1448            C: C 'y' | ;
1449          "
1450        ).unwrap();
1451
1452        let a_ridx = grm.rule_idx("A").unwrap();
1453        let b_ridx = grm.rule_idx("B").unwrap();
1454        let c_ridx = grm.rule_idx("C").unwrap();
1455        assert!(grm.has_path(a_ridx, b_ridx));
1456        assert!(grm.has_path(a_ridx, c_ridx));
1457        assert!(grm.has_path(b_ridx, b_ridx));
1458        assert!(grm.has_path(b_ridx, c_ridx));
1459        assert!(grm.has_path(c_ridx, c_ridx));
1460        assert!(!grm.has_path(a_ridx, a_ridx));
1461        assert!(!grm.has_path(b_ridx, a_ridx));
1462        assert!(!grm.has_path(c_ridx, a_ridx));
1463    }
1464
1465    #[test]
1466    #[rustfmt::skip]
1467    fn test_rule_min_costs() {
1468        let grm = YaccGrammar::new(
1469            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1470            "
1471            %start A
1472            %%
1473            A: A B | ;
1474            B: C | D | E;
1475            C: 'x' B | 'x';
1476            D: 'y' B | 'y' 'z';
1477            E: 'x' A | 'x' 'y';
1478          "
1479        ).unwrap();
1480
1481        let scores = rule_min_costs(&grm, &[1, 1, 1]);
1482        assert_eq!(scores[usize::from(grm.rule_idx("A").unwrap())], 0);
1483        assert_eq!(scores[usize::from(grm.rule_idx("B").unwrap())], 1);
1484        assert_eq!(scores[usize::from(grm.rule_idx("C").unwrap())], 1);
1485        assert_eq!(scores[usize::from(grm.rule_idx("D").unwrap())], 2);
1486        assert_eq!(scores[usize::from(grm.rule_idx("E").unwrap())], 1);
1487    }
1488
1489    #[test]
1490    fn test_min_sentences() {
1491        let grm = YaccGrammar::new(
1492            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1493            "
1494            %start A
1495            %%
1496            A: A B | ;
1497            B: C | D;
1498            C: 'x' B | 'x';
1499            D: 'y' B | 'y' 'z';
1500          ",
1501        )
1502        .unwrap();
1503
1504        let sg = grm.sentence_generator(|_| 1);
1505
1506        let find = |nt_name: &str, str_cnds: Vec<Vec<&str>>| {
1507            let cnds = str_cnds
1508                .iter()
1509                .map(|x| {
1510                    x.iter()
1511                        .map(|y| grm.token_idx(y).unwrap())
1512                        .collect::<Vec<_>>()
1513                })
1514                .collect::<Vec<_>>();
1515
1516            let ms = sg.min_sentence(grm.rule_idx(nt_name).unwrap());
1517            if !cnds.iter().any(|x| x == &ms) {
1518                panic!("{:?} doesn't have any matches in {:?}", ms, str_cnds);
1519            }
1520
1521            let min_sts = sg.min_sentences(grm.rule_idx(nt_name).unwrap());
1522            assert_eq!(cnds.len(), min_sts.len());
1523            for ms in min_sts {
1524                if !cnds.iter().any(|x| x == &ms) {
1525                    panic!("{:?} doesn't have any matches in {:?}", ms, str_cnds);
1526                }
1527            }
1528        };
1529
1530        find("A", vec![vec![]]);
1531        find("B", vec![vec!["x"]]);
1532        find("C", vec![vec!["x"]]);
1533        find("D", vec![vec!["y", "x"], vec!["y", "z"]]);
1534    }
1535
1536    #[test]
1537    #[rustfmt::skip]
1538    fn test_rule_max_costs1() {
1539        let grm = YaccGrammar::new(
1540            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1541            "
1542            %start A
1543            %%
1544            A: A B | ;
1545            B: C | D | E;
1546            C: 'x' B | 'x';
1547            D: 'y' B | 'y' 'z';
1548            E: 'x' A | 'x' 'y';
1549          "
1550        ).unwrap();
1551
1552        let scores = rule_max_costs(&grm, &[1, 1, 1]);
1553        assert_eq!(scores[usize::from(grm.rule_idx("A").unwrap())], u16::MAX);
1554        assert_eq!(scores[usize::from(grm.rule_idx("B").unwrap())], u16::MAX);
1555        assert_eq!(scores[usize::from(grm.rule_idx("C").unwrap())], u16::MAX);
1556        assert_eq!(scores[usize::from(grm.rule_idx("D").unwrap())], u16::MAX);
1557        assert_eq!(scores[usize::from(grm.rule_idx("E").unwrap())], u16::MAX);
1558    }
1559
1560    #[test]
1561    #[rustfmt::skip]
1562    fn test_rule_max_costs2() {
1563        let grm = YaccGrammar::new(
1564            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1565            "
1566            %start A
1567            %%
1568            A: A B | B;
1569            B: C | D;
1570            C: 'x' 'y' | 'x';
1571            D: 'y' 'x' | 'y' 'x' 'z';
1572          "
1573        ).unwrap();
1574
1575        let scores = rule_max_costs(&grm, &[1, 1, 1]);
1576        assert_eq!(scores[usize::from(grm.rule_idx("A").unwrap())], u16::MAX);
1577        assert_eq!(scores[usize::from(grm.rule_idx("B").unwrap())], 3);
1578        assert_eq!(scores[usize::from(grm.rule_idx("C").unwrap())], 2);
1579        assert_eq!(scores[usize::from(grm.rule_idx("D").unwrap())], 3);
1580    }
1581
1582    #[test]
1583    fn test_out_of_order_productions() {
1584        // Example taken from p54 of Locally least-cost error repair in LR parsers, Carl Cerecke
1585        let grm = YaccGrammar::new(
1586            YaccKind::Original(YaccOriginalActionKind::GenericParseTree),
1587            "
1588            %start S
1589            %%
1590            S: A 'c' 'd'
1591             | B 'c' 'e';
1592            A: 'a';
1593            B: 'a'
1594             | 'b';
1595            A: 'b';
1596            ",
1597        )
1598        .unwrap();
1599
1600        assert_eq!(
1601            &*grm.prods_rules,
1602            &[
1603                RIdx(1),
1604                RIdx(1),
1605                RIdx(2),
1606                RIdx(3),
1607                RIdx(3),
1608                RIdx(2),
1609                RIdx(0)
1610            ]
1611        );
1612    }
1613
1614    #[test]
1615    fn test_token_spans() {
1616        let src = "%%\nAB: 'a' | 'foo';";
1617        let grm =
1618            YaccGrammar::new(YaccKind::Original(YaccOriginalActionKind::NoAction), src).unwrap();
1619        let token_map = grm.tokens_map();
1620        let a_tidx = token_map.get("a");
1621        let foo_tidx = token_map.get("foo");
1622        let a_span = grm.token_span(*a_tidx.unwrap()).unwrap();
1623        let foo_span = grm.token_span(*foo_tidx.unwrap()).unwrap();
1624        let ab_span = grm.rule_name_span(grm.rule_idx("AB").unwrap());
1625        assert_eq!(a_span, Span::new(8, 9));
1626        assert_eq!(foo_span, Span::new(14, 17));
1627        assert_eq!(ab_span, Span::new(3, 5));
1628        assert_eq!(&src[a_span.start()..a_span.end()], "a");
1629        assert_eq!(&src[foo_span.start()..foo_span.end()], "foo");
1630        assert_eq!(&src[ab_span.start()..ab_span.end()], "AB");
1631    }
1632
1633    #[test]
1634    fn token_span_issue296() {
1635        let src = "%%
1636                   S: | AB;
1637                   A: 'a' 'b';
1638                   B: 'b' 'c';
1639                   AB: A AB | B ';' AB;
1640                   %%
1641                   ";
1642        let grm =
1643            YaccGrammar::new(YaccKind::Original(YaccOriginalActionKind::NoAction), src).unwrap();
1644        let token_map = grm.tokens_map();
1645        let c_tidx = token_map.get("c").unwrap();
1646        assert_eq!(grm.token_name(*c_tidx), Some("c"));
1647        let c_span = grm.token_span(*c_tidx).unwrap();
1648        assert_eq!(&src[c_span.start()..c_span.end()], "c");
1649    }
1650
1651    #[test]
1652    fn test_grmtools_section_yacckinds() {
1653        let srcs = [
1654            "%grmtools{yacckind: Original(NoAction)}
1655                 %%
1656                 Start: ;",
1657            "%grmtools{yacckind: YaccKind::Original(GenericParseTree)}
1658                 %%
1659                 Start: ;",
1660            "%grmtools{yacckind: YaccKind::Original(yaccoriginalactionkind::useraction)}
1661                 %actiontype ()
1662                 %%
1663                 Start: ;",
1664            "%grmtools{yacckind: Original(YACCOriginalActionKind::NoAction)}
1665                 %%
1666                 Start: ;",
1667            "%grmtools{yacckind: YaccKind::Grmtools}
1668                 %%
1669                 Start -> () : ;",
1670        ];
1671        for src in srcs {
1672            YaccGrammar::<u32>::from_str(src).unwrap();
1673        }
1674    }
1675
1676    #[test]
1677    fn test_grmtools_section_invalid_yacckinds() {
1678        let srcs = [
1679            "%grmtools{yacckind: Foo}",
1680            "%grmtools{yacckind: YaccKind::Foo}",
1681            "%grmtools{yacckindof: YaccKind::Grmtools}",
1682            "%grmtools{yacckindof: Grmtools}",
1683            "%grmtools{yacckindof: YaccKindFoo::Foo}",
1684            "%grmtools{yacckind: Foo::Grmtools}",
1685            "%grmtools{yacckind: YaccKind::Original}",
1686            "%grmtools{yacckind: YaccKind::OriginalFoo}",
1687            "%grmtools{yacckind: YaccKind::Original()}",
1688            "%grmtools{yacckind: YaccKind::Original(Foo)}",
1689            "%grmtools{yacckind: YaccKind::Original(YaccOriginalActionKind)}",
1690            "%grmtools{yacckind: YaccKind::Original(YaccOriginalActionKind::Foo)}",
1691            "%grmtools{yacckind: YaccKind::Original(Foo::NoActions)}",
1692            "%grmtools{yacckind: YaccKind::Original(Foo::NoActionsBar)}",
1693        ];
1694
1695        for src in srcs {
1696            let s = format!("{}\n%%\nStart();\n", src);
1697            assert!(YaccGrammar::<u32>::from_str(&s).is_err());
1698        }
1699    }
1700
1701    #[test]
1702    fn test_grmtools_section_commas() {
1703        // We can't actually test much here, because
1704        // We don't have a second value to test.
1705        //
1706        // `RecoveryKind` seemed like an option for an additional value to allow,
1707        // but that is part of `lrpar` which cfgrammar doesn't depend upon.
1708        let src = r#"
1709                %grmtools{
1710                    yacckind: YaccKind::Grmtools,
1711                }
1712                %%
1713                Start -> () : ;
1714            "#;
1715        YaccGrammar::<u32>::from_str(src).unwrap();
1716        let src = r#"
1717                %grmtools{
1718                    yacckind: YaccKind::Grmtools
1719                }
1720                %%
1721                Start -> () : ;
1722            "#;
1723        YaccGrammar::<u32>::from_str(src).unwrap();
1724    }
1725}