Skip to main content

lrpar/
codegen.rs

1use std::{
2    any::type_name,
3    fmt::{self, Write},
4    hash::Hash,
5    marker::PhantomData,
6    path::Path,
7};
8
9use crate::{
10    LexerTypes, RecoveryKind, RustEdition, SerialisationFormat, Visibility,
11    ctbuilder::{FixIntConfig, VarIntConfig},
12};
13
14use cfgrammar::{
15    Location, RIdx, Span, Symbol,
16    header::{GrmtoolsSectionParser, Header, HeaderError, HeaderValue},
17    markmap::MergeError,
18    yacc::{
19        YaccGrammar, YaccGrammarError, YaccKind, YaccOriginalActionKind, ast::ASTWithValidityInfo,
20    },
21};
22
23use lrtable::{Minimiser, StateGraph, StateTable, StateTableError, from_yacc};
24use proc_macro2::{Literal, TokenStream};
25use quote::{ToTokens, TokenStreamExt, format_ident, quote};
26use syn::{Generics, parse_quote};
27use wincode::SchemaWrite;
28
29const ACTION_PREFIX: &str = "__gt_";
30const GLOBAL_PREFIX: &str = "__GT_";
31const ACTIONS_KIND: &str = "__GtActionsKind";
32const ACTIONS_KIND_PREFIX: &str = "Ak";
33const ACTIONS_KIND_HIDDEN: &str = "__GtActionsKindHidden";
34
35#[non_exhaustive]
36pub(crate) enum ParserSrcEnvError {
37    GrmtoolsSectionParseError(Vec<HeaderError<Span>>),
38    GrmtoolsSectionMergeError(MergeError<String, Box<HeaderValue<Location>>>),
39    GrmtoolsSectionLookupError(HeaderError<Location>),
40    MissingYaccKind,
41    MissingModName,
42}
43
44#[non_exhaustive]
45pub(crate) enum ParserBuildEnvError<LexerTypesT>
46where
47    LexerTypesT: LexerTypes,
48    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
49{
50    StateTableError(StateTableError<LexerTypesT::StorageT>),
51    YaccGrammarErrors(Vec<YaccGrammarError>),
52    GrmtoolsSectionUnusedKeys(Vec<String>),
53    GrmtoolsSectionMissingRequiredKeys(Vec<String>),
54}
55
56#[non_exhaustive]
57pub(crate) enum CodegenError {
58    ProcMacro2Error(proc_macro2::LexError),
59    InvalidRustIdentifierModName(syn::Error, String),
60    InvalidParseGenerics(syn::Error),
61    WincodeError(wincode::WriteError),
62}
63
64impl From<Vec<HeaderError<Span>>> for ParserSrcEnvError {
65    fn from(it: Vec<HeaderError<Span>>) -> Self {
66        ParserSrcEnvError::GrmtoolsSectionParseError(it)
67    }
68}
69
70impl From<MergeError<String, Box<HeaderValue<Location>>>> for ParserSrcEnvError {
71    fn from(it: MergeError<String, Box<HeaderValue<Location>>>) -> Self {
72        ParserSrcEnvError::GrmtoolsSectionMergeError(it)
73    }
74}
75
76impl From<HeaderError<Location>> for ParserSrcEnvError {
77    fn from(it: HeaderError<Location>) -> Self {
78        ParserSrcEnvError::GrmtoolsSectionLookupError(it)
79    }
80}
81
82impl<LexerTypesT> From<Vec<YaccGrammarError>> for ParserBuildEnvError<LexerTypesT>
83where
84    LexerTypesT: LexerTypes,
85    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
86{
87    fn from(it: Vec<YaccGrammarError>) -> Self {
88        ParserBuildEnvError::YaccGrammarErrors(it)
89    }
90}
91
92impl<LexerTypesT> From<StateTableError<LexerTypesT::StorageT>> for ParserBuildEnvError<LexerTypesT>
93where
94    LexerTypesT: LexerTypes,
95    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
96{
97    fn from(it: StateTableError<LexerTypesT::StorageT>) -> Self {
98        ParserBuildEnvError::StateTableError(it)
99    }
100}
101
102impl From<proc_macro2::LexError> for CodegenError {
103    fn from(it: proc_macro2::LexError) -> Self {
104        CodegenError::ProcMacro2Error(it)
105    }
106}
107
108impl From<wincode::WriteError> for CodegenError {
109    fn from(it: wincode::WriteError) -> Self {
110        CodegenError::WincodeError(it)
111    }
112}
113
114impl fmt::Display for ParserSrcEnvError {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        f.write_str(&match self {
117            Self::GrmtoolsSectionParseError(errs) => errs
118                .iter()
119                .map(|e| e.to_string())
120                .collect::<Vec<_>>()
121                .join("\n"),
122            Self::GrmtoolsSectionMergeError(e) => e.to_string(),
123            Self::GrmtoolsSectionLookupError(e) => e.to_string(),
124            Self::MissingYaccKind => "Code generator cannot resolve yacc kind".to_string(),
125            Self::MissingModName => "Code generator requires a mod name".to_string(),
126        })
127    }
128}
129
130impl<LexerTypesT> fmt::Display for ParserBuildEnvError<LexerTypesT>
131where
132    LexerTypesT: LexerTypes,
133    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
134{
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        f.write_str(&match self {
137            Self::StateTableError(e) => format!("{}", e).to_string(),
138            Self::YaccGrammarErrors(errs) => errs
139                .iter()
140                .map(|e| e.to_string())
141                .collect::<Vec<_>>()
142                .join("\n"),
143            Self::GrmtoolsSectionUnusedKeys(keys) => {
144                format!("Unused keys in %grmtools section: {}", keys.join(", "))
145            }
146            Self::GrmtoolsSectionMissingRequiredKeys(keys) => format!(
147                "Required keys are missing from %grmtools section: {}",
148                keys.join(", ")
149            ),
150        })
151    }
152}
153impl fmt::Display for CodegenError {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        f.write_str(&match self {
156            Self::ProcMacro2Error(e) => e.to_string(),
157            Self::InvalidRustIdentifierModName(e, s) => format!(
158                "mod_name '{}' is not a valid rust identifier due to '{}'",
159                s, e
160            ),
161            Self::InvalidParseGenerics(e) => format!("Unable to parse %parse-generics '{e}'"),
162            Self::WincodeError(e) => format!("Unable to serialize parser {e}"),
163        })
164    }
165}
166
167pub(crate) struct ParserSrcEnv<'a, LexerTypesT>
168where
169    LexerTypesT: LexerTypes,
170    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
171{
172    src: &'a str,
173    fallback_modname: Option<String>,
174    grammar_path_cache_entry: Option<String>,
175    header: Header<Location>,
176    phantom: PhantomData<LexerTypesT::StorageT>,
177}
178
179pub(crate) struct ParserBuildEnvArgs<'a> {
180    /// If the input came from a preparsed AST, this will be Some
181    ast_with_validity_info: Option<&'a ASTWithValidityInfo>,
182    mod_name: Option<String>,
183    rust_edition: RustEdition,
184    visibility: Visibility,
185    error_on_conflicts: bool,
186    show_warnings: bool,
187    warnings_are_errors: bool,
188}
189
190pub(crate) struct ParserBuildEnv<'a, LexerTypesT>
191where
192    LexerTypesT: LexerTypes,
193    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
194{
195    ast_with_validity_info: ASTWithValidityInfo,
196    recoverer: RecoveryKind,
197    serialisation_format: SerialisationFormat,
198    // Preserve the args for generating the cache.
199    cache_args: ParserBuildEnvArgs<'a>,
200    phantom_storaget: PhantomData<LexerTypesT::StorageT>,
201    mod_name: String,
202    grammar_path: Option<String>,
203    header: Header<Location>,
204}
205
206pub(crate) struct ParserCodegen<LexerTypesT>
207where
208    LexerTypesT: LexerTypes,
209    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
210{
211    grm: YaccGrammar<LexerTypesT::StorageT>,
212    stable: StateTable<LexerTypesT::StorageT>,
213    sgraph: StateGraph<LexerTypesT::StorageT>,
214    timestamp: String,
215}
216
217impl<'a> ParserBuildEnvArgs<'a> {
218    pub(crate) fn new() -> Self {
219        ParserBuildEnvArgs {
220            ast_with_validity_info: None,
221            mod_name: None,
222            visibility: Visibility::Private,
223            rust_edition: RustEdition::Rust2021,
224            error_on_conflicts: true,
225            show_warnings: true,
226            warnings_are_errors: true,
227        }
228    }
229
230    /// Set this to `Some(ast)` if the the parser should be built from a pre-parsed AST
231    /// instead of from parsing a source string.
232    pub(crate) fn ast_with_validity_info(mut self, ast: Option<&'a ASTWithValidityInfo>) -> Self {
233        self.ast_with_validity_info = ast;
234        self
235    }
236
237    pub(crate) fn mod_name(mut self, mod_name: Option<&str>) -> Self {
238        self.mod_name = mod_name.map(|s| s.to_string());
239        self
240    }
241
242    pub(crate) fn rust_edition(mut self, rust_edition: RustEdition) -> Self {
243        self.rust_edition = rust_edition;
244        self
245    }
246    pub(crate) fn visibility(mut self, visibility: Visibility) -> Self {
247        self.visibility = visibility;
248        self
249    }
250    pub(crate) fn error_on_conflicts(mut self, error_on_conflicts: bool) -> Self {
251        self.error_on_conflicts = error_on_conflicts;
252        self
253    }
254    pub(crate) fn show_warnings(mut self, show_warnings: bool) -> Self {
255        self.show_warnings = show_warnings;
256        self
257    }
258    pub(crate) fn warnings_are_errors(mut self, warnings_are_errors: bool) -> Self {
259        self.warnings_are_errors = warnings_are_errors;
260        self
261    }
262}
263
264impl<'a, LexerTypesT> ParserSrcEnv<'a, LexerTypesT>
265where
266    LexerTypesT: LexerTypes,
267    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
268{
269    pub(crate) fn new_with_header(
270        src: &'a str,
271        path: Option<&Path>,
272        header: Header<Location>,
273    ) -> ParserSrcEnv<'a, LexerTypesT> {
274        let fallback_modname = if let Some(path) = path {
275            // When the user hasn't specified a module name, so we create one automatically: what we
276            // do is strip off all the filename extensions (note that it's likely that inp ends
277            // with `y.rs`, so we potentially have to strip off more than one extension) and
278            // then add `_y` to the end.
279            let mut stem = path.to_str().unwrap();
280            loop {
281                let new_stem = Path::new(stem).file_stem().unwrap().to_str().unwrap();
282                if stem == new_stem {
283                    break;
284                }
285                stem = new_stem;
286            }
287            Some(format!("{}_y", stem))
288        } else {
289            None
290        };
291        let grammar_path_cache_entry = path.map(|s| s.to_string_lossy().to_string());
292        ParserSrcEnv {
293            src,
294            fallback_modname,
295            grammar_path_cache_entry,
296            header,
297            phantom: PhantomData,
298        }
299    }
300
301    fn merge_headers(&mut self) -> Result<(), ParserSrcEnvError> {
302        let (parsed_header, _) = self.parse_header()?;
303        Ok(self.header.merge_from(parsed_header)?)
304    }
305
306    fn parse_header(&self) -> Result<(Header<Span>, usize), Vec<HeaderError<Span>>> {
307        GrmtoolsSectionParser::new(self.src, false).parse()
308    }
309
310    /// Looks up the `yacckind` field from the header, marks the field
311    /// as used then constructs AST of that kind.
312    fn resolve_ast_with_validity_info(
313        &mut self,
314        from_ast: Option<&ASTWithValidityInfo>,
315    ) -> Result<ASTWithValidityInfo, ParserSrcEnvError> {
316        self.header.mark_used(&"cfgrammar.yacckind".to_string());
317        if let Some(ast) = from_ast {
318            Ok(ast.clone())
319        } else if let Some(yk) = self
320            .header
321            .get("cfgrammar.yacckind")
322            .map(|HeaderValue(_, val)| val)
323            .map(YaccKind::try_from)
324            .transpose()?
325        {
326            Ok(ASTWithValidityInfo::new(yk, self.src))
327        } else {
328            Err(ParserSrcEnvError::MissingYaccKind)?
329        }
330    }
331
332    /// Looks up the `recoverer` field in the header, marks the field
333    /// as used, and defaulting to `CPCTPlus` if unfound.
334    fn resolve_recoverer(&mut self) -> Result<RecoveryKind, ParserSrcEnvError> {
335        self.header.mark_used(&"lrpar.recoverer".to_string());
336        let rk_val = self
337            .header
338            .get("lrpar.recoverer")
339            .map(|HeaderValue(_, rk_val)| rk_val);
340        if let Some(rk_val) = rk_val {
341            Ok(RecoveryKind::try_from(rk_val)?)
342        } else {
343            // Fallback to the default recoverykind.
344            Ok(RecoveryKind::CPCTPlus)
345        }
346    }
347
348    /// Looks up the `serialisation_format` field in the header, marks the field
349    /// as used, and defaults to `VariableSizedInteger` if unfound.
350    fn resolve_serialisation_format(&mut self) -> Result<SerialisationFormat, ParserSrcEnvError> {
351        self.header
352            .mark_used(&"lrpar.serialisation_format".to_string());
353        if let Some(ec_val) = self
354            .header
355            .get("lrpar.serialisation_format")
356            .map(|HeaderValue(_, ec_val)| ec_val)
357        {
358            Ok(SerialisationFormat::try_from(ec_val)?)
359        } else {
360            Ok(SerialisationFormat::VariableSizedInteger)
361        }
362    }
363
364    /// Looks up the `mod_name` from the `args`, and defaults to
365    /// the `{filename}_y` with any file extenstion stripped off.
366    fn resolve_mod_name(&self, args: &ParserBuildEnvArgs) -> Result<String, ParserSrcEnvError> {
367        match &args.mod_name {
368            Some(s) => Ok(s.to_owned()),
369            None => self
370                .fallback_modname
371                .as_ref()
372                .ok_or(ParserSrcEnvError::MissingModName)
373                .map(|s| s.to_string()),
374        }
375    }
376
377    pub(crate) fn build_env(
378        mut self,
379        args: ParserBuildEnvArgs<'a>,
380    ) -> Result<ParserBuildEnv<'a, LexerTypesT>, ParserSrcEnvError>
381    where
382        LexerTypesT: LexerTypes,
383        usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
384    {
385        self.merge_headers()?;
386        let ast_with_validity_info =
387            self.resolve_ast_with_validity_info(args.ast_with_validity_info)?;
388        let recoverer = self.resolve_recoverer()?;
389        let serialisation_format = self.resolve_serialisation_format()?;
390        let mod_name = self.resolve_mod_name(&args)?;
391        let grammar_path = self.grammar_path_cache_entry;
392
393        Ok(ParserBuildEnv {
394            ast_with_validity_info,
395            cache_args: args,
396            recoverer,
397            serialisation_format,
398            mod_name,
399            grammar_path,
400            header: self.header,
401            phantom_storaget: PhantomData,
402        })
403    }
404}
405
406impl<'a, LexerTypesT> ParserBuildEnv<'a, LexerTypesT>
407where
408    LexerTypesT: LexerTypes,
409    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
410{
411    pub(crate) fn ast_with_validity_info(&self) -> &ASTWithValidityInfo {
412        &self.ast_with_validity_info
413    }
414
415    pub(crate) fn header_mut(&mut self) -> &mut Header<Location> {
416        &mut self.header
417    }
418
419    pub(crate) fn serialisation_format(&self) -> &SerialisationFormat {
420        &self.serialisation_format
421    }
422
423    pub(crate) fn derived_mod_name(&self) -> &str {
424        &self.mod_name
425    }
426
427    pub(crate) fn specified_mod_name(&self) -> Option<&str> {
428        self.cache_args.mod_name.as_deref()
429    }
430
431    pub(crate) fn recoverer(&self) -> RecoveryKind {
432        self.recoverer
433    }
434
435    pub(crate) fn rust_edition(&self) -> RustEdition {
436        self.cache_args.rust_edition
437    }
438
439    pub(crate) fn visibility(&self) -> &Visibility {
440        &self.cache_args.visibility
441    }
442
443    pub(crate) fn show_warnings(&self) -> bool {
444        self.cache_args.show_warnings
445    }
446
447    pub(crate) fn warnings_are_errors(&self) -> bool {
448        self.cache_args.warnings_are_errors
449    }
450
451    pub(crate) fn error_on_conflicts(&self) -> bool {
452        self.cache_args.error_on_conflicts
453    }
454
455    pub(crate) fn yacc_kind(&self) -> YaccKind {
456        self.ast_with_validity_info.yacc_kind()
457    }
458
459    pub(crate) fn check_unused_header_keys(&self) -> Result<(), ParserBuildEnvError<LexerTypesT>> {
460        let unused_keys = self.header.unused();
461        if !unused_keys.is_empty() {
462            return Err(ParserBuildEnvError::GrmtoolsSectionUnusedKeys(unused_keys));
463        }
464        let missing_keys = self
465            .header
466            .missing()
467            .iter()
468            .map(|s| s.to_string())
469            .collect::<Vec<_>>();
470        if !missing_keys.is_empty() {
471            Err(ParserBuildEnvError::GrmtoolsSectionMissingRequiredKeys(
472                missing_keys,
473            ))
474        } else {
475            Ok(())
476        }
477    }
478
479    pub(crate) fn code_generator(
480        &self,
481        timestamp: &str,
482    ) -> Result<ParserCodegen<LexerTypesT>, ParserBuildEnvError<LexerTypesT>> {
483        let grm = YaccGrammar::<LexerTypesT::StorageT>::new_from_ast_with_validity_info(
484            &self.ast_with_validity_info,
485        )?;
486        let (sgraph, stable) = from_yacc(&grm, Minimiser::Pager)?;
487        Ok(ParserCodegen {
488            grm,
489            stable,
490            sgraph,
491            timestamp: timestamp.to_string(),
492        })
493    }
494}
495
496impl<LexerTypesT> ParserCodegen<LexerTypesT>
497where
498    LexerTypesT: LexerTypes,
499    usize: num_traits::AsPrimitive<LexerTypesT::StorageT>,
500    LexerTypesT::StorageT: 'static
501        + fmt::Debug
502        + Hash
503        + num_traits::PrimInt
504        + SchemaWrite<FixIntConfig, Src = LexerTypesT::StorageT>
505        + SchemaWrite<VarIntConfig, Src = LexerTypesT::StorageT>
506        + num_traits::Unsigned,
507    LexerTypesT: LexerTypes,
508{
509    pub(crate) fn grm(&self) -> &YaccGrammar<LexerTypesT::StorageT> {
510        &self.grm
511    }
512
513    pub(crate) fn stable(&self) -> &StateTable<LexerTypesT::StorageT> {
514        &self.stable
515    }
516
517    pub(crate) fn sgraph(&self) -> &StateGraph<LexerTypesT::StorageT> {
518        &self.sgraph
519    }
520
521    pub(crate) fn finish(
522        self,
523    ) -> (
524        YaccGrammar<LexerTypesT::StorageT>,
525        StateGraph<LexerTypesT::StorageT>,
526        StateTable<LexerTypesT::StorageT>,
527    ) {
528        (self.grm, self.sgraph, self.stable)
529    }
530
531    pub(crate) fn generate(
532        &self,
533        build_env: &ParserBuildEnv<LexerTypesT>,
534    ) -> Result<String, CodegenError> {
535        let mod_name = build_env.derived_mod_name();
536        let visibility = build_env.visibility();
537        let user_actions = if let YaccKind::Original(YaccOriginalActionKind::UserAction)
538        | YaccKind::Grmtools = build_env.yacc_kind()
539        {
540            Some(self.gen_user_actions()?)
541        } else {
542            None
543        };
544        let rule_consts = self.gen_rule_consts()?;
545        let token_epp = self.gen_token_epp()?;
546        let parse_function = self.gen_parse_function(build_env)?;
547        let action_wrappers = match build_env.yacc_kind() {
548            YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools => {
549                Some(self.gen_wrappers(build_env)?)
550            }
551            YaccKind::Original(YaccOriginalActionKind::NoAction)
552            | YaccKind::Original(YaccOriginalActionKind::GenericParseTree) => None,
553            _ => unreachable!(),
554        };
555
556        let additional_decls = if let YaccKind::Original(YaccOriginalActionKind::GenericParseTree) =
557            build_env.yacc_kind()
558        {
559            // `lrpar::Node`` is deprecated within the lrpar crate, but not from within this module,
560            // Once it is removed from `lrpar`, we should move the declaration here entirely.
561            Some(quote! {
562                #[allow(unused_imports)]
563                pub use ::lrpar::parser::_deprecated_moved_::Node;
564            })
565        } else {
566            None
567        };
568
569        let mod_name = match syn::parse_str::<proc_macro2::Ident>(mod_name) {
570            Ok(s) => s,
571            Err(e) => {
572                return Err(CodegenError::InvalidRustIdentifierModName(
573                    e,
574                    mod_name.to_string(),
575                ));
576            }
577        };
578        let out_tokens = quote! {
579            #visibility mod #mod_name {
580                // At the top so that `user_actions` may contain #![inner_attribute]
581                #user_actions
582                mod _parser_ {
583                    #![allow(clippy::type_complexity)]
584                    #![allow(clippy::unnecessary_wraps)]
585                    #![deny(unsafe_code)]
586                    #[allow(unused_imports)]
587                    use super::*;
588                    #additional_decls
589                    #parse_function
590                    #rule_consts
591                    #token_epp
592                    #action_wrappers
593                } // End of `mod _parser_`
594                #[allow(unused_imports)]
595                pub use _parser_::*;
596                #[allow(unused_imports)]
597                use ::lrpar::Lexeme;
598            } // End of `mod #mod_name`
599        };
600        // Try and run a code formatter on the generated code.
601        let unformatted = out_tokens.to_string();
602        Ok(syn::parse_str(&unformatted)
603            .map(|syntax_tree| prettyplease::unparse(&syntax_tree))
604            .unwrap_or(unformatted))
605    }
606
607    /// Generate the cache, which determines if anything's changed enough that we need to
608    /// regenerate outputs and force rustc to recompile.
609    fn gen_cache(&self, build_env: &ParserBuildEnv<LexerTypesT>) -> TokenStream {
610        let grm = self.grm();
611        let build_time = &self.timestamp;
612        let grammar_path = &build_env.grammar_path;
613        let mod_name = QuoteOption(build_env.specified_mod_name());
614        let visibility = build_env.visibility().to_variant_tokens();
615        let rust_edition = build_env.rust_edition().to_variant_tokens();
616        let yacckind = build_env.yacc_kind();
617        let rule_map = grm
618            .iter_tidxs()
619            .map(|tidx| {
620                QuoteTuple((
621                    usize::from(tidx),
622                    grm.token_name(tidx).unwrap_or("<unknown>"),
623                ))
624            })
625            .collect::<Vec<_>>();
626        let derived_mod_name = build_env.derived_mod_name();
627        let serialisation_format = build_env.serialisation_format();
628        let recoverer = build_env.recoverer();
629        let error_on_conflicts = build_env.error_on_conflicts();
630        let show_warnings = build_env.show_warnings();
631        let warnings_are_errors = build_env.warnings_are_errors();
632        let cache_info = quote! {
633            BUILD_TIME = #build_time
634            DERIVED_MOD_NAME = #derived_mod_name
635            ENCODING_CONFIG = #serialisation_format
636            GRAMMAR_PATH = #grammar_path
637            MOD_NAME = #mod_name
638            RECOVERER = #recoverer
639            YACC_KIND = #yacckind
640            ERROR_ON_CONFLICTS = #error_on_conflicts
641            SHOW_WARNINGS = #show_warnings
642            WARNINGS_ARE_ERRORS = #warnings_are_errors
643            RUST_EDITION = #rust_edition
644            RULE_IDS_MAP = [#(#rule_map,)*]
645            VISIBILITY = #visibility
646        };
647        let cache_info_str = cache_info.to_string();
648        quote!(#cache_info_str)
649    }
650
651    pub(crate) fn cache_str(&self, build_env: &ParserBuildEnv<LexerTypesT>) -> String {
652        self.gen_cache(build_env).to_string()
653    }
654
655    /// Generate the user action functions (if any).
656    fn gen_user_actions(&self) -> Result<TokenStream, CodegenError> {
657        let grm = self.grm();
658        let programs = grm
659            .programs()
660            .as_ref()
661            .map(|s| str::parse::<TokenStream>(s))
662            .transpose()?;
663        let mut action_fns = TokenStream::new();
664        // Convert actions to functions
665        let parsed_parse_generics = make_generics(grm.parse_generics().as_deref())?;
666        let (generics, _, where_clause) = parsed_parse_generics.split_for_impl();
667        let (parse_paramname, parse_paramdef, parse_param_unit);
668        match grm.parse_param() {
669            Some((name, tyname)) => {
670                parse_param_unit = tyname.trim() == "()";
671                parse_paramname = str::parse::<TokenStream>(name)?;
672                let ty = str::parse::<TokenStream>(tyname)?;
673                parse_paramdef = quote!(#parse_paramname: #ty);
674            }
675            None => {
676                parse_param_unit = true;
677                parse_paramname = quote!(());
678                parse_paramdef = quote! {_: ()};
679            }
680        };
681        for pidx in grm.iter_pidxs() {
682            if pidx == grm.start_prod() {
683                continue;
684            }
685
686            // Work out the right type for each argument
687            let mut args = Vec::with_capacity(grm.prod(pidx).len());
688            for i in 0..grm.prod(pidx).len() {
689                let argt = match grm.prod(pidx)[i] {
690                    Symbol::Rule(ref_ridx) => {
691                        let action_type = grm.actiontype(ref_ridx)
692                           .as_ref()
693                           .expect("actiontype should have been checked during complete_and_validate for this YaccKind");
694                        str::parse::<TokenStream>(action_type)?
695                    }
696                    Symbol::Token(_) => {
697                        let lexemet =
698                            str::parse::<TokenStream>(type_name::<LexerTypesT::LexemeT>())?;
699                        quote!(::std::result::Result<#lexemet, #lexemet>)
700                    }
701                };
702                let arg = format_ident!("{}arg_{}", ACTION_PREFIX, i + 1);
703                args.push(quote!(mut #arg: #argt));
704            }
705
706            // If this rule's `actiont` is `()` then Clippy will warn that the return type `-> ()`
707            // is pointless (which is true). We therefore avoid outputting a return type if actiont
708            // is the unit type.
709            let returnt = {
710                let actiont = grm.actiontype(grm.prod_to_rule(pidx)).as_ref().unwrap();
711                if actiont == "()" {
712                    None
713                } else {
714                    let actiont = str::parse::<TokenStream>(actiont)?;
715                    Some(quote!( -> #actiont))
716                }
717            };
718            let action_fn = format_ident!("{}action_{}", ACTION_PREFIX, usize::from(pidx));
719            let lexer_var = format_ident!("{}lexer", ACTION_PREFIX);
720            let span_var = format_ident!("{}span", ACTION_PREFIX);
721            let ridx_var = format_ident!("{}ridx", ACTION_PREFIX);
722            let storaget = str::parse::<TokenStream>(type_name::<LexerTypesT::StorageT>())?;
723            let lexertypest = str::parse::<TokenStream>(type_name::<LexerTypesT>())?;
724            let bind_parse_param = if !parse_param_unit {
725                Some(quote! {let _ = #parse_paramname;})
726            } else {
727                None
728            };
729
730            // Iterate over all $-arguments and replace them with their respective
731            // element from the argument vector (e.g. $1 is replaced by args[0]).
732            let pre_action = grm.action(pidx).as_ref().expect("action code should have been checked during complete_and_validate for this YaccKind");
733            let mut last = 0;
734            let mut outs = String::new();
735            loop {
736                match pre_action[last..].find('$') {
737                    Some(off) => {
738                        if pre_action[last + off..].starts_with("$$") {
739                            outs.push_str(&pre_action[last..last + off + "$".len()]);
740                            last = last + off + "$$".len();
741                        } else if pre_action[last + off..].starts_with("$lexer") {
742                            outs.push_str(&pre_action[last..last + off]);
743                            write!(outs, "{prefix}lexer", prefix = ACTION_PREFIX).ok();
744                            last = last + off + "$lexer".len();
745                        } else if pre_action[last + off..].starts_with("$span") {
746                            outs.push_str(&pre_action[last..last + off]);
747                            write!(outs, "{prefix}span", prefix = ACTION_PREFIX).ok();
748                            last = last + off + "$span".len();
749                        } else if last + off + 1 < pre_action.len()
750                            && pre_action[last + off + 1..].starts_with(|c: char| c.is_numeric())
751                        {
752                            outs.push_str(&pre_action[last..last + off]);
753                            write!(outs, "{prefix}arg_", prefix = ACTION_PREFIX).ok();
754                            last = last + off + "$".len();
755                        } else {
756                            unreachable!("action variables checked during complete_and_validate");
757                        }
758                    }
759                    None => {
760                        outs.push_str(&pre_action[last..]);
761                        break;
762                    }
763                }
764            }
765
766            let action_body = str::parse::<TokenStream>(&outs)?;
767            action_fns.extend(quote! {
768                #[allow(clippy::too_many_arguments)]
769                fn #action_fn #generics (
770                    #ridx_var: ::cfgrammar::RIdx<#storaget>,
771                    #lexer_var: &'lexer dyn ::lrpar::NonStreamingLexer<'input, #lexertypest>,
772                    #span_var: ::cfgrammar::Span,
773                    #parse_paramdef,
774                    #(#args,)*
775                ) #returnt
776                #where_clause
777                {
778                    #bind_parse_param
779                    #action_body
780                }
781            })
782        }
783        Ok(quote! {
784            #programs
785            #action_fns
786        })
787    }
788
789    fn gen_rule_consts(&self) -> Result<TokenStream, proc_macro2::LexError> {
790        let grm = self.grm();
791        let mut toks = TokenStream::new();
792        for ridx in grm.iter_rules() {
793            if !grm.rule_to_prods(ridx).contains(&grm.start_prod()) {
794                let r_const = format_ident!("R_{}", grm.rule_name_str(ridx).to_ascii_uppercase());
795                let storage_ty = str::parse::<TokenStream>(type_name::<LexerTypesT::StorageT>())?;
796                let ridx = UnsuffixedUsize(usize::from(ridx));
797                toks.extend(quote! {
798                    #[allow(dead_code)]
799                    pub const #r_const: #storage_ty = #ridx;
800                });
801            }
802        }
803        Ok(toks)
804    }
805
806    fn gen_token_epp(&self) -> Result<TokenStream, proc_macro2::LexError> {
807        let grm = self.grm();
808        let mut tidxs = Vec::new();
809        for tidx in grm.iter_tidxs() {
810            tidxs.push(QuoteOption(grm.token_epp(tidx)));
811        }
812        let const_epp_ident = format_ident!("{}EPP", GLOBAL_PREFIX);
813        let storage_ty = str::parse::<TokenStream>(type_name::<LexerTypesT::StorageT>())?;
814        Ok(quote! {
815            const #const_epp_ident: &[::std::option::Option<&str>] = &[
816                #(#tidxs,)*
817            ];
818
819            /// Return the %epp entry for token `tidx` (where `None` indicates \"the token has no
820            /// pretty-printed value\"). Panics if `tidx` doesn't exist.
821            #[allow(dead_code)]
822            pub fn token_epp<'a>(tidx: ::cfgrammar::TIdx<#storage_ty>) -> ::std::option::Option<&'a str> {
823                #const_epp_ident[usize::from(tidx)]
824            }
825        })
826    }
827
828    /// Generate the main parse() function for the output file.
829    fn gen_parse_function(
830        &self,
831        build_env: &ParserBuildEnv<LexerTypesT>,
832    ) -> Result<TokenStream, CodegenError> {
833        let stable = self.stable();
834        let grm = self.grm();
835        let storaget = str::parse::<TokenStream>(type_name::<LexerTypesT::StorageT>())?;
836        let lexertypest = str::parse::<TokenStream>(type_name::<LexerTypesT>())?;
837        let recoverer = build_env.recoverer();
838        let run_parser = match build_env.yacc_kind() {
839            YaccKind::Original(YaccOriginalActionKind::GenericParseTree) => {
840                quote! {
841                    ::lrpar::RTParserBuilder::new(grm, stable)
842                        .recoverer(#recoverer)
843                        .parse_map(
844                            lexer,
845                            &|lexeme| Node::Term{lexeme},
846                            &|ridx, nodes| Node::Nonterm{ridx, nodes}
847                        )
848                }
849            }
850            YaccKind::Original(YaccOriginalActionKind::NoAction) => {
851                quote! {
852                    ::lrpar::RTParserBuilder::new(grm, stable)
853                        .recoverer(#recoverer)
854                        .parse_map(lexer, &|_| (), &|_, _| ()).1
855                }
856            }
857            YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools => {
858                let actionskind = str::parse::<TokenStream>(ACTIONS_KIND)?;
859                let parsed_parse_generics = make_generics(grm.parse_generics().as_deref())?;
860                let (_, type_generics, _) = parsed_parse_generics.split_for_impl();
861                // actions always have a parse_param argument, and when the `parse` function lacks one
862                // that parameter will be unit.
863                let (action_fn_parse_param, action_fn_parse_param_ty) = match grm.parse_param() {
864                    Some((name, ty)) => {
865                        let name = str::parse::<TokenStream>(name)?;
866                        let ty = str::parse::<TokenStream>(ty)?;
867                        (quote!(#name), quote!(#ty))
868                    }
869                    None => (quote!(()), quote!(())),
870                };
871                let wrappers = grm.iter_pidxs().map(|pidx| {
872                    let pidx = usize::from(pidx);
873                    format_ident!("{}wrapper_{}", ACTION_PREFIX, pidx)
874                });
875                let edition_lifetime = if build_env.rust_edition() != RustEdition::Rust2015 {
876                    quote!('_,)
877                } else {
878                    quote!()
879                };
880                let ridx = usize::from(self.user_start_ridx());
881                let action_ident = format_ident!("{}{}", ACTIONS_KIND_PREFIX, ridx);
882
883                quote! {
884                    let actions: ::std::vec::Vec<
885                            &dyn Fn(
886                                    ::cfgrammar::RIdx<#storaget>,
887                                    &'lexer dyn ::lrpar::NonStreamingLexer<'input, #lexertypest>,
888                                    ::cfgrammar::Span,
889                                    ::std::vec::Drain<#edition_lifetime ::lrpar::parser::AStackType<<#lexertypest as ::lrpar::LexerTypes>::LexemeT, #actionskind #type_generics>>,
890                                    #action_fn_parse_param_ty
891                            ) -> #actionskind #type_generics
892                        > = ::std::vec![#(&#wrappers,)*];
893                    match ::lrpar::RTParserBuilder::new(grm, stable)
894                        .recoverer(#recoverer)
895                        .parse_actions(lexer, &actions, #action_fn_parse_param) {
896                            (Some(#actionskind::#action_ident(x)), y) => (Some(x), y),
897                            (None, y) => (None, y),
898                            _ => unreachable!()
899                    }
900                }
901            }
902            kind => panic!("YaccKind {:?} not supported", kind),
903        };
904
905        let parsed_parse_generics: Generics = match build_env.yacc_kind() {
906            YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools => {
907                make_generics(grm.parse_generics().as_deref())?
908            }
909            _ => make_generics(None)?,
910        };
911        let (generics, _, where_clause) = parsed_parse_generics.split_for_impl();
912
913        // `parse()` may or may not have an argument for `%parseparam`.
914        let parse_fn_parse_param = match build_env.yacc_kind() {
915            YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools => {
916                if let Some((name, tyname)) = grm.parse_param() {
917                    let name = str::parse::<TokenStream>(name)?;
918                    let tyname = str::parse::<TokenStream>(tyname)?;
919                    Some(quote! {#name: #tyname})
920                } else {
921                    None
922                }
923            }
924            _ => None,
925        };
926        let parse_fn_return_ty = match build_env.yacc_kind() {
927            YaccKind::Original(YaccOriginalActionKind::UserAction) | YaccKind::Grmtools => {
928                let actiont = grm
929                    .actiontype(self.user_start_ridx())
930                    .as_ref()
931                    .map(|at| str::parse::<TokenStream>(at))
932                    .transpose()?;
933                quote! {
934                    (::std::option::Option<#actiont>, ::std::vec::Vec<::lrpar::LexParseError<#storaget, #lexertypest>>)
935                }
936            }
937            YaccKind::Original(YaccOriginalActionKind::GenericParseTree) => quote! {
938                (::std::option::Option<Node<<#lexertypest as ::lrpar::LexerTypes>::LexemeT, #storaget>>,
939                    ::std::vec::Vec<::lrpar::LexParseError<#storaget, #lexertypest>>)
940            },
941            YaccKind::Original(YaccOriginalActionKind::NoAction) => quote! {
942                ::std::vec::Vec<::lrpar::LexParseError<#storaget, #lexertypest>>
943            },
944            _ => unreachable!(),
945        };
946
947        let serialisation_format = build_env.serialisation_format();
948        // Note that the configuration types use associated consts, and thus these configurations represent distinct types.
949        let (grm_data, stable_data): (Vec<u8>, Vec<u8>) = match serialisation_format {
950            SerialisationFormat::FixedSizeInteger => {
951                let config = wincode::config::Configuration::default().with_fixint_encoding();
952                let grm = wincode::config::serialize(grm, config)?;
953                let stable = wincode::config::serialize(stable, config)?;
954                (grm, stable)
955            }
956            SerialisationFormat::VariableSizedInteger => {
957                let config = wincode::config::Configuration::default().with_varint_encoding();
958                let grm = wincode::config::serialize(grm, config)?;
959                let stable = wincode::config::serialize(stable, config)?;
960                (grm, stable)
961            }
962        };
963        let serialisation_format_str = quote!(serialisation_format).to_string();
964        Ok(quote! {
965            const __GRM_DATA: &[u8] = &[#(#grm_data,)*];
966            const __STABLE_DATA: &[u8] = &[#(#stable_data,)*];
967            const __SERIALISATION_FORMAT: ::lrpar::ctbuilder::SerialisationFormat = #serialisation_format;
968
969            fn __lrpar_parser_data() -> &'static ::lrpar::ParserData<#storaget> {
970                static DATA: ::std::sync::OnceLock<::lrpar::ParserData<#storaget>>
971                    = ::std::sync::OnceLock::new();
972                DATA.get_or_init(
973                    || {
974                        // We have to call reconstitute like this because the config parameter takes a trait
975                        // which uses const generics. Thus the two config parameters here are not actually of the same type.
976                        match __SERIALISATION_FORMAT {
977                            ::lrpar::ctbuilder::SerialisationFormat::FixedSizeInteger => {
978                                ::lrpar::ctbuilder::_reconstitute(__GRM_DATA, __STABLE_DATA, ::lrpar::ctbuilder::wincode::config::Configuration::default().with_fixint_encoding())
979                            }
980                            ::lrpar::ctbuilder::SerialisationFormat::VariableSizedInteger => {
981                                ::lrpar::ctbuilder::_reconstitute(__GRM_DATA, __STABLE_DATA, ::lrpar::ctbuilder::wincode::config::Configuration::default().with_varint_encoding())
982                            }
983                            _ => {
984                                panic!("Parser source was generated using unknown `SerialisationFormat`: {:?}", #serialisation_format_str)
985                            }
986                        }
987                    }
988                )
989            }
990
991            #[allow(dead_code)]
992            pub fn parse #generics (
993                 lexer: &'lexer dyn ::lrpar::NonStreamingLexer<'input, #lexertypest>,
994                 #parse_fn_parse_param
995            ) -> #parse_fn_return_ty
996            #where_clause
997            {
998                let __data = __lrpar_parser_data();
999                let grm = __data.grm();
1000                let stable = __data.stable();
1001                #run_parser
1002            }
1003        })
1004    }
1005
1006    /// Generate the wrappers that call user actions
1007    fn gen_wrappers(
1008        &self,
1009        build_env: &ParserBuildEnv<LexerTypesT>,
1010    ) -> Result<TokenStream, CodegenError> {
1011        let grm = self.grm();
1012        let parsed_parse_generics = make_generics(grm.parse_generics().as_deref())?;
1013        let (generics, type_generics, where_clause) = parsed_parse_generics.split_for_impl();
1014
1015        let (parse_paramname, parse_paramdef);
1016        match grm.parse_param() {
1017            Some((name, tyname)) => {
1018                parse_paramname = str::parse::<TokenStream>(name)?;
1019                let ty = str::parse::<TokenStream>(tyname)?;
1020                parse_paramdef = quote!(#parse_paramname: #ty);
1021            }
1022            None => {
1023                parse_paramname = quote!(());
1024                parse_paramdef = quote! {_: ()};
1025            }
1026        };
1027
1028        let mut wrappers = TokenStream::new();
1029        for pidx in grm.iter_pidxs() {
1030            let ridx = grm.prod_to_rule(pidx);
1031
1032            // Iterate over all $-arguments and replace them with their respective
1033            // element from the argument vector (e.g. $1 is replaced by args[0]). At
1034            // the same time extract &str from tokens and actiontype from nonterminals.
1035            let wrapper_fn = format_ident!("{}wrapper_{}", ACTION_PREFIX, usize::from(pidx));
1036            let ridx_var = format_ident!("{}ridx", ACTION_PREFIX);
1037            let lexer_var = format_ident!("{}lexer", ACTION_PREFIX);
1038            let span_var = format_ident!("{}span", ACTION_PREFIX);
1039            let args_var = format_ident!("{}args", ACTION_PREFIX);
1040            let storaget = str::parse::<TokenStream>(type_name::<LexerTypesT::StorageT>())?;
1041            let lexertypest = str::parse::<TokenStream>(type_name::<LexerTypesT>())?;
1042            let actionskind = str::parse::<TokenStream>(ACTIONS_KIND)?;
1043            let edition_lifetime = if build_env.rust_edition() != RustEdition::Rust2015 {
1044                Some(quote!('_,))
1045            } else {
1046                None
1047            };
1048            let mut wrapper_fn_body = TokenStream::new();
1049            if grm.action(pidx).is_some() {
1050                // Unpack the arguments passed to us by the drain
1051                for i in 0..grm.prod(pidx).len() {
1052                    let arg = format_ident!("{}arg_{}", ACTION_PREFIX, i + 1);
1053                    wrapper_fn_body.extend(match grm.prod(pidx)[i] {
1054                        Symbol::Rule(ref_ridx) => {
1055                            let ref_ridx = usize::from(ref_ridx);
1056                            let actionvariant = format_ident!("{}{}", ACTIONS_KIND_PREFIX, ref_ridx);
1057                            quote! {
1058                                #[allow(clippy::let_unit_value)]
1059                                let #arg = match #args_var.next().unwrap() {
1060                                    ::lrpar::parser::AStackType::ActionType(#actionskind::#type_generics::#actionvariant(x)) => x,
1061                                    _ => unreachable!()
1062                                };
1063                            }
1064                        }
1065                        Symbol::Token(_) => {
1066                            quote! {
1067                                let #arg = match #args_var.next().unwrap() {
1068                                    ::lrpar::parser::AStackType::Lexeme(l) => {
1069                                        if l.faulty() {
1070                                            Err(l)
1071                                        } else {
1072                                            Ok(l)
1073                                        }
1074                                    },
1075                                    ::lrpar::parser::AStackType::ActionType(_) => unreachable!()
1076                                };
1077                            }
1078                        }
1079                    })
1080                }
1081
1082                // Call the user code
1083                let args = (0..grm.prod(pidx).len())
1084                    .map(|i| format_ident!("{}arg_{}", ACTION_PREFIX, i + 1))
1085                    .collect::<Vec<_>>();
1086                let action_fn = format_ident!("{}action_{}", ACTION_PREFIX, usize::from(pidx));
1087                let actionsvariant = format_ident!("{}{}", ACTIONS_KIND_PREFIX, usize::from(ridx));
1088
1089                wrapper_fn_body.extend(match grm.actiontype(ridx) {
1090                    Some(s) if s == "()" => {
1091                        // If the rule `r` that we're calling has the unit type then Clippy will warn that
1092                        // `enum::A(wrapper_r())` is pointless. We thus have to split it into two:
1093                        // `wrapper_r(); enum::A(())`.
1094                        quote! {
1095                            #action_fn(#ridx_var, #lexer_var, #span_var, #parse_paramname, #(#args,)*);
1096                            #actionskind::#type_generics::#actionsvariant(())
1097                        }
1098                    }
1099                    _ => {
1100                        quote! {
1101                            #actionskind::#type_generics::#actionsvariant(#action_fn(#ridx_var, #lexer_var, #span_var, #parse_paramname, #(#args,)*))
1102                        }
1103                    }
1104                })
1105            } else if pidx == grm.start_prod() {
1106                wrapper_fn_body.extend(quote!(unreachable!()));
1107            } else {
1108                unreachable!(
1109                    "Production in rule '{}' must have an action body, which should have been handled by gen_user_actions.",
1110                    grm.rule_name_str(grm.prod_to_rule(pidx))
1111                );
1112            };
1113
1114            let attrib = if pidx == grm.start_prod() {
1115                // The start prod has an unreachable body so it doesn't use it's variables.
1116                Some(quote!(#[allow(unused_variables)]))
1117            } else {
1118                None
1119            };
1120            wrappers.extend(quote! {
1121                #attrib
1122                fn #wrapper_fn #generics (
1123                    #ridx_var: ::cfgrammar::RIdx<#storaget>,
1124                    #lexer_var: &'lexer dyn ::lrpar::NonStreamingLexer<'input, #lexertypest>,
1125                    #span_var: ::cfgrammar::Span,
1126                    mut #args_var: ::std::vec::Drain<#edition_lifetime ::lrpar::parser::AStackType<<#lexertypest as ::lrpar::LexerTypes>::LexemeT, #actionskind #type_generics>>,
1127                    #parse_paramdef
1128                ) -> #actionskind #type_generics
1129                #where_clause
1130                {
1131                    #wrapper_fn_body
1132                }
1133             })
1134        }
1135        let mut actionskindvariants = Vec::new();
1136        let actionskindhidden = format_ident!("_{}", ACTIONS_KIND_HIDDEN);
1137        let actionskind = str::parse::<TokenStream>(ACTIONS_KIND).unwrap();
1138        let mut phantom_data_type = Vec::new();
1139        for ridx in grm.iter_rules() {
1140            if let Some(actiont) = grm.actiontype(ridx) {
1141                let actionskindvariant =
1142                    format_ident!("{}{}", ACTIONS_KIND_PREFIX, usize::from(ridx));
1143                let actiont = str::parse::<TokenStream>(actiont).unwrap();
1144                actionskindvariants.push(quote! {
1145                    #actionskindvariant(#actiont)
1146                })
1147            }
1148        }
1149        for lifetime in parsed_parse_generics.lifetimes() {
1150            let lifetime = &lifetime.lifetime;
1151            phantom_data_type.push(quote! { &#lifetime () });
1152        }
1153        for type_param in parsed_parse_generics.type_params() {
1154            let ident = &type_param.ident;
1155            phantom_data_type.push(quote! { #ident });
1156        }
1157        actionskindvariants.push(quote! {
1158            #actionskindhidden(::std::marker::PhantomData<(#(#phantom_data_type,)*)>)
1159        });
1160        wrappers.extend(quote! {
1161            #[allow(dead_code)]
1162            enum #actionskind #generics #where_clause {
1163                #(#actionskindvariants,)*
1164            }
1165        });
1166        Ok(wrappers)
1167    }
1168
1169    /// Return the `RIdx` of the %start rule in the grammar (which will not be the same as
1170    /// grm.start_rule_idx because the latter has an additional rule insert by cfgrammar
1171    /// which then calls the user's %start rule).
1172    fn user_start_ridx(&self) -> RIdx<LexerTypesT::StorageT> {
1173        let grm = self.grm();
1174        debug_assert_eq!(grm.prod(grm.start_prod()).len(), 1);
1175        match grm.prod(grm.start_prod())[0] {
1176            Symbol::Rule(ridx) => ridx,
1177            _ => unreachable!(),
1178        }
1179    }
1180}
1181
1182/// The quote impl of `ToTokens` for `Option` prints an empty string for `None`
1183/// and the inner value for `Some(inner_value)`.
1184///
1185/// This wrapper instead emits both `Some` and `None` variants.
1186/// See: [quote #20](https://github.com/dtolnay/quote/issues/20)
1187struct QuoteOption<T>(Option<T>);
1188
1189impl<T: ToTokens> ToTokens for QuoteOption<T> {
1190    fn to_tokens(&self, tokens: &mut TokenStream) {
1191        tokens.append_all(match self.0 {
1192            Some(ref t) => quote! { ::std::option::Option::Some(#t) },
1193            None => quote! { ::std::option::Option::None },
1194        });
1195    }
1196}
1197
1198/// This wrapper adds a missing impl of `ToTokens` for tuples.
1199/// For a tuple `(a, b)` emits `(a.to_tokens(), b.to_tokens())`
1200struct QuoteTuple<T>(T);
1201
1202impl<A: ToTokens, B: ToTokens> ToTokens for QuoteTuple<(A, B)> {
1203    fn to_tokens(&self, tokens: &mut TokenStream) {
1204        let (a, b) = &self.0;
1205        tokens.append_all(quote!((#a, #b)));
1206    }
1207}
1208
1209/// The wrapped `&str` value will be emitted with a call to `to_string()`
1210struct QuoteToString<'a>(&'a str);
1211
1212impl ToTokens for QuoteToString<'_> {
1213    fn to_tokens(&self, tokens: &mut TokenStream) {
1214        let x = &self.0;
1215        tokens.append_all(quote! { #x.to_string() });
1216    }
1217}
1218
1219/// The quote impl of `ToTokens` for `usize` prints literal values
1220/// including a type suffix for example `0usize`.
1221///
1222/// This wrapper omits the type suffix emitting `0` instead.
1223struct UnsuffixedUsize(usize);
1224
1225impl ToTokens for UnsuffixedUsize {
1226    fn to_tokens(&self, tokens: &mut TokenStream) {
1227        tokens.append(Literal::usize_unsuffixed(self.0))
1228    }
1229}
1230
1231impl RustEdition {
1232    fn to_variant_tokens(self) -> TokenStream {
1233        match self {
1234            RustEdition::Rust2015 => quote!(::lrpar::RustEdition::Rust2015),
1235            RustEdition::Rust2018 => quote!(::lrpar::RustEdition::Rust2018),
1236            RustEdition::Rust2021 => quote!(::lrpar::RustEdition::Rust2021),
1237        }
1238    }
1239}
1240
1241impl ToTokens for Visibility {
1242    fn to_tokens(&self, tokens: &mut TokenStream) {
1243        tokens.extend(match self {
1244            Visibility::Private => quote!(),
1245            Visibility::Public => quote! {pub},
1246            Visibility::PublicSuper => quote! {pub(super)},
1247            Visibility::PublicSelf => quote! {pub(self)},
1248            Visibility::PublicCrate => quote! {pub(crate)},
1249            Visibility::PublicIn(data) => {
1250                let other = str::parse::<TokenStream>(data).unwrap();
1251                quote! {pub(in #other)}
1252            }
1253        })
1254    }
1255}
1256
1257impl Visibility {
1258    fn to_variant_tokens(&self) -> TokenStream {
1259        match self {
1260            Visibility::Private => quote!(::lrpar::Visibility::Private),
1261            Visibility::Public => quote!(::lrpar::Visibility::Public),
1262            Visibility::PublicSuper => quote!(::lrpar::Visibility::PublicSuper),
1263            Visibility::PublicSelf => quote!(::lrpar::Visibility::PublicSelf),
1264            Visibility::PublicCrate => quote!(::lrpar::Visibility::PublicCrate),
1265            Visibility::PublicIn(data) => {
1266                let data = QuoteToString(data);
1267                quote!(::lrpar::Visibility::PublicIn(#data))
1268            }
1269        }
1270    }
1271}
1272
1273impl ToTokens for SerialisationFormat {
1274    fn to_tokens(&self, tokens: &mut TokenStream) {
1275        tokens.extend(match self {
1276            SerialisationFormat::FixedSizeInteger => {
1277                quote! {::lrpar::ctbuilder::SerialisationFormat::FixedSizeInteger}
1278            }
1279            SerialisationFormat::VariableSizedInteger => {
1280                quote! {::lrpar::ctbuilder::SerialisationFormat::VariableSizedInteger}
1281            }
1282        })
1283    }
1284}
1285
1286pub(crate) fn make_generics(parse_generics: Option<&str>) -> Result<Generics, CodegenError> {
1287    if let Some(parse_generics) = parse_generics {
1288        let tokens = str::parse::<TokenStream>(parse_generics)?;
1289        match syn::parse2(quote!(<'lexer, 'input: 'lexer, #tokens>)) {
1290            Ok(res) => Ok(res),
1291            Err(err) => Err(CodegenError::InvalidParseGenerics(err)),
1292        }
1293    } else {
1294        Ok(parse_quote!(<'lexer, 'input: 'lexer>))
1295    }
1296}