282 lines
11 KiB
Scheme
282 lines
11 KiB
Scheme
;;; Copyright (c) 2000-2015 Dipanwita Sarkar, Andrew W. Keep, R. Kent Dybvig, Oscar Waddell
|
|
;;; See the accompanying file Copyright for details
|
|
|
|
;;; AWK - TODO - Once the meta-parser can handle language passes that match
|
|
;;; a single variable.
|
|
;;; FIXME - For Ikarus, I needed to use "dots" instead of the ".."
|
|
;;; because Ikarus sees .. as a syntax error, even when it is
|
|
;;; exported as an auxiliary keyword.
|
|
|
|
;;; Time-stamp: <2000-01-10 12:29:38 kemillik>
|
|
;;; (time-stamp generated by emacs: Type M-x time-stamp anywhere to update)
|
|
|
|
;;; syncase is a pattern matcher where patterns are quoted or
|
|
;;; quasiquoted expressions, or symbols. Unquoted symbols denote
|
|
;;; pattern variables. All quoted things must match precisely.
|
|
;;; Also, there is a symbol ".." that may be used to allow repetitions
|
|
;;; of the preceeding pattern. Any pattern variables within are bound
|
|
;;; to a list of matches. ".." may be nested.
|
|
;;; Below is the canonical example of "let"
|
|
|
|
;;; [`(let ([,var ,rhs] ..) ,body0 ,body1 ..)
|
|
;;; (guard (for-all symbol? var) (no-duplicates? var))
|
|
;;; `((lambda ,var ,body0 ,@body1) ,@rhs)]
|
|
|
|
;;; For the pattern to match, the optional guard requires its
|
|
;;; arguments to be true. The guard also uses the pattern
|
|
;;; variables.
|
|
|
|
;;; We have added three obvious new forms: synlambda, synlet, and
|
|
;;; synlet*. Finally, we have added a very useful operation,
|
|
;;; make-double-collector-over-list, whose description follows from the
|
|
;;; very simple code below.
|
|
;;; Here are some descriptive examples of each of the new special forms.
|
|
|
|
;;;> (define foo
|
|
;;; (synlambda `((if ,exp0 ,exp1) ,env)
|
|
;;; (guard (number? exp1))
|
|
;;; `(,env (if ,exp0 ,exp1 0))))
|
|
;;;> (foo '(if 1 2) 'anenv)
|
|
;;;(anenv (if 1 2 0))
|
|
|
|
;;;> (synlet ([`(if ,exp0 ,exp1)
|
|
;;; (guard (number? exp0))
|
|
;;; '(if 0 1)])
|
|
;;; `(if ,exp1, exp0))
|
|
;;;(if 1 0)
|
|
|
|
;;;> (synlet ([`(if ,x ,y ,z) '(if 1 2 3)]
|
|
;;; [`(if ,a then ,b else ,c) '(if 1 then 2 else 3)]
|
|
;;; [`(when ,u ,w) (guard (number? u) (number? w) (= u w))
|
|
;;; '(when 1 1)])
|
|
;;; (list x y z a b c a b))
|
|
;;; (1 2 3 1 2 3 1 2)
|
|
|
|
;;;> (synlet* ([`(if ,exp0 ,exp1) (guard (number? exp0)) '(if 0 1)]
|
|
;;; [`(if ,x ,y ,exp2) `(if ,exp0 ,exp1 5)])
|
|
;;; `(if ,exp0 ,y ,exp2))
|
|
;;;(if 0 1 5)
|
|
|
|
(library (tests synforms)
|
|
(export syncase)
|
|
(import (rnrs))
|
|
|
|
(define-syntax syncase
|
|
(syntax-rules ()
|
|
[(_ Exp (Clause ...) ...)
|
|
(let ([x Exp])
|
|
(call/cc
|
|
(lambda (succeed)
|
|
(pm:c start x succeed Clause ...)
|
|
...
|
|
(error 'syncase "No match for ~s" x))))]))
|
|
|
|
(define-syntax pm:c
|
|
(syntax-rules (guard start finish)
|
|
[(pm:c start V Succ Pattern (guard Exp ...) Body0 Body ...)
|
|
(pm:parse start Pattern
|
|
(pm:c finish V
|
|
(when (and Exp ...)
|
|
(Succ (begin Body0 Body ...)))))]
|
|
[(pm:c finish V Body Pattern UsedFormals)
|
|
(pm:find-dup UsedFormals
|
|
(cont (Dup)
|
|
(pm:error "Duplicate patvar ~s in pattern ~s" Dup Pattern))
|
|
(cont () (pm V Pattern Body)))]
|
|
[(_ start V Succ Pattern Body0 Body ...)
|
|
(pm:c start V Succ Pattern (guard) Body0 Body ...)]
|
|
[(_ start V Succ Pattern)
|
|
(pm:error "Missing body for pattern ~s" Pattern)]))
|
|
|
|
(define-syntax pm:parse ;; returns parsed thing + used formals
|
|
(syntax-rules (dots quasiquote quote unquote start)
|
|
[(pm:parse start () K) (pm:ak K (null) ())]
|
|
[(pm:parse start (unquote X) K) (pm:ak K (formal X) (X))]
|
|
[(pm:parse start (A . D) K) (pm:parseqq start (A . D) K)]
|
|
[(pm:parse start X K) (pm:ak K (keyword X) ())]))
|
|
|
|
(define-syntax pm:parseqq;; returns parsed thing + used formals
|
|
(lambda (x)
|
|
(syntax-case x (unquote start dothead dottail dottemps pairhead pairtail)
|
|
[(pm:parseqq start (unquote ()) K) #'(pm:error "Bad variable: ~s" ())]
|
|
[(pm:parseqq start (unquote (quasiquote X)) K) #'(pm:parseqq start X K)]
|
|
[(pm:parseqq start (unquote (X . Y)) K)
|
|
#'(pm:error "Bad variable: ~s" (X . Y))]
|
|
[(pm:parseqq start (unquote #(X ...)) K)
|
|
#'(pm:error "Bad variable: ~s" #(X ...))]
|
|
[(pm:parseqq start (unquote X) K) #'(pm:ak K (formal X) (X))]
|
|
[(pm:parseqq start (X dots . Y) K)
|
|
(eq? (syntax->datum #'dots) '...)
|
|
#'(pm:parseqq start X (pm:parseqq dothead Y K))]
|
|
[(pm:parseqq dothead Y K Xpat Xformals)
|
|
#'(pm:parseqq^ start Y () ()
|
|
(pm:parseqq dottail Xpat Xformals K))]
|
|
[(pm:parseqq dottail Xpat Xformals K Yrevpat Yformals)
|
|
#'(pm:gen-temps Xformals ()
|
|
(pm:parseqq dottemps Xpat Yrevpat Xformals Yformals K))]
|
|
[(pm:parseqq dottemps Xpat Yrevpat (Xformal ...) (Yformal ...) K Xtemps)
|
|
#'(pm:ak K (dots (Xformal ...) Xtemps Xpat Yrevpat)
|
|
(Xformal ... Yformal ...))]
|
|
[(pm:parseqq start (X . Y) K)
|
|
#'(pm:parseqq start X (pm:parseqq pairhead Y K))]
|
|
[(pm:parseqq pairhead Y K Xpat Xformals)
|
|
#'(pm:parseqq start Y (pm:parseqq pairtail Xpat Xformals K))]
|
|
[(pm:parseqq pairtail Xpat (Xformal ...) K Ypat (Yformal ...))
|
|
#'(pm:ak K (pair Xpat Ypat) (Xformal ... Yformal ...))]
|
|
[(pm:parseqq start X K) #'(pm:ak K (keyword X) ())])))
|
|
|
|
(define-syntax pm:parseqq^;; returns list-of parsed thing + used formals
|
|
(syntax-rules (dots start pairhead)
|
|
[(pm:parseqq^ start () Acc Used K) (pm:ak K Acc ())]
|
|
[(pm:parseqq^ start (dots . Y) Acc Used K)
|
|
(pm:error "Illegal continuation of list pattern beyond dots: ~s" Y)]
|
|
[(pm:parseqq^ start (X . Y) Acc Used K)
|
|
(pm:parseqq start X (pm:parseqq^ pairhead Y Acc Used K))]
|
|
[(pm:parseqq^ pairhead Y Acc (Used ...) K Xpat (Xformal ...))
|
|
(pm:parseqq^ start Y (Xpat . Acc) (Used ... Xformal ...) K)]
|
|
[(pm:parseqq^ start X Acc Used K) (pm:error "Bad pattern ~s" X)]))
|
|
|
|
(define-syntax pm
|
|
(syntax-rules (keyword formal dots null pair)
|
|
[(pm V (keyword K) Body) (when (eqv? V 'K) Body)]
|
|
[(pm V (formal F) Body) (let ((F V)) Body)]
|
|
[(pm V (dots Dformals DTemps DPat (PostPat ...)) Body)
|
|
(when (list? V)
|
|
(let ((rev (reverse V)))
|
|
(pm:help rev (PostPat ...) Dformals DTemps DPat Body)))]
|
|
[(pm V (null) Body) (when (null? V) Body)]
|
|
[(pm V (pair P0 P1) Body)
|
|
(when (pair? V)
|
|
(let ((X (car V)) (Y (cdr V)))
|
|
(pm X P0 (pm Y P1 Body))))]))
|
|
|
|
(define-syntax pm:help
|
|
(syntax-rules ()
|
|
[(pm:help V () (DFormal ...) (DTemp ...) DPat Body)
|
|
(let f ((ls V) (DTemp '()) ...)
|
|
(if (null? ls)
|
|
(let ((DFormal DTemp) ...) Body)
|
|
(let ((X (car ls)) (Y (cdr ls)))
|
|
(pm X DPat
|
|
(f Y (cons DFormal DTemp) ...)))))]
|
|
[(pm:help V (Post0 PostPat ...) DFormals DTemps DPat Body)
|
|
(when (pair? V)
|
|
(let ((X (car V)) (Y (cdr V)))
|
|
(pm X Post0
|
|
(pm:help Y (PostPat ...) DFormals DTemps DPat Body))))]))
|
|
|
|
(define-syntax pm:error
|
|
(syntax-rules ()
|
|
[(pm:error X ...) (error 'syncase 'X ...)]))
|
|
|
|
(define-syntax pm:eq?
|
|
(syntax-rules ()
|
|
[(_ A B SK FK) ; b should be an identifier
|
|
(let-syntax ([f (syntax-rules (B)
|
|
[(f B _SK _FK) (pm:ak _SK)]
|
|
[(f nonB _SK _FK) (pm:ak _FK)])])
|
|
(f A SK FK))]))
|
|
|
|
(define-syntax pm:member?
|
|
(syntax-rules ()
|
|
[(pm:member? A () SK FK) (pm:ak FK)]
|
|
[(pm:member? A (Id0 . Ids) SK FK)
|
|
(pm:eq? A Id0 SK (cont () (pm:member? A Ids SK FK)))]))
|
|
|
|
(define-syntax pm:find-dup
|
|
(syntax-rules ()
|
|
[(pm:find-dup () SK FK) (pm:ak FK)]
|
|
[(pm:find-dup (X . Y) SK FK)
|
|
(pm:member? X Y
|
|
(cont () (pm:ak SK X)) (cont () (pm:find-dup Y SK FK)))]))
|
|
|
|
(define-syntax pm:gen-temps
|
|
(syntax-rules ()
|
|
[(_ () Acc K) (pm:ak K Acc)]
|
|
[(_ (X . Y) Acc K) (pm:gen-temps Y (temp . Acc) K)]))
|
|
|
|
;;; ------------------------------
|
|
;;; Continuation representation and stuff
|
|
(define-syntax cont ; broken for non-nullary case
|
|
(syntax-rules ()
|
|
[(_ () Body) Body]
|
|
[(_ (Var ...) Body Exp ...)
|
|
(let-syntax ([f (syntax-rules ()
|
|
[(_ Var ...) Body])])
|
|
(f Exp ...))]))
|
|
|
|
(define-syntax pm:ak
|
|
(syntax-rules ()
|
|
[(_ (X Y ...) Z ...) (X Y ... Z ...)]))
|
|
|
|
;;; ------------------------------
|
|
;;; tests
|
|
|
|
;(define exp0
|
|
; '(syncase '((a) (b) (c d))
|
|
; ((,zz ,ww) ((,zz .. ,ww) ..)
|
|
; zz)))
|
|
|
|
;(define test
|
|
; (lambda (x)
|
|
; (pretty-print x)
|
|
; (pretty-print (eval x))
|
|
; (newline)))
|
|
;
|
|
;(define test0 (lambda () (test exp0)))
|
|
|
|
;;; There are three additional special forms, which should be obvious.
|
|
(define-syntax synlambda
|
|
(syntax-rules (guard)
|
|
[(_ pat (guard g ...) body0 body1 ...)
|
|
(lambda (x)
|
|
(syncase x
|
|
[pat (guard g ...) (begin body0 body1 ...)]))]
|
|
[(_ pat body0 body1 ...)
|
|
(lambda (x)
|
|
(syncase x
|
|
[pat (begin body0 body1 ...)]))]))
|
|
|
|
(define-syntax synlet
|
|
(syntax-rules (guard)
|
|
[(_ ([pat (guard g) rhs] ...) body0 body1 ...)
|
|
((synlambda `(,pat ...)
|
|
(guard (and g ...)) body0 body1 ...) `(,rhs ...))]
|
|
[(_ ([pat rhs] ...) body0 body1 ...)
|
|
((synlambda `(,pat ...) body0 body1 ...) `(,rhs ...))]
|
|
[(_ stuff ...) (synlet-all-guarded () stuff ...)]))
|
|
|
|
(define-syntax synlet-all-guarded
|
|
(syntax-rules (guard)
|
|
[(_ (x ...) () body0 body1 ...) (synlet (x ...) body0 body1 ...)]
|
|
[(_ (x ...) ([pat (guard g0 g1 g2 ...) rhs] decl ...) body0 body1 ...)
|
|
(synlet-all-guarded (x ... [pat (guard (and g0 g1 g2 ...)) rhs])
|
|
(decl ...) body0 body1 ...)]
|
|
[(_ (x ...) ([pat rhs] decl ...) body0 body1 ...)
|
|
(synlet-all-guarded (x ... [pat (guard #t) rhs])
|
|
(decl ...) body0 body1 ...)]
|
|
[(_ (x ...) ([pat] decl ...) body0 body1 ...)
|
|
(pm:error "synlet missing right-hand-side for pattern: ~s" pat)]
|
|
[(_ () (decl ...)) (pm:error "synlet missing body")]))
|
|
|
|
(define-syntax synlet*
|
|
(syntax-rules ()
|
|
[(_ (dec) body0 body1 ...) (synlet (dec) body0 body1 ...)]
|
|
[(_ (dec0 decl ...) body0 body1 ...)
|
|
(synlet (dec0) (synlet* (decl ...) body0 body1 ...))]))
|
|
|
|
(define make-double-collector-over-list
|
|
(lambda (constructor1 base1 constructor2 base2)
|
|
(letrec ((loop42 (lambda args
|
|
(if (not (= (length args) 2))
|
|
(error 'syncase "Invalid rhs expression"))
|
|
(let ([f (car args)] [arg (cadr args)])
|
|
(cond
|
|
[(null? arg) `(,base1 ,base2)]
|
|
[else
|
|
(synlet ([`(,x ,y) (f (car arg))]
|
|
[`(,x* ,y*) (loop42 f (cdr arg))])
|
|
`(,(constructor1 x x*)
|
|
,(constructor2 y y*)))])))))
|
|
loop42))))
|