#lang scheme/base
(require (for-syntax scheme/base)
scheme/contract
srfi/26/cut)
(define (make-yieldable yield->body)
(define caller #f)
(define resume #f)
(define (yield . args)
(apply values
(let/cc k
(set! resume k)
(apply caller args))))
(define (return . args)
(apply values
(let/cc k
(set! resume #f)
(apply caller args))))
(define body
(yield->body yield))
(lambda args
(let/cc k
(set! caller k)
(if resume
(resume args)
(call-with-values (cut apply body args)
return)))))
(define-syntax (yieldable stx)
(syntax-case stx ()
[(_ yield statement ...)
#'(make-yieldable (lambda (yield) statement ...))]))
(provide yieldable)
(provide/contract
[make-yieldable (-> procedure? procedure?)])