compile/extend-syntax
Syntax: (extend-syntax NAME TRANSFORMER), with the same transformer
heads as syntax, bare-syntax included.
Behaviour: Rebinds compile/NAME at the module to the combination
of the existing transformer and the new spec, through
define-global, so the form may
sit inside a function body and still extends the module’s transformer.
The new arms exist once the form has run, and apply to forms compiled
after that, as with every transformer bound from a body. The new arms
take precedence: a base transformer can carry a generic fall-through
case and a later extension that adds a more specific case wins wherever
both match. That is the basis of open dispatch, a base
(config (tp name) ...) plus per-type extend-syntax config cases
keyed on a literal head.
A syntax written inside a body is scoped to that
body and is never bound as compile/NAME, so an extend-syntax of it
reads an unbound name when the body runs. Give a body-scoped
transformer its arms in its own syntax form, or use
let-syntax.
The original docstring carries forward, and a docstring in the extension
is appended to it. A transformer holds at most one bare form, so
extending with bare-syntax replaces the existing bare arm.
Extensions compose across imports. After import-from mod foo,
extending foo in the importing module adds cases that route there
while the base rules still apply to inputs the new cases do not match.
A library can ship a base macro and let each consumer specialize it.
Examples:
syntax greet:
syntax-rules []:
greet name:
f"hello {name}"
extend-syntax greet:
syntax-rules [loud]:
greet loud name:
f"HELLO {name}"
(greet "a") ;; "hello a"
(greet loud "b") ;; "HELLO b"
See also: syntax,
define-syntax,
decorate-subject, whose shape arms are
extended this way.