3.1 Syntax Objects
The '…' form produces a syntax object. The syntax object holds an unparsed shrubbery, not a parsed Rhombus expression.
> '1'
'1'
> 'hello'
'hello'
> '1 + 2'
'1 + 2'
> 'x:
y'
'x: y'
> '1' + 2
+: value does not satisfy annotation
annotation: Number
value: ’1’
Within the '…', the $ operator unquotes the immediately following term. That is, the term after $ is a Rhombus expression whose value replaces the $ and its argument within the quoted form.
'1 + 5'
A $ only unquotes when it is followed by a term, otherwise the $ itself remains quoted.
'1 + $ 2'
Nesting quotes do not require a corresponding nesting of escaping $ to escape outside the original quotes. For example, '('$(1+2)')' is the same as '('3')' in Rhombus, even though the escape is inside two layers of quotes.
Like $, ... is treated specially within a '…'-quoted term (except, like $, when it’s the only thing in the term). When ... immediately follows a term that includes at least one $, the form after that $ must refer to a repetition. Then, instead of the parenthesized group in place of $, the term before ... is replicated as many times as the repetition has items, and each of those items is used in one replication.
When ... is the only term in a group, and when that group follows another, then ... replicates the preceding group. For example, putting ... after a , in parentheses means that it follows a the group before the ,, which effectively replicates that group with its separating comma:
'(hi 1, hi 2, hi 3)'
Along the same lines, ... just after a | can replicate a preceding | block:
'cond
| 1
| 2
| 3'
In other words, ... in various places within a quoted shrubbery works the way you’d expect it to work.
When '…' is used in a binding position, it constructs a pattern that matches syntax objects, and it binds variables that are escaped in the pattern with $.
> x
'1'
> y
'(2 + 3)'
A ... works the way you would expect in a syntax pattern, matching any ...-replicated pattern variables to form a repetition of matches:
A tail pattern $id ... combined with a tail template $id ... is similar to using . in S-expression patterns and templates, where it allows sharing between the input and output syntax objects. That sharing and an associated expansion-cost difference is all the more important in the Rhombus expansion protocol, which must thread potentially long sequences into and out of macro transformers.
A $-escaped variable in a '…' pattern matches one term in with a group, or it matches a whole group if the a $-escaped variable is alone within its group.
> x
'1'
> y
'2'
> x
'1 2 3'
A block created with : counts as a single term of its enclosing group, and a sequence of | alternatives (not an individual alternative) similarly counts as one term.
> x
'block'
> y
': 1 2 3'
> z
'cond'
> w
'| is_ok: "good"
| ~else: "bad"'
Keep in mind that '…' creates syntax objects containing shrubberies that are not yet parsed, so single-term escape will not be matched to a multi-term sequence that would be parsed as an expression. For example, a pattern variable y cannot be matched to a sequence 2 * 3 if there’s another escape after $y.
def: value does not satisfy annotation
value: ’1 + 2 * 3’
annotation: ’1 + $y’
In the same way that an escaped variable alone in its group matches the whole group as a sequence of terms, a pattern variable that is alone in a multi-group context matches a sequence of groups. This rule applies only for multi-group contexts where groups are not separated by ,, such as in a block.
> [group, ...]
['def x = 1', 'x + 1']
> body
'def x = 1
x + 1'
Multi-term and multi-group syntax objects can be spliced into templates where a single term or single group is expected. A list of terms can similarly splice into a context where a single term is expected.
A list of group syntax objects does not splice into a group context, because that would create ambiguities among group and term contexts; instead, the list of group syntax objects must be converted to a multi-group syntax object for splicing when that is the intent. Meanwhile, a single-term syntax object can be used as a group syntax object, a single-group syntax object can be used as a multi-group syntax object, and a single-term syntax object can be used as a multi-group syntax object.
For a multi-group match and template splice, there is no constraint that the original and destination contexts have the same shape, so a match from a block-like context can be put into a brackets context, for example.
> '[$x]'
'[1 + 2 + 3, 4 * 5 * 6]'
Although a $ escape followed by variable in a '…' pattern normally matches only one term, a variable can be annotated with the TermSequence syntax class to match multiple terms. Sequence matches can be ambiguous, in which case ambiguity is resolved by eagerly matching terms to earlier escapes.
> x
'1'
> y
'2 * 3'
> x
'0 + 1'
> y
'2 * 3'
The Group syntax class is similar to Sequence, except that it matches only non-empty term sequences, and it is allowed only in specific positions that do not create ambiguity: places within a group with no escapes afterward. There are several other predefined syntax classes, such as Identifier to match an identifier, String to match a string literal, and Int to match an integer literal.
Use Block to match the full content block, but also keep the enclosing : (preserve its source location and raw text), so that the bound identifier is a block as a single term instead of the block body as a sequence of groups.