>>31
Also, an implementation of CL's
tagbody
(not exactly, same semantics, different syntax) in Racket, but it should be easily portable to R6RS too:
(define-syntax-parameter goto
(lambda (stx)
(raise-syntax-error 'goto (if (identifier? stx) "bad syntax" "bad syntax (not inside a tagbody)") stx)))
(define-syntax (tagbody stx)
(define (%tag-next x)
(let ((x (syntax->list x)))
(do ((x x (cdr x))
(y (cdr x) (cdr y))
(r (list (car x)) (cons (list (car x) (car y)) r)))
((null? y) (reverse (cons (list (car x) #'void) r))))))
(syntax-case stx ()
((tagbody (tag b ...) ...)
(andmap identifier? (syntax->list #'(tag ...)))
(with-syntax (((first (tag next) ...) (%tag-next #'(tag ...))))
#'(letrec ((tag
(lambda ()
(let/ec escape
(syntax-parameterize
((goto (lambda (stx)
(syntax-case stx ()
((goto label)
(if (and (identifier? #'label)
(or (free-identifier=? #'label #'tag) ...))
#'(escape label)
(raise-syntax-error 'goto "bad syntax (not a valid label)" stx #'label)))))))
b ...
(next))))) ...)
(let loop ((f (first)))
(if (procedure? f) (loop (f)) f)))))))
;; Example taken from the HyperSpec: http://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm
(define-syntax-rule (inc! x n) (set! x (+ x n)))
(let ((val #f))
(tagbody
(start
(set! val 1)
(goto point-a)
(inc! val 16))
(point-c
(inc! val 4)
(goto point-b)
(inc! val 32))
(point-a
(inc! val 2)
(goto point-c)
(inc! val 64))
(point-b
(inc! val 8)))
val)
; 15
Really, more languages should provide some non-local exit mechanism, and not in the form of exceptions.