[racket-dev] generalized `begin-for-syntax'

From: Vincent St-Amour (stamourv at ccs.neu.edu)
Date: Thu Sep 8 17:32:55 EDT 2011

This is great!

Vincent


At Thu, 8 Sep 2011 14:56:18 -0600,
Matthew Flatt wrote:
> 
> The `begin-for-syntax' form in v5.1.3.7 supports variable and macro
> definitions within a module for all phases N >= 0 (finally!).
> 
> 
> As a simple example, you can use `struct' for-syntax without having to
> add `#:omit-define-syntaxes':
> 
>  #lang racket
> 
>  (begin-for-syntax
>   (require racket/match)
> 
>   (struct posn (x y)) ; binds `posn' as syntax
> 
>   (match (posn 1 2)
>     [(posn x y) ; uses `posn' as syntax
>      (displayln (list x y))]))
> 
> 
> You can also define macros at the top level of a module to
> be used by macro implementations within the module:
> 
>  #lang racket
> 
>  (begin-for-syntax
>   ;; like `syntax-rules', but quasiquotes the template:
>   (define-syntax-rule (syntax-rules~ () [pat tmpl] ...)
>     (lambda (stx)
>       (syntax-case stx ()
>         [pat #`tmpl]
>         ...)))
>   ;; plain old compile-time helper:
>   (define (check-id stx)
>     (unless (identifier? stx)
>       (raise-syntax-error #f "not an identifier" stx))
>     stx))
> 
>  (define-syntax define-five
>    (syntax-rules~ ()
>      [(_ id) (define #,(check-id #'id) 5)]
>      [(_ id 5) (define-five id)]))
> 
>  (define-five V)
>  (define-five wu 5)
>  (+ V wu)
> 
> 
> Perhaps most usefully, you can define a syntax class in the same module
> as a macro that uses `syntax-parse':
> 
>  #lang racket
>  (require (for-syntax syntax/parse))
> 
>  (begin-for-syntax
>   (define-syntax-class two
>     (pattern [x y])))
> 
>  (define-syntax (ark stx)
>    (syntax-parse stx
>      [(_ a:two ...)
>       #'(list '(a ...))]))
> 
>  (ark [snake snake] [tiger tiger] [ant ant])
> 
> 
> A `begin-for-syntax' form can contain `begin-for-syntax' forms with
> phase-2 definitions, and so on.
> 
> ----------------------------------------
> 
> As part of this change, the grammar of fully expanded expressions has
> changed. It no longer includes `define-values-for-syntax', but
> `begin-with-syntax' is a core form, and `begin-with-syntax' forms can
> be nested.
> 
> Code that uses `kernel-syntax-case' with a `define-values-for-syntax'
> case needs to be changed to one with a `begin-with-syntax' case. (I've
> changed the ones in the main code repo.) Fortunately, most code that
> uses `kernel-syntax-case' only handles expressions, in which case there
> is no `define-values-for-syntax' case.
> 
> The `syntax-local-module-defined-identifiers' function now returns a
> hash table mapping phase levels to lists, instead of two lists.
> 
> Some structs from `compiler/zo-structs' have changed: `def-for-syntax'
> is gone, `seq-for-syntax' is added, some `mod' fields have changed
> (such as a `syntax-bodies' instead of `syntax-body'), and
> `def-syntaxes' has a new field.
> 
> The order of expansion for a module body has changed slightly. A
> `begin-for-syntax' form is expanded with the same two-pass algorithm as
> a module body overall, which means that partial expansion is used to
> expose definitions and meta-forms before expanding expressions. All
> `provide' (or, more precisely, `#%provide') forms across all phases are
> delayed until the module is otherwise expanded, and then the
> `#%provide' forms are expanded in the order that they appear within the
> module (independent of phase).
> 
> _________________________________________________
>   For list-related administrative tasks:
>   http://lists.racket-lang.org/listinfo/dev


Posted on the dev mailing list.