diff --git a/Base/usr/share/man/man5/Shell.md b/Base/usr/share/man/man5/Shell.md index 5c0f1cd8ba..278f197e46 100644 --- a/Base/usr/share/man/man5/Shell.md +++ b/Base/usr/share/man/man5/Shell.md @@ -44,6 +44,17 @@ Any sequence of _Double Quoted String Part_ tokens: * Evaluate expressions * Escaped sequences +##### Heredocs +Heredocs are made in two parts, the _initiator_ and the _contents_, the _initiator_ may be used in place of a string (i.e. wherever a string is allowed to be used), with the constraint that the _contents_ must follow the _sequence_ that the _initiator_ is used in. + +There are four different _initiators_: +- `<<-token`: The _contents_ may contain interpolations, and are terminated with a line containing only whitespace and then _token_ +- `<<-'token'`: The _contents_ may _not_ contain interpolations, but otherwise is the same as `<<-token` +- `<<~token`: Similar to `<<-token`, but the starting whitespace of the lines in the _contents_ is stripped, note that this happens after any and all expansions/interpolations are done. +- `<<~'token'`: Dedents (i.e. strips the initial whitespace) like `<<~token`, and disallows interpolations like `<<-'token'`. + +Note that heredocs _must_ be listed in the same order as they are used after a sequence that has been terminated with a newline. + ##### Variable Reference Any sequence of _Identifier_ characters, or a _Special Variable_ following a `$`. Variables may be followed by a _Slice_ (see [Slice](#Slice)) @@ -387,7 +398,9 @@ and_logical_sequence :: pipe_sequence '&' '&' and_logical_sequence | pipe_sequence terminator :: ';' - | '\n' + | '\n' [?!heredoc_stack.is_empty] heredoc_entries + +heredoc_entries :: { .*? (heredoc_entry) '\n' } [each heredoc_entries] variable_decls :: identifier '=' expression (' '+ variable_decls)? ' '* | identifier '=' '(' pipe_sequence ')' (' '+ variable_decls)? ' '* @@ -407,7 +420,7 @@ control_structure[c] :: for_expr continuation_control :: 'break' | 'continue' -for_expr :: 'for' ws+ (('enum' ' '+ identifier)? identifier ' '+ 'in' ws*)? expression ws+ '{' [c] toplevel '}' +for_expr :: 'for' ws+ (('index' ' '+ identifier ' '+)? identifier ' '+ 'in' ws*)? expression ws+ '{' [c] toplevel '}' loop_expr :: 'loop' ws* '{' [c] toplevel '}' @@ -451,6 +464,12 @@ string_composite :: string string_composite? | bareword string_composite? | glob string_composite? | brace_expansion string_composite? + | heredoc_initiator string_composite? {append to heredoc_entries} + +heredoc_initiator :: '<' '<' '-' bareword {*bareword, interpolate, no deindent} + | '<' '<' '-' "'" [^']* "'" {*string, no interpolate, no deindent} + | '<' '<' '~' bareword {*bareword, interpolate, deindent} + | '<' '<' '~' "'" [^']* "'" {*bareword, no interpolate, deindent} string :: '"' dquoted_string_inner '"' | "'" [^']* "'" @@ -476,7 +495,7 @@ comment :: '#' [^\n]* immediate_expression :: '$' '{' immediate_function expression* '}' -immediate_function :: identifier { predetermined list of names, see Shell.h:ENUMERATE_SHELL_IMMEDIATE_FUNCTIONS } +immediate_function :: identifier { predetermined list of names, see Shell.h:ENUMERATE_SHELL_IMMEDIATE_FUNCTIONS } history_designator :: '!' event_selector (':' word_selector_composite)?