scsh-0.5/bcomp/usual.scm

234 lines
6.9 KiB
Scheme

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