On this page:
5.1 Syntax Objects
5.1.1 Contracts
syntax-datum/ c
syntax-listof/ c
syntax-list/ c
5.1.2 Syntax Lists
5.1.3 Syntax Conversions
5.1.4 Source Locations Source Location Representations
src/ c
src-known? Syntax Object Source Locations
5.1.5 Macro Transformers
5.1.6 Syntax Errors
5.1.7 Pattern Bindings
5.2 Definitions
5.2.1 Interleaving Definitions and Expressions
5.2.2 Deferred Evaluation in Modules
5.2.3 Conditional Binding
5.2.4 Renaming Definitions
5.2.5 Forward Declarations
5.2.6 Definition Shorthands
5.2.7 Effectful Transformation
in-phase1/ pass2

5 Macros

5.1 Syntax Objects

 (require (planet cce/scheme:7:2/syntax))

This module provides tools for macro transformers.

5.1.1 Contracts

(syntax-datum/c datum/c)  flat-contract?
  datum/c : any/c
Recognizes syntax objects stx such that (syntax->datum stx) satisfies datum/c.

(syntax-listof/c elem/c)  flat-contract?
  elem/c : any/c
Recognizes syntax objects stx such that (syntax->list stx) satisfies (listof elem/c).

(syntax-list/c elem/c ...)  flat-contract?
  elem/c : any/c
Recognizes syntax objects stx such that (syntax->list stx) satisfies (list/c elem/c ...).

5.1.2 Syntax Lists

