@@ -412,8 +412,14 @@ peg::parser! {
412412 }
413413
414414 // N.B. Non-sh extensions allows use of the 'function' word to indicate a function definition.
415+ // N.B. Without the 'function' keyword, reserved words cannot be used as function names
416+ // (bash rejects e.g. `for (){ :; }`). With the 'function' keyword, reserved words are
417+ // allowed as function names (bash accepts e.g. `function for { :; }`).
415418 rule function_definition( ) -> ast:: FunctionDefinition =
416- specific_word( "function" ) ? fname: fname( ) body: function_parens_and_body( ) {
419+ specific_word( "function" ) fname: fname( ) body: function_parens_and_body( ) {
420+ ast:: FunctionDefinition { fname, body }
421+ } /
422+ fname: non_reserved_fname( ) body: function_parens_and_body( ) {
417423 ast:: FunctionDefinition { fname, body }
418424 } /
419425 specific_word( "function" ) fname: fname( ) linebreak( ) body: function_body( ) {
@@ -433,6 +439,9 @@ peg::parser! {
433439 // TODO(parser): Find a way to make this still work without requiring this targeted exception.
434440 w: [ Token :: Word ( word, l) if !word. ends_with( '=' ) ] { ast:: Word :: with_location( word, l) }
435441
442+ rule non_reserved_fname( ) -> ast:: Word =
443+ !reserved_word( ) w: fname( ) { w }
444+
436445 rule brace_group( ) -> ast:: BraceGroupCommand =
437446 start: specific_word( "{" ) list: compound_list( ) end: specific_word( "}" ) {
438447 let loc = SourceSpan :: within( start. location( ) , end. location( ) ) ;
0 commit comments