4 More Topics to Cover
Basic macrology
A macro is a rewrite rule. It only applies to certain terms (no general rewriters like optimization). It only applies in certain context. Expansion is outward-in: discovery process.
Expressions have dynamic and static contexts.
Dynamic context: continuation marks, parameters, other state (order of evaluation, etc).
Static context: environment, syntax parameters. More exotic: phase, submodule.
Basic hygiene.
Basic pattern matching.
Don’t use a macro when a function would suffice.
Not every macro needs to be written.
Intermediate Macrology: Specifying and Validating Syntax
syntax-parse, syntax specification (grammars), validation and error-checking
The structure of syntax. Think in terms of nonterminals. When writing functions on syntax, write one function per nonterminal.
Do functions on subterms first, then talk about moving code to stxclass attrs.
syntax ergonomics, eg positional forms vs keyords vs identifier-tagged subforms.
Ergonomics/conventions: Eval subexprs in original order. Do error checking of arguments in order, when possible.
special subforms (w/o extensibility)
syntax-case and error-checking (aside)
Note: this section might need forward references to Phases section (just point out compile-time vs run-time code, say Phases deals with in more detail later).
Intermediate Macrology: Syntax Objects
Below the pattern-matching abstractions: syntax-e, datum->syntax, and quote-syntax.
Rule: Never use syntax->datum on an expression or a term containing expressions.
Source information.
Syntax properties.
Intermediate Macrology: Phases
Compile-time helper functions, modules, begin-for-syntax, phases, require for-{syntax,template}.
The Why of Phases.
syntax templates, phases, env catalog
Intermediate Macrology: communication w/ syntax-local-value
Communication via syntax-local-value. - ordinary communication - extensible subforms
Intermediate Macrology: uncategorized
Racket language elements: expressions, definitions, module-form forms, etc. Modules and languages.
Communication via compile-time state (eg, identifier tables). Define vs attach.
#%expression
Identifier comparisons: bound-id=?, free-id=? (and phases).
3d syntax.
Hygiene details: marks, renames, namespaces, gradual discovery.
Breaking hygiene: how to do it right, and alternatives.
How to test macros: Test run-time behavior, test binding, test syntax errors.
Monolithic vs microlithic macros. Trampoline style macros.
Applicable structs and macros that act as expressions as well as something else (eg struct names).
template tricks: template, ellipsis-escaping, etc
macro-defining macros, using make-X-transformer to prevent code explosion
Advanced Macrology
Head expansion.
Full expansion, analysis, and transformation (instrumentation). In macro w/ local-expand; in run-time tool w/ expand.
(refer back to monolithic/microlithic/trampoline)
Languages
Two ways of embedding language X in Racket:
(Racket) expr ::= .... | X
X forms are Racket macros. X grammar must not collide with Racket grammar.(Racket) expr ::= .... | (begin-X X)
X forms are not Racket macros. X grammar can collide with Racket grammar. Can have separate begin-X forms for different interpretations/behaviors of X fragments (eg for regular expressions: match vs enumerate).
In (1), if X ::= .... | expr also, then it’s not a language, it’s probably just a library or a data type.
(1) works most naturally with compositional translations. (2) can handle non-compositional translation, but can also do compositional via trampoline style.
Can also have hybrid style (3?) where every X form, when used in Racket context, implicitly does begin-X with self inside.
Other languages notes:
#%module-begin
namespace mangagement: subtracting Racket bindings, renaming, etc
custom macro expanders, syntax-local-value vs static