(syntax-list template ...)
This form constructs a list of syntax objects based on the given templates. It is equivalent to (syntax->list #'(template ...)).


  > (with-syntax ([(x ...) #'(1 2 3)])  (syntax-list x ...))

  '(#<syntax:2:0 1> #<syntax:2:0 2> #<syntax:2:0 3>)

(syntax-map f stx)  (listof A)
  f : (-> syntax? A)
  stx : syntax?
Performs (map f (syntax->list stx)).


  > (syntax-map syntax-e #'(a (b c) d))

  '(a (#<syntax:2:0 b> #<syntax:2:0 c>) d)

5.1.3 Syntax Conversions

(to-syntax datum    
  [#:stx stx    
  #:src src    
  #:ctxt ctxt    
  #:prop prop    
  #:cert cert])  syntax?
  datum : any/c
  stx : (or/c false/c syntax?) = #f
  src : src/c = stx
  ctxt : (or/c false/c syntax?) = stx
  prop : (or/c false/c syntax?) = stx
  cert : (or/c false/c syntax?) = stx
A wrapper for datum->syntax with keyword arguments.

The "master" keyword #:stx sets all attributes from a single syntax object, defaulting to #f for unadorned syntax objects.

The individual keywords #:src, #:ctxt, #:prop, and #:cert override #:stx for individual syntax object attributes. They control source src information, lexical context information, syntax object properties, and syntax certificates, respectively.


  (define blank-stx (to-syntax 'car))
  > blank-stx

  #<syntax car>

  > (syntax-e blank-stx)


  > (free-identifier=? blank-stx #'car)


  (define full-stx (to-syntax 'car #:stx #'here))
  > full-stx

  #<syntax:6:0 car>

  > (syntax-e full-stx)


  > (free-identifier=? full-stx #'car)


  (define partial-stx (to-syntax 'car #:ctxt #'here))
  > partial-stx

  #<syntax car>

  > (syntax-e partial-stx)


  > (free-identifier=? partial-stx #'car)


(to-datum x)  (not/c syntax?)
  x : any/c
A wrapper for syntax->datum. Produces (syntax->datum x) if x is a syntax object and x otherwise.


  > (to-datum #'(a b c))

  '(a b c)

  > (to-datum (list #'a #'b #'c))

  '(#<syntax:3:0 a> #<syntax:3:0 b> #<syntax:3:0 c>)

5.1.4 Source Locations Source Location Representations

This contract recognizes various representations of source locations, including srcloc structures and those accepted by datum->syntax: syntax objects, source location lists, source location vectors, and #f.

(src->srcloc loc ...)  srcloc?
  loc : src/c
(src->syntax loc ...)  syntax?
  loc : src/c
(src->list loc ...)
(list/c any/c
        (or/c exact-positive-integer? #f)
        (or/c exact-nonnegative-integer? #f)
        (or/c exact-nonnegative-integer? #f)
        (or/c exact-positive-integer? #f))
  loc : src/c
(src->vector loc ...)
(vector/c any/c
          (or/c exact-positive-integer? #f)
          (or/c exact-nonnegative-integer? #f)
          (or/c exact-nonnegative-integer? #f)
          (or/c exact-positive-integer? #f))
  loc : src/c
These functions combine multiple source locations and convert them to a specific format. If all provided source locations come from the same source, the result is a source location from the same source that spans all the lines, columns, and positions included in the originals. If no source locations are provided, or locations from different sources are provided, the result is a source location with no information (#f for source, line, column, position, and span).


  > (src->srcloc (datum->syntax #f null (list 'source 2 3 4 5)))

  (srcloc 'source 2 3 4 5)

  > (src->syntax (make-srcloc 'source 2 3 4 5))

  #<syntax:2:3 ()>

  > (src->list (list 'source 2 3 4 5) (vector 'source 6 7 8 9))

  '(source 2 3 4 13)

  > (src->vector)

  '#(#f #f #f #f #f)

(src-known? loc)  boolean?
  loc : src/c
Reports whether loc has any non-#f fields.


  > (src-known? (list #f #f #f #f #f))


  > (src-known? (list 'source #f #f #f #f))


  > (src-known? (list 'source 1 2 3 4))

  #t Syntax Object Source Locations

(syntax-source-directory stx)  (or/c path? #f)
  stx : syntax?
(syntax-source-file-name stx)  (or/c path? #f)
  stx : syntax?
These produce the directory and file name, respectively, of the path with which stx is associated, or #f if stx is not associated with a path.


  (define loc
    (list (build-path "/tmp" "dir" "somewhere.ss")
          #f #f #f #f))
  (define stx1 (datum->syntax #f 'somewhere loc))
  > (syntax-source-directory stx1)


  > (syntax-source-file-name stx1)


  (define stx2 (datum->syntax #f 'nowhere #f))
  > (syntax-source-directory stx2)


  > (syntax-source-directory stx2)


(syntax-source-planet-package stx)
(or/c (list/c string?
  stx : syntax?
(syntax-source-planet-package-owner stx)  (or/c string? #f)
  stx : syntax?
(syntax-source-planet-package-name stx)  (or/c string? #f)
  stx : syntax?
(syntax-source-planet-package-major stx)
  (or/c exact-nonnegative-integer? #f)
  stx : syntax?
(syntax-source-planet-package-minor stx)
  (or/c exact-nonnegative-integer? #f)
  stx : syntax?
(syntax-source-planet-package-symbol stx    
  [text])  (or/c symbol? #f)
  stx : syntax?
  text : (or/c text? #f) = #f
These functions extract the planet package with which stx is associated, if any, based on its source location information and the currently installed set of planet packages. They produce, respectively, the planet package s-expression, its owner, name, major version number, minor version number, or a symbol corresponding to a planet module path. They each produce #f if stx is not associated with a planet package.


  (define loc
    (list (build-path (current-directory) "file.ss")
          #f #f #f #f))
  (define stx (datum->syntax #f 'stx loc))
  > (syntax-source-planet-package stx)

  '("cce" "scheme.plt" 7 2)

  > (syntax-source-planet-package-owner stx)


  > (syntax-source-planet-package-name stx)


  > (syntax-source-planet-package-major stx)


  > (syntax-source-planet-package-minor stx)


  > (syntax-source-planet-package-symbol stx)


  > (syntax-source-planet-package-symbol stx "there")


(make-planet-path stx id)  syntax?
  stx : syntax?
  id : (or/c identifier? #f)
Constructs a syntax object representing a require spec for the planet package from which stx arises, with suffix id (if any).


  (define loc
    (list (build-path (current-directory) "file.ss")
          #f #f #f #f))
  (define stx (datum->syntax #f 'stx loc))
  > (make-planet-path stx #f)

  #<syntax (planet cce/scheme:7:2)>

  > (make-planet-path stx #'there)

  #<syntax:5:0 (planet cce/scheme:7:2/there)>

5.1.5 Macro Transformers

Constructs a function that behaves like a rename transformer; it does not cooperate with syntax-local-value like a rename transformer does, but unlike a rename transformer it may be used as a function to transform a syntax object referring to one identifier into a syntax object referring to another.


  > ((redirect-transformer #'x) #'a)

  #<syntax:2:0 x>

  > ((redirect-transformer #'y) #'(a b c))

  #<syntax:3:0 (y b c)>

(head-expand stx stop-list)  syntax?
  stx : syntax?
  stop-list : (listof identifier?)
This function performs head expansion on stx. In other words, it uses local-expand to expand stx until its head identifier is a core form (a member of (full-kernel-form-identifier-list)) or a member of stop-list, or until it can not be expanded further (e.g. due to error).

It is equivalent to (local-expand stx (syntax-local-context) (append stop-ids (full-kernel-form-identifier-list) #f)).

This function produces the full list of identifiers that may be found in fully expanded code produced by expand, local-expand, and related functions. It is similar to kernel-form-identifier-list, except that in prior versions of PLT Scheme that excluded module top-level forms from the list, this function includes them.


  > (full-kernel-form-identifier-list)

  '(#<syntax #%require> #<syntax #%provide> #<syntax module> #<syntax #%plain-module-begin> #<syntax begin> #<syntax begin0> #<syntax define-values> #<syntax define-syntaxes> #<syntax define-values-for-syntax> #<syntax set!> #<syntax let-values> #<syntax letrec-values> #<syntax #%plain-lambda> #<syntax case-lambda> #<syntax if> #<syntax quote> #<syntax letrec-syntaxes+values> #<syntax with-continuation-mark> #<syntax #%expression> #<syntax #%plain-app> #<syntax #%top> #<syntax #%datum> #<syntax #%variable-reference>)

Produces a transformer that can emit multiple results during macro expansion, to be spliced together via begin. This can be useful for compound expansion that relies on transformer definitions, as well as on expansion state that is difficult to marshall.

Specifically, f is invoked with three arguments. The first is the function used to emit intermediate results (other than the last one). The second applies the syntax mark used for the entire expansion; syntax-local-introduce will not be reliable during this process. The third is the syntax object to expand.


  > (define-syntax magic-begin
       (lambda (emit intro stx)
         (syntax-case stx ()
           [(_ term ...)
            (let loop ([terms (syntax->list #'(term ...))])
               [(null? terms) #'(begin)]
               [(null? (cdr terms)) (car terms)]
                (printf "Presto: ~s!\n"
                        (syntax->datum (car terms)))
                (emit (car terms))
                (loop (cdr terms))]))]))))
   (define x 1)
   (define y 2)
   (+ x y))

  Presto: (define x 1)!

  Presto: (define y 2)!


(quote-transformer x)  syntax?
  x : any/c
Produces a syntax object representing an expression that reconstructs x when executed, including faithfully reconstructing any syntax objects contained in x. Note that quote normally converts syntax objects to non-syntax data, and quote-syntax does the opposite.


  > (define-for-syntax x (list 1 #'(2 3) 4))
  > (define-syntax (the-many-faces-of-x stx)
      (with-syntax ([x x] [qx (quote-transformer x)])
       #'(list 'x
               (quote-syntax x)
  > (the-many-faces-of-x)

  '((1 (2 3) 4) #<syntax (1 (2 3) 4)> (1 #<syntax:2:0 (2 3)> 4))

5.1.6 Syntax Errors

A parameter that may be used to store the current syntax object being transformed. It is not used by the expander; you have to assign to it yourself. This parameter is used by syntax-error, below. It defaults to #f.

(syntax-error stx fmt arg ...)  none/c
  stx : syntax?
  fmt : string?
  arg : any/c
Raises a syntax error based on the locations of (current-syntax) and stx, with (format fmt arg ...) as its message.


  (define stx #'(a b c))
  > (parameterize ([current-syntax #f])
      (syntax-error stx "~s location" 'general))

  eval:2:0: a: general location in: (a b c)

  > (parameterize ([current-syntax stx])
      (syntax-error (car (syntax-e stx)) "~s location" 'specific))

  eval:2:0: a: specific location at: a in: (a b c)

5.1.7 Pattern Bindings

(with-syntax* ([pattern expr] ...) body ...+)
Like with-syntax, but with nested scope.


  > (with-syntax* ([a #'id] [b #'a]) (syntax-e #'b))


5.2 Definitions

 (require (planet cce/scheme:7:2/define))

This module provides macros for creating and manipulating definitions.

5.2.1 Interleaving Definitions and Expressions

(block def-or-expr ...)
This expression establishes a lexically scoped block (i.e. an internal definition context) in which definitions and expressions may be interleaved. Its result is that of the last term (after begin-splicing), executed in tail position, if the term is an expression; if there are no terms, or the last term is a definition, its result is (void).

This form is equivalent to (begin-with-definitions def-or-expr ...).


  (define (intersection list-one list-two)
      (define hash-one (make-hash))
      (for ([x (in-list list-one)])
        (hash-set! hash-one x #t))
      (define hash-two (make-hash))
      (for ([x (in-list list-two)])
        (hash-set! hash-two x #t))
      (for/list ([x (in-hash-keys hash-one)]
                 #:when (hash-has-key? hash-two x))
  > (intersection (list 1 2 3) (list 2 3 4))

  '(2 3)

5.2.2 Deferred Evaluation in Modules

(at-end expr)
When used at the top level of a module, evaluates expr at the end of the module. This can be useful for calling functions before their definitions.


  > (module Failure scheme
      (f 5)
      (define (f x) x))
  > (require 'Failure)

  reference to an identifier before its definition: f in

  module: 'Failure

  > (module Success scheme
      (require (planet cce/scheme))
      (at-end (f 5))
      (define (f x) x))
  > (require 'Success)

5.2.3 Conditional Binding

(define-if-unbound x e)
(define-if-unbound (f . args) body ...)
(define-values-if-unbound [x ...] e)
(define-syntax-if-unbound x e)
(define-syntax-if-unbound (f . args) body ...)
(define-syntaxes-if-unbound [x ...] e)
These forms define each x (or f) if no such binding exists, or do nothing if the name(s) is(are) already bound. The define-values-if-unbound and define-syntaxes-if-unbound forms raise a syntax error if some of the given names are bound and some are not.

These are useful for writing programs that are portable across versions of PLT Scheme with different bindings, to provide an implementation of a binding for versions that do not have it but use the built-in one in versions that do.


  > (define-if-unbound x 1)
  > x


  (define y 2)
  > (define-if-unbound y 3)
  > y


5.2.4 Renaming Definitions

(define-renamings [new old] ...)
This form establishes a rename transformer for each new identifier, redirecting it to the corresponding old identifier.


  > (define-renamings [def define] [lam lambda])
  > (def plus (lam (x y) (+ x y)))
  > (plus 1 2)


5.2.5 Forward Declarations

(declare-names x ...)
This form provides forward declarations of identifiers to be defined later. It is useful for macros which expand to mutually recursive definitions, including forward references, that may be used at the PLT Scheme top level.

5.2.6 Definition Shorthands

(define-with-parameter name parameter)
Defines the form name as a shorthand for setting the parameter parameter. Specifically, (name value body ...) is equivalent to (parameterize ([parameter value]) body ...).


  > (define-with-parameter with-input current-input-port)
  > (with-input (open-input-string "Tom Dick Harry") (read))


(define-single-definition define-one-name define-many-name)
This form defines a marco define-one-name as a single identifier definition form with function shorthand like define and define-syntax, based on an existing macro define-many-name which works like define-values or define-syntaxes.


  > (define-single-definition define-like define-values)
  > (define-like x 0)
  > x


  > (define-like (f a b c) (printf "~s, ~s\n" a b) c)
  > (f 1 2 3)

  1, 2


5.2.7 Effectful Transformation

This form executes e during phase 1 (the syntax transformation phase) relative to its context, during pass 1 if it occurs in a head expansion position.

This form executes e during phase 1 (the syntax transformation phase) relative to its context, during pass 2 (after head expansion).