This repository has been archived on 2022-08-10. You can view files and clone it, but cannot push or open issues or pull requests.
chez-openbsd/nanopass/tests/synforms.ss
2022-07-29 15:12:07 +02:00

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))))