racket/collects/unstable/scribblings/syntax.scrbl
Ryan Culpepper f8e22d4cad syntax/parse: changed minimatch to use make, catch struct errors
unstable: added syntax-local-eval, internal-definition-context-apply

svn: r17144
2009-12-01 20:32:32 +00:00

315 lines
9.2 KiB
Racket

#lang scribble/manual
@(require scribble/struct
scribble/decode
scribble/eval
"utils.ss"
(for-label scheme/base
scheme/contract
unstable/syntax))
@(define the-eval (make-base-eval))
@(the-eval '(require unstable/syntax))
@(the-eval '(require (for-syntax scheme/base unstable/syntax)))
@title[#:tag "syntax"]{Syntax}
@defmodule[unstable/syntax]
@unstable[@author+email["Ryan Culpepper" "ryanc@plt-scheme.org"]]
@defparam[current-syntax-context stx (or/c syntax? false/c)]{
The current contextual syntax object, defaulting to @scheme[#f]. It
determines the special form name that prefixes syntax errors created
by @scheme[wrong-syntax].
@;{
If it is a syntax object with a @scheme['report-error-as] syntax
property whose value is a symbol, then that symbol is used as the
special form name. Otherwise, the same rules apply as in
@scheme[raise-syntax-error].
}
}
@defproc[(wrong-syntax [stx syntax?] [format-string string?] [v any/c] ...)
any]{
Raises a syntax error using the result of
@scheme[(current-syntax-context)] as the ``major'' syntax object and
the provided @scheme[stx] as the specific syntax object. (The latter,
@scheme[stx], is usually the one highlighted by DrScheme.) The error
message is constructed using the format string and arguments, and it
is prefixed with the special form name as described under
@scheme[current-syntax-context].
@examples[#:eval the-eval
(wrong-syntax #'here "expected ~s" 'there)
(parameterize ((current-syntax-context #'(look over here)))
(wrong-syntax #'here "expected ~s" 'there))
]
A macro using @scheme[wrong-syntax] might set the syntax context at the very
beginning of its transformation as follows:
@SCHEMEBLOCK[
(define-syntax (my-macro stx)
(parameterize ((current-syntax-context stx))
(syntax-case stx ()
___)))
]
Then any calls to @scheme[wrong-syntax] during the macro's
transformation will refer to @scheme[my-macro] (more precisely, the name that
referred to @scheme[my-macro] where the macro was used, which may be
different due to renaming, prefixing, etc).
@;{
A macro that expands into a helper macro can insert its own name into
syntax errors raised by the helper macro by installing a
@scheme['report-error-as] syntax property on the helper macro
expression.
@examples[#:eval the-eval
(define-syntax (public-macro stx)
(syntax-case stx ()
[(public-macro stuff)
(syntax-property #'(private-macro stuff)
'report-error-as
(syntax-e #'public-macro))]))
(define-syntax (private-macro stx)
(parameterize ((current-syntax-context stx))
(syntax-case stx ()
[(private-macro arg)
(wrong-syntax #'arg "just no good")])))
(public-macro 5)
]
}
}
@;{----}
@defform[(define/with-syntax pattern expr)]{
Definition form of @scheme[with-syntax]. That is, it matches the
syntax object result of @scheme[expr] against @scheme[pattern] and
creates pattern variable definitions for the pattern variables of
@scheme[pattern].
@examples[#:eval the-eval
(define/with-syntax (px ...) #'(a b c))
(define/with-syntax (tmp ...) (generate-temporaries #'(px ...)))
#'([tmp px] ...)
]
}
@defform[(define-pattern-variable id expr)]{
Evaluates @scheme[expr] and binds it to @scheme[id] as a pattern
variable, so @scheme[id] can be used in subsequent @scheme[syntax]
patterns.
@examples[#:eval the-eval
(define-pattern-variable name #'Alice)
#'(hello name)
]
}
@;{----}
@defform[(with-temporaries (temp-id ...) . body)]{
Evaluates @scheme[body] with each @scheme[temp-id] bound as a pattern
variable to a freshly generated identifier.
@examples[#:eval the-eval
(with-temporaries (x) #'(lambda (x) x))
]
}
@defproc[(generate-temporary [name-base any/c 'g]) identifier?]{
Generates one fresh identifier. Singular form of
@scheme[generate-temporaries]. If @scheme[name-base] is supplied, it
is used as the basis for the identifier's name.
}
@defproc[(generate-n-temporaries [n exact-nonnegative-integer?])
(listof identifier?)]{
Generates a list of @scheme[n] fresh identifiers.
}
@;{----}
@defparam[current-caught-disappeared-uses ids
(or/c (listof identifier?) false/c)]{
Parameter for tracking disappeared uses. Tracking is ``enabled'' when
the parameter has a non-false value. This is done automatically by
forms like @scheme[with-disappeared-uses].
}
@defform[(with-disappeared-uses stx-expr)
#:contracts ([stx-expr syntax?])]{
Evaluates the @scheme[stx-expr], catching identifiers looked up using
@scheme[syntax-local-value/catch]. Adds the caught identifiers to the
@scheme['disappeared-uses] syntax property of the resulting syntax
object.
}
@defform[(with-catching-disappeared-uses body-expr)]{
Evaluates the @scheme[body-expr], catching identifiers looked up using
@scheme[syntax-local-value/catch]. Returns two values: the result of
@scheme[body-expr] and the list of caught identifiers.
}
@defproc[(syntax-local-value/catch [id identifier?] [predicate (-> any/c boolean?)])
any/c]{
Looks up @scheme[id] in the syntactic environment (as
@scheme[syntax-local-value]). If the lookup succeeds and returns a
value satisfying the predicate, the value is returned and @scheme[id]
is recorded (``caught'') as a disappeared use. If the lookup fails or
if the value does not satisfy the predicate, @scheme[#f] is returned
and the identifier is not recorded as a disappeared use.
If not used within the extent of a @scheme[with-disappeared-uses] form
or similar, has no effect.
}
@defproc[(record-disappeared-uses [ids (listof identifier?)])
void?]{
Add @scheme[ids] to the current disappeared uses.
If not used within the extent of a @scheme[with-disappeared-uses] form
or similar, has no effect.
}
@;{----}
@defproc[(format-symbol [fmt string?]
[v (or/c string? symbol? identifier? keyword? char? number?)] ...)
symbol?]{
Like @scheme[format], but produces a symbol. The format string must
use only @litchar{~a} placeholders. Identifiers in the argument list
are automatically converted to symbols.
@examples[#:eval the-eval
(format-symbol "make-~a" 'triple)
]
}
@defproc[(format-id [lctx (or/c syntax? #f)]
[#:source src (or/c syntax? #f) #f]
[#:props props (or/c syntax? #f) #f]
[#:cert cert (or/c syntax? #f) #f]
[fmt string?]
[v (or/c string? symbol? identifier? keyword? char? number?)] ...)
identifier?]{
Like @scheme[format-symbol], but converts the symbol into an
identifier using @scheme[lctx] for the lexical context, @scheme[src]
for the source location, @scheme[props] for the properties, and
@scheme[cert] for the inactive certificates. (See
@scheme[datum->syntax].)
The format string must use only @litchar{~a} placeholders. Identifiers
in the argument list are automatically converted to symbols.
@examples[#:eval the-eval
(define-syntax (make-pred stx)
(syntax-case stx ()
[(make-pred name)
(format-id #'name "~a?" (syntax-e #'name))]))
(make-pred pair)
(make-pred none-such)
(define-syntax (better-make-pred stx)
(syntax-case stx ()
[(better-make-pred name)
(format-id #'name #:source #'name
"~a?" (syntax-e #'name))]))
(better-make-pred none-such)
]
(Scribble doesn't show it, but the DrScheme pinpoints the location of
the second error but not of the first.)
}
@defproc[(internal-definition-context-apply [intdef-ctx internal-definition-context?]
[stx syntax?])
syntax?]{
Applies the renamings of @scheme[intdef-ctx] to @scheme[stx].
}
@defproc[(syntax-local-eval [stx syntax?]
[intdef-ctx (or/c internal-definition-context? #f) #f])
any]{
Evaluates @scheme[stx] as an expression in the current transformer
environment (that is, at phase level 1), optionally extended with
@scheme[intdef-ctx].
@examples[#:eval the-eval
(define-syntax (show-me stx)
(syntax-case stx ()
[(show-me expr)
(begin
(printf "at compile time produces ~s\n"
(syntax-local-eval #'expr))
#'(printf "at run time produes ~s\n"
expr))]))
(show-me (+ 2 5))
(define-for-syntax fruit 'apple)
(define fruit 'pear)
(show-me fruit)
#|
(define-syntax (show-me* stx)
(syntax-case stx ()
[(show-me expr1)
(call-with-values (lambda () (syntax-local-eval #'expr1))
(lambda vals
(with-syntax ([vals vals])
#'(quote vals))))]))
(define-for-syntax (sum-and-difference a b)
(values (+ a b) (- a b)))
(show-me* (sum-and-difference 12 9))
|#
]
}
@addition{Sam Tobin-Hochstadt}
@defform[(with-syntax* ([pattern stx-expr] ...)
body ...+)]{
Similar to @scheme[with-syntax], but the pattern variables are bound in the remaining
@scheme[stx-expr]s as well as the @scheme[body]s, and the @scheme[pattern]s need not
bind distinct pattern variables; later bindings shadow earlier bindings.
@examples[#:eval the-eval
(with-syntax* ([(x y) (list #'val1 #'val2)]
[nest #'((x) (y))])
#'nest)
]
}
@defproc[(syntax-map [f (-> syntax? A)] [stxl syntax?] ...) (listof A)]{
Performs @scheme[(map f (syntax->list stxl) ...)].
@examples[#:eval the-eval
(syntax-map syntax-e #'(a b c))]
}