; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING. ; This is file derive.scm. ;;;; Macro expanders for the standard macros (define the-usual-transforms (make-table)) (define (define-usual-macro name n proc aux-names) (table-set! the-usual-transforms name (cons (lambda (exp rename compare) (if (long-enough? (cdr exp) n) (apply proc rename compare (cdr exp)) exp)) aux-names))) (define (usual-transform name) (or (table-ref the-usual-transforms name) (call-error "no such transform" usual-transform name))) (define (long-enough? l n) (if (= n 0) #t (and (pair? l) (long-enough? (cdr l) (- n 1))))) ; (define-usual-macro 'and 0 (lambda (rename compare . conjuncts) (cond ((null? conjuncts) `#t) ((null? (cdr conjuncts)) (car conjuncts)) (else `(,(rename 'if) ,(car conjuncts) (,(rename 'and) ,@(cdr conjuncts)) ,#f)))) ; bootstrapping does not allow #F embedded in ; quoted structure '(if and)) ; Tortuously crafted so as to avoid dependency on any (unspecific) ; procedure. (define-usual-macro 'cond 1 (lambda (rename compare . clauses) (let ((result (let recur ((clauses clauses)) (if (null? clauses) '() (list (let ((clause (car clauses)) (more-clauses (cdr clauses))) (cond ((not (pair? clause)) (syntax-error "invalid COND clause" clause)) ((and (null? more-clauses) (compare (car clause) (rename 'else))) `(,(rename 'begin) ,@(cdr clause))) ((null? (cdr clause)) `(,(rename 'or) ,(car clause) ,@(recur more-clauses))) ((compare (cadr clause) (rename '=>)) (let ((temp (rename 'temp))) `(,(rename 'let) ((,temp ,(car clause))) (,(rename 'if) ,temp (,(caddr clause) ,temp) ,@(recur more-clauses))))) (else `(,(rename 'if) ,(car clause) (,(rename 'begin) ,@(cdr clause)) ,@(recur more-clauses)))))))))) (if (null? result) (syntax-error "empty COND") (car result)))) '(or cond begin let if begin)) (define-usual-macro 'do 2 (lambda (rename compare . (specs end . body)) (let ((%loop (rename 'loop)) (%letrec (rename 'letrec)) (%lambda (rename 'lambda)) (%cond (rename 'cond))) `(,%letrec ((,%loop (,%lambda ,(map car specs) (,%cond ,end (else ,@body (,%loop ,@(map (lambda (y) (if (null? (cddr y)) (car y) (caddr y))) specs))))))) (,%loop ,@(map cadr specs))))) '(letrec lambda cond)) (define-usual-macro 'let 2 (lambda (rename compare . (specs . body)) (cond ((list? specs) `((,(rename 'lambda) ,(map car specs) ,@body) ,@(map cadr specs))) ((name? specs) (let ((tag specs) (specs (car body)) (body (cdr body)) (%letrec (rename 'letrec)) (%lambda (rename 'lambda))) `(,%letrec ((,tag (,%lambda ,(map car specs) ,@body))) (,tag ,@(map cadr specs))))) (else (syntax-error "invalid LET syntax" `(let ,specs ,@body))))) '(lambda letrec)) (define-usual-macro 'let* 2 (lambda (rename compare . (specs . body)) (if (or (null? specs) (null? (cdr specs))) `(,(rename 'let) ,specs ,@body) `(,(rename 'let) (,(car specs)) (,(rename 'let*) ,(cdr specs) ,@body)))) '(let let*)) (define-usual-macro 'or 0 (lambda (rename compare . disjuncts) (cond ((null? disjuncts) #f) ;not '#f ((null? (cdr disjuncts)) (car disjuncts)) (else (let ((temp (rename 'temp))) `(,(rename 'let) ((,temp ,(car disjuncts))) (,(rename 'if) ,temp ,temp (,(rename 'or) ,@(cdr disjuncts)))))))) '(let if or)) ; CASE needs auxiliary MEMV. (define-usual-macro 'case 2 (lambda (rename compare . (key . clauses)) (let ((temp (rename 'temp)) (%eqv? (rename 'eq?)) (%memv (rename 'memv)) (%quote (rename 'quote))) `(,(rename 'let) ((,temp ,key)) (,(rename 'cond) ,@(map (lambda (clause) `(,(cond ((compare (car clause) (rename 'else)) (car clause)) ((null? (car clause)) #f) ((null? (cdar clause)) ;+++ `(,%eqv? ,temp (,%quote ,(caar clause)))) (else `(,%memv ,temp (,%quote ,(car clause))))) ,@(cdr clause))) clauses))))) '(let cond eqv? memv quote)) ; Quasiquote (define-usual-macro 'quasiquote 1 (lambda (rename compare . (x)) (define %quote (rename 'quote)) (define %quasiquote (rename 'quasiquote)) (define %unquote (rename 'unquote)) (define %unquote-splicing (rename 'unquote-splicing)) (define %append (rename 'append)) (define %cons (rename 'cons)) (define %list->vector (rename 'list->vector)) (define (expand-quasiquote x level) (descend-quasiquote x level finalize-quasiquote)) (define (finalize-quasiquote mode arg) (cond ((eq? mode 'quote) `(,%quote ,arg)) ((eq? mode 'unquote) arg) ((eq? mode 'unquote-splicing) (syntax-error ",@ in invalid context" arg)) (else `(,mode ,@arg)))) (define (descend-quasiquote x level return) (cond ((vector? x) (descend-quasiquote-vector x level return)) ((not (pair? x)) (return 'quote x)) ((interesting-to-quasiquote? x %quasiquote) (descend-quasiquote-pair x (+ level 1) return)) ((interesting-to-quasiquote? x %unquote) (cond ((= level 0) (return 'unquote (cadr x))) (else (descend-quasiquote-pair x (- level 1) return)))) ((interesting-to-quasiquote? x %unquote-splicing) (cond ((= level 0) (return 'unquote-splicing (cadr x))) (else (descend-quasiquote-pair x (- level 1) return)))) (else (descend-quasiquote-pair x level return)))) (define (descend-quasiquote-pair x level return) (descend-quasiquote (car x) level (lambda (car-mode car-arg) (descend-quasiquote (cdr x) level (lambda (cdr-mode cdr-arg) (cond ((and (eq? car-mode 'quote) (eq? cdr-mode 'quote)) (return 'quote x)) ((eq? car-mode 'unquote-splicing) ;; (,@mumble ...) (cond ((and (eq? cdr-mode 'quote) (null? cdr-arg)) (return 'unquote car-arg)) (else (return %append (list car-arg (finalize-quasiquote cdr-mode cdr-arg)))))) (else (return %cons (list (finalize-quasiquote car-mode car-arg) (finalize-quasiquote cdr-mode cdr-arg)))))))))) (define (descend-quasiquote-vector x level return) (descend-quasiquote (vector->list x) level (lambda (mode arg) (case mode ((quote) (return 'quote x)) (else (return %list->vector (list (finalize-quasiquote mode arg)))))))) (define (interesting-to-quasiquote? x marker) (and (pair? x) (compare (car x) marker))) (expand-quasiquote x 0)) '(append cons list->vector quasiquote unquote unquote-splicing))