mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-11 00:00:49 +02:00
160 lines
4.1 KiB
Scheme
160 lines
4.1 KiB
Scheme
;;;"scmactst.scm" test syntactic closures macros
|
|
;;; From "sc-macro.doc", A Syntactic Closures Macro Facility by Chris Hanson
|
|
|
|
(define errs '())
|
|
(define test
|
|
(lambda (expect fun . args)
|
|
(write (cons fun args))
|
|
(display " ==> ")
|
|
((lambda (res)
|
|
(write res)
|
|
(newline)
|
|
(cond ((not (equal? expect res))
|
|
(set! errs (cons (list res expect (cons fun args)) errs))
|
|
(display " BUT EXPECTED ")
|
|
(write expect)
|
|
(newline)
|
|
#f)
|
|
(else #t)))
|
|
(if (procedure? fun) (apply fun args) (car args)))))
|
|
|
|
(require 'syntactic-closures)
|
|
|
|
(macro:expand
|
|
'(define-syntax push
|
|
(syntax-rules ()
|
|
((push item list)
|
|
(set! list (cons item list))))))
|
|
|
|
(test '(set! foo (cons bar foo)) 'push (macro:expand '(push bar foo)))
|
|
|
|
(macro:expand
|
|
'(define-syntax push1
|
|
(transformer
|
|
(lambda (exp env)
|
|
(let ((item
|
|
(make-syntactic-closure env '() (cadr exp)))
|
|
(list
|
|
(make-syntactic-closure env '() (caddr exp))))
|
|
`(set! ,list (cons ,item ,list)))))))
|
|
|
|
(test '(set! foo (cons bar foo)) 'push1 (macro:expand '(push1 bar foo)))
|
|
|
|
(macro:expand
|
|
'(define-syntax loop
|
|
(transformer
|
|
(lambda (exp env)
|
|
(let ((body (cdr exp)))
|
|
`(call-with-current-continuation
|
|
(lambda (exit)
|
|
(let f ()
|
|
,@(map (lambda (exp)
|
|
(make-syntactic-closure env '(exit)
|
|
exp))
|
|
body)
|
|
(f)))))))))
|
|
|
|
(macro:expand
|
|
'(define-syntax let1
|
|
(transformer
|
|
(lambda (exp env)
|
|
(let ((id (cadr exp))
|
|
(init (caddr exp))
|
|
(exp (cadddr exp)))
|
|
`((lambda (,id)
|
|
,(make-syntactic-closure env (list id) exp))
|
|
,(make-syntactic-closure env '() init)))))))
|
|
|
|
(test 93 'let1 (macro:eval '(let1 a 90 (+ a 3))))
|
|
|
|
(macro:expand
|
|
'(define-syntax loop-until
|
|
(syntax-rules
|
|
()
|
|
((loop-until id init test return step)
|
|
(letrec ((loop
|
|
(lambda (id)
|
|
(if test return (loop step)))))
|
|
(loop init))))))
|
|
|
|
(test (macro:expand '(letrec ((loop (lambda (foo) (if #t 12 (loop 33)))))
|
|
(loop 3)))
|
|
'loop
|
|
(macro:expand '(loop-until foo 3 #t 12 33)))
|
|
|
|
(macro:expand
|
|
'(define-syntax loop-until1
|
|
(transformer
|
|
(lambda (exp env)
|
|
(let ((id (cadr exp))
|
|
(init (caddr exp))
|
|
(test (cadddr exp))
|
|
(return (cadddr (cdr exp)))
|
|
(step (cadddr (cddr exp)))
|
|
(close
|
|
(lambda (exp free)
|
|
(make-syntactic-closure env free exp))))
|
|
`(letrec ((loop
|
|
,(capture-syntactic-environment
|
|
(lambda (env)
|
|
`(lambda (,id)
|
|
(,(make-syntactic-closure env '() `if)
|
|
,(close test (list id))
|
|
,(close return (list id))
|
|
(,(make-syntactic-closure env '()
|
|
`loop)
|
|
,(close step (list id)))))))))
|
|
(loop ,(close init '()))))))))
|
|
|
|
(test (macro:expand '(letrec ((loop (lambda (foo) (if #t 12 (loop 33)))))
|
|
(loop 3)))
|
|
'loop1
|
|
(macro:expand '(loop-until1 foo 3 #t 12 33)))
|
|
|
|
(test '#t 'identifier (identifier? 'a))
|
|
;;; this needs to setup ENV.
|
|
;;;(test '#t 'identifier
|
|
;;; (identifier? (macro:expand (make-syntactic-closure env '() 'a))))
|
|
(test #f 'identifier (identifier? "a"))
|
|
(test #f 'identifier (identifier? #\a))
|
|
(test #f 'identifier (identifier? 97))
|
|
(test #f 'identifier (identifier? #f))
|
|
(test #f 'identifier (identifier? '(a)))
|
|
(test #f 'identifier (identifier? '#(a)))
|
|
|
|
(test '(#t #f)
|
|
'syntax
|
|
(macro:eval
|
|
'(let-syntax
|
|
((foo
|
|
(transformer
|
|
(lambda (form env)
|
|
(capture-syntactic-environment
|
|
(lambda (transformer-env)
|
|
(identifier=? transformer-env 'x env 'x)))))))
|
|
(list (foo)
|
|
(let ((x 3))
|
|
(foo))))))
|
|
|
|
|
|
(test '(#f #t)
|
|
'syntax
|
|
(macro:eval
|
|
'(let-syntax ((bar foo))
|
|
(let-syntax
|
|
((foo
|
|
(transformer
|
|
(lambda (form env)
|
|
(capture-syntactic-environment
|
|
(lambda (transformer-env)
|
|
(identifier=? transformer-env 'foo
|
|
env (cadr form))))))))
|
|
(list (foo foo)
|
|
(foo bar))))))
|
|
|
|
(newline)
|
|
(cond ((null? errs) (display "Passed all tests"))
|
|
(else (display "errors were:") (newline)
|
|
(display "(got expected (call))") (newline)
|
|
(for-each (lambda (l) (write l) (newline)) errs)))
|
|
(newline)
|