Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Macro Expansion

The three-pass pipeline (DD-13):

Pass 0: Import

Scan for import-macros declarations. Compile the referenced macro modules to JavaScript. Register exported macros in the macro environment.

Pass 1: Fixed-Point Expansion

Process each top-level form. If it contains a macro call, expand it. If the expansion introduces new macro calls, expand again. Repeat until no more expansions occur. This is order-independent — a macro defined on line 10 is available on line 1.

Pass 2: Final Walk

Recursive top-down expansion with a per-node limit to prevent infinite loops.

How Macros Execute

Macro bodies are compiled to JavaScript and evaluated via new Function() — not import(). This keeps compilation synchronous: no async pipeline, no Promise-based phases. The macro runs immediately and returns the expansion.

User-Defined Macros

(macro unless (test (rest body))
  `(if (not ,test) (block ,@body)))

The macro receives s-expression arguments and returns an s-expression expansion. Quasiquote (`), unquote (,), and splicing (,@) build the template. Enforced gensym (# suffix on identifiers) prevents variable capture — accidental hygiene.