2.3 At-Notation Parsing
See At-Notation Using @ for an overview of @ notation.
As shown in Token Parsing, each use of @ has one of these forms:
@ command ( argument , ... ) braced_text ...
Converts tocommand_splice(argument, ..., [converted_text, ...], ...)
where command_splice is the same as command, except that an immediately wrapping «…» (if any) is removed, and the conversion of braced_text is described below.
The allowed form of command is described in Token Parsing as ‹command›, and it always corresponds to a group. A group that ends in a block or sequence of alternatives is disallowed. Each argument is also a group, with no additional constraints, but the separating , is optional for arguments that are newline-separated groups. The form of braced_text is described below.
No space is allowed between @ and command, between command and (, between ) and the first braced_text, or between successive braced_texts. Zero or more braced_texts are allowed.
Although a character other than ( after command would normally mean that one of the other @ forms is being used, a [ in that position is treated as a parse error. (This prohibition is intended to support better error reporting when S-expression @ syntax is misused in a shrubbery context.)
@ command braced_text braced_text ...
Converts tocommand_splice([converted_text, ...], ...)
The allowed forms of command and braced_text and the spacing rules are the same as for the first case of @, with no space allowed between command and the first braced_text. One or more braced_texts are allowed.
@ braced_text braced_text ...
Converts to([converted_text, ...], ...)
The allowed forms of braced_text and the spacing rules are the same as preceding @ cases, with no space allowed between @ and the first braced_text. One or more braced_texts are allowed.
@ command
Converts tocommand_splice
The allowed forms of command are the same as for the preceding cases of @, except that command is allowed to be a group that ends in a block or sequence of alternatives if the @ is at the end of the enclosing group. If parentheses or a braced_text follow command, then one of the preceding @ cases applies, instead.
@(« command »)
Converts tocommand
where command is allowed to be any group (but ending in a block or sequence of alternatives only when @ is at the end of the enclosing group), and space is allowed between @(« and command or between command and »).
@// braced_text
A comment form, but allowed only within a braced_text. No space is allowed between @// and braced_text.
@// line newline
A line-comment form, but allowed only within a braced_text, where line does not contain newline characters, and newline is a newline character. (Return characters are not treated as newline characters.) The comment also consumes leading whitespace on the next line.
This form applies only when line does not start with a braced_text opener as described below.
A braced_text starts with an opener, ends with a closer, and has a escape from literal-text mode:
The opener can be {, in which case the closer is } and the escape is @.
The opener can be |, a sequence of non-{ ASCII symbol and punctuation characters, and {. In that case, the closer is }, the flipped sequence of ASCII characters from the opener, and |. In a flipped sequence, not only are the characters in the reverse order, but certain individual characters are flipped: ( to ), ) to (, [ to ], ] to [, < to >, and > to <. The escape is the same sequence as opener, but with @ in place of {. When a sequence after @ could be parsed either as an operator or as part of an opener ending with {, the parse as part of an opener takes precedence.
When multiple braced_texts parts are part of a @ form, each braced_text can use a different opener and closer.
The starting opener and ending closer of a braced_text do not count as part of the braced_text content. Between the starting opener and ending closer, nested instances of the opener and closer can appear. That is, for each opener encountered within braced_text, it is treated as literal, and a balancing closer is also treated as literal instead of the end of the braced_text.
Within braced_text, a use of escape triggers at-notation parsing the same as @ outside of a braced_text, but @// comment forms are also allowed.
The conversion of a braced_text to converted_text proceeds in steps, starting with the content between opener and closer:
Comment escapes are discarded. A line comment using escape followed by // causes the terminating newline to be discarded along with leading whitespace on the next line.
Trailing whitespace on each line is discarded.
The remaining content of braced_text is split into lines, where escapes are treated as atomic elements of a line (i.e., within a line, even if the escape internally has multiple lines of text). Return characters are not treated as newlines, but note that a return–linefeed sequence will act like linefeed, because the return is stripped as trailing whitespace. Each run of literal text between escaped items is a single element within the line. When two escapes are adjacent with no literal text in between, the escaped elements are consecutive in the line, and not separated by an empty literal element. Escapes are never treated as literal text, even when the result of an escape is an immediate string.
If the first line contains only whitespace, the line is discarded. Similarly, if the last line contains only whitespace, the line is discarded. Afterward, if the remaining last line ends with a newline, that trailing newline is also discarded.
The newline associated with each line is split into its own element, if it is not a separate element already.
Leading whitespace on each line is broken out into its own literal element, if it is not a separate element already.
Note that a line that originally contained only whitespace will have just a newline at this point (not even that, if it’s the last line), since trailing whitespace was previously discarded.
Leading whitespace that starts every non-empty line is removed from that element, where a line is non-empty if it contains more than just a newline element. If a leading-whitespace element becomes an empty as a result of removing a shared prefix, the element is removed.
The elements for all lines are concatenated into a single list, and the elements of that list are the converted_texts.