(define-syntax block
(syntax-rules ()
((block) (void))
((block X) X)
((block (X ...) REST ...)
(X ... (block REST ...)))))
(define-syntax abortable-block
(syntax-rules ()
((abortable-block ABORT BODY ...)
(call-with-current-continuation
(lambda (ABORT)
(block BODY ...))))))
(import matchable)
(define-syntax /let
(syntax-rules ()
((/let X Y BODY)
(match-let ((X Y))
BODY))))
(define-syntax /flet
(syntax-rules ()
((/flet (FUNC . ARGS) FBODY BODY)
(letrec ((FUNC (lambda ARGS FBODY)))
BODY))))
(define-syntax /finally
(syntax-rules ()
((/finally ACTIONS ... BODY)
(let* ((thunk (lambda () ACTIONS ...))
(return-value
(handle-exceptions
exn
(begin
(thunk)
(abort exn))
BODY)))
(thunk)
return-value))))
(define-syntax /assert
(syntax-rules ()
((/assert EXP OBJ ... BODY)
(begin
(assert EXP OBJ ...)
BODY))))
(define-syntax ->
(syntax-rules ()
((-> CONTINUE BODY CONTINUE-BODY)
(let ((CONTINUE (lambda () CONTINUE-BODY)))
BODY))))
(import test)
(define b 1)
(test 4
(block
(/let a 1)
(begin (set! b 2))
(/let b 3)
(+ a b)))
(test 2 b)
(test 1
(abortable-block
return
(begin (return 1))
2))
(test 3
(block
(/let (a b) '(1 2))
(+ a b)))
(test 123
(block
(/flet (sum a b) (+ a b))
(sum 120 3)))
(test #t
(block
(/flet (odd? x)
(cond
((zero? x) #f)
((eq? 1 x) #t)
(else (odd? (- x 2)))))
(odd? 5)))
(test 3
(block
(let* ((a 1)
(b (+ a 1))))
(+ a b)))
(test 2
(block
(if #f 1)
(if #t 2)
(if #f 3)
4))
(test 2
(block
(handle-exceptions
exn
2)
(error "Something bad")))
(define finally-test 0)
(test "test"
(block
(/finally
(set! finally-test (+ finally-test 1)))
"test"))
(test 1 finally-test)
(set! finally-test 0)
(test-error "test"
(block
(/finally
(set! finally-test (+ finally-test 1)))
(error "Expected error")))
(test 1 finally-test)
(test 2
(block
(-> ok (if #t (ok) 1))
2))
(test 1
(block
(-> ok (if #f (ok) 1))
2))
(test-error
(block
(/assert #f)
123))
(test-error
(block
(/assert #f 'location "Oh dear" 1 2 3)
123))