Generic Syntax Expanders
This library provides forms to define generic syntax expanders. These are essentially macros that have no meaning on their own, but other macros can be told to expand all generic syntax expanders of some type in some portion of their body before themselves expanding. This is similar to how Racket’s built in match form has match expanders, which allows the grammar of the match form to be extended with custom match expanders using define-match-expander. This library generalizes the concept, making complex macros more composable and extensible.
Source code is available at https://github.com/jackfirth/generic-syntax-expanders
1 Expanders And Transformers
Generic expanders are implemented as values of the expander? struct bound with define-syntax, that store both a type and a transformer procedure. Future versions of this library may support storing an additional transformer for use outside expander-contexts in normal syntax parsing. This could be used for better error messages, or for an expander meant to have meaning in both a particularly typed expansion context and a normal expression expansion context.
procedure
(expander-of-type? type expander) → boolean?
type : expander-type? expander : expander?
> (define A (make-expander-type)) > (define exp (expander A (λ (stx) stx))) > (expander-of-type? A exp) #t
procedure
(expand-syntax-tree-with-expanders-of-type type syntax) → syntax? type : expander-type? syntax : syntax?
2 Expander Types
Under the hood, each generic expander defined with this library has an associated expander type. Syntax transformers built with this library examine this type to determine whether or not they should expand them.
procedure
> (expander-type? (make-expander-type)) #t
> (expander-type? 'foo) #f
procedure
> (make-expander-type) '#s(expander-type g42277)
procedure
(make-union-expander-type type ...+) → expander-type?
type : expander-type?
> (make-union-expander-type (make-expander-type) (make-expander-type)) '#s(expander-type (g43535 g43536))
procedure
(expander-type-includes? type-1 type-2) → boolean?
type-1 : expander-type? type-2 : expander-type?
> (define A (make-expander-type)) > (define B (make-expander-type)) > (define C (make-expander-type)) > (expander-type-includes? A A) #t
> (expander-type-includes? B C) #f
> (define AB (make-union-expander-type A B)) > (define BC (make-union-expander-type B C)) > (expander-type-includes? AB A) #t
> (expander-type-includes? AB C) #f
> (expander-type-includes? AB BC) #t
3 Defining Generic Syntax Expanders
This module provides a high-level API for creating generic expanders for use with other macros.
syntax
(define-expander-type id)
id-expander-type - a new unique expander-type? bound at phase level 1
make-id-expander - a procedure bound at phase level 1 that accepts a transformer procedure and returns an expander? with id-expander-type
id-expander? - a predicate bound at phase level 1 recognizing expanders produced by make-id-expander
define-id-expander - a syntactic form at phase level 0 that takes an identifier and a transformer procedure and binds the identifier as a id-expander? for use in a transformer environment
expand-all-id-expanders - a procedure bound at phase level 1 that’s equivalent to expand-syntax-tree-with-expanders-of-type with the id-expander-type as the type argument
4 Lens Scoped Syntax Transformers
This module uses the lens package to create syntax transformers that affect only some small subpiece of a syntax object and compose them with other transformers. This allows for the creation of a macro that cedes control to other macros to pre-expand parts of its body before the macro expands. Combined with the syntax transformer produced by define-expander-type, this makes it easy to define a macro that expands all instances of a generic expander type in a specific subpiece of its body, turning it into an extensible macro.
procedure
((with-scoped-pre-transformer transformer stx-lens pre-transformer) stx) → syntax? transformer : (-> syntax? syntax?) stx-lens : lens? pre-transformer : (-> syntax? syntax?) stx : syntax?
procedure
((with-scoped-pre-transformers transformer pre-transformer-lens-pairs) stx) → syntax? transformer : (-> syntax? syntax?)
pre-transformer-lens-pairs :
(listof (list/c lens? (-> syntax? syntax?))) stx : syntax?
5 Lens Scoped Syntax Transformers - Definition Form
Syntax definition forms built on with-scoped-pre-transformer and friends.
syntax
(define-syntax-with-scoped-pre-transformers id ([stx-lens pre-transformer] ...) transformer-expr)
6 require and provide transformers
require transformer
(expander-in require-spec id)
id-expander-type
make-id-expander
id-expander?
define-id-expander
expand-all-id-expanders
provide transformer
(expander-out id)
id-expander-type
make-id-expander
id-expander?
define-id-expander
expand-all-id-expanders