[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
New improved CASE macro
Well, Martin's jumping on me for my variable naming style made me sit down and
do it *right*, i.e. with no variable conflicts possible at all. Below, the
new improved code. You cannot tromp on the runtime variables of this solution.
Aren't lexically scoped lisps fun?
-Olin
----------
(herald case)
;;******************************************************************************
;; CASE with specifiable PREDicate to compare the cases with.
;; Original CASE is equivalent to: (CASE eq? key . clauses) [now called CASEQ].
;; Ashwin Ram, May 1985.
;; Rewritten by Olin Shivers (shivers@a.cs.cmu.edu) 2/26/86
;; CASE now evaluates the KEY and PRED forms exactly once, in the
;; environment that the CASE statement appears in.
(define **case-fell-off-end** '**case-fell-off-end**)
(define-syntax (case pred key . clauses)
(labels (((expand-case-1 names clauses)
(if (atom? clauses) '**case-fell-off-end**
(let ((clause (car clauses)) (clauses (cdr clauses))
(name (car names)) (names (cdr names)))
(cond ((list? (car clause))
`(if (or . ,(map (lambda (k) `(pred key ',k))
(car clause)))
(,name)
,(expand-case-1 names clauses)))
((memq? (car clause) '(t else))
`(,name))
;; Should never come here.
(t (lose clause))))))
((syntax-check-keys keys)
(or (memq? keys '(t else))
(and (list? keys)
(every (lambda (k) (atom? k)) keys))))
((lose clause)
(syntax-error "bad ~s clause syntax: ~s" 'case clauses)))
;; A little initial syntax checking.
(walk (lambda (c) (if (or (not (pair? c))
(not (syntax-check-keys (car c))))
(lose c)))
clauses)
(let ((names (map (lambda (()) (generate-symbol 'thunk)) clauses))
(thunks (map (lambda (c) `(lambda () . ,(cdr c))) clauses)))
`(let ((key ,key) (pred ,pred)
. , (map (lambda (name thunk) `(,name ,thunk)) names thunks))
,(expand-case-1 names clauses)))))
;;; Example:
;(CASE (POP PREDLIST) (HAIRY-COMPUTATION)
; ((5 9 8) (FOO) (BAR 3) (BAZ))
; (("T" "Scheme") 37)
; ((franz FORTRAN) 0)))
;;; Expands as
;(LET ((KEY (HAIRY-COMPUTATION))
; (PRED (POP PREDLIST))
; (THUNK.64 (LAMBDA () (FOO) (BAR 3) (BAZ)))
; (THUNK.65 (LAMBDA () 37))
; (THUNK.66 (LAMBDA () 0)))
; (IF (OR (PRED KEY (QUOTE 5))
; (PRED KEY (QUOTE 9))
; (PRED KEY (QUOTE 8)))
; (THUNK.64)
; (IF (OR (PRED KEY (QUOTE "T"))
; (PRED KEY (QUOTE "Scheme")))
; (THUNK.65)
; (IF (OR (PRED KEY (QUOTE FRANZ))
; (PRED KEY (QUOTE FORTRAN)))
; (THUNK.66)
; **CASE-FELL-OFF-END**))))
(define-syntax (xcase pred key . clauses)
`(case ,pred ,key ,@clauses (else (losing-xcase))))
(define (losing-xcase)
(error "no clause selected in ~s expression" 'xcase))
(define-syntax (caseq key . clauses)
`(case eq? ,key ,@clauses))
(define-syntax (casev key . clauses)
`(case alikev? ,key ,@clauses))
;;; EOF