! Copyright (C) 2003, 2010 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: arrays vectors kernel kernel.private sequences namespaces make math splitting sorting quotations assocs combinators combinators.private accessors words ; IN: continuations : with-datastack ( stack quot -- new-stack ) [ [ [ datastack ] dip swap [ { } like set-datastack ] dip ] dip swap [ call datastack ] dip swap [ set-datastack ] dip ] (( stack quot -- new-stack )) call-effect-unsafe ; SYMBOL: original-error SYMBOL: error SYMBOL: error-continuation SYMBOL: error-thread SYMBOL: restarts c ( continuation -- ) catchstack* push ; : c> ( -- continuation ) catchstack* pop ; ! We have to defeat some optimizations to make continuations work : dummy-1 ( -- obj ) f ; : dummy-2 ( obj -- obj ) dup drop ; : catchstack ( -- catchstack ) catchstack* clone ; inline : set-catchstack ( catchstack -- ) >vector 1 set-context-object ; inline : init-catchstack ( -- ) f set-catchstack ; PRIVATE> TUPLE: continuation data call retain name catch ; C: continuation : continuation ( -- continuation ) datastack callstack retainstack namestack catchstack ; continuation< ( continuation -- data call retain name catch ) { [ data>> ] [ call>> ] [ retain>> ] [ name>> ] [ catch>> ] } cleave ; PRIVATE> : ifcc ( capture restore -- ) [ dummy-1 continuation ] 2dip [ dummy-2 ] prepose ?if ; inline : callcc0 ( quot -- ) [ drop ] ifcc ; inline : callcc1 ( quot -- obj ) [ ] ifcc ; inline continuation< set-catchstack set-namestack set-retainstack [ set-datastack ] dip set-callstack ] (( continuation -- * )) call-effect-unsafe ; PRIVATE> : continue-with ( obj continuation -- * ) [ swap 4 set-special-object >continuation< set-catchstack set-namestack set-retainstack [ set-datastack drop 4 special-object f 4 set-special-object f ] dip set-callstack ] (( obj continuation -- * )) call-effect-unsafe ; : continue ( continuation -- * ) f swap continue-with ; SYMBOL: return-continuation : with-return ( quot -- ) [ [ return-continuation set ] prepose callcc0 ] with-scope ; inline : return ( -- * ) return-continuation get continue ; GENERIC: compute-restarts ( error -- seq ) SYMBOL: thread-error-hook : rethrow ( error -- * ) dup save-error catchstack* empty? [ thread-error-hook get-global [ original-error get-global die ] or (( error -- * )) call-effect-unsafe ] when c> continue-with ; : recover ( ..a try: ( ..a -- ..b ) recovery: ( ..a error -- ..b ) -- ..b ) [ [ swap >c call c> drop ] curry ] dip ifcc ; inline : ignore-errors ( quot -- ) [ drop ] recover ; inline : cleanup ( try cleanup-always cleanup-error -- ) [ compose [ dip rethrow ] curry recover ] [ drop ] 2bi call ; inline ERROR: attempt-all-error ; : attempt-all ( ... seq quot: ( ... elt -- ... obj ) -- ... obj ) over empty? [ attempt-all-error ] [ [ [ [ , f ] compose [ , drop t ] recover ] curry all? ] { } make last swap [ rethrow ] when ] if ; inline TUPLE: condition error restarts continuation ; C: condition ( error restarts cc -- condition ) : throw-restarts ( error restarts -- restart ) [ throw ] callcc1 2nip ; : rethrow-restarts ( error restarts -- restart ) [ rethrow ] callcc1 2nip ; : throw-continue ( error -- ) { { "Continue" t } } throw-restarts drop ; TUPLE: restart name obj continuation ; C: restart : restart ( restart -- * ) [ obj>> ] [ continuation>> ] bi continue-with ; M: object compute-restarts drop { } ; M: condition compute-restarts [ error>> compute-restarts ] [ [ restarts>> ] [ continuation>> [ ] curry ] bi { } assoc>map ] bi append ;