10 Utilities for Macros
(require lathe-comforts/syntax) | |
package: lathe-comforts-lib |
The lathe-comforts/syntax module defines utilities for use at macroexpansion time.
Some of these utilities are useful for parsing syntax in a way that requires a property we call autopticity. We consider a macro call to be autoptic when all the cons cells, keywords, unquotes, and other structural elements that need to be crawled into or checked for identity (excluding things at the leaves like expressions, data literals, and identifiers not given meaning by the macro’s own design) are all right there at the macro call site, where we can see them all at once. In technical detail, a syntax object representing one of these cons cells or other structural elements is required to have a set of scopes that’s equal to or a superset of the set of scopes on the overall macro call, as though the macro call has created local bindings of what these particular structural elements mean in these particular positions. This helps ensure that even though Racket expressions are often made of cons cells, an arbitrary Racket expression inserted into one of these positions by a macro’s syntax template will not have its cons cells misinterpreted.
An example of a situation which would be ameliorated by use of autoptic parsing is the cond syntax. Racket’s cond is extended by both a => clause notation and the ability to use internal definitions. Someone who wants to define another control flow operation that allows internal definitions might simply insert the user’s definitions into the cond body, but this can inadvertently allow a user to write => at the start of the body as a way to elicit unintended behavior from the control flow abstraction. If the => notation were recognized as a structural element whose meaning was bound by the cons form, then it would simply not be in scope within the user’s inserted definitions, just as for any other local binding within a macroexpansion template.
procedure
(scopes-empty? stx) → boolean?
stx : syntax?
pattern expander
{~autoptic-list-to surrounding-stx pattern}
surrounding-stx : syntax?
Parsing using this pattern helps to ensure autopticity of the call site being parsed.
This syntax itself must also be called with autopticity. An occurrence of a cons cell that’s part of the call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the entire call, as though the call has created a local binding of what a cons cell means in these positions. This helps ensure that even though Racket expressions are often made of cons cells, an expression inserted into one of these positions by a macro’s syntax template will not have its cons cells misinterpreted.
pattern expander
{~autoptic pattern}
Parsing using this pattern helps to ensure autopticity of the call site being parsed.
This syntax itself must also be called with autopticity. An occurrence of a cons cell that’s part of the call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the entire call, as though the call has created a local binding of what a cons cell means in these positions. This helps ensure that even though Racket expressions are often made of cons cells, an expression inserted into one of these positions by a macro’s syntax template will not have its cons cells misinterpreted.
pattern expander
{~autoptic-list pattern}
Parsing using this pattern helps to ensure autopticity of the call site being parsed.
This syntax itself must also be called with autopticity. An occurrence of a cons cell that’s part of the call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the entire call, as though the call has created a local binding of what a cons cell means in these positions. This helps ensure that even though Racket expressions are often made of cons cells, an expression inserted into one of these positions by a macro’s syntax template will not have its cons cells misinterpreted.