add pattern-expanders to syntax/parse
This commit is contained in:
parent
89690c6de9
commit
81cc6bf4d0
|
@ -1033,3 +1033,46 @@ definition in a @racket[~do] block.
|
||||||
[(a b (~do (printf "a was ~s\n" #'a)) c:id) 'ok])
|
[(a b (~do (printf "a was ~s\n" #'a)) c:id) 'ok])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@;{--------}
|
||||||
|
|
||||||
|
@section{Pattern Expanders}
|
||||||
|
|
||||||
|
@defproc[(pattern-expander [proc (-> syntax? syntax?)]) pattern-expander?]{
|
||||||
|
returns a pattern-expander that uses @racket[proc] to transform the pattern.
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(define-syntax ~foo
|
||||||
|
(pattern-expander
|
||||||
|
(syntax-rules ()
|
||||||
|
[(_ pat) pat])))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defthing[prop:pattern-expander (struct-type-property/c (-> pattern-expander? (-> syntax? syntax?)))]{
|
||||||
|
a struct-type property for pattern-expanders.
|
||||||
|
|
||||||
|
@myexamples[
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct thing (proc pattern-expander) #:transparent
|
||||||
|
#:property prop:procedure (struct-field-index proc)
|
||||||
|
#:property prop:pattern-expander (λ (this) (thing-pattern-expander this))))
|
||||||
|
(define-syntax ~foo
|
||||||
|
(thing
|
||||||
|
(lambda (stx) #'"I am the macro ~foo")
|
||||||
|
(lambda (stx) #'"I am the pattern-expander ~foo")))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defproc[(pattern-expander? [v any/c]) boolean?]{
|
||||||
|
returns @racket[#t] if @racket[v] is a pattern expander, otherwise returns @racket[#f].
|
||||||
|
}
|
||||||
|
|
||||||
|
@defproc[(pattern-expander-proc [pat-exp pattern-expander?]) (-> syntax? syntax?)]{
|
||||||
|
returns the transformer procedure used by @racket[pat-exp].
|
||||||
|
}
|
||||||
|
|
||||||
|
@defproc[(syntax-local-syntax-parse-pattern-introduce [stx syntax?]) syntax?]{
|
||||||
|
like @racket[syntax-local-introduce], but for pattern-expanders.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -542,3 +542,37 @@
|
||||||
#:attributes (a)
|
#:attributes (a)
|
||||||
[pattern ((~seq (~optional :one #:defaults [(a 'bar)])))])
|
[pattern ((~seq (~optional :one #:defaults [(a 'bar)])))])
|
||||||
(void)))
|
(void)))
|
||||||
|
|
||||||
|
;; from http://lists.racket-lang.org/users/archive/2014-June/063095.html
|
||||||
|
(test-case "pattern-expanders"
|
||||||
|
(let ()
|
||||||
|
(define-splicing-syntax-class binding #:literals (=)
|
||||||
|
[pattern (~seq name:id = expr:expr)])
|
||||||
|
|
||||||
|
(define-syntax ~separated
|
||||||
|
(pattern-expander
|
||||||
|
(lambda (stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(separated sep pat)
|
||||||
|
(with-syntax ([ooo '...])
|
||||||
|
#'((~seq pat (~or (~peek-not _)
|
||||||
|
(~seq sep (~peek _))))
|
||||||
|
ooo))]))))
|
||||||
|
|
||||||
|
(define-splicing-syntax-class bindings
|
||||||
|
[pattern (~separated (~datum /) b:binding)
|
||||||
|
#:with (name ...) #'(b.name ...)
|
||||||
|
#:with (expr ...) #'(b.expr ...)])
|
||||||
|
|
||||||
|
(define (parse-my-let stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(_ bs:bindings body)
|
||||||
|
#'(let ([bs.name bs.expr] ...)
|
||||||
|
body)]))
|
||||||
|
|
||||||
|
(check-equal? (syntax->datum
|
||||||
|
(parse-my-let #'(my-let (x = 1 / y = 2 / z = 3)
|
||||||
|
(+ x y z))))
|
||||||
|
(syntax->datum #'(let ([x 1] [y 2] [z 3])
|
||||||
|
(+ x y z))))
|
||||||
|
))
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require "private/sc.rkt"
|
(require "private/sc.rkt"
|
||||||
"private/litconv.rkt"
|
"private/litconv.rkt"
|
||||||
"private/lib.rkt")
|
"private/lib.rkt"
|
||||||
|
(for-syntax "private/pattern-expander.rkt"))
|
||||||
(provide (except-out (all-from-out "private/sc.rkt")
|
(provide (except-out (all-from-out "private/sc.rkt")
|
||||||
define-integrable-syntax-class
|
define-integrable-syntax-class
|
||||||
syntax-parser/template
|
syntax-parser/template
|
||||||
parser/rhs)
|
parser/rhs)
|
||||||
(all-from-out "private/litconv.rkt")
|
(all-from-out "private/litconv.rkt")
|
||||||
(all-from-out "private/lib.rkt"))
|
(all-from-out "private/lib.rkt")
|
||||||
|
(for-syntax (all-from-out "private/pattern-expander.rkt")))
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(require racket/contract/base)
|
||||||
|
|
||||||
|
(define-values (prop:pattern-expander pattern-expander? get-proc-getter)
|
||||||
|
(make-struct-type-property 'pattern-expander))
|
||||||
|
|
||||||
|
(define (pattern-expander-proc pat-expander)
|
||||||
|
(define get-proc (get-proc-getter pat-expander))
|
||||||
|
(get-proc pat-expander))
|
||||||
|
|
||||||
|
(define current-syntax-parse-pattern-introducer
|
||||||
|
(make-parameter
|
||||||
|
(lambda (stx)
|
||||||
|
(error 'syntax-local-syntax-parse-pattern-introduce "not expanding syntax-parse pattern"))))
|
||||||
|
|
||||||
|
(define (syntax-local-syntax-parse-pattern-introduce stx)
|
||||||
|
((current-syntax-parse-pattern-introducer) stx))
|
||||||
|
|
||||||
|
(provide (contract-out
|
||||||
|
[prop:pattern-expander
|
||||||
|
(struct-type-property/c (-> pattern-expander? (-> syntax? syntax?)))]
|
||||||
|
[pattern-expander?
|
||||||
|
(-> any/c boolean?)]
|
||||||
|
[pattern-expander-proc
|
||||||
|
(-> pattern-expander? (-> syntax? syntax?))]
|
||||||
|
[current-syntax-parse-pattern-introducer
|
||||||
|
(parameter/c (-> syntax? syntax?))]
|
||||||
|
[syntax-local-syntax-parse-pattern-introduce
|
||||||
|
(-> syntax? syntax?)]
|
||||||
|
))
|
25
racket/collects/syntax/parse/private/pattern-expander.rkt
Normal file
25
racket/collects/syntax/parse/private/pattern-expander.rkt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(provide prop:pattern-expander
|
||||||
|
pattern-expander
|
||||||
|
pattern-expander?
|
||||||
|
pattern-expander-proc
|
||||||
|
syntax-local-syntax-parse-pattern-introduce
|
||||||
|
)
|
||||||
|
|
||||||
|
(require "pattern-expander-prop.rkt")
|
||||||
|
|
||||||
|
(module pattern-expander-struct racket/base
|
||||||
|
(require racket/contract/base)
|
||||||
|
|
||||||
|
(require (only-in "pattern-expander-prop.rkt" prop:pattern-expander))
|
||||||
|
|
||||||
|
(struct pattern-expander (proc) #:transparent
|
||||||
|
#:property prop:pattern-expander
|
||||||
|
(λ (this) (pattern-expander-proc this))) ; needs to be wrapped in (λ (this) (_ this))
|
||||||
|
|
||||||
|
(provide (contract-out
|
||||||
|
[struct pattern-expander ([proc (-> syntax? syntax?)])]
|
||||||
|
)))
|
||||||
|
|
||||||
|
(require (only-in 'pattern-expander-struct pattern-expander))
|
|
@ -17,7 +17,8 @@
|
||||||
"rep-data.rkt"
|
"rep-data.rkt"
|
||||||
"rep-patterns.rkt"
|
"rep-patterns.rkt"
|
||||||
syntax/parse/private/residual-ct ;; keep abs. path
|
syntax/parse/private/residual-ct ;; keep abs. path
|
||||||
"kws.rkt")
|
"kws.rkt"
|
||||||
|
"pattern-expander-prop.rkt")
|
||||||
|
|
||||||
;; Error reporting
|
;; Error reporting
|
||||||
;; All entry points should have explicit, mandatory #:context arg
|
;; All entry points should have explicit, mandatory #:context arg
|
||||||
|
@ -435,6 +436,8 @@
|
||||||
|
|
||||||
;; parse-*-pattern : stx DeclEnv boolean boolean -> Pattern
|
;; parse-*-pattern : stx DeclEnv boolean boolean -> Pattern
|
||||||
(define (parse-*-pattern stx decls allow-head? allow-action?)
|
(define (parse-*-pattern stx decls allow-head? allow-action?)
|
||||||
|
(define (recur stx)
|
||||||
|
(parse-*-pattern stx decls allow-head? allow-action?))
|
||||||
(define (check-head! x)
|
(define (check-head! x)
|
||||||
(unless allow-head?
|
(unless allow-head?
|
||||||
(wrong-syntax stx "head pattern not allowed here"))
|
(wrong-syntax stx "head pattern not allowed here"))
|
||||||
|
@ -449,6 +452,30 @@
|
||||||
~seq ~optional ~! ~bind ~fail ~parse ~do
|
~seq ~optional ~! ~bind ~fail ~parse ~do
|
||||||
~post ~peek ~peek-not ~delimit-cut ~commit ~reflect
|
~post ~peek ~peek-not ~delimit-cut ~commit ~reflect
|
||||||
~splicing-reflect)
|
~splicing-reflect)
|
||||||
|
[id
|
||||||
|
(and (identifier? #'id)
|
||||||
|
(not (safe-name? #'id))
|
||||||
|
(pattern-expander? (syntax-local-value #'id (λ () #f))))
|
||||||
|
(let* ([proc (pattern-expander-proc (syntax-local-value #'id))]
|
||||||
|
[introducer (make-syntax-introducer)]
|
||||||
|
[mstx (introducer (syntax-local-introduce stx))]
|
||||||
|
[mresult (parameterize ([current-syntax-parse-pattern-introducer introducer])
|
||||||
|
(proc mstx))]
|
||||||
|
[result (syntax-local-introduce (introducer mresult))])
|
||||||
|
(disappeared! #'id)
|
||||||
|
(recur result))]
|
||||||
|
[(id . rst)
|
||||||
|
(and (identifier? #'id)
|
||||||
|
(not (safe-name? #'id))
|
||||||
|
(pattern-expander? (syntax-local-value #'id (λ () #f))))
|
||||||
|
(let* ([proc (pattern-expander-proc (syntax-local-value #'id))]
|
||||||
|
[introducer (make-syntax-introducer)]
|
||||||
|
[mstx (introducer (syntax-local-introduce stx))]
|
||||||
|
[mresult (parameterize ([current-syntax-parse-pattern-introducer introducer])
|
||||||
|
(proc mstx))]
|
||||||
|
[result (syntax-local-introduce (introducer mresult))])
|
||||||
|
(disappeared! #'id)
|
||||||
|
(recur result))]
|
||||||
[wildcard
|
[wildcard
|
||||||
(wildcard? #'wildcard)
|
(wildcard? #'wildcard)
|
||||||
(begin (disappeared! stx)
|
(begin (disappeared! stx)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user