Syntax Parse Examples
1 How to browse the examples
2 How to use the examples in another project
3 How to contribute a new example
4 Tutorials
5 A syntax-parse Crash Course
6 The Examples
6.1 first-class-or
6.2 optional-assert
exn:  fail:  optional-assert?
6.3 Cross Macro Communication
6.4 let-star
6.5 def
6.6 conditional-require
6.7 multi-check-true
6.8 define-datum-literal-set
6.9 rec/  c
rec/  c
6.10 struct-list
6.11 syntax-class-contract
6.12 except-in-quiet
6.13 dot-underscore
7 Example-Formatting Tools
tech/  guide
tech/  reference

Syntax Parse Examples

Source code:

This package is a collection of useful and/or illustrative macros written using the syntax/parse library.
The Example-Formatting Tools section documents the syntax-parse-example language.

1 How to browse the examples

Two options:
  • Scroll through this document, read the macros’ source code and look at the example uses of each macro.

  • The source code for each macro is in a top-level folder at For example, the source for a macro named big-mac would be in the folder

2 How to use the examples in another project

Three options, ordered from best to worst.
  • Copy/paste the example code into a new file in your project, require that new file normally.

  • Install the syntax-parse-example package, then require the macro’s defining module. For example, the defining module for the first-class-or macro is "syntax-parse-example/first-class-or/first-class-or".

  • Clone the source code, then require the module path of the file that defines the macro.

3 How to contribute a new example

To create an example named EUGENE:
  • Clone this repository (link).

  • Run raco syntax-parse-example --new EUGENE in the top-level folder of the cloned repository. This generates three new files:
    • EUGENE/EUGENE.rkt (source code)

    • EUGENE/EUGENE-test.rkt (tests)

    • EUGENE/EUGENE-doc.scrbl (Scribble documentation)

  • Fill the holes in the newly-generated files with an implementation, some unit tests, and documentation.

  • Run raco setup syntax-parse-example to generate the documentation.

4 Tutorials

Where to learn about syntax-parse?

The Fear of Macros tutorial is a great resource for basic macro engineering (though, not syntax-parse in particular).

5 A syntax-parse Crash Course

The syntax-parse form is a tool for un-packing data from a syntax object. It is similar to Racket’s match. Since the input to a macro is always a syntax object, syntax-parse is helpful for writing macros.

A syntax object is a Racket representation of source code. For example, #'(+ 1 2) is a syntax object that represents the sequence of characters (+ 1 2), along with the information that the + identifier is bound to a function in the racket/base library.

A macro is a compile-time function on syntax objects. In other words, a macro: (1) is a function, (2) expects a syntax object as input, (3) returns a new syntax object, and (4) runs at compile-time (see Expansion).

Here is a simple macro that expects two arguments and returns its first argument. Note that when the expander finds a macro application, it invokes the macro with a syntax object representing the whole application (see also: Macro Transformer Procedures).

The name K is historic (link) and pretentious, enjoy.

