svn: r9127
This commit is contained in:
Eli Barzilay 2008-04-01 20:37:55 +00:00
parent 75ceb53bf7
commit fac8cf7328
12 changed files with 680 additions and 604 deletions

View File

@ -1,8 +1,6 @@
#lang scheme/base
(require (for-template scheme/base "patterns.ss" scheme/stxparam)
mzlib/trace
mzlib/etc
syntax/boundmap
syntax/stx
"patterns.ss"
@ -19,11 +17,11 @@
(define (hash-on f elems #:equal? [eql #t])
(define ht (apply make-hash-table (if eql (list 'equal) null)))
;; put all the elements e in the ht, indexed by (f e)
(for-each (lambda (r)
(define k (f r))
(hash-table-put! ht k (cons r (hash-table-get ht k (lambda () null)))))
;; they need to be in the original order when they come out
(reverse elems))
(for ([r
;; they need to be in the original order when they come out
(reverse elems)])
(define k (f r))
(hash-table-put! ht k (cons r (hash-table-get ht k (lambda () null)))))
ht)
;; generate a clause of kind k
@ -31,15 +29,17 @@
;; escaping to esc
(define (gen-clause k rows x xs esc)
(define-syntax-rule (constant-pat predicate-stx)
(with-syntax
([rhs
(compile* (cons x xs)
(map (lambda (row)
(define-values (p ps) (Row-split-pats row))
(define p* (Atom-p p))
(make-Row (cons p* ps) (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
rows)
esc)])
(with-syntax ([rhs (compile* (cons x xs)
(map (lambda (row)
(define-values (p ps)
(Row-split-pats row))
(define p* (Atom-p p))
(make-Row (cons p* ps)
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
rows)
esc)])
#`[(#,predicate-stx #,x) rhs]))
(define (compile-con-pat accs pred pat-acc)
(with-syntax ([(tmps ...) (generate-temporaries accs)])
@ -49,20 +49,21 @@
(append (syntax->list #'(tmps ...)) xs)
(map (lambda (row)
(define-values (p1 ps) (Row-split-pats row))
(make-Row (append (pat-acc p1) ps) (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
(make-Row (append (pat-acc p1) ps)
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
rows)
esc)])
#`[(pred #,x)
(let ([tmps (accs #,x)] ...)
body)])))
#`[(pred #,x) (let ([tmps (accs #,x)] ...) body)])))
(cond
[(eq? 'box k)
[(eq? 'box k)
(compile-con-pat (list #'unbox) #'box? (compose list Box-p))]
[(eq? 'pair k)
(compile-con-pat (list #'car #'cdr) #'pair?
(compile-con-pat (list #'car #'cdr) #'pair?
(lambda (p) (list (Pair-a p) (Pair-d p))))]
[(eq? 'mpair k)
(compile-con-pat (list #'mcar #'mcdr) #'mpair?
(compile-con-pat (list #'mcar #'mcdr) #'mpair?
(lambda (p) (list (MPair-a p) (MPair-d p))))]
[(eq? 'string k) (constant-pat #'string?)]
[(eq? 'number k) (constant-pat #'number?)]
@ -77,32 +78,36 @@
;; because each arity is like a different constructor
[(eq? 'vector k)
(let ()
(define ht (hash-on (lambda (r) (length (Vector-ps (Row-first-pat r)))) rows))
(with-syntax ([(clauses ...)
(hash-table-map
ht
(lambda (arity rows)
(define ns (build-list arity values))
(with-syntax ([(tmps ...) (generate-temporaries ns)])
(with-syntax
([body (compile* (append (syntax->list #'(tmps ...)) xs)
(map (lambda (row)
(define-values (p1 ps) (Row-split-pats row))
(make-Row (append (Vector-ps p1) ps)
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
rows)
esc)]
(define ht
(hash-on (lambda (r) (length (Vector-ps (Row-first-pat r)))) rows))
(with-syntax
([(clauses ...)
(hash-table-map
ht
(lambda (arity rows)
(define ns (build-list arity values))
(with-syntax ([(tmps ...) (generate-temporaries ns)])
(with-syntax ([body
(compile*
(append (syntax->list #'(tmps ...)) xs)
(map (lambda (row)
(define-values (p1 ps)
(Row-split-pats row))
(make-Row (append (Vector-ps p1) ps)
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
rows)
esc)]
[(n ...) ns])
#`[(#,arity)
(let ([tmps (vector-ref #,x n)] ...)
body)]))))])
#`[(#,arity)
(let ([tmps (vector-ref #,x n)] ...)
body)]))))])
#`[(vector? #,x)
(case (vector-length #,x)
clauses ...)]))]
clauses ...)]))]
;; it's a structure
[(box? k)
[(box? k)
;; all the rows are structures with the same predicate
(let* ([s (Row-first-pat (car rows))]
[accs (Struct-accessors s)]
@ -110,94 +115,115 @@
(compile-con-pat accs pred Struct-ps))]
[else (error 'compile "bad key: ~a" k)]))
;; produces the syntax for a let clause
(define (compile-one vars block esc)
(define-values (first rest-pats) (Row-split-pats (car block)))
(define x (car vars))
(define xs (cdr vars))
(cond
(cond
;; the Exact rule
[(Exact? first)
(let ([ht (hash-on (compose Exact-v Row-first-pat) block #:equal? #t)])
(with-syntax ([(clauses ...) (hash-table-map
ht
(lambda (k v)
#`[(equal? #,x '#,k)
#,(compile* xs
(map (lambda (row)
(make-Row (cdr (Row-pats row))
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
v)
esc)]))])
(with-syntax ([(clauses ...)
(hash-table-map
ht
(lambda (k v)
#`[(equal? #,x '#,k)
#,(compile* xs
(map (lambda (row)
(make-Row (cdr (Row-pats row))
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
v)
esc)]))])
#`(cond clauses ... [else (#,esc)])))]
;; the Var rule
[(Var? first)
(let ([transform (lambda (row)
(define-values (p ps) (Row-split-pats row))
(define v (Var-v p))
(define seen (Row-vars-seen row))
;; a new row with the rest of the patterns
(cond
;; if this was a wild-card variable, don't bind
[(Dummy? p) (make-Row ps (Row-rhs row) (Row-unmatch row) (Row-vars-seen row))]
;; if we've seen this variable before, check that it's equal to the one we saw
[(ormap (lambda (e)
(let ([v* (car e)]
[id (cdr e)])
(and (bound-identifier=? v v*) id)))
seen)
=>
(lambda (id)
(make-Row ps
#`(if ((match-equality-test) #,x #,id)
#,(Row-rhs row)
(fail))
(Row-unmatch row)
seen))]
;;otherwise, bind the matched variable to x, and add it to the list of vars we've seen
[else (let ([v* (free-identifier-mapping-get (current-renaming) v (lambda () v))])
(make-Row ps
#`(let ([#,v* #,x]) #,(Row-rhs row))
(Row-unmatch row)
(cons (cons v x) (Row-vars-seen row))))]))])
(let ([transform
(lambda (row)
(define-values (p ps) (Row-split-pats row))
(define v (Var-v p))
(define seen (Row-vars-seen row))
;; a new row with the rest of the patterns
(cond
;; if this was a wild-card variable, don't bind
[(Dummy? p) (make-Row ps
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row))]
;; if we've seen this variable before, check that it's equal to
;; the one we saw
[(ormap (lambda (e)
(let ([v* (car e)] [id (cdr e)])
(and (bound-identifier=? v v*) id)))
seen)
=>
(lambda (id)
(make-Row ps
#`(if ((match-equality-test) #,x #,id)
#,(Row-rhs row)
(fail))
(Row-unmatch row)
seen))]
;; otherwise, bind the matched variable to x, and add it to the
;; list of vars we've seen
[else (let ([v* (free-identifier-mapping-get
(current-renaming) v (lambda () v))])
(make-Row ps
#`(let ([#,v* #,x]) #,(Row-rhs row))
(Row-unmatch row)
(cons (cons v x) (Row-vars-seen row))))]))])
;; compile the transformed block
(compile* xs (map transform block) esc))]
;; the Constructor rule
[(CPat? first)
(let ;; put all the rows in the hash-table, indexed by their constructor
([ht (hash-on (lambda (r) (pat-key (Row-first-pat r))) block)])
(with-syntax ([(clauses ...) (hash-table-map ht (lambda (k v) (gen-clause k v x xs esc)))])
(with-syntax ([(clauses ...)
(hash-table-map
ht (lambda (k v) (gen-clause k v x xs esc)))])
#`(cond clauses ... [else (#,esc)])))]
;; the Or rule
[(Or? first)
;; we only handle 1-row Ors atm - this is all the mixture rule should give us
;; we only handle 1-row Ors atm - this is all the mixture rule should give
;; us
(unless (null? (cdr block))
(error 'compile-one "Or block with multiple rows: ~a" block))
(let* ([row (car block)]
[pats (Row-pats row)]
;; all the pattern alternatives
[qs (Or-ps (car pats))]
;; the variables bound by this pattern - they're the same for the whole list
;; the variables bound by this pattern - they're the same for the
;; whole list
[vars (bound-vars (car qs))])
(with-syntax ([vars vars])
;; do the or matching, and bind the results to the appropriate variables
;; do the or matching, and bind the results to the appropriate
;; variables
#`(let/ec exit
(let ([esc* (lambda () (exit (#,esc)))])
(let-values ([vars #,(compile* (list x) (map (lambda (q) (make-Row (list q) #'(values . vars) #f (Row-vars-seen row)))
qs)
#'esc*)])
(let-values ([vars
#,(compile* (list x)
(map (lambda (q)
(make-Row (list q)
#'(values . vars)
#f
(Row-vars-seen row)))
qs)
#'esc*)])
;; then compile the rest of the row
#,(compile* xs
(list (make-Row (cdr pats) (Row-rhs row) (Row-unmatch row)
#,(compile* xs
(list (make-Row (cdr pats)
(Row-rhs row)
(Row-unmatch row)
(let ([vs (syntax->list #'vars)])
(append (map cons vs vs) (Row-vars-seen row)))))
(append (map cons vs vs)
(Row-vars-seen row)))))
esc))))))]
;; the App rule
[(App? first)
;; we only handle 1-row Apps atm - this is all the mixture rule should give us
;; we only handle 1-row Apps atm - this is all the mixture rule should
;; give us
(unless (null? (cdr block))
(error 'compile-one "App block with multiple rows: ~a" block))
(let* ([row (car block)]
@ -205,11 +231,15 @@
(with-syntax ([(t) (generate-temporaries #'(t))])
#`(let ([t (#,(App-expr first) #,x)])
#,(compile* (cons #'t xs)
(list (make-Row (cons (App-p first) (cdr pats)) (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
(list (make-Row (cons (App-p first) (cdr pats))
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
esc))))]
;; the And rule
[(And? first)
;; we only handle 1-row Ands atm - this is all the mixture rule should give us
;; we only handle 1-row Ands atm - this is all the mixture rule should
;; give us
(unless (null? (cdr block))
(error 'compile-one "And block with multiple rows: ~a" block))
(let* ([row (car block)]
@ -217,11 +247,15 @@
;; all the patterns
[qs (And-ps (car pats))])
(compile* (append (map (lambda _ x) qs) xs)
(list (make-Row (append qs (cdr pats)) (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
(list (make-Row (append qs (cdr pats))
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
esc))]
;; the Not rule
[(Not? first)
;; we only handle 1-row Nots atm - this is all the mixture rule should give us
;; we only handle 1-row Nots atm - this is all the mixture rule should
;; give us
(unless (null? (cdr block))
(error 'compile-one "Not block with multiple rows: ~a" block))
(let* ([row (car block)]
@ -229,23 +263,33 @@
;; the single pattern
[q (Not-p (car pats))])
(with-syntax ([(f) (generate-temporaries #'(f))])
#`(let
;; if q fails, we jump to here
([f (lambda ()
#,(compile* xs
(list (make-Row (cdr pats) (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
esc))])
#`(let ;; if q fails, we jump to here
([f (lambda ()
#,(compile* xs
(list (make-Row (cdr pats)
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
esc))])
#,(compile* (list x)
;; if q doesn't fail, we jump to esc and fail the not pattern
(list (make-Row (list q) #`(#,esc) (Row-unmatch row) (Row-vars-seen row)))
;; if q doesn't fail, we jump to esc and fail the not
;; pattern
(list (make-Row (list q)
#`(#,esc)
(Row-unmatch row)
(Row-vars-seen row)))
#'f))))]
[(Pred? first)
;; multiple preds iff they have the identical predicate
[(Pred? first)
;; multiple preds iff they have the identical predicate
(with-syntax ([pred? (Pred-pred first)]
[body (compile* xs
(map (lambda (row)
(define-values (_1 ps) (Row-split-pats row))
(make-Row ps (Row-rhs row) (Row-unmatch row) (Row-vars-seen row)))
(define-values (_1 ps)
(Row-split-pats row))
(make-Row ps
(Row-rhs row)
(Row-unmatch row)
(Row-vars-seen row)))
block)
esc)])
#`(cond [(pred? #,x) body] [else (#,esc)]))]
@ -262,9 +306,8 @@
(lambda (ps)
(define (loop ps pat)
(if (pair? ps)
(make-Pair (car ps)
(loop (cdr ps) pat))
pat))
(make-Pair (car ps) (loop (cdr ps) pat))
pat))
(loop ps (make-Var xvar)))]
[heads
(for/list ([ps headss])
@ -285,106 +328,116 @@
[(maxrepconstraint ...)
;; FIXME: move to side condition to appropriate pattern
(for/list ([repvar reps] [maxrep maxs])
(if maxrep
#`(< #,repvar #,maxrep)
#`#t))]
(if maxrep #`(< #,repvar #,maxrep) #`#t))]
[(minrepclause ...)
(for/list ([repvar reps] [minrep mins] #:when minrep)
#`[(< #,repvar #,minrep)
(fail)])]
#`[(< #,repvar #,minrep) (fail)])]
[((hid-rhs ...) ...)
(for/list ([hid-args hid-argss] [once? onces?])
(for/list ([hid-arg hid-args])
(if once?
#`(car (reverse #,hid-arg))
#`(reverse #,hid-arg))))]
[(parse-loop failkv fail-tail) (generate-temporaries #'(parse-loop failkv fail-tail))])
(for/list ([hid-arg hid-args])
(if once?
#`(car (reverse #,hid-arg))
#`(reverse #,hid-arg))))]
[(parse-loop failkv fail-tail)
(generate-temporaries #'(parse-loop failkv fail-tail))])
(with-syntax ([(rhs ...)
#`[(let ([hid-arg (cons hid* hid-arg)] ...)
(if maxrepconstraint
(let ([rep (add1 rep)])
(parse-loop x #,@hid-args #,@reps fail))
(begin
(fail))))
(let ([rep (add1 rep)])
(parse-loop x #,@hid-args #,@reps fail))
(begin (fail))))
...]]
[tail-rhs
#`(cond minrepclause ...
[else
(let ([hid hid-rhs] ... ...
[fail-tail fail])
#,(compile* (cdr vars)
(list (make-Row rest-pats k (Row-unmatch (car block)) (Row-vars-seen (car block))))
#'fail-tail))])])
(parameterize ([current-renaming
(for/fold ([ht (copy-mapping (current-renaming))])
([id (apply append head-idss)]
[id* (apply append head-idss*)])
(free-identifier-mapping-put! ht id id*)
(free-identifier-mapping-for-each
ht
(lambda (k v)
(when (free-identifier=? v id)
(free-identifier-mapping-put! ht k id*))))
ht)])
#`(let parse-loop ([x var0] [hid-arg null] ... ... [rep 0] ... [failkv #,esc])
#,(compile* (list #'x)
#,(compile*
(cdr vars)
(list (make-Row rest-pats k
(Row-unmatch (car block))
(Row-vars-seen
(car block))))
#'fail-tail))])])
(parameterize ([current-renaming
(for/fold ([ht (copy-mapping (current-renaming))])
([id (apply append head-idss)]
[id* (apply append head-idss*)])
(free-identifier-mapping-put! ht id id*)
(free-identifier-mapping-for-each
ht
(lambda (k v)
(when (free-identifier=? v id)
(free-identifier-mapping-put! ht k id*))))
ht)])
#`(let parse-loop ([x var0]
[hid-arg null] ... ...
[rep 0] ...
[failkv #,esc])
#,(compile* (list #'x)
(append
(map (lambda (pats rhs) (make-Row pats rhs (Row-unmatch (car block)) null))
(map (lambda (pats rhs)
(make-Row pats
rhs
(Row-unmatch (car block))
null))
(map list heads)
(syntax->list #'(rhs ...)))
(list (make-Row (list tail) #`tail-rhs (Row-unmatch (car block)) null)))
(list (make-Row (list tail)
#`tail-rhs
(Row-unmatch (car block))
null)))
#'failkv))))))]
[else (error 'compile "unsupported pattern: ~a~n" first)]))
[else (error 'compile "unsupported pattern: ~a~n" first)]))
(define (compile* vars rows esc)
(define (let/wrap clauses body)
(if (stx-null? clauses)
body
(quasisyntax (let* #,clauses #,body))))
(if (stx-null? clauses)
body
(quasisyntax (let* #,clauses #,body))))
(if (null? vars)
;; if we have no variables, there are no more patterns to match
;; so we just pick the first RHS
(let ([fns
(let loop ([blocks (reverse rows)] [esc esc] [acc null])
(cond
;; if we're done, return the blocks
[(null? blocks) (reverse acc)]
[else (with-syntax (;; f is the name this block will have
[(f) (generate-temporaries #'(f))]
;; compile the block, with jumps to the previous esc
[c (with-syntax ([rhs #`(syntax-parameterize ([fail (make-rename-transformer (quote-syntax #,esc))])
#,(Row-rhs (car blocks)))])
(if
(Row-unmatch (car blocks))
#`(let/ec k
(let ([#,(Row-unmatch (car blocks)) (lambda () (k (#,esc)))])
rhs))
#'rhs))])
;; then compile the rest, with our name as the esc
(loop (cdr blocks) #'f (cons #'[f (lambda () c)] acc)))]))])
(with-syntax ([(fns ... [_ (lambda () body)]) fns])
(let/wrap #'(fns ...) #'body)))
;; otherwise, we split the matrix into blocks
;; and compile each block with a reference to its continuation
(let ([fns
(let loop ([blocks (reverse (split-rows rows))] [esc esc] [acc null])
(cond
;; if we're done, return the blocks
[(null? blocks) (reverse acc)]
[else (with-syntax (;; f is the name this block will have
[(f) (generate-temporaries #'(f))]
;; compile the block, with jumps to the previous esc
[c (compile-one vars (car blocks) esc)])
;; then compile the rest, with our name as the esc
(loop (cdr blocks) #'f (cons #'[f (lambda () c)] acc)))]))])
;; if we have no variables, there are no more patterns to match
;; so we just pick the first RHS
(let ([fns
(let loop ([blocks (reverse rows)] [esc esc] [acc null])
(if (null? blocks)
;; if we're done, return the blocks
(reverse acc)
(with-syntax
(;; f is the name this block will have
[(f) (generate-temporaries #'(f))]
;; compile the block, with jumps to the previous esc
[c (with-syntax ([rhs #`(syntax-parameterize
([fail (make-rename-transformer
(quote-syntax #,esc))])
#,(Row-rhs (car blocks)))])
(if (Row-unmatch (car blocks))
#`(let/ec k
(let ([#,(Row-unmatch (car blocks))
(lambda () (k (#,esc)))])
rhs))
#'rhs))])
;; then compile the rest, with our name as the esc
(loop (cdr blocks) #'f (cons #'[f (lambda () c)] acc)))))])
(with-syntax ([(fns ... [_ (lambda () body)]) fns])
(let/wrap #'(fns ...) #'body)))
;; otherwise, we split the matrix into blocks
;; and compile each block with a reference to its continuation
(let ([fns
(let loop ([blocks (reverse (split-rows rows))] [esc esc] [acc null])
(if (null? blocks)
;; if we're done, return the blocks
(reverse acc)
(with-syntax (;; f is the name this block will have
[(f) (generate-temporaries #'(f))]
;; compile the block, with jumps to the previous
;; esc
[c (compile-one vars (car blocks) esc)])
;; then compile the rest, with our name as the esc
(loop (cdr blocks) #'f (cons #'[f (lambda () c)] acc)))))])
(with-syntax ([(fns ... [_ (lambda () body)]) fns])
(let/wrap #'(fns ...) #'body)))))
;(trace compile* compile-one)
;; (require mzlib/trace)
;; (trace compile* compile-one)

View File

@ -8,32 +8,29 @@
(provide define-forms)
(define-syntax-rule (define-forms parse-id
match match* match-lambda match-lambda* match-let match-let* match-define match-letrec)
(define-syntax-rule (define-forms parse-id
match match* match-lambda match-lambda* match-let
match-let* match-define match-letrec)
(...
(begin
(provide match match* match-lambda match-lambda* match-let match-let* match-define match-letrec)
(provide match match* match-lambda match-lambda* match-let match-let*
match-define match-letrec)
(define-syntax (match* stx)
(syntax-case stx ()
[(_ es . clauses)
(go parse-id stx #'es #'clauses (syntax-local-certifier))]))
(define-syntax-rule (match arg [p . es] ...)
(match* (arg)
[(p) . es]
...))
(match* (arg) [(p) . es] ...))
(define-syntax (match-lambda stx)
(syntax-case stx ()
[(k . clauses)
(syntax/loc stx (lambda (exp) (match exp . clauses)))]))
[(k . clauses) (syntax/loc stx (lambda (exp) (match exp . clauses)))]))
(define-syntax (match-lambda* stx)
(syntax-case stx ()
[(k . clauses)
(syntax/loc stx (lambda exp (match exp . clauses)))]))
[(k . clauses) (syntax/loc stx (lambda exp (match exp . clauses)))]))
(define-syntax (match-lambda** stx)
(syntax-case stx ()
[(k [pats . rhs] ...)
@ -41,13 +38,14 @@
[ps1 (car pss)]
[len (length (syntax->list ps1))])
(for/list ([ps pss])
(unless (= (length (syntax->list ps)) len)
(raise-syntax-error 'match "unequal number of patterns in match clauses" stx ps ps1)))
(unless (= (length (syntax->list ps)) len)
(raise-syntax-error
'match "unequal number of patterns in match clauses"
stx ps ps1)))
(with-syntax ([(vars ...) (generate-temporaries (car pss))])
(syntax/loc stx (lambda (vars ...) (match* (vars ...) [pats . rhs] ...)))))]))
(syntax/loc stx
(lambda (vars ...) (match* (vars ...) [pats . rhs] ...)))))]))
;; there's lots of duplication here to handle named let
;; some factoring out would do a lot of good
(define-syntax (match-let stx)
@ -58,36 +56,33 @@
(match:syntax-err stx "bad syntax (empty body)")]
[(_ (clauses ...)) (match:syntax-err stx "bad syntax (empty body)")]
;; with no bindings, there's nothing to do
[(_ name () body ...)
[(_ name () body ...)
(identifier? #'name)
(syntax/loc stx (let name () body ...))]
[(_ () body ...) (syntax/loc stx (let () body ...))]
;; optimize the all-variable case
;; optimize the all-variable case
[(_ ([pat exp]...) body ...)
(andmap pattern-var? (syntax->list #'(pat ...)))
(syntax/loc stx (let name ([pat exp] ...) body ...))]
(syntax/loc stx (let name ([pat exp] ...) body ...))]
[(_ name ([pat exp]...) body ...)
(and (identifier? (syntax name))
(andmap pattern-var? (syntax->list #'(pat ...))))
(syntax/loc stx (let name ([pat exp] ...) body ...))]
;; now the real cases
[(_ name ([pat exp] ...) . body)
(syntax/loc stx (letrec ([name (match-lambda** ((pat ...) . body))])
(syntax/loc stx (letrec ([name (match-lambda** ((pat ...) . body))])
(name exp ...)))]
[(_ ([pat exp] ...) . body)
(syntax/loc stx (match* (exp ...) [(pat ...) . body]))]))
(define-syntax (match-let* stx)
(syntax-case stx ()
[(_ (clauses ...)) (match:syntax-err stx "bad syntax (empty body)")]
((_ () body ...)
(syntax/loc stx (let* () body ...)))
((_ ([pat exp] rest ...) body ...)
(syntax/loc stx (match exp [pat (match-let* (rest ...) body ...)])))
))
[(_ () body ...)
(syntax/loc stx (let* () body ...))]
[(_ ([pat exp] rest ...) body ...)
(syntax/loc stx (match exp [pat (match-let* (rest ...) body ...)]))]))
(define-syntax (match-letrec stx)
(syntax-case stx ()
[(_ (clauses ...)) (match:syntax-err stx "bad syntax (empty body)")]
@ -96,12 +91,8 @@
(syntax->list #'(pat ...)))
(syntax/loc stx (letrec ([pat exp] ...) . body))]
[(_ ([pat exp] ...) . body)
(syntax/loc stx (let ()
(match-define pat exp) ...
. body))]))
(syntax/loc stx (let () (match-define pat exp) ... . body))]))
(define-syntax (match-define stx)
(syntax-case stx ()
[(_ pat exp)
@ -112,6 +103,4 @@
(let ([p (parse-id #'pat (syntax-local-certifier))])
(with-syntax ([vars (bound-vars p)])
(syntax/loc stx
(define-values vars
(match rhs
[pat (values . vars)])))))])))))
(define-values vars (match rhs [pat (values . vars)])))))])))))

View File

@ -10,37 +10,51 @@
;; go : syntax syntax syntax certifier -> syntax
(define (go parse/cert stx exprs clauses cert)
(parameterize ([orig-stx stx])
(syntax-case clauses ()
[([pats . rhs] ...)
(let ([len (length (syntax->list exprs))])
(with-syntax ([(xs ...) (generate-temporaries exprs)]
[(exprs ...) exprs]
[(fail) (generate-temporaries #'(fail))])
(with-syntax ([body (compile* (syntax->list #'(xs ...))
(map (lambda (pats rhs)
(unless (= len (length (syntax->list pats)))
(raise-syntax-error 'match
(format "wrong number of match clauses, expected ~a and got ~a"
len (length (syntax->list pats)))
pats))
(syntax-case* rhs (=>)
(lambda (x y) (eq? (syntax-e x) (syntax-e y)))
[((=> unm) . rhs)
(make-Row (map (lambda (s) (parse/cert s cert)) (syntax->list pats))
#`(begin . rhs)
#'unm
null)]
[_
(make-Row (map (lambda (s) (parse/cert s cert)) (syntax->list pats))
#`(begin . #,rhs)
#f
null)]))
(syntax->list #'(pats ...))
(syntax->list #'(rhs ...)))
#'fail)]
[orig-expr (if (= 1 len) (stx-car #'(xs ...)) #'(list xs ...))])
(quasisyntax/loc stx
(let ([xs exprs]
...)
(let ([fail (lambda () #,(syntax/loc stx (match:error orig-expr)))])
body))))))])))
(syntax-case clauses ()
[([pats . rhs] ...)
(let ([len (length (syntax->list exprs))])
(with-syntax ([(xs ...) (generate-temporaries exprs)]
[(exprs ...) exprs]
[(fail) (generate-temporaries #'(fail))])
(with-syntax ([body (compile*
(syntax->list #'(xs ...))
(map (lambda (pats rhs)
(unless (= len
(length (syntax->list pats)))
(raise-syntax-error
'match
(format "~a, expected ~a and got ~a"
"wrong number of match clauses"
len
(length (syntax->list pats)))
pats))
(syntax-case* rhs (=>)
(lambda (x y)
(eq? (syntax-e x)
(syntax-e y)))
[((=> unm) . rhs)
(make-Row (map (lambda (s)
(parse/cert s cert))
(syntax->list pats))
#`(begin . rhs)
#'unm
null)]
[_
(make-Row (map (lambda (s)
(parse/cert s cert))
(syntax->list pats))
#`(begin . #,rhs)
#f
null)]))
(syntax->list #'(pats ...))
(syntax->list #'(rhs ...)))
#'fail)]
[orig-expr (if (= 1 len)
(stx-car #'(xs ...))
#'(list xs ...))])
(quasisyntax/loc stx
(let ([xs exprs]
...)
(let ([fail (lambda ()
#,(syntax/loc stx (match:error orig-expr)))])
body))))))])))

View File

@ -1,12 +1,22 @@
#lang scheme/base
(require (only-in "patterns.ss" match-equality-test match-...-nesting exn:misc:match?)
(only-in "match-expander.ss" define-match-expander)
(require (only-in "patterns.ss"
match-equality-test
match-...-nesting
exn:misc:match?)
(only-in "match-expander.ss"
define-match-expander)
"define-forms.ss"
(for-syntax "parse-legacy.ss" "gen-match.ss")
(for-syntax (only-in "patterns.ss" match-...-nesting)))
(for-syntax "parse-legacy.ss"
"gen-match.ss"
(only-in "patterns.ss" match-...-nesting)))
(provide (for-syntax match-...-nesting) match-equality-test match-...-nesting define-match-expander exn:misc:match?)
(provide (for-syntax match-...-nesting)
match-equality-test
match-...-nesting
define-match-expander
exn:misc:match?)
(define-forms parse/legacy/cert
match match* match-lambda match-lambda* match-let match-let* match-define match-letrec)
match match* match-lambda match-lambda* match-let match-let*
match-define match-letrec)

View File

@ -12,19 +12,19 @@
(define (parse args)
(let loop ([args args]
[alist '()])
(if (null? args)
alist
(let* ([stx-v (car args)]
[v (syntax-e stx-v)])
(cond
[(not (keyword? v))
(raise-syntax-error #f "Argument must be a keyword" stx stx-v)]
[(not (memq v '(#:expression #:plt-match #:match)))
(raise-syntax-error #f (format "Keyword argument ~a is not a correct keyword" v) stx stx-v)]
[else
(loop (cddr args)
(cons (list v (cadr args))
alist))])))))
(if (null? args)
alist
(let* ([stx-v (car args)]
[v (syntax-e stx-v)])
(cond
[(not (keyword? v))
(raise-syntax-error #f "argument must be a keyword" stx stx-v)]
[(not (memq v '(#:expression #:plt-match #:match)))
(raise-syntax-error
#f (format "keyword argument ~a is not a correct keyword" v)
stx stx-v)]
[else
(loop (cddr args) (cons (list v (cadr args)) alist))])))))
(syntax-case stx ()
[(_ id kw . rest)
(keyword? (syntax-e #'kw))
@ -33,29 +33,36 @@
(with-syntax
([legacy-xform (lookup '#:match parsed-args)]
[match-xform (lookup '#:plt-match parsed-args)]
[macro-xform (or (lookup '#:expression parsed-args)
#'(lambda (stx)
(raise-syntax-error #f "This match expander must be used inside match" stx)))])
[macro-xform
(or (lookup '#:expression parsed-args)
#'(lambda (stx)
(raise-syntax-error
#f "this match expander must be used inside match"
stx)))])
(if (identifier? #'macro-xform)
(syntax/loc stx
(define-syntax id (make-match-expander match-xform
legacy-xform
(lambda (stx)
(syntax-case stx (set!)
[(nm args (... ...)) #'(macro-xform args (... ...))]
[nm #'macro-xform]))
(syntax-local-certifier))))
(syntax/loc stx
(define-syntax id (make-match-expander match-xform legacy-xform macro-xform (syntax-local-certifier)))))))]
(syntax/loc stx
(define-syntax id
(make-match-expander
match-xform
legacy-xform
(lambda (stx)
(syntax-case stx (set!)
[(nm args (... ...)) #'(macro-xform args (... ...))]
[nm #'macro-xform]))
(syntax-local-certifier))))
(syntax/loc stx
(define-syntax id
(make-match-expander match-xform legacy-xform macro-xform
(syntax-local-certifier)))))))]
;; implement legacy syntax
[(_ id plt-match-xform match-xform std-xform)
#'(define-match-expander id #:plt-match plt-match-xform #:match match-xform #:expression std-xform)]
#'(define-match-expander id #:plt-match plt-match-xform
#:match match-xform
#:expression std-xform)]
[(_ id plt-match-xform std-xform)
#'(define-match-expander id #:plt-match plt-match-xform #:expression std-xform)]
[(_ id plt-match-xform)
#'(define-match-expander id #:plt-match plt-match-xform
#:expression std-xform)]
[(_ id plt-match-xform)
#'(define-match-expander id #:plt-match plt-match-xform)]
;; error checking
[_ (raise-syntax-error #f "Invalid use of define-match-expander" stx)]
))
[_ (raise-syntax-error #f "invalid use of define-match-expander" stx)]))

View File

@ -1,12 +1,22 @@
#lang scheme/base
(require (only-in "patterns.ss" match-equality-test match-...-nesting exn:misc:match?)
(only-in "match-expander.ss" define-match-expander)
(require (only-in "patterns.ss"
match-equality-test
match-...-nesting
exn:misc:match?)
(only-in "match-expander.ss"
define-match-expander)
"define-forms.ss"
(for-syntax "parse.ss" "gen-match.ss")
(for-syntax (only-in "patterns.ss" match-...-nesting)))
(for-syntax "parse.ss"
"gen-match.ss"
(only-in "patterns.ss" match-...-nesting)))
(provide (for-syntax match-...-nesting) match-equality-test match-...-nesting define-match-expander exn:misc:match?)
(provide (for-syntax match-...-nesting)
match-equality-test
match-...-nesting
define-match-expander
exn:misc:match?)
(define-forms parse/cert
match match* match-lambda match-lambda* match-let match-let* match-define match-letrec)
match match* match-lambda match-lambda* match-let match-let*
match-define match-letrec)

View File

@ -8,16 +8,17 @@
"compiler.ss"
(only-in srfi/1 delete-duplicates))
(provide ddk? parse-literal all-vars pattern-var? match:syntax-err
(provide ddk? parse-literal all-vars pattern-var? match:syntax-err
match-expander-transform matchable? trans-match parse-struct
dd-parse parse-quote parse-id)
;; parse x as a match variable
;; x : identifier
(define (parse-id x)
(define (parse-id x)
(cond [(eq? '_ (syntax-e x))
(make-Dummy x)]
[(ddk? x) (raise-syntax-error 'match "incorrect use of ... in pattern" #'x)]
[(ddk? x) (raise-syntax-error 'match "incorrect use of ... in pattern"
#'x)]
[else (make-Var x)]))
;; stx : syntax of pattern, starting with quote
@ -32,15 +33,14 @@
[(quote vec)
(vector? (syntax-e #'vec))
(make-Vector (for/list ([e (vector->list (syntax-e #'vec))])
(parse (quasisyntax/loc stx (quote #,e)))))]
(parse (quasisyntax/loc stx (quote #,e)))))]
[(quote bx)
(vector? (syntax-e #'bx))
(make-Box (parse (quasisyntax/loc stx (quote #,(syntax-e #'bx)))))]
[(quote v)
(or (parse-literal (syntax-e #'v))
(raise-syntax-error 'match "non-literal in quote pattern" stx #'v))]
[_
(raise-syntax-error 'match "syntax error in quote pattern" stx)]))
[_ (raise-syntax-error 'match "syntax error in quote pattern" stx)]))
;; parse : the parse fn
;; p : the repeated pattern
@ -48,16 +48,15 @@
;; rest : the syntax for the rest
(define (dd-parse parse p dd rest)
(let* ([count (ddk? dd)]
[min (if (number? count) count #f)])
(make-GSeq
(parameterize ([match-...-nesting (add1 (match-...-nesting))])
(list (list (parse p))))
(list min)
;; no upper bound
(list #f)
;; patterns in p get bound to lists
(list #f)
(parse rest))))
[min (and (number? count) count)])
(make-GSeq (parameterize ([match-...-nesting (add1 (match-...-nesting))])
(list (list (parse p))))
(list min)
;; no upper bound
(list #f)
;; patterns in p get bound to lists
(list #f)
(parse rest))))
;; stx : the syntax object for the whole pattern
;; cert : the certifier
@ -66,34 +65,44 @@
;; pats : syntax representing the member patterns
;; returns a pattern
(define (parse-struct stx cert parse struct-name pats)
(let* ([fail (lambda ()
(raise-syntax-error 'match (format "~a does not refer to a structure definition" (syntax->datum struct-name)) stx struct-name))]
(let* ([fail (lambda ()
(raise-syntax-error
'match (format "~a does not refer to a structure definition"
(syntax->datum struct-name))
stx struct-name))]
[v (syntax-local-value (cert struct-name) fail)])
(unless (struct-info? v)
(fail))
(let-values ([(id _1 pred acc _2 super) (apply values (extract-struct-info v))])
(unless (struct-info? v) (fail))
(let-values ([(id _1 pred acc _2 super)
(apply values (extract-struct-info v))])
;; this produces a list of all the super-types of this struct
;; ending when it reaches the top of the hierarchy, or a struct that we can't access
;; ending when it reaches the top of the hierarchy, or a struct that we
;; can't access
(define (get-lineage struct-name)
(let ([super (list-ref
(extract-struct-info (syntax-local-value struct-name))
5)])
(let ([super (list-ref (extract-struct-info (syntax-local-value
struct-name))
5)])
(cond [(equal? super #t) '()] ;; no super type exists
[(equal? super #f) '()] ;; super type is unknown
[else (cons super (get-lineage super))])))
(let* (;; the accessors come in reverse order
[acc (reverse acc)]
;; remove the first element, if it's #f
[acc (cond [(null? acc) acc] [(not (car acc)) (cdr acc)] [else acc])])
(make-Struct id pred (get-lineage (cert struct-name)) acc
[acc (cond [(null? acc) acc]
[(not (car acc)) (cdr acc)]
[else acc])])
(make-Struct id pred (get-lineage (cert struct-name)) acc
(if (eq? '_ (syntax-e pats))
(map make-Dummy acc)
(let* ([ps (syntax->list pats)])
(unless (= (length ps) (length acc))
(raise-syntax-error 'match (format "wrong number for fields for structure ~a: expected ~a but got ~a"
(syntax->datum struct-name) (length acc) (length ps))
stx pats))
(map parse ps))))))))
(map make-Dummy acc)
(let* ([ps (syntax->list pats)])
(unless (= (length ps) (length acc))
(raise-syntax-error
'match
(format "~a structure ~a: expected ~a but got ~a"
"wrong number for fields for"
(syntax->datum struct-name) (length acc)
(length ps))
stx pats))
(map parse ps))))))))
(define (trans-match pred transformer pat)
(make-And (list (make-Pred pred) (make-App transformer pat))))
@ -106,9 +115,10 @@
;; accessor : match-expander -> syntax transformer/#f
;; error-msg : string
;; produces a parsed pattern
(define (match-expander-transform parse/cert cert expander stx accessor error-msg)
(define (match-expander-transform parse/cert cert expander stx accessor
error-msg)
(let* ([expander (syntax-local-value (cert expander))]
[transformer (accessor expander)])
[transformer (accessor expander)])
(unless transformer (raise-syntax-error #f error-msg #'expander))
(let* ([introducer (make-syntax-introducer)]
[certifier (match-expander-certifier expander)]
@ -122,7 +132,6 @@
(define (matchable? e)
(or (string? e) (bytes? e)))
;; raise an error, blaming stx
(define (match:syntax-err stx msg)
(raise-syntax-error #f msg stx))
@ -130,67 +139,56 @@
;; pattern-var? : syntax -> bool
;; is p an identifier representing a pattern variable?
(define (pattern-var? p)
(and (identifier? p)
(not (ddk? p))))
(and (identifier? p) (not (ddk? p))))
;; ddk? : syntax -> number or boolean
;; if #f is returned, was not a ddk identifier
;; if #t is returned, no minimum
;; if a number is returned, that's the minimum
(define (ddk? s*)
(define (./_ c)
(or (equal? c #\.)
(equal? c #\_)))
(define (./_ c) (or (equal? c #\.) (equal? c #\_)))
(let ([s (syntax->datum s*)])
(and (symbol? s)
(if (memq s '(... ___)) #t
(let* ((s (symbol->string s)))
(and (3 . <= . (string-length s))
(./_ (string-ref s 0))
(./_ (string-ref s 1))
(let ([n (string->number (substring s 2))])
(cond
[(not n) #f]
[(zero? n) #t]
[(exact-nonnegative-integer? n) n]
[else (raise-syntax-error 'match "invalid number for ..k pattern" s*)]))))))))
(if (memq s '(... ___))
#t
(let* ([m (regexp-match #rx"^(?:\\.\\.|__)([0-9]+)$"
(symbol->string s))]
[n (and m (string->number (cadr m)))])
(cond [(not n) #f]
[(zero? n) #t]
[(exact-nonnegative-integer? n) n]
[else (raise-syntax-error
'match "invalid number for ..k pattern"
s*)]))))))
;; parse-literal : scheme-val -> pat option
;; is v is a literal, return a pattern matching it
;; otherwise, return #f
(define (parse-literal v)
(if (or (number? v)
(string? v)
(keyword? v)
(symbol? v)
(bytes? v)
(regexp? v)
(boolean? v)
(char? v))
(make-Exact v)
#f))
(if (or (number? v) (string? v) (keyword? v) (symbol? v) (bytes? v)
(regexp? v) (boolean? v) (char? v))
(make-Exact v)
#f))
;; (listof pat) syntax -> void
;; check that all the ps bind the same set of variables
(define (all-vars ps stx)
(when (null? ps)
(error 'bad))
(when (null? ps) (error 'bad))
(let* ([first-vars (bound-vars (car ps))]
[l (length ps)]
[ht (make-free-identifier-mapping)])
(for-each (lambda (v) (free-identifier-mapping-put! ht v 1)) first-vars)
(for-each (lambda (p)
(for-each (lambda (v)
(cond [(free-identifier-mapping-get ht v (lambda () #f))
=>
(lambda (n)
(free-identifier-mapping-put! ht v (add1 n)))]
[else (raise-syntax-error 'match "variable not bound in all or patterns" stx v)]))
(bound-vars p)))
(cdr ps))
(for ([v first-vars]) (free-identifier-mapping-put! ht v 1))
(for* ([p (cdr ps)]
[v (bound-vars p)])
(cond [(free-identifier-mapping-get ht v (lambda () #f))
=> (lambda (n)
(free-identifier-mapping-put! ht v (add1 n)))]
[else (raise-syntax-error 'match
"variable not bound in all or patterns"
stx v)]))
(free-identifier-mapping-for-each
ht
(lambda (v n)
(unless (= n l)
(raise-syntax-error 'match "variable not bound in all or patterns" stx v))))))
(raise-syntax-error 'match "variable not bound in all or patterns"
stx v))))))

View File

@ -5,7 +5,7 @@
syntax/stx
scheme/struct-info
"patterns.ss"
"compiler.ss"
"compiler.ss"
"parse-helper.ss"
"parse-quasi.ss"
(only-in srfi/1 delete-duplicates))
@ -15,13 +15,14 @@
(define (parse/legacy/cert stx cert)
(define (parse stx) (parse/legacy/cert stx cert))
(syntax-case* stx (not $ ? and or = quasiquote quote)
(lambda (x y) (eq? (syntax-e x) (syntax-e y)))
(lambda (x y) (eq? (syntax-e x) (syntax-e y)))
[(expander args ...)
(and (identifier? #'expander)
(match-expander? (syntax-local-value (cert #'expander) (lambda () #f))))
(match-expander-transform parse/legacy/cert cert #'expander stx match-expander-legacy-xform
"This expander only works with the standard match syntax")]
(match-expander?
(syntax-local-value (cert #'expander) (lambda () #f))))
(match-expander-transform
parse/legacy/cert cert #'expander stx match-expander-legacy-xform
"This expander only works with the standard match syntax")]
[(and p ...)
(make-And (map parse (syntax->list #'(p ...))))]
[(or p ...)
@ -32,19 +33,21 @@
;; nots are conjunctions of negations
(let ([ps (map (compose make-Not parse) (syntax->list #'(p ...)))])
(make-And ps))]
[bx
[bx
(box? (syntax-e #'bx))
(make-Box (parse (unbox (syntax-e #'bx))))]
[#(es ...)
(ormap ddk? (syntax->list #'(es ...)))
(make-And (list (make-Pred #'vector?) (make-App #'vector->list (parse (syntax/loc stx (es ...))))))]
(make-And (list (make-Pred #'vector?)
(make-App #'vector->list
(parse (syntax/loc stx (es ...))))))]
[#(es ...)
(make-Vector (map parse (syntax->list #'(es ...))))]
(make-Vector (map parse (syntax->list #'(es ...))))]
[($ s . pats)
(parse-struct stx cert parse #'s #'pats)]
[(? p q1 qs ...)
(make-And (cons (make-Pred (cert #'p)) (map parse (syntax->list #'(q1 qs ...)))))]
(make-And (cons (make-Pred (cert #'p))
(map parse (syntax->list #'(q1 qs ...)))))]
[(? p)
(make-Pred (cert #'p))]
[(= f p)
@ -61,7 +64,7 @@
(ddk? #'..)
(dd-parse parse #'p #'.. #'rest)]
[(e . es)
(make-Pair (parse #'e) (parse (syntax/loc stx es)))]
(make-Pair (parse #'e) (parse (syntax/loc stx es)))]
[x
(identifier? #'x)
(parse-id #'x)]

View File

@ -13,23 +13,19 @@
;; is pat a pattern representing a list?
(define (null-terminated? pat)
(cond [(Pair? pat)
(null-terminated? (Pair-d pat))]
[(GSeq? pat)
(null-terminated? (GSeq-tail pat))]
(cond [(Pair? pat) (null-terminated? (Pair-d pat))]
[(GSeq? pat) (null-terminated? (GSeq-tail pat))]
[(Null? pat) #t]
[else #f]))
;; combine a null-terminated pattern with another pattern to match afterwards
(define (append-pats p1 p2)
(cond [(Pair? p1)
(make-Pair (Pair-a p1) (append-pats (Pair-d p1) p2))]
[(GSeq? p1)
(make-GSeq (GSeq-headss p1)
(GSeq-mins p1)
(GSeq-maxs p1)
(GSeq-onces? p1)
(append-pats (GSeq-tail p1) p2))]
(cond [(Pair? p1) (make-Pair (Pair-a p1) (append-pats (Pair-d p1) p2))]
[(GSeq? p1) (make-GSeq (GSeq-headss p1)
(GSeq-mins p1)
(GSeq-maxs p1)
(GSeq-onces? p1)
(append-pats (GSeq-tail p1) p2))]
[(Null? p1) p2]
[else (error 'match "illegal input to append-pats")]))
@ -38,19 +34,20 @@
(define (parse-quasi stx cert parse/cert)
(define (pq s) (parse-quasi s cert parse/cert))
(syntax-case stx (quasiquote unquote quote unquote-splicing)
[(unquote p) (parse/cert #'p cert)]
[(unquote p) (parse/cert #'p cert)]
[((unquote-splicing p) . rest)
(let ([pat (parse/cert #'p cert)]
[rpat (pq #'rest)])
(if (null-terminated? pat)
(append-pats pat rpat)
(raise-syntax-error 'match "non-list pattern inside unquote-splicing" stx #'p)))]
(append-pats pat rpat)
(raise-syntax-error 'match "non-list pattern inside unquote-splicing"
stx #'p)))]
[(p dd)
(ddk? #'dd)
(let* ([count (ddk? #'..)]
[min (if (number? count) count #f)]
[max (if (number? count) count #f)])
(make-GSeq
(make-GSeq
(parameterize ([match-...-nesting (add1 (match-...-nesting))])
(list (list (pq #'p))))
(list min)
@ -68,10 +65,9 @@
[(unquote-splicing . _) #t]
[_ #f])))
(syntax->list #'(p ...)))
(make-And (list
(make-Pred #'vector?)
(make-App #'vector->list
(pq (quasisyntax/loc stx (p ...))))))]
(make-And (list (make-Pred #'vector?)
(make-App #'vector->list
(pq (quasisyntax/loc stx (p ...))))))]
[#(p ...)
(make-Vector (map pq (syntax->list #'(p ...))))]
[bx
@ -81,4 +77,4 @@
(make-Null (make-Dummy #f))]
[v
(or (parse-literal (syntax-e #'v))
(raise-syntax-error 'match "syntax error in quasipattern" stx))]))
(raise-syntax-error 'match "syntax error in quasipattern" stx))]))

View File

@ -13,26 +13,26 @@
(provide parse/cert)
(define (ht-pat-transform p)
(define (ht-pat-transform p)
(syntax-case p ()
[(a b) #'(list a b)]
[x
(identifier? #'x)
#'x]))
[x (identifier? #'x) #'x]))
;; parse : syntax -> Pat
;; compile stx into a pattern, using the new syntax
(define (parse/cert stx cert)
(define (parse stx) (parse/cert stx cert))
(syntax-case* stx (not var struct box cons list vector ? and or quote app regexp pregexp
list-rest list-no-order hash-table quasiquote mcons list*)
(lambda (x y) (eq? (syntax-e x) (syntax-e y)))
(syntax-case* stx (not var struct box cons list vector ? and or quote app
regexp pregexp list-rest list-no-order hash-table
quasiquote mcons list*)
(lambda (x y) (eq? (syntax-e x) (syntax-e y)))
[(expander args ...)
(and (identifier? #'expander)
(match-expander? (syntax-local-value (cert #'expander) (lambda () #f))))
(match-expander-transform parse/cert cert #'expander stx match-expander-match-xform
"This expander only works with the legacy match syntax")]
(match-expander? (syntax-local-value (cert #'expander)
(lambda () #f))))
(match-expander-transform
parse/cert cert #'expander stx match-expander-match-xform
"This expander only works with the legacy match syntax")]
[(var v)
(identifier? #'v)
(make-Var #'v)]
@ -47,17 +47,27 @@
(let ([ps (map (compose make-Not parse) (syntax->list #'(p ...)))])
(make-And ps))]
[(regexp r)
(trans-match #'matchable? #'(lambda (e) (regexp-match r e)) (make-Pred #'values))]
(trans-match #'matchable?
#'(lambda (e) (regexp-match r e))
(make-Pred #'values))]
[(regexp r p)
(trans-match #'matchable? #'(lambda (e) (regexp-match r e)) (parse #'p))]
[(pregexp r)
(trans-match #'matchable? #'(lambda (e) (regexp-match (if (pregexp? r) r (pregexp r)) e)) (make-Pred #'values))]
(trans-match #'matchable?
#'(lambda (e)
(regexp-match (if (pregexp? r) r (pregexp r)) e))
(make-Pred #'values))]
[(pregexp r p)
(trans-match #'matchable? #'(lambda (e) (regexp-match (if (pregexp? r) r (pregexp r)) e)) (parse #'p))]
[(box e) (make-Box (parse #'e))]
(trans-match #'matchable?
#'(lambda (e)
(regexp-match (if (pregexp? r) r (pregexp r)) e))
(parse #'p))]
[(box e) (make-Box (parse #'e))]
[(vector es ...)
(ormap ddk? (syntax->list #'(es ...)))
(trans-match #'vector? #'vector->list (parse (syntax/loc stx (list es ...))))]
(trans-match #'vector?
#'vector->list
(parse (syntax/loc stx (list es ...))))]
[(vector es ...)
(make-Vector (map parse (syntax->list #'(es ...))))]
[(hash-table p ... dd)
@ -65,49 +75,50 @@
(trans-match
#'hash-table?
#'(lambda (e) (hash-table-map e list))
(with-syntax ([(elems ...) (map ht-pat-transform (syntax->list #'(p ...)))])
(with-syntax ([(elems ...)
(map ht-pat-transform (syntax->list #'(p ...)))])
(parse (syntax/loc stx (list-no-order elems ... dd)))))]
[(hash-table p ...)
(ormap ddk? (syntax->list #'(p ...)))
(raise-syntax-error 'match "dot dot k can only appear at the end of hash-table patterns" stx
(ormap (lambda (e) (and (ddk? e) e)) (syntax->list #'(p ...))))]
(ormap ddk? (syntax->list #'(p ...)))
(raise-syntax-error
'match "dot dot k can only appear at the end of hash-table patterns" stx
(ormap (lambda (e) (and (ddk? e) e)) (syntax->list #'(p ...))))]
[(hash-table p ...)
(trans-match
#'hash-table?
#'(lambda (e) (hash-table-map e list))
(with-syntax ([(elems ...) (map ht-pat-transform (syntax->list #'(p ...)))])
(parse (syntax/loc stx (list-no-order elems ...)))))]
(trans-match #'hash-table?
#'(lambda (e) (hash-table-map e list))
(with-syntax ([(elems ...)
(map ht-pat-transform
(syntax->list #'(p ...)))])
(parse (syntax/loc stx (list-no-order elems ...)))))]
[(hash-table . _)
(raise-syntax-error 'match "syntax error in hash-table pattern" stx)]
[(list-no-order p ... lp dd)
(ddk? #'dd)
(ddk? #'dd)
(let* ([count (ddk? #'dd)]
[min (if (number? count) count #f)]
[max (if (number? count) count #f)]
[ps (syntax->list #'(p ...))])
(make-GSeq
(cons (list (parse #'lp))
(for/list ([p ps])
(list (parse p))))
(cons min (map (lambda _ 1) ps))
(cons max (map (lambda _ 1) ps))
;; vars in lp are lists, vars elsewhere are not
(cons #f (map (lambda _ #t) ps))
(make-Null (make-Dummy #f))))]
(make-GSeq (cons (list (parse #'lp))
(for/list ([p ps]) (list (parse p))))
(cons min (map (lambda _ 1) ps))
(cons max (map (lambda _ 1) ps))
;; vars in lp are lists, vars elsewhere are not
(cons #f (map (lambda _ #t) ps))
(make-Null (make-Dummy #f))))]
[(list-no-order p ...)
(ormap ddk? (syntax->list #'(p ...)))
(raise-syntax-error 'match "dot dot k can only appear at the end of unordered match patterns" stx
(ormap (lambda (e) (and (ddk? e) e)) (syntax->list #'(p ...))))]
(raise-syntax-error
'match "dot dot k can only appear at the end of unordered match patterns"
stx
(ormap (lambda (e) (and (ddk? e) e)) (syntax->list #'(p ...))))]
[(list-no-order p ...)
(let ([ps (syntax->list #'(p ...))])
(make-GSeq
(for/list ([p ps])
(list (parse p)))
(map (lambda _ 1) ps)
(map (lambda _ 1) ps)
;; all of these patterns get bound to only one thing
(map (lambda _ #t) ps)
(make-Null (make-Dummy #f))))]
(make-GSeq (for/list ([p ps]) (list (parse p)))
(map (lambda _ 1) ps)
(map (lambda _ 1) ps)
;; all of these patterns get bound to only one thing
(map (lambda _ #t) ps)
(make-Null (make-Dummy #f))))]
[(list) (make-Null (make-Dummy stx))]
[(list ..)
(ddk? #'..)
@ -131,7 +142,8 @@
[(struct s pats)
(parse-struct stx cert parse #'s #'pats)]
[(? p q1 qs ...)
(make-And (cons (make-Pred (cert #'p)) (map parse (syntax->list #'(q1 qs ...)))))]
(make-And (cons (make-Pred (cert #'p))
(map parse (syntax->list #'(q1 qs ...)))))]
[(? p)
(make-Pred (cert #'p))]
[(app f p)
@ -149,8 +161,4 @@
(or (parse-literal (syntax-e #'v))
(raise-syntax-error 'match "syntax error in pattern" stx))]))
;(trace parse)
;; (trace parse)

View File

@ -1,7 +1,6 @@
#lang scheme/base
(require syntax/boundmap
mzlib/trace
scheme/stxparam
scheme/contract
(for-syntax scheme/base))
@ -14,10 +13,11 @@
exn:misc:match?)
(define-struct (exn:misc:match exn:fail) (value))
(define (match:error val) (raise (make-exn:misc:match (format "match: no matching clause for ~e" val)
(current-continuation-marks)
val)))
(define (match:error val)
(raise (make-exn:misc:match (format "match: no matching clause for ~e" val)
(current-continuation-marks)
val)))
(define orig-stx (make-parameter #f))
@ -31,8 +31,7 @@
(define-struct (Dummy Var) ()
#:transparent
#:property
prop:custom-write (lambda (v p w?)
(fprintf p "_")))
prop:custom-write (lambda (v p w?) (fprintf p "_")))
;; constructor patterns
(define-struct (CPat Pat) () #:transparent)
@ -84,7 +83,8 @@
;; headss : listof listof pattern
;; mins : listof option number
;; maxs : listof option number
;; onces? : listof boolean -- is this pattern being bound only once (take the car of the variables)
;; onces? : listof boolean -- is this pattern being bound only once (take the
;; car of the variables)
;; tail : pattern
(define-struct (GSeq Pat) (headss mins maxs onces? tail) #:transparent)
@ -98,14 +98,12 @@
;; vars-seen is a listof identifiers
(define-struct Row (pats rhs unmatch vars-seen) #:transparent
#:property
prop:custom-write (lambda (v p w?)
(fprintf p "(Row ~a <expr>)" (Row-pats v))))
prop:custom-write
(lambda (v p w?) (fprintf p "(Row ~a <expr>)" (Row-pats v))))
(define struct-key-ht (make-free-identifier-mapping))
(define (get-key id)
(free-identifier-mapping-get
(free-identifier-mapping-get
struct-key-ht id
(lambda ()
(let ([k (box-immutable (syntax-e id))])
@ -117,24 +115,24 @@
;; (eq? (pat-key p) (pat-key q)) if p and q match the same constructor
;; the result is #f if p is not a constructor pattern
(define (pat-key p)
(cond
[(Struct? p) (get-key (Struct-id p))]
[(Box? p) 'box]
[(Vector? p) 'vector]
[(Pair? p) 'pair]
[(MPair? p) 'mpair]
[(String? p) 'string]
[(Symbol? p) 'symbol]
[(Number? p) 'number]
[(Bytes? p) 'bytes]
[(Char? p) 'char]
[(Regexp? p) 'regexp]
[(Keyword? p) 'keyword]
[(Boolean? p) 'boolean]
[(Null? p) 'null]
[else #f]))
(cond [(Struct? p) (get-key (Struct-id p))]
[(Box? p) 'box]
[(Vector? p) 'vector]
[(Pair? p) 'pair]
[(MPair? p) 'mpair]
[(String? p) 'string]
[(Symbol? p) 'symbol]
[(Number? p) 'number]
[(Bytes? p) 'bytes]
[(Char? p) 'char]
[(Regexp? p) 'regexp]
[(Keyword? p) 'keyword]
[(Boolean? p) 'boolean]
[(Null? p) 'null]
[else #f]))
;(trace pat-key)
;; (require mzlib/trace)
;; (trace pat-key)
;; Row-first-pat : Row -> Pat
;; Row must not have empty list of pats
@ -145,29 +143,23 @@
(define p (Row-pats r))
(values (car p) (cdr p)))
;; merge : (liftof (listof id)) -> (listof id)
;; merges lists of identifiers, removing module-identifier=?
;; duplicates
;; merges lists of identifiers, removing module-identifier=? duplicates
(define (merge l)
(cond
[(null? l) null]
[(null? (cdr l)) (car l)]
[else (let ([m (make-module-identifier-mapping)])
(for-each (lambda (ids)
(for-each (lambda (id)
(module-identifier-mapping-put! m id #t))
ids))
l)
(module-identifier-mapping-map m (lambda (k v) k)))]))
(cond [(null? l) null]
[(null? (cdr l)) (car l)]
[else (let ([m (make-module-identifier-mapping)])
(for* ([ids l] [id ids])
(module-identifier-mapping-put! m id #t))
(module-identifier-mapping-map m (lambda (k v) k)))]))
;; bound-vars : Pat -> listof identifiers
(define (bound-vars p)
(cond
[(Dummy? p) null]
[(Pred? p) null]
[(Var? p) (let* ([v (Var-v p)]
[v* (free-identifier-mapping-get (current-renaming) v (lambda () v))])
(list v*))]
[(Var? p)
(let ([v (Var-v p)])
(list (free-identifier-mapping-get (current-renaming) v (lambda () v))))]
[(Or? p)
(bound-vars (car (Or-ps p)))]
[(Box? p)
@ -178,11 +170,10 @@
[(MPair? p)
(merge (list (bound-vars (MPair-a p)) (bound-vars (MPair-d p))))]
[(GSeq? p)
(merge (cons
(bound-vars (GSeq-tail p))
(for/list ([pats (GSeq-headss p)])
(merge (for/list ([pat pats])
(bound-vars pat))))))]
(merge (cons (bound-vars (GSeq-tail p))
(for/list ([pats (GSeq-headss p)])
(merge (for/list ([pat pats])
(bound-vars pat))))))]
[(Vector? p)
(merge (map bound-vars (Vector-ps p)))]
[(Struct? p)
@ -200,15 +191,15 @@
(define-syntax-parameter fail
(lambda (stx)
(raise-syntax-error #f
"used out of context: not in match pattern"
stx)))
(raise-syntax-error
#f "used out of context: not in match pattern" stx)))
(define current-renaming (make-parameter (make-free-identifier-mapping)))
(define (copy-mapping ht)
(define new-ht (make-free-identifier-mapping))
(free-identifier-mapping-for-each ht (lambda (k v) (free-identifier-mapping-put! new-ht k v)))
(free-identifier-mapping-for-each
ht (lambda (k v) (free-identifier-mapping-put! new-ht k v)))
new-ht)
#|
@ -230,9 +221,10 @@
(provide/contract (struct Row ([pats (listof Pat?)]
[rhs syntax?]
[unmatch (or/c identifier? false/c)]
[vars-seen (listof (cons/c identifier? identifier?))])))
[vars-seen (listof (cons/c identifier?
identifier?))])))
(define-struct match-expander (match-xform legacy-xform macro-xform certifier)
#:property prop:procedure (struct-field-index macro-xform))
(provide (struct-out match-expander))
(provide (struct-out match-expander))

View File

@ -6,80 +6,76 @@
;; split-rows : Listof[Row] -> Listof[Listof[Row]]
;; takes a matrix, and returns a list of matricies
;; each returned matrix does not require the mixture rule to do compilation of the first column.
;; each returned matrix does not require the mixture rule to do compilation of
;; the first column.
(define (split-rows rows [acc null])
(define (loop/var matched-rows prev-mats rows)
(cond [(null? rows)
(reverse (cons (reverse matched-rows) prev-mats))]
[else
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond
[(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(Var? p)
(loop/var (cons r matched-rows) prev-mats rs)]
[else
(split-rows rows (cons (reverse matched-rows) prev-mats))]))]))
(if (null? rows)
(reverse (cons (reverse matched-rows) prev-mats))
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond [(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(Var? p)
(loop/var (cons r matched-rows) prev-mats rs)]
[else
(split-rows rows (cons (reverse matched-rows) prev-mats))]))))
(define (loop/con matched-rows prev-mats struct-key rows)
(cond [(null? rows)
(reverse (cons (reverse matched-rows) prev-mats))]
[else
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond
[(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(and (Struct? p) struct-key (eq? (pat-key p) struct-key))
;(printf "struct-keys were equal: ~a~n" struct-key)
(loop/con (cons r matched-rows) prev-mats struct-key rs)]
[(and (Struct? p) (not struct-key))
;(printf "no struct-key so far: ~a~n" struct-key)
(loop/con (cons r matched-rows) prev-mats (pat-key p) rs)]
[(and (CPat? p) (not (Struct? p)))
;(printf "wasn't a struct: ~a~n" p)
(loop/con (cons r matched-rows) prev-mats struct-key rs)]
[else (split-rows rows (cons (reverse matched-rows) prev-mats))]))]))
(if (null? rows)
(reverse (cons (reverse matched-rows) prev-mats))
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond [(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(and (Struct? p) struct-key (eq? (pat-key p) struct-key))
;; (printf "struct-keys were equal: ~a~n" struct-key)
(loop/con (cons r matched-rows) prev-mats struct-key rs)]
[(and (Struct? p) (not struct-key))
;; (printf "no struct-key so far: ~a~n" struct-key)
(loop/con (cons r matched-rows) prev-mats (pat-key p) rs)]
[(and (CPat? p) (not (Struct? p)))
;; (printf "wasn't a struct: ~a~n" p)
(loop/con (cons r matched-rows) prev-mats struct-key rs)]
[else (split-rows rows (cons (reverse matched-rows)
prev-mats))]))))
(define (loop/exact matched-rows prev-mats rows)
(cond [(null? rows)
(reverse (cons (reverse matched-rows) prev-mats))]
[else
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond
[(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(Exact? p)
(loop/exact (cons r matched-rows) prev-mats rs)]
[else (split-rows rows (cons (reverse matched-rows) prev-mats))]))]))
(cond
[(null? rows) (reverse acc)]
[else
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond
[(Row-unmatch r)
(split-rows rs (cons (list r) acc))]
[(Var? p)
(loop/var (list r) acc rs)]
[(Exact? p)
(loop/exact (list r) acc rs)]
[(CPat? p)
(if (Struct? p)
(begin
;(printf "found a struct: ~a~n" (pat-key r))
(loop/con (list r) acc (pat-key p) rs))
(loop/con (list r) acc #f rs))]
[else (split-rows rs (cons (list r) acc))]))]))
(if (null? rows)
(reverse (cons (reverse matched-rows) prev-mats))
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond
[(Row-unmatch r)
(split-rows rows (cons (reverse matched-rows) prev-mats))]
[(Exact? p)
(loop/exact (cons r matched-rows) prev-mats rs)]
[else (split-rows rows (cons (reverse matched-rows) prev-mats))]))))
(if (null? rows)
(reverse acc)
(let* ([r (car rows)]
[p (Row-first-pat r)]
[rs (cdr rows)])
(cond [(Row-unmatch r)
(split-rows rs (cons (list r) acc))]
[(Var? p)
(loop/var (list r) acc rs)]
[(Exact? p)
(loop/exact (list r) acc rs)]
[(CPat? p)
(if (Struct? p)
(begin
;; (printf "found a struct: ~a~n" (pat-key r))
(loop/con (list r) acc (pat-key p) rs))
(loop/con (list r) acc #f rs))]
[else (split-rows rs (cons (list r) acc))]))))
(require mzlib/trace)
;(trace split-rows)
;; (require mzlib/trace)
;; (trace split-rows)
;; EXAMPLES:
#|
(define mat1 (list r1 r2 r3))
(define mat2 (list r1 r3 r2 r1))|#
(define mat2 (list r1 r3 r2 r1))
|#