(module mymatch mzscheme
(require-for-syntax "private/mkmatch.ss"
(lib "stx.ss" "syntax")
(lib "struct.ss" "syntax"))
(provide
match-fail
match
match-lambda
match-lambda*
match-letrec
match-let
match-let*
match-define)
(define match:version "Version 1.10mz, Feb 5, 1996")
(define-struct (exn:misc:match exn) (value))
(define match-fail (gensym 'match-fail))
(define match:error
(case-lambda
((val) match-fail)
((val expr) match-fail)))
(define-syntax parse-pattern
(lambda (p)
(let parse-pattern ([p p])
(define (r l) (map parse-pattern (syntax->list l)))
(define (i v) (match:syntax-err p (format "illegal use of ~a" v)))
(syntax-case* p (_ quote $ ? and or not set! get! quasiquote ... ___) module-or-top-identifier=?
[_ '_]
[(quote x) `(quote ,(syntax-object->datum (syntax x)))]
[(quote . _) (i "quote")]
[($ struct p ...)
(let ([name (syntax struct)])
(unless (identifier? name)
(i "$; not followed by an identifier"))
(let ([info (syntax-local-value name (lambda () #f))])
(unless (struct-declaration-info? info)
(i (format "$; `~a' is not the name of a structure type"
(syntax-e name))))
(let ([pred (caddr info)]
[sel (reverse
(let loop ([l (list-ref info 3)])
(if (or (null? l) (not (car l)))
null
(cons (car l) (loop (cdr l))))))])
(unless (= (length sel)
(length (syntax->list (syntax (p ...)))))
(i (format "$; wrong number of fields for `~a'"
(syntax-e name))))
`($ ,(cons pred sel) ,@(r (syntax (p ...)))))))]
[($ . _) (i "$")]
[(and p ...)
`(and ,@(r (syntax (p ...))))]
[(and . _) (i "and")]
[(or p ...)
`(or ,@(r (syntax (p ...))))]
[(or . _) (i "or")]
[(not p ...)
`(not ,@(r (syntax (p ...))))]
[(not . _) (i "not")]
[(? pred p ...)
`(? ,(syntax pred) ,@(r (syntax (p ...))))]
[(? . _) (i "?")]
[(set! i)
`(set! ,(syntax i))]
[(set! . _) (i "set!")]
[(get! i)
`(get! ,(syntax i))]
[(get! . _) (i "get!")]
[(quasiquote q)
`(,'quasiquote ,(:ucall parse-quasipattern (syntax q)))]
[(quasiquote . _) (i "quasiquote")]
[(p (... ...))
`(,(parse-pattern (syntax p)) ...)]
[(p ___)
`(,(parse-pattern (syntax p)) ___)]
[(p ..k)
(and (identifier? (syntax ..k))
(let ([s (symbol->string (syntax-e (syntax ..k)))])
(regexp-match re:..k s)))
`(,(parse-pattern (syntax p)) ,(syntax-e (syntax ..k)))]
[(p . rest)
(identifier? (syntax i))
(cons (parse-pattern (syntax p)) (parse-pattern (syntax rest)))]
[i (identifier? (syntax i)) (syntax i)]
[_else
(let ([s (syntax-e p)])
(cond
[(vector? s) (list->vector (map parse-pattern (vector->list s)))]
[(box? s) (box (parse-pattern (unbox s)))]
[else s]))]))))
(define-syntax parse-quasipattern
(lambda (p)
(define (i v) (match:syntax-err p (format "illegal use of ~a" v)))
(let parse-quasipattern ([p p])
(syntax-case p (unquote unquote-splicing ...)
[(unquote x) `(,'unquote ,(:ucall parse-pattern (syntax x)))]
[(unquote . _) (i "unquote")]
[(unquote-splicing x) `(,'unquote-splicing ,(:ucall parse-pattern (syntax x)))]
[(unquote-splicing . _) (i "unquote-splicing")]
[(p (... ...))
`(,(parse-quasipattern (syntax p)) ...)]
[(p ..k)
(and (identifier? (syntax ..k))
(let ([s (symbol->string (syntax-e (syntax ..k)))])
(regexp-match re:..k s)))
`(,(parse-quasipattern (syntax p)) ,(syntax-e (syntax ..k)))]
[(i . rest)
(identifier? (syntax i))
(cons (syntax-object->datum (syntax i)) (parse-quasipattern (syntax rest)))]
[(qp . rest)
(cons (parse-quasipattern (syntax qp)) (parse-quasipattern (syntax rest)))]
[_else
(let ([s (syntax-e p)])
(cond
[(vector? s) (list->vector (map parse-quasipattern (vector->list s)))]
[(box? s) (box (parse-quasipattern (unbox s)))]
[else s]))]))))
(define-syntax match
(lambda (stx)
(syntax-case stx ()
[(_ exp clause ...)
(with-syntax ([body
(datum->syntax-object
(quote-syntax here)
(genmatch
(quote-syntax mv)
(map
(lambda (c)
(syntax-case c (=>)
[(p (=> i) e e1 ...)
`(,(:ucall parse-pattern (syntax p))
(=> ,(syntax i))
,@(syntax->list (syntax (e e1 ...))))]
[(p e e1 ...)
`(,(:ucall parse-pattern (syntax p))
,@(syntax->list (syntax (e e1 ...))))]
[_else
(match:syntax-err
c
"bad match clause")]))
(syntax->list (syntax (clause ...))))
stx)
stx)])
(syntax/loc stx
(let ([mv exp])
body)))])))
(define-syntax match-lambda
(lambda (stx)
(syntax-case stx ()
[(_ clause ...)
(syntax/loc stx (lambda (x) (match x clause ...)))])))
(define-syntax match-lambda*
(lambda (stx)
(syntax-case stx ()
[(_ clause ...)
(syntax/loc stx (lambda x (match x clause ...)))])))
(define-syntax match-let*
(lambda (stx)
(syntax-case stx ()
[(_ () body1 body ...)
(syntax/loc stx (begin body1 body ...))]
[(_ ([pat1 exp1] [pat exp] ...) body1 body ...)
(syntax/loc stx (match exp1
[pat1 (match-let* ([pat exp] ...)
body1 body ...)]))])))
(define-syntax match-let
(lambda (stx)
(syntax-case stx ()
[(_ ([pat exp] ...) body1 body ...)
(syntax/loc stx (match-let* ([(pat ...) (list exp ...)])
body1 body ...))])))
(define-syntax match-letrec
(lambda (stx)
(syntax-case stx ()
[(_ ([pat exp] ...) body1 body ...)
(datum->syntax-object
(quote-syntax here)
(genletrec
(map (lambda (p) (:ucall parse-pattern p)) (syntax->list (syntax (pat ...))))
(syntax->list (syntax (exp ...)))
(syntax->list (syntax (body1 body ...)))
stx)
stx)])))
(define-syntax match-define
(lambda (stx)
(syntax-case stx ()
[(_ pat exp)
(datum->syntax-object
(quote-syntax here)
(gendefine (:ucall parse-pattern (syntax pat))
(syntax exp)
stx)
stx)]))))