> (require (for-syntax racket/base))
> (define-syntax (K args-stx)
    (define args (syntax-e args-stx))
    (if (= (length args) 3)
      (cadr args)
        "syntax object containing a list with 3 elements"
> (K 1 2)


> (K 1)

K: contract violation

  expected: syntax object containing a list with 3 elements

  given: #<syntax:eval:4:0 (K 1)>

> (K 1 2 3)

K: contract violation

  expected: syntax object containing a list with 3 elements

  given: #<syntax:eval:5:0 (K 1 2 3)>

Here is the same macro, defined using syntax-parse instead of the low-level syntax-e and cadr functions:

> (require (for-syntax racket/base syntax/parse))
> (define-syntax (K args-stx)
    (syntax-parse args-stx
     [(_ ?arg0 ?arg1)
> (K 1 2)


> (K 1)

eval:4:0: K: expected more terms starting with any term

  at: ()

  within: (K 1)

  in: (K 1)

> (K 1 2 3)

eval:5:0: K: unexpected term

  at: 3

  in: (K 1 2 3)

I don’t expect that all this makes sense so far. Try running and modifying these examples. Try reading the documentation for define-syntax and syntax-e and syntax-parse and syntax (aka #').

The last thing to point out is that (_ ?arg0 ?arg1) is a syntax pattern.
  • the parentheses say this pattern matches a (special kind of) list,

  • the underscore (_) means the first element of the list can be anything,

  • the name ?arg0 means the second element of the list can be anything and gets bound to the pattern variable ?arg0,

  • the name ?arg1 binds the third element to another pattern variable,

  • and if the list has more or fewer elements the pattern does not match.

A pattern variable is a special kind of variable; it can only be referenced inside a new syntax object. The name ?arg0 starts with a ? as a style choice — it helps me remember that it is the name of a pattern variable.

6 The Examples

6.1 first-class-or

 (require syntax-parse-example/first-class-or/first-class-or)
  package: syntax-parse-example


(first-class-or expr ...)

Racket’s or is a macro, not a function. It cannot be used like a normal value (i.e., evaluated as an identifier).

> (or #false #true)


> (apply or '(#false #true 0))

eval:2:0: or: bad syntax

  in: or

Identifier macros can be evaluated as identifiers.

So we can write a first-class-or macro to:
  • expand like Racket’s or when called like a function, and

  • expand to a function definition when used like an identifier.

In the latter case, the function that first-class-or evaluates to is similar to or, but evaluates all its arguments.

> (first-class-or #false #true)


> (apply first-class-or '(#false #true 0))


> (first-class-or (+ 2 3) (let loop () (loop)))


> (map first-class-or '(9 #false 3) '(8 #false #false))

'(9 #f 3)

The macro:

  #lang racket/base
  (provide first-class-or)
  (require (for-syntax racket/base syntax/parse))
  (define-syntax (first-class-or stx)
    (syntax-parse stx
     [(_ ?a . ?b)
      #'(let ([a-val ?a])
          (if a-val a-val (first-class-or . ?b)))]
      #'(lambda arg*
          (let loop ([arg* arg*])
             [(null? arg*)
             [(car arg*)
              (car arg*)]
              (loop (cdr arg*))])))]))

Some comments:
  • The first two syntax/parse clauses define what happens when or is called like a function.

  • The pattern _:id matches any identifier.

  • The dot notation in (_ ?a . ?b) could be (_ ?a ?b ...) instead. See Pairs, Lists, and Racket Syntax for intuition about what the dot means, and Syntax Patterns for what it means in a syntax pattern.

6.2 optional-assert

 (require syntax-parse-example/optional-assert/optional-assert)
  package: syntax-parse-example


(optional-assert expr ...)

The optional-assert form expands to either:
  • a test that evaluates an expression and halts the program if the result is #f,

  • or nothing

depending on the compile-time value of the environment variable DISABLE_OPTIONAL_ASSERT.

  #lang racket/base
  (provide optional-assert exn:fail:optional-assert?)
  (require (for-syntax racket/base syntax/parse))
  (define-for-syntax no-asserts? (getenv "DISABLE_OPTIONAL_ASSERT"))
  (struct exn:fail:optional-assert exn:fail ())
  (define (make-exn:fail:optional-assert datum)
    (exn:fail:optional-assert (format "assertion failure: ~a" datum)
  (define-syntax (optional-assert stx)
    (syntax-parse stx
     [(_ e:expr)
      (if no-asserts?
        #'(unless e
            (raise (make-exn:fail:optional-assert 'e))))]))


(exn:fail:optional-assert? x)  boolean?

  x : any/c
Predicate for an assertion failure.

6.3 Cross Macro Communication

 (require syntax-parse-example/cross-macro-communication/cross-macro-communication)
  package: syntax-parse-example


(define-for-macros id expr)


(get-macroed id)

The define-for-macros and get-macroed demonstrate the use of syntax-local-value when communicating information across macros. Anything defined with define-for-macros can be accessed (at compile/macro expansion time) by get-macroed.

> (define-for-macros cake 42)
> (get-macroed cake)


> cake

eval:3:0: cake: illegal use of syntax

  in: cake

  value at phase 1: 42

This communication works even if the identifiers are defined and used in different files or modules:

> (module the-definition racket
    (require syntax-parse-example/cross-macro-communication/cross-macro-communication)
    (define-for-macros shake 54)
    (provide shake))
> (require 'the-definition
> (get-macroed shake)


The following is the source code for define-for-macros and get-macroed:

  #lang racket/base
  (provide define-for-macros get-macroed)
  (require (for-syntax racket/base syntax/parse))
  (define-syntax (define-for-macros stx)
    (syntax-parse stx
      [(_ name:id expr)
       #'(define-syntax name expr)]))
  (define-syntax (get-macroed stx)
    (syntax-parse stx
      [(_ name:id)
       #`(#%datum . #,(syntax-local-value #'name))]))

In define-for-macros, the macro simply binds a new value at compile time using define-syntax. In this example define-for-macros is mostly synonymous with define-syntax, but it demonstrates that the name could be changed (to say add a question mark at the end), and the given expression can be changed. The get-macroed form simply takes the compile time value and puts it in the run time module. If name is used outside of a macro then a syntax error is raised.

The point of #%datum is to make it seem like a value was part of the source code. See Expansion Steps for details.

6.4 let-star

 (require syntax-parse-example/let-star/let-star)
  package: syntax-parse-example


(let-star ((id expr) ...) expr)

Racket’s let binds identifiers simultaneously; Racket’s let* binds identifiers in sequence. For example:

(let* ([a 1]
       [b (+ a 1)])

behaves the same as a nested let:

(let ([a 1])
  (let ([b (+ a 1)])

The let-star macro implements let* in terms of let.

  #lang racket/base
  (provide let-star)
  (require (for-syntax racket/base syntax/parse))
  (define-syntax (let-star stx)
    (syntax-parse stx
     [(_ ([x:id v:expr]) body* ...+)
      #'(let ([x v])
          body* ...)]
     [(_ ([x:id v:expr] . bind*) body* ...+)
      #'(let ([x v])
          (let-star bind* body* ...))]
     [(_ bad-binding body* ...+)
      (raise-syntax-error 'let-star
        "not a sequence of identifier--expression pairs" stx #'bad-binding)]
     [(_ (bind*))
      (raise-syntax-error 'let-star
        "missing body" stx)]))

  • The macro is recursive. The use of let-star in the second clause will later expand to a sequence of lets.

  • The pattern ...+ matches one or more of the previous pattern.

> (let-star 1)

eval:1:0: let-star: expected more terms starting with any


  at: ()

  within: (let-star 1)

  in: (let-star 1)

> (let-star ([a 1]))

eval:2:0: let-star: missing body

  in: (let-star ((a 1)))

> (let-star ([a 1]
             [b (+ a 1)]
             [c (+ b 1)])


6.5 def

 (require syntax-parse-example/def/def)
  package: syntax-parse-example

The def macro is similar to define but:
  • requires a docstring

  • requires test cases;

  • optionally accepts contract annotations on its arguments; and

  • optionally accepts pre- and post- conditions.


(def (id argspec ...)
  optional-pre-post ...
  body ...+)
argspec = arg-id
  | (arg-id : contract?)
testcases = #:tests [test ...]
test = (boolean-expr ==> result-expr)
optional-pre-post = #:pre [(pre-comparison-fn failure-doc) ...]
  | #:post [(post-comparison-fn failure-doc) ...]
  arg-id : symbol?
  pre-comparison-fn : (-> any/c ... boolean?)
  post-comparison-fn : (-> any/c boolean?)
  failure-doc : string?
  doc-string : string?
The pre-comparison-fn is applied to the list of function arguments and should return true if the preconditions are satisfied. The post-comparison-fn is applied to the result to verify the post-conditions.

The expansion of def must occur inside a module (rather than a REPL) because it adds (module+ test) for the #:test code. Ordinarily def will be used inside a file, so it will automatically be inside a module.

> (module snoc racket/base
    (require syntax-parse-example/def/def)
    (def (snoc (x* : list?) x)
      "Append the value `x` to the end of the given list"
      #:test [
        ((snoc '(1 2) 3) ==> '(1 2 3))
        ((snoc '(a b) '(c)) ==> '(a b (c)))]
      (append x* (list x)))
    (provide snoc))
> (require 'snoc)
> (snoc 1 '(2 3))

snoc: contract violation

  expected: list?

  given: 1

> (snoc '(1 2) 3)

'(1 2 3)

> (module gcd racket/base
    (require syntax-parse-example/def/def)
    (def (gcd (x : integer?) (y : integer?))
      "greatest common divisor"
      #:pre [
        (>= "First argument must be greater-or-equal than second")]
      #:test [
        ((gcd 10 3) ==> 1)
        ((gcd 12 3) ==> 3)]
       [(zero? y) x]
       [else (gcd y (- x (* y (quotient x y))))]))
     (provide gcd))
> (require 'gcd)
> (gcd 42 777)

gcd: First argument must be greater-or-equal than second

> (gcd 777 42)


If the docstring or test cases are missing, def throws a syntax error.

> (def (f x)

eval:9:0: def: expected string or expected one of these

literals: #:test, #:pre, or #:post

  at: x

  in: (def (f x) x)

> (def (f x)

eval:10:0: def: expected string or expected one of these

literals: #:test, #:pre, or #:post

  at: x

  in: (def (f x) "identity" x)

> (def (f x)
    #:test [((f 1) ==> 1)]

eval:11:0: def: expected string or expected one of these

literals: #:test, #:pre, or #:post

  at: x

  in: (def (f x) #:test (((f 1) ==> 1)) x)

How to read the macro:
  1. The begin-for-syntax defines two syntax classes (see Syntax Classes). The first syntax class, arg-spec, captures arguments with an optional contract annotation. The second, doc-spec, captures docstrings.

  2. The large ~or pattern captures the required-and-optional stuff that def accepts: the docstring, the #:test test cases, the #:pre pre-conditions, and the #:post post-conditions.

  3. The four #:with clauses build syntax objects that run unit tests and/or checks.

  4. The syntax object made from the #:test clause creates a post-submodule (module+ test ....) and uses parameterize to capture everything that the tests print to current-output-port.

  5. The examples in the docs for the ~optional pattern help explain (1) why #'#f can be a useful #:default and (2) when it is necessary to specify the ellipses depth in a #:default, as in (check-pre* 1).

The def macro:

  #lang racket/base
  (provide def)
  (require rackunit (for-syntax racket/base syntax/parse))
    (define-syntax-class arg-spec
      #:attributes (name type)
      #:datum-literals (:)
        (name:id : type:expr))
       #:with type #'#f))
    (define-syntax-class doc-spec
  (define-syntax (def stx)
    (syntax-parse stx #:datum-literals (==>)
     [(_ (name:id arg*:arg-spec ...)
        (~or ;; using (~or (~once a) ...) to simulate an unordered (~seq a ...)
          (~once (~describe #:role "docstring" "docstring" doc:doc-spec))
          (~once (~seq #:test ((in* ==> out*
                               (~optional (~seq #:stdout expected-output*:str)
                                          #:defaults ([expected-output* #'#f])))
          (~once (~optional (~seq #:pre ([check-pre* pre-doc*:doc-spec] ...))
                            #:defaults ([(check-pre* 1) '()] [(pre-doc* 1) '()])))
          (~once (~optional (~seq #:post ([check-post* post-doc*:doc-spec] ...))
                            #:defaults ([(check-post* 1) '()] [(post-doc* 1) '()])))) ...
      #:with check-types
        #'(for ([arg-name (in-list (list arg*.name ...))]
                [arg-type (in-list (list arg*.type ...))]
                [i        (in-naturals)]
                #:when arg-type)
            (unless (arg-type arg-name)
              (raise-argument-error 'name (symbol->string (object-name arg-type)) i arg-name)))
      #:with check-pre
        #'(for ([pre-check (in-list (list check-pre* ...))]
                [pre-doc   (in-list (list pre-doc* ...))])
            (unless (pre-check arg*.name ...)
              (raise-user-error 'name pre-doc)))
      #:with check-post
        #'(lambda (result)
            (for ([post-check (in-list (list check-post* ...))]
                  [post-doc   (in-list (list post-doc* ...))])
              (unless (post-check result)
                (error 'name post-doc))))
      #:with test-cases
        #'(module+ test
            (let* ([p (open-output-string)]
                   [result-val (parameterize ([current-output-port p]) in*)]
                   [result-str (begin0 (get-output-string p)
                                       (close-output-port p))])
                (check-equal? result-val out*)
                (when expected-output*
                  (check-equal? result-str expected-output*)))
          (define (name arg*.name ...)
            (let ([result body])
              (begin0 result
                      (check-post result)))))]))

  • This macro gives poor error messages when the docstring or test cases are missing.

  • The doc-spec syntax class could be extended to accept Scribble, or another kind of docstring syntax.

  • A #:test case may optionally use the #:stdout keyword. If given, the test will fail unless running the test prints the same string to current-output-port.

6.6 conditional-require

 (require syntax-parse-example/conditional-require/conditional-require)
  package: syntax-parse-example


(conditional-require expr id id)

This macro conditionally requires one of two module paths based on a compile-time condition.

  #lang racket/base
  (provide conditional-require)
  (require (for-syntax racket/base syntax/parse))
    (define-syntax-class mod-name
      (pattern _:id)
      (pattern _:str)))
  (define-syntax (conditional-require stx)
    (syntax-parse stx
     [(_ test:boolean r1:mod-name r2:mod-name)
      (if (syntax-e #'test)
        #'(require r1)
        #'(require r2))]))


6.7 multi-check-true

 (require syntax-parse-example/multi-check-true/multi-check-true)
  package: syntax-parse-example


(multi-check-true expr ...)

The multi-check-true expands into a sequence of check-true unit tests. For example:

  (even? 0))

expands to code that behaves the same as:

(check-true #true)
(check-true #false)
(check-true (even? 0))

The main difference between the macro and the example is that the macro uses with-check-info* to improve test failure messages. If part of a multi-check-true fails, the error message points to the bad expression (rather than the multi-check-true macro).

  #lang racket/base
  (provide multi-check-true)
  (require rackunit (for-syntax racket/base syntax/srcloc syntax/parse))
  (define-syntax (multi-check-true stx)
    (syntax-parse stx
     [(_ e* ...)
          #,@(for/list ([e (in-list (syntax-e #'(e* ...)))])
               (define loc (build-source-location-list e))
               #`(with-check-info* (list (make-check-location '#,loc))
                   (λ () (check-true #,e)))))]))

6.8 define-datum-literal-set

 (require syntax-parse-example/define-datum-literal-set/define-datum-literal-set)
  package: syntax-parse-example


(define-datum-literal-set id (id ...))

syntax-parse can match literal symbols using the #:datum-literals option or the ~datum pattern form. These work well for a small number of literals.

Given a sequence of symbols, the define-datum-literal-set macro builds a syntax class that matches these symbols.

(define-datum-literal-set C-keyword
  (auto break case char const continue default do double else))
(define-syntax (is-C-keyword? stx)
  (syntax-parse stx
   [(_ x:C-keyword)
   [(_ x)
(is-C-keyword? else)
(is-C-keyword? synchronized)

The macro works by defining a literal set and then a syntax class.

  #lang racket/base
  (provide define-datum-literal-set)
  (require (for-syntax racket/base racket/syntax syntax/parse))
  (define-syntax (define-datum-literal-set stx)
    (syntax-parse stx
     [(_ cls-name:id (lit*:id ...))
      #:with set-name (format-id stx "~a-set" (syntax-e #'cls-name))
        (define-literal-set set-name
          #:datum-literals (lit* ...)
        (define-syntax-class cls-name
          #:literal-sets ([set-name])
          (pattern (~or lit* ...)))) ]))

6.9 rec/c

 (require syntax-parse-example/rec-contract/rec-contract)
  package: syntax-parse-example


(rec/c id expr)

The rec/c macro uses Racket’s recursive-contract form to create anonymous recursive contracts.

  #lang racket/base
  (provide rec/c)
  (require racket/contract (for-syntax racket/base syntax/parse))
  (define-syntax-rule (rec/c t ctc)
    (letrec ([rec-ctc
              (let-syntax ([t (syntax-parser (_:id #'(recursive-contract rec-ctc)))])

> (define/contract (deep n)
    (-> integer? (rec/c t (or/c integer? (list/c t))))
    (if (zero? n)
      (list (deep (- n 1)))))
> (deep 4)


6.10 struct-list

 (require syntax-parse-example/struct-list/struct-list)
  package: syntax-parse-example


(struct-list expr ...)

The struct-list macro has similar syntax as Typed Racket’s struct form, but creates a new datatype backed by a list instead of an actual struct. The only cosmetic difference is that type #:type-name keyword is required, and must supply a name that is different from the struct name.

> (struct-list foo ([a : String] [b : String]) #:type-name Foo)
> (define f (foo "hello" "world"))
> (foo? f)

- : Boolean


> (string-append (foo-a f) " " (foo-b f))

- : String

"hello world"

> (ann f Foo)

- : Foo

'(foo "hello" "world")

The implementation:
  1. extracts the names and type names from the syntax,

  2. creates an identifier for the predicate and a sequence of identifiers for the accessors (see the #:with clauses),

  3. and defines a constructor and predicate and accessor(s).

  #lang typed/racket/base
  (provide struct-list)
  (require (for-syntax racket/base racket/syntax syntax/parse))
  (define-syntax (struct-list stx)
    (syntax-parse stx #:datum-literals (:)
     [(_ name:id ([f*:id : t*] ...) #:type-name Name:id)
      #:fail-when (free-identifier=? #'name #'Name)
                  "struct name and #:type-name must be different"
      #:with name?
             (format-id stx "~a?" (syntax-e #'name))
      #:with ((name-f* i*) ...)
             (for/list ([f (in-list (syntax-e #'(f* ...)))]
                        [i (in-naturals 1)])
               (list (format-id stx "~a-~a" (syntax-e #'name) (syntax-e f)) i))
      (syntax/loc stx
          (define-type Name (Pairof 'name (Listof Any)))
          (define (name (f* : t*) ...) : Name
            (list 'name f* ...))
          (define (name? (v : Any)) : Boolean
            (and (list? v) (not (null? v)) (eq? 'name (car v))))
          (define (name-f* (p : Name)) : t*
            (cast (list-ref p 'i*) t*))

6.11 syntax-class-contract

 (require syntax-parse-example/syntax-class-contract/syntax-class-contract)
  package: syntax-parse-example

The syntax-class-contract function is one way to put a contract on a macro. If you give it a syntax class value, it returns a contract that accepts a syntax object #'(A B) where A is anything and B matches the syntax class. The contract can be attached to a normal macro — with a little ingenuity.

> (define-syntax add-hello
      (-> (syntax-class-contract (reify-syntax-class str))
      (lambda (stx)
        (let ([orig-str (syntax-e (cadr (syntax-e stx)))])
          (with-syntax ([new-str (string-append "hello" " " orig-str)])
> (add-hello "world")

"hello world"

> (add-hello 'not-string)

add-hello: contract violation

  expected: (syntax-parse-arg/c

#(struct:reified-syntax-class -string ...))

  given: #<syntax:eval:3:0 (add-hello (quote not-string))>

  in: the 1st argument of







  contract from: this-macro

  blaming: the-macro-user

   (assuming the contract is correct)


  #lang racket/base
  (provide syntax-class-contract)
  (require racket/contract
  (define (syntax-class-contract cls)
    (flat-named-contract `(syntax-parse-arg/c ,cls)
        [(_ (~reflect arg (cls))) #true]
        [_ #false])))

Special thanks to Michael Ballantyne for developing this macro tool.

Challenge: try making a kind of contract-out that can attach contracts to macros.

6.12 except-in-quiet

 (require syntax-parse-example/except-in-quiet/except-in-quiet)
  package: syntax-parse-example

Thanks to Leif Andersen for the original macro.

Racket’s except-in form subtracts a sequence of identifiers from a source. If the source does not provide one of the named identifiers, then except-in raises a syntax error.

> (require (except-in racket/list second))
> (first '(1 2 3))


> (second '(1 2 3))

second: undefined;

 cannot reference an identifier before its definition

  in module: top-level

> (require (except-in racket/list snd))

eval:4:0: except-in: identifier `snd' not included in nested

require spec

  at: racket/list

  in: (except-in racket/list snd)


(except-in-quiet expr ...)

Similar to except-in but does not raise an error when asked to subtract a missing identifier.

> (require (except-in-quiet racket/list second))
> (first '(1 2 3))


> (second '(1 2 3))

second: undefined;

 cannot reference an identifier before its definition

  in module: top-level

> (require (except-in-quiet racket/list snd))

The macro (or rather, require transformer) should work in four steps:

  1. resolve the required expression to a module,

  2. find all exports from that module,

  3. subtract names from the export list, and

  4. proceed with a call to expand-import.

Steps 2 through 4 are implemented fairly well below. Step 1, however, is done in a very simple way. It works for basic paths like racket/base but nothing more complicated.

  #lang racket/base
  (provide except-in-quiet)
  (define-for-syntax (export-list->phase0-ids phase-dict)
    (define phase0-id-info*
        (or (assoc 0 phase-dict)
            (cons #f '()))))
    (map car phase0-id-info*))
  (define-syntax except-in-quiet
        [(_ modname:id exception-names:id ...)
         (define-values [provided-vals provided-macros]
           (module->exports (syntax-e #'modname)))
         (define exceptions
           (map syntax-e (attribute exception-names)))
         (define excluded
               (export-list->phase0-ids provided-vals)
               (export-list->phase0-ids provided-macros))))
         (expand-import #`(except-in modname #,@excluded))])))

6.13 dot-underscore

Contributed by soegaard (#15) during the 2021 Syntax Parse Bee.

 (require syntax-parse-example/dot-underscore/dot-underscore)
  package: syntax-parse-example

The dot-underscore example shows how to:
  • implement dot notation for object field access using a custom #%top

  • implement method invocation without explicit send using a custom #%app

See the source file dot-underscore.rkt for explanation.

There are examples in test-dot-underscore.rkt.

7 Example-Formatting Tools

The syntax-parse-example language is a small language for documenting example macros. It:
  • uses the reader from scribble/base; and

  • provides a few utility functions, documented below.

Helpers for rendering documentation.


(tech/guide pre-content ...)  element?

  pre-content : pre-content?
Similar to tech, but links to The Racket Guide.


(tech/reference pre-content ...)  element?

  pre-content : pre-content?
Similar to tech, but links to The Racket Reference.


(racketfile filename)  element?

  filename : path-string?
Typesets the contents of the given file as if its contents were wrapped in a racketblock.