12.12 Syntax Utilities
(require racket/syntax) | package: base |
12.12.1 Creating formatted identifiers
procedure
(format-id lctx fmt v ... [ #:source src #:props props #:cert ignored #:subs? subs? #:subs-intro subs-introducer]) → identifier? lctx : (or/c syntax? #f) fmt : string?
v :
(or/c string? symbol? keyword? char? number? (syntax/c (or/c string? symbol? keyword? char? number?))) src : (or/c syntax? #f) = #f props : (or/c syntax? #f) = #f ignored : (or/c syntax? #f) = #f subs? : boolean? = #f
subs-introducer : (-> syntax? syntax?) = (if (syntax-transforming?) syntax-local-introduce values)
The format string must use only ~a placeholders. Syntax objects in the argument list are automatically unwrapped (e.g., identifiers will be automatically converted to symbols).
> (define-syntax (make-pred stx) (syntax-case stx () [(make-pred name) (format-id #'name "~a?" (syntax-e #'name))])) > (make-pred pair) #<procedure:pair?>
> (make-pred none-such) none-such?: undefined;
cannot reference an identifier before its definition
in module: top-level
> (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) none-such?: undefined;
cannot reference an identifier before its definition
in module: top-level
(Scribble doesn’t show it, but the DrRacket pinpoints the location of the second error but not of the first.)
If subs? is #t, then a 'sub-range-binders syntax property is added to the result that records the position of each identifier in the vs. The subs-intro procedure is applied to each identifier, and its result is included in the sub-range binder record. This property value overrides a 'sub-range-binders property copied from props.
> (syntax-property (format-id #'here "~a/~a-~a" #'point 2 #'y #:subs? #t) 'sub-range-binders)
'(#(#<syntax point/2-y> 8 1 0.5 0.5 #<syntax:eval:8:0 y> 0 1 0.5 0.5)
#(#<syntax point/2-y> 0 5 0.5 0.5 #<syntax:eval:8:0 point> 0 5 0.5 0.5))
Changed in version 7.4.0.5 of package base: Added the #:subs? and
#:subs-intro arguments.
Changed in version 8.7.0.7: Allowed v to be a syntax object
wrapping a string, a keyword, a character, or a number.
procedure
(format-symbol fmt v ...) → symbol?
fmt : string?
v :
(or/c string? symbol? keyword? char? number? (syntax/c (or/c string? symbol? keyword? char? number?)))
> (format-symbol "make-~a" 'triple) 'make-triple
Changed in version 8.7.0.7 of package base: Allowed v to be a syntax object wrapping a string, a keyword, a character, or a number.
12.12.2 Pattern variables
syntax
(define/with-syntax pattern stx-expr)
stx-expr : syntax?
> (define/with-syntax (px ...) #'(a b c)) > (define/with-syntax (tmp ...) (generate-temporaries #'(px ...))) > #'([tmp px] ...) #<syntax:eval:12:0 ((a9 a) (b10 b) (c11 c))>
> (define/with-syntax name #'Alice) > #'(hello name) #<syntax:eval:14:0 (hello Alice)>
12.12.3 Error reporting
parameter
(current-syntax-context) → (or/c syntax? #f)
(current-syntax-context stx) → void? stx : (or/c syntax? #f)
procedure
(wrong-syntax stx format-string v ...) → any
stx : syntax? format-string : string? v : any/c
> (wrong-syntax #'here "expected ~s" 'there) eval:15:0: ?: expected there
at: here
> (parameterize ([current-syntax-context #'(look over here)]) (wrong-syntax #'here "expected ~s" 'there)) eval:16:0: look: expected there
at: here
in: (look over here)
(define-syntax (my-macro stx) (parameterize ([current-syntax-context stx]) (syntax-case stx () __)))
12.12.4 Recording disappeared uses
parameter
→ (or/c (listof identifier?) #f) (current-recorded-disappeared-uses ids) → void? ids : (or/c (listof identifier?) #f)
syntax
(with-disappeared-uses body-expr ... stx-expr)
stx-expr : syntax?
Changed in version 6.5.0.7 of package base: Added the option to include body-exprs.
procedure
(syntax-local-value/record id predicate) → any/c
id : identifier? predicate : (-> any/c boolean?)
procedure
(record-disappeared-uses id [intro?]) → void?
id : (or/c identifier? (listof identifier?)) intro? : boolean? = (syntax-transforming?)
If not used within the extent of a with-disappeared-uses form or similar, has no effect.
Changed in version 6.5.0.7 of package base: Added the option to pass a single identifier instead of
requiring a list.
Changed in version 7.2.0.11: Added the intro? argument.
12.12.5 Miscellaneous utilities
procedure
(generate-temporary [name-base]) → identifier?
name-base : any/c = 'g
procedure
(internal-definition-context-apply intdef-ctx stx) → syntax? intdef-ctx : internal-definition-context? stx : syntax?
procedure
(syntax-local-eval stx [intdef-ctx]) → any
stx : any/c
intdef-ctx :
(or/c internal-definition-context? #f (listof internal-definition-context?)) = '()
> (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 produces ~s\n" expr))])) > (show-me (+ 2 5))
at compile time produces 7
at run time produces 7
> (define-for-syntax fruit 'apple) > (define fruit 'pear) > (show-me fruit)
at compile time produces apple
at run time produces pear
Changed in version 6.90.0.27 of package base: Changed intdef-ctx to accept a list of internal-definition contexts in addition to a single internal-definition context or #f.
syntax
(with-syntax* ([pattern stx-expr] ...) body ...+)
stx-expr : syntax?
> (with-syntax* ([(x y) (list #'val1 #'val2)] [nest #'((x) (y))]) #'nest) #<syntax:eval:22:0 ((val1) (val2))>