original commit: 895f54cc9e7fcca636efb47f2c29fd9db2b9b9bb
This commit is contained in:
Robby Findler 2003-02-15 02:55:11 +00:00
parent 8828d22d25
commit 7559137473

View File

@ -114,7 +114,8 @@
match-letrec
match-define)
(require-for-syntax (lib "stx.ss" "syntax"))
(require-for-syntax (lib "stx.ss" "syntax")
(lib "etc.ss"))
(define-struct (exn:misc:match exn:misc) (value))
@ -190,15 +191,6 @@
((number? x) (number->string x))
(else x)))
l)))))
;; we definitely want inturned variables here
(get-exp-var
(let ((count 0))
(lambda ()
(set! count (add1 count))
(string->symbol
(string-append "exp"
(number->string count))))))
;; struct-pred-accessors - given a syntax object that is the
;; name of a structure this function returns two values:
;; 1) the predicate function for that structure (i.e. posn?)
@ -215,12 +207,12 @@
(else (cons (car ac-list)
(RC (cdr ac-list))))))))
(reverse (RC l))))))
(lambda (struct-name)
(let* ((info-on-struct (syntax-local-value struct-name))
(lambda (struct-name failure-thunk)
(let* ((info-on-struct (syntax-local-value struct-name failure-thunk))
(accessors (handle-acc-list
(list-ref info-on-struct accessors-index)))
(pred (list-ref info-on-struct pred-index)))
(values pred accessors)))))
(values pred accessors)))))
;; unreachable - takes a list of unreached clauses and the original
;; match expression and prints a warning for each of the unreached
@ -238,7 +230,16 @@
x
(syntax-object->datum match-expr)))
plist)))
;; it is important that we start
;; the count over for each new row so
;; that we can eliminate duplicate tests
(get-exp-var
(let ((count 0))
(lambda ()
(set! count (add1 count))
(string->symbol
(string-append "exp"
(number->string count))))))
;; gen-match and its helper function gen are the workhorses
;; of the library. It compiles a series of if expressions
;; for a given pattern.
@ -263,19 +264,19 @@
;; and it should return a syntax object.
(gen-match
(lambda (exp tsf patlist stx . success-func)
(opt-lambda (exp tsf patlist stx [success-func #f])
(let* ((unrb (box #f))
(compiled-match
(quasisyntax/loc stx
(let ((match-failure
(lambda ()
(match:error #,exp (quote #,stx)))))
#,(if (null? success-func)
(gen exp tsf patlist
stx unrb (syntax (match-failure)))
(gen exp tsf patlist
stx unrb (syntax (match-failure))
(car success-func)))))))
#,(gen exp tsf patlist
stx
unrb
'()
(syntax (match-failure))
success-func)))))
(if (unbox unrb)
(unreachable (unbox unrb) stx))
compiled-match)))
@ -296,7 +297,7 @@
;; bottom of the recursion tree. For more information on this
;; function see the _next_ function.
(gen
(lambda (exp tsf patlist stx unreach-box failure-func . success-func)
(opt-lambda (exp tsf patlist stx unreach-box lbsf failure-func [success-func #f])
(if (stx-null? patlist)
failure-func ;(quasisyntax/loc stx (match:error #,exp (quote #,stx)))
(with-syntax (((clause1 clauselist ...) patlist))
@ -309,20 +310,26 @@
((pat body ...)
(values (syntax pat)
(syntax (body ...)) #f)))))
(let* ((fail (lambda (sf bv)
(let* ((rest-of-clauses (syntax (clauselist ...)))
(fail (lambda (sf bv lbsf)
;; i don't pass the success-func forward
;; because it is only used for match-define
;; and match-letrec which only have one
;; clause
(gen exp
sf
(syntax (clauselist ...))
rest-of-clauses
stx
unreach-box
lbsf
failure-func)))
(success
(begin (let ((tail (syntax-object->datum
(syntax (clauselist ...)))))
(set-box! unreach-box
(if (null? tail) #f tail)))
(if (null? success-func)
(lambda (sf bv)
(if (not success-func)
(lambda (sf bv lbsf)
(if fail-sym
(quasisyntax/loc stx (call-with-current-continuation
(lambda (fail-cont)
@ -331,7 +338,7 @@
(lambda ()
(fail-cont
; it seems like fail is called twice in this situation
#,(fail sf bv)))))
#,(fail sf bv lbsf)))))
((lambda (#,fail-sym
#,@(map car bv))
#,@body)
@ -339,7 +346,7 @@
#,@(map cdr bv))))))
(quasisyntax/loc stx ((lambda #,(map car bv)
#,@body) #,@(map cdr bv)))))
(car success-func)))))
success-func))))
;; next is the major internal function of gen
;; This is implemented in what Wright terms as mock-continuation-passing
;; style. The functions that create the syntax for a match success and failure
@ -353,22 +360,49 @@
;; look at how proper and improper lists are handled.
;;
(let next ((p pat)
(e exp)
(e exp) ;; this is the expression that has been abreviated
;; by reusing pairs
(ae exp) ;; this is the actual expression
(let-bound lbsf) ;; alist of let-bindings for pair reuse
(sf tsf)
(bv '())
(kf fail)
(ks success))
;; this is a hacky way to get variables that are to be bound for a pattern
(letrec ((getbindings
;(write let-bound) (newline)
;(write e) (newline) (write ae) (newline)
(letrec ((call-next-and-bind
(lambda (pat e ae let-bound sf bv kf ks)
;; first check to se if it is already bound by a let
;; if not continue on with the bound name
;; otherwise bind this one
(let ((binding-pair (assoc (syntax-object->datum ae) let-bound)))
(if binding-pair
(next pat (cdr binding-pair) ae let-bound sf bv kf ks)
(let ((exp-var (get-exp-var)))
#`(let ((#,exp-var #,e))
#,(next pat
#`#,exp-var
ae
(cons (cons (syntax-object->datum ae)
#`#,exp-var)
let-bound)
sf
bv
kf
ks)))))))
(getbindings
(lambda (pat-syntax)
(let/cc out
(next
pat-syntax
(quote-syntax dummy)
(quote-syntax dummy)
let-bound
'()
'()
(lambda (sf bv) '(dummy-symbol))
(lambda (sf bv) (out (map car bv)))))))
(lambda (sf bv lbsf) '(dummy-symbol))
(lambda (sf bv lbsf) (out (map car bv)))))))
(parse-quasi (lambda (phrase)
(syntax-case phrase (unquote unquote-splicing)
(p
@ -380,6 +414,12 @@
(number? pat)))
(syntax p))
(p
;; although it is not in the grammer for quasi patterns
;; it seems important to not allow unquote splicing to be
;; a symbol in this case `,@(a b c). In this unquote-splicing
;; is treated as a symbol and quoted to be matched.
;; this is probably not what the programmer intends so
;; it may be better to throw a syntax error
(identifier? (syntax p))
(syntax/loc phrase 'p))
(,p (syntax p))
@ -402,43 +442,62 @@
(box? (syntax-object->datum (syntax p)))
#`#,(box (parse-quasi (unbox (syntax-e (syntax p))))))
(p (match:syntax-err
(syntax-object->datum (syntax p)
"syntax error in quasi-pattern")))))))
(syntax-object->datum (syntax p))
"syntax error in quasi-pattern"))))))
(syntax-case* p (_ quote quasiquote ? = and or not $ set!
get! ... ___ unquote unquote-splicing) stx-equal?
(_ (ks sf bv))
(_ (ks sf bv let-bound))
(pt
(and (identifier? (syntax pt))
(pattern-var? (syntax-object->datum (syntax pt)))
(not (stx-dot-dot-k? (syntax pt))))
(ks sf (cons (cons (syntax pt) e) bv)))
(() (emit (quasisyntax/loc p (null? #,e)) sf bv kf ks))
(ks sf (cons (cons (syntax pt) e) bv) let-bound))
(() (emit (quasisyntax/loc p (null? #,e))
#`(null? #,ae)
let-bound
sf
bv
kf
ks))
(pt
;; could convert the syntax once
(or (stx-? string? (syntax pt))
(stx-? boolean? (syntax pt))
(stx-? char? (syntax pt))
(stx-? number? (syntax pt)))
(emit (quasisyntax/loc p (equal? #,e pt)) sf bv kf ks))
(emit (quasisyntax/loc p (equal? #,e pt))
#`(equal? #,ae pt)
let-bound
sf bv kf ks))
((quote _)
(emit (quasisyntax/loc p (equal? #,e #,p)) sf bv kf ks))
(emit (quasisyntax/loc p (equal? #,e #,p))
#`(equal? #,ae #,p)
let-bound
sf bv kf ks))
(`quasi-pat
(next (parse-quasi (syntax quasi-pat)) e sf bv kf ks))
(next (parse-quasi (syntax quasi-pat)) e ae let-bound sf bv kf ks))
('item
(emit (quasisyntax/loc p (equal? #,e #,p)) sf bv kf ks))
(emit (quasisyntax/loc p (equal? #,e #,p))
#`(equal? #,ae #,p)
let-bound
sf bv kf ks))
;('(items ...)
;(emit (quasisyntax/loc p (equal? #,e #,p)) sf bv kf ks))
((? pred pat1 pats ...)
(next (syntax (and (? pred) pat1 pats ...))
e
ae
let-bound
sf
bv
kf
ks))
;; could we check to see if a predicate is a procedure here?
((? pred)
(emit (quasisyntax/loc p (pred #,e)) sf bv kf ks))
(emit (quasisyntax/loc p (pred #,e))
#`(pred #,ae)
let-bound
sf bv kf ks))
;; syntax checking
((? pred ...)
(match:syntax-err
@ -447,7 +506,11 @@
"a predicate pattern must have a predicate following the ?"
"syntax error in predicate pattern")))
((= op pat)
(next (syntax pat)(quasisyntax/loc p (op #,e)) sf bv kf ks))
(call-next-and-bind (syntax pat)
(quasisyntax/loc p (op #,e))
#`(op #,ae)
let-bound
sf bv kf ks))
;; syntax checking
((= op ...)
(match:syntax-err
@ -459,41 +522,52 @@
(let loop
((p (syntax (pats ...)))
(seensofar sf)
(boundvars bv))
(boundvars bv)
(let-bound let-bound))
(syntax-case p ()
(() (ks sf boundvars))
(() (ks sf boundvars let-bound))
((pat1 pats ...)
(next (syntax pat1)
e
ae
let-bound
seensofar
boundvars ;; keep collecting vars
kf
(lambda (sf bv) ;; if it succeeds check nest one
(lambda (sf bv lbsf) ;; if it succeeds check nest one
(loop (syntax (pats ...))
sf bv)))))))
sf bv lbsf)))))))
((or pats ...)
(let loop
((p (syntax (pats ...)))
(seensofar sf)
(boundvars bv))
(boundvars bv)
(let-bound let-bound))
(syntax-case p ()
(() (kf sf boundvars))
(() (kf sf boundvars let-bound))
((pat1 pats ...)
(next (syntax pat1)
e
ae
let-bound
seensofar
bv ;; get rid of collected vars and start over
(lambda (sf bv) ; if it fails check next one
(lambda (sf bv lbsf) ; if it fails check next one
(loop (syntax (pats ...))
sf bv))
sf bv lbsf))
ks)))))
((not pat)
(next (syntax pat) e sf bv ks kf)) ;; swap success and fail
(next (syntax pat) e ae let-bound sf bv ks kf)) ;; swap success and fail
;; could try to catch syntax local value error and rethrow syntax error
(($ struct-name fields ...)
(let ((num-of-fields (stx-length (syntax (fields ...)))))
(let-values (((pred accessors)
(struct-pred-accessors (syntax struct-name))))
(struct-pred-accessors
(syntax struct-name)
(lambda ()
(match:syntax-err
(syntax struct-name)
"not a defined structure")))))
(let ((dif (- (length accessors) num-of-fields)))
(if (not (zero? dif))
(match:syntax-err
@ -502,16 +576,20 @@
(if (> dif 0) "not enough " "too many ")
"fields for structure in pattern"))
(emit (quasisyntax/loc stx (#,pred #,e))
#`(#,pred #,ae)
let-bound
sf
bv
kf
(let rloop ((n 0))
(lambda (sf bv)
(lambda (sf bv lbsf)
(if (= n num-of-fields)
(ks sf bv)
(next
(ks sf bv lbsf)
(call-next-and-bind
(list-ref (syntax->list (syntax (fields ...))) n)
(quasisyntax/loc stx (#,(list-ref accessors n) #,e))
#`(#,(list-ref accessors n) #,ae)
let-bound
sf
bv
kf
@ -528,7 +606,7 @@
"syntax error in structure pattern")))
((set! ident)
(identifier? (syntax ident))
(ks sf (cons (cons (syntax ident) (setter e p)) bv)))
(ks sf (cons (cons (syntax ident) (setter ae p)) bv) let-bound))
;; syntax checking
((set! ident ...)
(let ((x (length (syntax-e (syntax (ident ...))))))
@ -541,7 +619,7 @@
"be one identifier after set! in pattern")))))
((get! ident)
(identifier? (syntax ident))
(ks sf (cons (cons (syntax ident) (getter e p)) bv)))
(ks sf (cons (cons (syntax ident) (getter ae p)) bv) let-bound))
((get! ident ...)
(let ((x (length (syntax-e (syntax (ident ...))))))
(match:syntax-err
@ -558,25 +636,29 @@
(stx-dot-dot-k? (syntax dot-dot-k)))
(emit
(quasisyntax/loc stx (list? #,e))
#`(list? #,ae)
let-bound
sf
bv
kf
(lambda (sf bv)
(lambda (sf bv lbsf)
(let* ((k (stx-dot-dot-k? (syntax dot-dot-k)))
(ksucc (lambda (sf bv)
(ksucc (lambda (sf bv lbsf)
(let ((bound (getbindings (syntax pat))))
(syntax-case (syntax pat) (_)
(_ (ks sf bv))
(_ (ks sf bv lbsf))
(the-pat
(null? bound)
(with-syntax ((exp-sym (syntax exp-sym)))
(let* ((ptst (next
(syntax pat)
(syntax exp-sym)
(syntax exp-sym)
lbsf
sf
bv
(lambda (sf bv) (syntax #f))
(lambda (sf bv) (syntax #t))))
(lambda (sf bv lbsf) (syntax #f))
(lambda (sf bv lbsf) (syntax #t))))
(tst (syntax-case ptst ()
((pred eta)
(and (identifier?
@ -590,13 +672,13 @@
(quasisyntax/loc stx (lambda (exp-sym)
#,ptst))))))
(assm (quasisyntax/loc stx (andmap #,tst #,e))
(kf sf bv)
(ks sf bv)))))
(kf sf bv lbsf)
(ks sf bv lbsf)))))
(id
(and (identifier? (syntax id))
(stx-equal? (syntax id)
(car bound)))
(next (syntax id) e sf bv kf ks))
(next (syntax id) e ae let-bound sf bv kf ks))
(the-pat
(let ((binding-list-names
(map (lambda (x)
@ -619,15 +701,18 @@
(lambda (x)
(quasisyntax/loc stx (reverse #,x)))
binding-list-names))
bv))
bv)
lbsf)
#,(next (syntax the-pat)
(syntax (car exp))
(syntax (car exp))
lbsf
sf
bv ;; we always start
;; over with the old
;; bindings
kf
(lambda (sf bv)
(lambda (sf bv lbsf)
(quasisyntax/loc stx (loop
(cdr exp)
#,@(map
@ -642,9 +727,14 @@
#,bindings-var)))
bound binding-list-names)))))))))))))))
(case k
((0) (ksucc sf bv))
((1) (emit (quasisyntax/loc stx (pair? #,e)) sf bv kf ksucc))
((0) (ksucc sf bv let-bound))
((1) (emit (quasisyntax/loc stx (pair? #,e))
#`(pair? #,ae)
lbsf
sf bv kf ksucc))
(else (emit (quasisyntax/loc stx (>= (length #,e) #,k))
#`(>= (length #,ae) #,k)
lbsf
sf bv kf ksucc)))))))
;; handle proper and improper lists
((car-pat . cdr-pat) ;pattern ;(pat1 pats ...)
@ -653,24 +743,29 @@
(stx-dot-dot-k? (syntax car-pat))))
(emit
(quasisyntax/loc stx (pair? #,e))
#`(pair? #,ae)
let-bound
sf
bv
kf
(lambda (sf bv)
(next (syntax car-pat)
(add-a e)
(lambda (sf bv lbsf)
(call-next-and-bind (syntax car-pat)
#`(car #,e) ;(add-a e)
(add-a ae)
lbsf
sf
bv
kf
(lambda (sf bv)
(let ((cdr-exp-var (get-exp-var)))
#`(let ((#,cdr-exp-var (cdr #,e)))
#,(next (syntax cdr-pat)
#`#,cdr-exp-var
sf
bv
kf
ks))))))))
(lambda (sf bv lbsf)
(call-next-and-bind
(syntax cdr-pat)
#`(cdr #,e)
(add-d ae)
lbsf
sf
bv
kf
ks))))))
(pt
(and (vector? (syntax-e (syntax pt)))
(let* ((temp (syntax-e (syntax pt)))
@ -686,26 +781,31 @@
;; 'pat' in pat ...
(bound (getbindings (vector-ref vec-stx vlen))))
(emit (quasisyntax/loc stx (vector? #,e))
#`(vector? #,ae)
let-bound
sf
bv
kf
(lambda (sf bv)
(lambda (sf bv lbsf)
(assm (quasisyntax/loc stx (>= (vector-length #,e) #,minlen))
(kf sf bv)
(kf sf bv lbsf)
((let vloop ((n 0))
(lambda (sf bv)
(lambda (sf bv lbsf)
(cond
((not (= n vlen))
(next (vector-ref vec-stx n)
(quasisyntax/loc stx (vector-ref #,e #,n))
sf
bv
kf
(vloop (+ 1 n))))
(call-next-and-bind
(vector-ref vec-stx n)
(quasisyntax/loc stx (vector-ref #,e #,n))
#`(vector-ref #,ae #,n)
lbsf
sf
bv
kf
(vloop (+ 1 n))))
((eq? (syntax-object->datum
(vector-ref vec-stx vlen))
'_)
(ks sf bv))
(ks sf bv lbsf))
(else
(let* ((binding-list-names
(map (lambda (x)
@ -720,58 +820,76 @@
#,@(map (lambda (x) (quasisyntax/loc stx (#,x '())))
binding-list-names))
(if (> #,vlen index)
#,(ks sf (append (map cons bound
#,(ks sf
(append (map cons bound
binding-list-names)
bv))
#,(next (vector-ref vec-stx n)
(quasisyntax/loc stx (vector-ref #,e index))
sf
bv ;; we alway start over
;; with the old bindings
kf
(lambda (sf bv)
(quasisyntax/loc stx (vloop
(- index 1)
#,@(map
(lambda (b-var
bv)
lbsf)
#,(call-next-and-bind
(vector-ref vec-stx n)
(quasisyntax/loc stx (vector-ref #,e index))
#`(vector-ref #,ae index)
lbsf
sf
bv ;; we alway start over
;; with the old bindings
kf
(lambda (sf bv lbsf)
(quasisyntax/loc
stx (vloop
(- index 1)
#,@(map
(lambda (b-var
bindings-var)
(quasisyntax/loc stx (cons
#,(cdr
(assq
b-var
bv))
#,bindings-var)))
bound
binding-list-names)))))))))))))
(quasisyntax/loc stx (cons
#,(cdr
(assq
b-var
bv))
#,bindings-var)))
bound
binding-list-names)))))))))))))
sf
bv))))))
bv
lbsf))))))
(pt
(stx-? vector? (syntax pt))
(let ((vlen (stx-? vector-length (syntax pt))))
(emit
(quasisyntax/loc stx (vector? #,e))
#`(vector? #,ae)
let-bound
sf bv kf
(lambda (sf bv)
(lambda (sf bv lbsf)
(emit (quasisyntax/loc stx (equal? (vector-length #,e) #,vlen))
#`(equal? (vector-length #,ae) #,vlen)
lbsf
sf bv kf
(let vloop ((n 0))
(lambda (sf bv)
(lambda (sf bv lbsf)
(if (= n vlen)
(ks sf bv)
(next (vector-ref (syntax-e (syntax pt)) n)
(quasisyntax/loc stx (vector-ref #,e #,n))
sf
bv
kf
(vloop (+ 1 n)))))))))))
(ks sf bv lbsf)
(call-next-and-bind
(vector-ref (syntax-e (syntax pt)) n)
(quasisyntax/loc stx (vector-ref #,e #,n))
#`(vector-ref #,ae #,n)
lbsf
sf
bv
kf
(vloop (+ 1 n)))))))))))
(pt
(stx-? box? (syntax pt))
(emit
(quasisyntax/loc stx (box? #,e))
#`(box? #,ae)
lbsf
sf bv kf
(lambda (sf bv)
(next (unbox (syntax-e (syntax pt)))
(lambda (sf bv lbsf)
(call-next-and-bind (unbox (syntax-e (syntax pt)))
(quasisyntax/loc stx (unbox #,e))
#`(unbox #,ae)
lbsf
sf
bv
kf
@ -789,11 +907,11 @@
;; emit adds implied truths to the test seen so far list so that
;; these truths can be checked against later.
(emit
(lambda (tst sf bv kf ks)
(let ((test (syntax-object->datum tst)))
(lambda (tst act-test lbsf sf bv kf ks)
(let ((test (syntax-object->datum act-test)))
(cond
((in test sf) (ks sf bv))
((in `(not ,test) sf) (kf sf bv))
((in test sf) (ks sf bv lbsf))
((in `(not ,test) sf) (kf sf bv lbsf))
(else
(let* ((pred (car test))
(exp (cadr test))
@ -816,8 +934,8 @@
(if (equal? pred 'list?)
(list `(not (null? ,exp)))
'()))
(s (ks (cons test (append implied sf)) bv))
(k (kf (cons `(not ,test) (append not-imp sf)) bv)))
(s (ks (cons test (append implied sf)) bv lbsf))
(k (kf (cons `(not ,test) (append not-imp sf)) bv lbsf)))
(assm tst k s)))))))
;; assm - this function is responsible for constructing the actual
@ -1184,9 +1302,9 @@
(let* ((**match-bound-vars** '())
(compiled-match (gen-match (syntax the-exp);(syntax (list exp ...))
'()
(list (syntax ((pat ...) never-used)))
(syntax (((pat ...) never-used)))
stx
(lambda (sf bv)
(lambda (sf bv lbsf)
(set! **match-bound-vars** bv)
(quasisyntax/loc stx (begin
#,@(map (lambda (x)
@ -1210,9 +1328,9 @@
(compiled-match
(gen-match (syntax the-exp)
'()
(list (syntax/loc (syntax pat) (pat never-used)))
(syntax/loc (syntax pat) ((pat never-used)))
stx
(lambda (sf bv)
(lambda (sf bv lbsf)
(set! **match-bound-vars** bv)
(quasisyntax/loc stx (begin
#,@(map (lambda (x)
@ -1235,3 +1353,4 @@
match-define-mac)))
)
;end