diff --git a/contrib/coroutines.factor b/contrib/coroutines.factor new file mode 100644 index 0000000000..371d5b2f88 --- /dev/null +++ b/contrib/coroutines.factor @@ -0,0 +1,84 @@ +! Copyright (C) 2005 Chris Double. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, +! this list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +! +IN: coroutines +USING: kernel lists generic ; + +TUPLE: coroutine resumecc exitcc ; + +: cocreate ( quot - co ) + #! Create a new coroutine, which will execute the quotation + #! when resumed. The quotation will have the coroutine + #! on the stack and an initial value (received from coresume) + #! when first resumed. ie. The quotation should have stack + #! effect ( co value -- ). + f f dup rot cons over set-coroutine-resumecc ; + +: coresume ( v co -- result ) + #! Resume a coroutine with 'v' as the first item on the + #! stack. The result placed on the stack is that of the + #! topmost argument on the stack when coyield is called + #! within the coroutine. + [ + over set-coroutine-exitcc + coroutine-resumecc call + ] callcc1 >r >r drop r> r> ; + +: coyield ( v co -- result ) + #! Suspend a coroutine, leaving the value 'v' on the + #! stack when control is passed to the 'coresume' caller. + [ + over set-coroutine-resumecc + coroutine-exitcc call + ] callcc1 >r >r drop r> r> ; + +: tree-each ( [ tree ] [ quotation ] -- ) + #! Perform a preorder iteration of the tree, calling + #! the quotation on each key. + over [ + over cons? [ + >r uncons r> tuck >r >r tree-each r> r> tree-each + ] [ + call + ] ifte + ] [ + 2drop + ] ifte ; + + +: test1 ( -- co ) + [ swap [ over coyield 2drop ] tree-each f swap coyield ] cocreate ; + +: test2 ( -- co ) + [ 1 over coyield drop 2 over coyield drop 3 over coyield ] cocreate ; + +USE: prettyprint +USE: sequences + +test2 f swap coresume . f swap coresume . f swap coresume . drop + +: test3 ( -- co ) + [ [ 1 2 3 ] [ over coyield drop ] each ] cocreate ; + +test3 f swap coresume . f swap coresume . f swap coresume . drop +