(module tagged-begin mzscheme
(provide tagged-begin)
(require-for-syntax (lib "match.ss")
(planet "42.ss" ("soegaard" "srfi.plt"))
(lib "list.ss" "srfi" "1"))
(define-syntax (tagged-begin stx)
(define tag? identifier?)
(define (non-tag? o) (not (tag? o)))
(define (generate-binding tag-exprs next-tag)
(match tag-exprs
[(tag exprs) (quasisyntax/loc stx [#,tag (lambda () #,@exprs (#,next-tag))])]))
(define (generate-last-binding tag-exprs return)
(match tag-exprs
[(tag exprs) (quasisyntax/loc stx [#,tag (lambda () #,@exprs (#,return (void)))])]))
(syntax-case stx ()
[(tagged-begin . tag/exprs-stx)
(let ([tes (syntax->list #'tag/exprs-stx)])
(when (not (tag? (car tes)))
(set! tes (cons #'start tes)))
(let* ([first-tag (car tes)]
[tag-exprs-list (list-ec (:pairs p tes)
(if (tag? (car p)))
(list (car p) (take-while non-tag? (cdr p))))]
[tags (map car tag-exprs-list)])
(with-syntax ([go (syntax-local-introduce (syntax/loc stx go))]
[return (syntax-local-introduce (syntax/loc stx return))])
#`((let/cc go
(let ([return (lambda (v) (go (lambda () v)))])
(letrec
(#,@(map generate-binding
(drop-right tag-exprs-list 1)
(cdr tags))
#,(generate-last-binding (last tag-exprs-list) #'return))
(#,first-tag))))))))]))
)
(begin (require tagged-begin)
(define (display/nl v)
(display v)
(newline))
(display/nl
(let ([i 0])
(tagged-begin
loop (set! i (+ i 1))
(if (< i 41) (go loop)))
i))
(display/nl
(let ([i 0])
(tagged-begin
loop (set! i (+ i 1))
(if (< i 42) (go loop))
(return i))))
(display/nl
(let ([i 0])
(tagged-begin
loop (set! i (+ i 1))
(go b)
a (if (< i 43) (go loop))
(return i)
b (go a))))
(let ((a 0))
(tagged-begin
start
(set! a 0)
part-1
(set! a (+ a 1))
(display/nl a)
(cond
((>= a 9) (go end))
((even? a) (go part-1))
(else (go part-2)))
part-2
(set! a (+ a 1))
(go part-1)
end
(display/nl "We're done printing the odd numbers between 0 and 10")))
(define permutation (vector 'dummy 6 2 1 5 4 3)) (define n (- (vector-length permutation) 1))
(define (X i) (vector-ref permutation i))
(define (X! i j) (vector-set! permutation i j))
(let ([m 0] [i 0] [j 0])
(tagged-begin
I1 (set! m n)
(set! j -1)
I2 (set! i (X m))
(if (< i 0) (go I5))
I3 (X! m j)
(set! j (- m))
(set! m i)
(set! i (X m))
I4 (if (> i 0) (go I3))
(set! i j)
I5 (X! m (- i))
I6 (set! m (- m 1))
(if (> m 0) (go I2))))
(display/nl permutation)
(define val 'foo)
(tagged-begin
(set! val 1)
(go a)
c (set! val (+ val 4))
(go b)
(set! val (+ val 32))
a (set! val (+ val 2))
(go c)
(set! val (+ val 64))
b (set! val (+ val 8)))
(display/nl val)
(define (f1 flag)
(let ((n 1))
(tagged-begin
(set! n (f2 flag (lambda () (go out))))
out
(display n))))
(define (f2 flag escape)
(if flag (escape) 2))
(display/nl (f1 #f))
(display/nl (f1 #t))
(tagged-begin
a (tagged-begin
(go b))
b (return 'hello-world))
(tagged-begin
a (tagged-begin
(go b)
(return 'wrong)
b (go c))
b (return 'wrong)
c (return 'correct))
)