@@ -973,7 +973,12 @@ where
973973 None
974974 } ;
975975
976- let mod_name = format_ident ! ( "{}" , mod_name) ;
976+ let mod_name = match syn:: parse_str :: < proc_macro2:: Ident > ( mod_name) {
977+ Ok ( s) => s,
978+ Err ( e) => {
979+ return Err ( format ! ( "CTParserBuilder::mod_name(\" {}\" ) is not a valid rust identifier due to '{}'" , mod_name, e) . into ( ) )
980+ }
981+ } ;
977982 let out_tokens = quote ! {
978983 #visibility mod #mod_name {
979984 // At the top so that `user_actions` may contain #![inner_attribute]
@@ -1801,6 +1806,34 @@ C : 'a';"
18011806 }
18021807 }
18031808
1809+ #[ test]
1810+ /// Tests a yacc .y filename containing a dash character leading to an invalid rust identifier
1811+ /// when that dash is subsequently used as the default `CTParserBuilder::mod_name`.
1812+ fn test_invalid_identifier_in_derived_mod_name ( ) {
1813+ let temp = TempDir :: new ( ) . unwrap ( ) ;
1814+ let mut file_path = PathBuf :: from ( temp. as_ref ( ) ) ;
1815+ file_path. push ( "contains-a-dash.y" ) ;
1816+ let mut f = File :: create ( & file_path) . unwrap ( ) ;
1817+ let _ = f. write_all (
1818+ "%start A
1819+ %%
1820+ A : 'a';"
1821+ . as_bytes ( ) ,
1822+ ) ;
1823+ match CTParserBuilder :: < TestLexerTypes > :: new ( )
1824+ . yacckind ( YaccKind :: Original ( YaccOriginalActionKind :: GenericParseTree ) )
1825+ . grammar_path ( file_path. to_str ( ) . unwrap ( ) )
1826+ . output_path ( file_path. with_extension ( "ignored" ) )
1827+ . build ( )
1828+ {
1829+ Ok ( _) => panic ! ( "Expected error" ) ,
1830+ Err ( e) => {
1831+ let err_string = e. to_string ( ) ;
1832+ assert_eq ! ( err_string, "CTParserBuilder::mod_name(\" contains-a-dash_y\" ) is not a valid rust identifier due to 'unexpected token'" ) ;
1833+ }
1834+ }
1835+ }
1836+
18041837 #[ cfg( test) ]
18051838 #[ test]
18061839 fn test_recoverer_header ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
0 commit comments