Block quasiquote

Syntax: `HEAD: BODY (reader shorthand); #`HEAD: BODY keeps hygiene marks

There is no quasiquote-block special. A backtick immediately before a block head is a reader shorthand that lowers to compile/quasiquote over the block’s raw #block: cons, through the layout/quasiquote handler; #` lowers to compile/quasiquote-syntax through layout/quasiquote-syntax.

Use-case: Capture an indented block as a template, with ,EXPR and ,@EXPR unquote sites active throughout the header and the body. This is how macros are written in block syntax.

Behaviour: The reader installs the , and ,@ reader macros for the duration of the header and body read, reads the block raw, and wraps it in a synthetic (#block: (quasiquote) INNER) form. The layout/quasiquote handler unboxes that to (compile/quasiquote INNER). The quasiquote fills the unquote sites and leaves the #block: structure in place; it runs no layout handlers.

After the header, a #block: holds one entry per body line: a #line: cons over that line’s elements, or a nested block. A line holding only an unquote-splicing form is marked #splice:, so the spliced forms spread into one (#line: FORM) entry each when the filled block is expanded. An unquote-splicing sharing a line with other elements splices into that line.

The backtick must open the statement, and it reads the primary block only – a peer written at the same indentation as the quasiquoted head is not gathered. Peers nested inside the block are ordinary nested #block: entries.

Examples:

>>> var forms '(1 2 3)
>>> var tmpl:
...   `begin:
...     ,@forms
>>> tmpl
(#block: (begin) (#splice: 1 2 3))

A nested peer stays a nested entry:

>>> var cnd '(> n 1)
>>> var thn "big"
>>> var els "small"
>>> var q:
...   `begin:
...     if ,cnd:
...       ,thn
...     else:
...       ,els
>>> q
(#block: (begin) (#block: (if (> n 1)) (#line: "big")) (#block: (else) (#line: "small")))

Expansion: A filled block is still reader form. Macro expansion runs the layout handlers over a transformer’s output before the captured material is unboxed, so a macro whose template is a block quasiquote needs no extra step. A pipeline that builds a block at run time and wants source out of it calls apply-layout itself:

>>> (apply-layout tmpl (globals))
(begin 1 2 3)

Nesting: A nested block quasiquote is ordinary nested quasiquote – the level increases, and the inner template is reconstructed as data rather than filled.

See also: compile/quasiquote, Block quote, Block quasiquote and layout expansion.