home *** CD-ROM | disk | FTP | other *** search
- ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
- ; File derive.scm / Copyright (c) 1991 Jonathan Rees / See file COPYING
-
- ;;;; Macro expanders for standard derived expression types
-
- (define (define-usual-syntax name expander)
- (program-env-define! revised^4-scheme-env
- name
- (make-macro (lambda (form r c)
- (apply expander r c (cdr form)))
- revised^4-scheme-env)))
-
- ; syntax-rules is defined elsewhere
-
- (program-env-define! revised^4-scheme-env
- 'syntax-rules
- (make-macro rewrite-syntax-rules revised^4-scheme-env))
-
- ; The expanders:
- ; r = rename
- ; c = compare
-
- (define-usual-syntax 'and
- (lambda (r c . conjuncts)
- c ;ignored
- (if (null? conjuncts)
- #t
- (let recur ((first (car conjuncts)) (rest (cdr conjuncts)))
- (if (null? rest)
- first
- `(,(r 'and-aux) ,first
- (,(r 'lambda) () ,(recur (car rest) (cdr rest)))))))))
-
- (define-usual-syntax 'or
- (lambda (r c . disjuncts)
- c ;ignored
- (if (null? disjuncts)
- #f
- (let recur ((first (car disjuncts)) (rest (cdr disjuncts)))
- (if (null? rest)
- first
- `(,(r 'or-aux) ,first
- (,(r 'lambda) () ,(recur (car rest) (cdr rest)))))))))
-
-
- ; (case key ((a b) x) ((c) y) (else z))
- ; ==> (case-aux key
- ; '((a b) (c))
- ; (lambda () z)
- ; (lambda () x)
- ; (lambda () y))
-
- (define-usual-syntax 'case
- (lambda (r c key . clauses)
- (let ((form-result
- (lambda (else-thunk thunks key-lists)
- `(,(r 'case-aux) ,key
- (,(r 'quote) ,(reverse key-lists))
- ,else-thunk
- ,@(reverse thunks)))))
- (let loop ((cs clauses) (thunks '()) (key-lists '()))
- (if (null? cs)
- (form-result `(,(r 'lambda) () ,(r 'unspecified))
- thunks key-lists)
- (let* ((clause (car cs))
- (key-list (car clause))
- (body (cdr clause)))
- (if (c key-list (r 'else))
- (form-result `(,(r 'lambda) () ,@body) thunks key-lists)
- (loop (cdr cs)
- (cons `(,(r 'lambda) () ,@body) thunks)
- (cons key-list key-lists)))))))))
-
- (define-usual-syntax 'cond
- (lambda (r c . clauses)
- (let recur ((clauses clauses))
- (if (null? clauses)
- (r 'unspecified)
- (process-cond-clause r c
- (car clauses)
- (recur (cdr clauses)))))))
-
- ; Auxiliary also used by DO
-
- (define (process-cond-clause r c clause rest)
- (cond ((null? (cdr clause))
- `(,(r 'or-aux) ,(car clause)
- (,(r 'lambda) () ,rest)))
- ((c (car clause) (r 'else))
- `(,(r 'begin) ,@(cdr clause)))
- ((c (cadr clause) (r '=>))
- `(,(r '=>-aux) ,(car clause)
- (,(r 'lambda) () ,(caddr clause))
- (,(r 'lambda) () ,rest)))
- (else
- `(,(r 'if) ,(car clause)
- (,(r 'begin) ,@(cdr clause))
- ,rest))))
-
- (define-usual-syntax 'delay
- (lambda (r c thing)
- c ;ignored
- `(,(r 'make-promise) (,(r 'lambda) () ,thing))))
-
- (define-usual-syntax 'do
- (lambda (r c specs end . body)
- c ;ignored
- (let ((loop (r 'loop)))
- `(,(r 'letrec) ((,loop
- (,(r 'lambda)
- ,(map car specs)
- ,(process-cond-clause
- r c
- end
- `(,(r 'begin) ,@body
- (,loop ,@(map (lambda (y)
- (if (null? (cddr y))
- (car y)
- (caddr y)))
- specs)))))))
- (,loop ,@(map cadr specs))))))
-
- (define-usual-syntax 'let
- (lambda (r c specs . body)
- c ;ignored
- (cond ((name? specs)
- (let ((tag specs)
- (specs (car body))
- (body (cdr body)))
- `(,(r 'letrec) ((,tag (,(r 'lambda) ,(map car specs) ,@body)))
- (,tag ,@(map cadr specs)))))
- (else
- `((,(r 'lambda) ,(map car specs) ,@body)
- ,@(map cadr specs))))))
-
- (define-usual-syntax 'let*
- (lambda (r c specs . body)
- c ;ignored
- (let recur ((specs specs))
- (if (null? specs)
- `(,(r 'begin) ,@body)
- (let ((name (car (car specs)))
- (val-exp (cadr (car specs))))
- `(,(r 'let) ((,name ,val-exp))
- ,(recur (cdr specs))))))))
-
- ;;;; Quasiquote
-
- (define-usual-syntax 'quasiquote
- (lambda (r c x)
- c ;ignored
- (qq-descend x 1 r)))
-
- (define (qq-descend x level r)
- (cond ((vector? x)
- (qq-descend-vector x level r))
- ((not (pair? x))
- (make-quotation x r))
- ((qq-interesting? x 'quasiquote)
- (qq-descend-pair x (+ level 1) r))
- ((qq-interesting? x 'unquote)
- (if (= level 1)
- (cadr x)
- (qq-descend-pair x (- level 1) r)))
- ((qq-interesting? x 'unquote-splicing)
- (if (= level 1)
- (error ",@ in illegal position" x)
- (qq-descend-pair x (- level 1) r)))
- (else
- (qq-descend-pair x level r))))
-
- (define (qq-descend-pair x level r)
- (let ((d-exp (qq-descend (cdr x) level r)))
- (if (and (qq-interesting? (car x) 'unquote-splicing)
- (= level 1))
- (let ((sc (cadr (car x))))
- (cond ((and (quotation? d-exp r)
- (null? (quotation-value d-exp)))
- sc)
- (else
- `(,(r 'append) ,sc ,d-exp))))
- (let ((a-exp (qq-descend (car x) level r)))
- (cond ((and (quotation? a-exp r)
- (quotation? d-exp r))
- (make-quotation x r))
- ((and (quotation? d-exp r)
- (eq? (quotation-value d-exp) '()))
- `(,(r 'list) ,a-exp))
- ((qq-interesting? d-exp 'list)
- `(,(r 'list) ,a-exp ,@(cdr d-exp)))
- ;;+++ Ought to use auxiliary CONS* procedure, for more
- ;; readable output
- (else
- `(,(r 'cons) ,a-exp ,d-exp)))))))
-
- (define (qq-descend-vector x level r)
- (let ((result (qq-descend (vector->list x) level r)))
- (if (quotation? result r)
- (make-quotation x r)
- `(,(r 'list->vector) ,result))))
-
- (define (qq-interesting? x marker)
- (and (pair? x)
- (eq? (car x) marker)
- (pair? (cdr x))
- (null? (cddr x))))
-
- (define (quotation? x r)
- (qq-interesting? x (r 'quote)))
-
- (define quotation-value cadr)
-
- (define (make-quotation value r)
- `(,(r 'quote) ,value))
-