racket/collects/syntax/scribblings/parse/ex-mods-stxclasses.scrbl
Ryan Culpepper d7a87c79e0 Merged changes to syntax/parse
Changed backtracking algorithm, runtime representations
    - syntax classes, ~describe no longer implicitly commit
    - ~describe no longer delimits effect of cut
  Added keyword & optional args for stxclasses
  Added ~do and #:do, ~post, ~commit and #:commit,
    ~delimit-cut and #:no-delimit-cut
  Added syntax/parse/debug, syntax/parse/experimental/*
    - expr/c for contracting macro sub-expressions
      moved from syntax/parse to syntax/parse/experimental/contract
    - syntax class reflection (~reflect, ~splicing-reflect)
    - eh-alternative-sets (~eh-var)
    - provide-syntax-class/contract
      (only for params, not attrs so far)
  Changed ~fail to not include POST progress (#:fail still does)
    old (~fail _) is now (~post (~fail _))
  Made msg argument of ~fail optional
  Removed generic "repetition constraint violated" msg
  Removed atom-in-list stxclass
  Removed unnecessary datum->syntax on cdr of pair pattern
    massive improvements to long-list microbenchmarks
  Optimization: integrable syntax classes (id, expr, keyword)
    need better measurements
  Optimization: ad hoc elimination of head/tail choice point
    for (EH ... . ()) patterns
  Added unstable/wrapc (proc version of expr/c)
2010-08-31 10:55:58 -06:00

108 lines
3.8 KiB
Racket

#lang scribble/doc
@(require scribble/manual
scribble/struct
scribble/decode
scribble/eval
"parse-common.rkt"
(for-label racket/class))
@title{Modules and reusable syntax classes}
As demonstrated in the @secref{stxparse-intro}, the simplest place to
define a syntax class is within the macro definition that uses it. But
this location, of course, limits the scope of the syntax class to the
one client macro. Creating reusable syntax classes is slightly
complicated, however, by the Racket @tech[#:doc '(lib
"scribblings/reference/reference.scrbl")]{phase level} separation. A
syntax class defined within a module cannot be used by macros in the
same module; it is defined at the wrong phase.
@myinteraction[
(module phase-mismatch-mod racket
(require syntax/parse (for-syntax syntax/parse))
(define-syntax-class foo
(pattern (a b c)))
(define-syntax (macro stx)
(syntax-parse stx
[(_ f:foo) #'(+ f.a f.b f.c)])))
]
In the module above, the syntax class @scheme[foo] is defined at phase
level 0. The reference to @scheme[foo] within @scheme[macro], however,
is at phase level 1, being the implementation of a macro
transformer. (Needing to require @schememodname[syntax/parse] twice,
once normally and once @scheme[for-syntax] is another sign of the
phase level incompatibility.) The only way to define reusable syntax
classes that can be used within macros is to define them in a separate
module and require that module @scheme[for-syntax].
@myinteraction[
(module stxclass-mod racket
(require syntax/parse)
(define-syntax-class foo
(pattern (a b c)))
(provide foo))
(module macro-mod racket
(require (for-syntax syntax/parse
'stxclass-mod))
(define-syntax (macro stx)
(syntax-parse stx
[(_ f:foo) #'(+ f.a f.b f.c)]))
(provide macro))
(require 'macro-mod)
(macro (1 2 3))
]
If the syntax classes refer to keywords, or if they compute
expressions via syntax templates, then the module containing the
syntax classes must generally require the keywords or bindings used in
the syntax templates @scheme[for-template].
@myinteraction[
(module arith-keywords-mod racket
(define-syntax plus (syntax-rules ()))
(define-syntax times (syntax-rules ()))
(provide plus times))
(module arith-stxclass-mod racket
(require syntax/parse
(for-template 'arith-keywords-mod
racket))
(define-syntax-class arith
#:literals (plus times)
(pattern n:nat
#:with expr #'n)
(pattern (plus a:arith b:arith)
#:with expr #'(+ a.expr b.expr))
(pattern (times a:arith b:arith)
#:with expr #'(* a.expr b.expr)))
(provide arith))
(module arith-macro-mod racket
(require (for-syntax syntax/parse
'arith-stxclass-mod)
'arith-keywords-mod)
(define-syntax (arith-macro stx)
(syntax-parse stx
[(_ a:arith)
#'(values 'a.expr a.expr)]))
(provide arith-macro
(all-from-out 'arith-keywords-mod)))
(require 'arith-macro-mod)
(arith-macro (plus 1 (times 2 3)))
]
In @scheme['arith-stxclass-mod], the module
@scheme['arith-keywords-mod] must be required @scheme[for-template]
because the keywords are used in phase-0 expressions. Likewise, the
module @schememodname[racket] must be required @scheme[for-template]
because the syntax class contains syntax templates involving
@scheme[+] and @scheme[*] (and, in fact, the implicit @scheme[#%app]
syntax). All of these identifiers (the keywords @scheme[plus] and
@scheme[times]; the procedures @scheme[+] and @scheme[*]; and the
implicit syntax @scheme[#%app]) must be bound at ``absolute'' phase
level 0. Since the module @scheme['arith-stxclass-mod] is required
with a phase level offset of 1 (that is, @scheme[for-syntax]), it must
compensate with a phase level offset of -1, or @scheme[for-template].