@@ -27,6 +27,8 @@ use filetime::FileTime;
2727use lazy_static:: lazy_static;
2828use lrtable:: { from_yacc, statetable:: Conflicts , Minimiser , StateGraph , StateTable } ;
2929use num_traits:: { AsPrimitive , PrimInt , Unsigned } ;
30+ use proc_macro2:: { Literal , TokenStream } ;
31+ use quote:: { quote, ToTokens , TokenStreamExt } ;
3032use regex:: Regex ;
3133use serde:: { de:: DeserializeOwned , Serialize } ;
3234
@@ -52,6 +54,34 @@ struct CTConflictsError<StorageT: Eq + Hash> {
5254 stable : StateTable < StorageT > ,
5355}
5456
57+ /// The quote impl of `ToTokens` for `Option` prints an empty string for `None`
58+ /// and the inner value for `Some(inner_value)`.
59+ ///
60+ /// This wrapper instead emits both `Some` and `None` variants.
61+ /// See: [quote #20](https://github.com/dtolnay/quote/issues/20)
62+ struct QuoteOption < T > ( Option < T > ) ;
63+
64+ impl < T : ToTokens > ToTokens for QuoteOption < T > {
65+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
66+ tokens. append_all ( match self . 0 {
67+ Some ( ref t) => quote ! { :: std:: option:: Option :: Some ( #t) } ,
68+ None => quote ! { :: std:: option:: Option :: None } ,
69+ } ) ;
70+ }
71+ }
72+
73+ /// The quote impl of `ToTokens` for `usize` prints literal values
74+ /// including a type suffix for example `0usize`.
75+ ///
76+ /// This wrapper omits the type suffix emitting `0` instead.
77+ struct UnsuffixedUsize ( usize ) ;
78+
79+ impl ToTokens for UnsuffixedUsize {
80+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
81+ tokens. append ( Literal :: usize_unsuffixed ( self . 0 ) )
82+ }
83+ }
84+
5585impl < StorageT > fmt:: Display for CTConflictsError < StorageT >
5686where
5787 StorageT : ' static + Debug + Hash + PrimInt + Unsigned ,
@@ -733,17 +763,23 @@ where
733763 // Record the time that this version of lrpar was built. If the source code changes and
734764 // rustc forces a recompile, this will change this value, causing anything which depends on
735765 // this build of lrpar to be recompiled too.
736- writeln ! ( cache, " Build time: {:?}" , env!( "VERGEN_BUILD_TIMESTAMP" ) ) . ok ( ) ;
737-
738- writeln ! ( cache, " Grammar path: {:?}" , self . grammar_path) . ok ( ) ;
739- writeln ! ( cache, " Mod name: {:?}" , self . mod_name) . ok ( ) ;
740- writeln ! ( cache, " Recoverer: {:?}" , self . recoverer) . ok ( ) ;
741- writeln ! ( cache, " YaccKind: {:?}" , self . yacckind) . ok ( ) ;
742- writeln ! ( cache, " Visibility: {:?}" , self . visibility. cow_str( ) ) . ok ( ) ;
766+ let build_time = env ! ( "VERGEN_BUILD_TIMESTAMP" ) ;
767+ let grammar_path = self . grammar_path . as_ref ( ) . unwrap ( ) . to_string_lossy ( ) ;
768+ let mod_name = self . mod_name ;
769+ let recoverer = self . recoverer ;
770+ let yacckind = self . yacckind ;
771+ let visibility = self . visibility . cow_str ( ) ;
772+ let error_on_conflicts = self . error_on_conflicts ;
773+ writeln ! ( cache, " Build time: {}" , quote!( #build_time) ) . ok ( ) ;
774+ writeln ! ( cache, " Grammar path: {}" , quote!( #grammar_path) ) . ok ( ) ;
775+ writeln ! ( cache, " Mod name: {}" , quote!( #mod_name) ) . ok ( ) ;
776+ writeln ! ( cache, " Recoverer: {}" , quote!( #recoverer) ) . ok ( ) ;
777+ writeln ! ( cache, " YaccKind: {}" , quote!( #yacckind) ) . ok ( ) ;
778+ writeln ! ( cache, " Visibility: {}" , quote!( #visibility) ) . ok ( ) ;
743779 writeln ! (
744780 cache,
745- " Error on conflicts: {:? }\n " ,
746- self . error_on_conflicts
781+ " Error on conflicts: {}\n " ,
782+ quote! ( # error_on_conflicts)
747783 )
748784 . ok ( ) ;
749785
@@ -840,11 +876,8 @@ where
840876 let wrappers = grm
841877 . iter_pidxs ( )
842878 . map ( |pidx| {
843- format ! (
844- "&{prefix}wrapper_{}" ,
845- usize :: from( pidx) ,
846- prefix = ACTION_PREFIX
847- )
879+ let pidx = UnsuffixedUsize ( usize:: from ( pidx) ) ;
880+ format ! ( "&{prefix}wrapper_{}" , quote!( #pidx) , prefix = ACTION_PREFIX )
848881 } )
849882 . collect :: < Vec < _ > > ( )
850883 . join ( ",\n " ) ;
@@ -867,6 +900,7 @@ where
867900 wrappers = wrappers,
868901 edition_lifetime = if self . rust_edition != RustEdition :: Rust2015 { "'_, " } else { "" } ,
869902 ) . ok ( ) ;
903+ let ridx = UnsuffixedUsize ( usize:: from ( self . user_start_ridx ( grm) ) ) ;
870904 write ! (
871905 outs,
872906 "
@@ -880,7 +914,7 @@ where
880914 parse_param = parse_param,
881915 actionskind = ACTIONS_KIND ,
882916 actionskindprefix = ACTIONS_KIND_PREFIX ,
883- ridx = usize :: from ( self . user_start_ridx ( grm ) ) ,
917+ ridx = quote! ( #ridx ) ,
884918 recoverer = recoverer,
885919 )
886920 . ok ( ) ;
@@ -920,7 +954,7 @@ where
920954 if !grm. rule_to_prods ( ridx) . contains ( & grm. start_prod ( ) ) {
921955 write ! (
922956 outs,
923- " #[allow(dead_code)]\n pub const R_{}: {} = {:? };\n " ,
957+ " #[allow(dead_code)]\n pub const R_{}: {} = {};\n " ,
924958 grm. rule_name_str( ridx) . to_ascii_uppercase( ) ,
925959 type_name:: <StorageT >( ) ,
926960 usize :: from( ridx)
@@ -934,10 +968,8 @@ where
934968 fn gen_token_epp ( & self , grm : & YaccGrammar < StorageT > ) -> String {
935969 let mut tidxs = Vec :: new ( ) ;
936970 for tidx in grm. iter_tidxs ( ) {
937- match grm. token_epp ( tidx) {
938- Some ( n) => tidxs. push ( format ! ( "Some(\" {}\" )" , str_escape( n) ) ) ,
939- None => tidxs. push ( "None" . to_string ( ) ) ,
940- }
971+ let tok_epp = QuoteOption ( grm. token_epp ( tidx) ) ;
972+ tidxs. push ( format ! ( "{}" , quote!( #tok_epp) ) ) ;
941973 }
942974 format ! (
943975 " const {prefix}EPP: &[::std::option::Option<&str>] = &[{}];
@@ -966,6 +998,7 @@ where
966998 } ;
967999 for pidx in grm. iter_pidxs ( ) {
9681000 let ridx = grm. prod_to_rule ( pidx) ;
1001+ let pidx_num = UnsuffixedUsize ( usize:: from ( pidx) ) ;
9691002
9701003 // Iterate over all $-arguments and replace them with their respective
9711004 // element from the argument vector (e.g. $1 is replaced by args[0]). At
@@ -977,7 +1010,7 @@ where
9771010 mut {prefix}args: ::std::vec::Drain<{edition_lifetime} ::lrpar::parser::AStackType<<{lexertypest} as ::lrpar::LexerTypes>::LexemeT, {actionskind}<'input>>>,
9781011 {parse_paramdef})
9791012 -> {actionskind}<'input> {{" ,
980- usize :: from ( pidx ) ,
1013+ quote! ( #pidx_num ) ,
9811014 storaget = type_name:: <StorageT >( ) ,
9821015 lexertypest = type_name:: <LexerTypesT >( ) ,
9831016 prefix = ACTION_PREFIX ,
@@ -1242,11 +1275,6 @@ where
12421275 }
12431276}
12441277
1245- /// Return a version of the string `s` which is safe to embed in source code as a string.
1246- fn str_escape ( s : & str ) -> String {
1247- s. replace ( '\\' , "\\ \\ " ) . replace ( '"' , "\\ \" " )
1248- }
1249-
12501278/// This function is called by generated files; it exists so that generated files don't require a
12511279/// dependency on serde and rmps.
12521280#[ doc( hidden) ]
0 commit comments