racket/collects/scheme/match/define-forms.ss
Sam Tobin-Hochstadt e7e34f304c Add match/derived' and match*/derived'.
Use `syntax-parse' to implement most of the match forms.
Avoid generating so much extraneous intermediate forms.
Add `go/one' for handling of `match'.
Make `cert' argument to `go' optional.

svn: r17281
2009-12-13 03:20:32 +00:00

111 lines
4.1 KiB
Scheme

#lang scheme/base
(require (for-syntax scheme/base
unstable/syntax
unstable/sequence
syntax/parse
"parse.ss"
"parse-helper.ss"
"patterns.ss"
"gen-match.ss"))
(provide define-forms)
(define-syntax-rule (define-forms parse-id
match match* match-lambda match-lambda*
match-lambda** match-let match-let*
match-define match-letrec
match/derived match*/derived)
(...
(begin
(provide match match* match-lambda match-lambda* match-lambda**
match-let match-let* match-define match-letrec
match/derived match*/derived)
(define-syntax (match* stx)
(syntax-parse stx
[(_ es . clauses)
(go parse-id stx #'es #'clauses)]))
(define-syntax (match*/derived stx)
(syntax-parse stx
[(_ es orig-stx . clauses)
(go parse-id #'orig-stx #'es #'clauses)]))
(define-syntax (match stx)
(syntax-parse stx
[(_ arg:expr clauses ...)
(go/one parse-id stx #'arg #'(clauses ...))]))
(define-syntax (match/derived stx)
(syntax-parse stx
[(_ arg:expr orig-stx clauses ...)
(go/one parse-id #'orig-stx #'arg #'(clauses ...))]))
(define-syntax (match-lambda stx)
(syntax-parse stx
[(_ . clauses)
(with-syntax* ([arg (generate-temporary)]
[body #`(match/derived arg #,stx . clauses)])
(syntax/loc stx (lambda (arg) body)))]))
(define-syntax (match-lambda* stx)
(syntax-parse stx
[(_ . clauses)
(with-syntax* ([arg (generate-temporary)]
[body #`(match/derived arg #,stx . clauses)])
(syntax/loc stx (lambda arg body)))]))
(define-syntax (match-lambda** stx)
(syntax-parse stx
[(_ (~and clauses [(pats ...) . rhs]) ...)
(with-syntax* ([vars (generate-temporaries (car #'((pats ...) ...)))]
[body #`(match*/derived #'vars #,stx #'(clauses ...))])
(syntax/loc stx (lambda vars body)))]))
;; there's lots of duplication here to handle named let
;; some factoring out would do a lot of good
(define-syntax (match-let stx)
(syntax-parse stx
[(_ nm:id (~and clauses ([pat init-exp:expr] ...)) body1 body ...)
(with-syntax*
([vars (generate-temporaries #'(pat ...))]
[loop-body #`(match*/derived vars #,stx
[(pat ...) (let () body1 body ...)])])
#'(letrec ([nm (lambda vars loop-body)])
(nm init-exp ...)))]
[(_ (~and clauses ([pat init-exp:expr] ...)) body1 body ...)
#`(match*/derived (init-exp ...) #,stx
[(pat ...) (let () body1 body ...)])]))
(define-syntax (match-let* stx)
(syntax-parse stx
[(_ () body1 body ...)
#'(let () body1 body ...)]
[(_ ([pat exp] rest-pats ...) body1 body ...)
#`(match*/derived
(exp)
#,stx
[(pat) #,(syntax/loc stx (match-let* (rest-pats ...)
body1 body ...))])]))
(define-syntax (match-letrec stx)
(syntax-parse stx
[(_ ((~and cl [pat exp]) ...) body1 body ...)
(quasisyntax/loc stx
(let ()
#,@(for/list ([c (in-syntax #'(cl ...))]
[p (in-syntax #'(pat ...))]
[e (in-syntax #'(exp ...))])
(quasisyntax/loc c (match-define #,p #,e)))
body1 body ...))]))
(define-syntax (match-define stx)
(syntax-parse stx
[(_ pat rhs:expr)
;; FIXME - calls parse twice
(let ([p (parse-id #'pat (syntax-local-certifier))])
(with-syntax ([vars (bound-vars p)])
(quasisyntax/loc stx
(define-values vars (match*/derived (rhs) #,stx
[(pat) (values . vars)])))))])))))