2008-02-06 14:47:19 -05:00
|
|
|
! Copyright (C) 2003, 2008 Slava Pestov.
|
2007-09-20 18:09:08 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
|
|
USING: arrays vectors kernel kernel.private sequences
|
2007-12-28 21:45:16 -05:00
|
|
|
namespaces math splitting sorting quotations assocs ;
|
2007-09-20 18:09:08 -04:00
|
|
|
IN: continuations
|
|
|
|
|
|
|
|
SYMBOL: error
|
|
|
|
SYMBOL: error-continuation
|
|
|
|
SYMBOL: restarts
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: catchstack* ( -- catchstack )
|
|
|
|
1 getenv { vector } declare ; inline
|
|
|
|
|
|
|
|
: >c ( continuation -- ) catchstack* push ;
|
|
|
|
|
|
|
|
: c> ( -- continuation ) catchstack* pop ;
|
|
|
|
|
2007-10-05 01:08:18 -04:00
|
|
|
: dummy ( -- obj )
|
|
|
|
#! Optimizing compiler assumes stack won't be messed with
|
|
|
|
#! in-transit. To ensure that a value is actually reified
|
|
|
|
#! on the stack, we put it in a non-inline word together
|
|
|
|
#! with a declaration.
|
|
|
|
f { object } declare ;
|
2007-10-03 17:35:48 -04:00
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
PRIVATE>
|
|
|
|
|
|
|
|
: catchstack ( -- catchstack ) catchstack* clone ; inline
|
|
|
|
|
|
|
|
: set-catchstack ( catchstack -- ) >vector 1 setenv ; inline
|
|
|
|
|
|
|
|
TUPLE: continuation data call retain name catch ;
|
|
|
|
|
|
|
|
C: <continuation> continuation
|
|
|
|
|
|
|
|
: continuation ( -- continuation )
|
|
|
|
datastack callstack retainstack namestack catchstack
|
|
|
|
<continuation> ;
|
|
|
|
|
|
|
|
: >continuation< ( continuation -- data call retain name catch )
|
|
|
|
{
|
|
|
|
continuation-data
|
|
|
|
continuation-call
|
|
|
|
continuation-retain
|
|
|
|
continuation-name
|
|
|
|
continuation-catch
|
|
|
|
} get-slots ;
|
|
|
|
|
2007-10-03 16:56:49 -04:00
|
|
|
: ifcc ( capture restore -- )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! After continuation is being captured, the stacks looks
|
|
|
|
#! like:
|
2007-10-03 16:56:49 -04:00
|
|
|
#! ( f continuation r:capture r:restore )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! so the 'capture' branch is taken.
|
|
|
|
#!
|
|
|
|
#! Note that the continuation itself is not captured as part
|
|
|
|
#! of the datastack.
|
|
|
|
#!
|
|
|
|
#! BUT...
|
|
|
|
#!
|
2007-10-03 16:56:49 -04:00
|
|
|
#! After the continuation is resumed, (continue-with) pushes
|
|
|
|
#! the given value together with f,
|
2007-09-20 18:09:08 -04:00
|
|
|
#! so now, the stacks looks like:
|
2007-10-03 16:56:49 -04:00
|
|
|
#! ( value f r:capture r:restore )
|
2007-09-20 18:09:08 -04:00
|
|
|
#! Execution begins right after the call to 'continuation'.
|
|
|
|
#! The 'restore' branch is taken.
|
2007-10-03 17:35:48 -04:00
|
|
|
>r >r dummy continuation r> r> ?if ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-10-03 16:56:49 -04:00
|
|
|
: callcc0 ( quot -- ) [ drop ] ifcc ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-10-03 16:56:49 -04:00
|
|
|
: callcc1 ( quot -- obj ) [ ] ifcc ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
2007-10-05 01:08:18 -04:00
|
|
|
: (continue) ( continuation -- )
|
|
|
|
>continuation<
|
|
|
|
set-catchstack
|
|
|
|
set-namestack
|
|
|
|
set-retainstack
|
|
|
|
>r set-datastack r>
|
|
|
|
set-callstack ;
|
|
|
|
|
2007-10-03 16:56:49 -04:00
|
|
|
: (continue-with) ( obj continuation -- )
|
|
|
|
swap 4 setenv
|
2007-09-20 18:09:08 -04:00
|
|
|
>continuation<
|
|
|
|
set-catchstack
|
|
|
|
set-namestack
|
|
|
|
set-retainstack
|
2007-10-08 22:56:02 -04:00
|
|
|
>r set-datastack drop 4 getenv f 4 setenv f r>
|
2007-09-20 18:09:08 -04:00
|
|
|
set-callstack ;
|
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
2007-10-05 01:08:18 -04:00
|
|
|
: set-walker-hook ( quot -- ) 3 setenv ; inline
|
|
|
|
|
|
|
|
: walker-hook ( -- quot ) 3 getenv f set-walker-hook ; inline
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: continue-with ( obj continuation -- )
|
|
|
|
[
|
|
|
|
walker-hook [ >r 2array r> ] when* (continue-with)
|
2008-02-11 14:50:29 -05:00
|
|
|
] 2 (throw) ;
|
2007-09-20 18:09:08 -04:00
|
|
|
|
2007-10-03 16:56:49 -04:00
|
|
|
: continue ( continuation -- )
|
|
|
|
f swap continue-with ;
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
GENERIC: compute-restarts ( error -- seq )
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: save-error ( error -- )
|
|
|
|
dup error set-global
|
|
|
|
compute-restarts restarts set-global ;
|
|
|
|
|
|
|
|
PRIVATE>
|
|
|
|
|
2008-02-18 06:07:40 -05:00
|
|
|
SYMBOL: thread-error-hook
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
: rethrow ( error -- * )
|
2008-02-18 06:07:40 -05:00
|
|
|
catchstack* empty? [
|
|
|
|
thread-error-hook get-global
|
|
|
|
[ 1 (throw) ] [ die ] if*
|
|
|
|
] when
|
2007-09-20 18:09:08 -04:00
|
|
|
dup save-error c> continue-with ;
|
|
|
|
|
|
|
|
: recover ( try recovery -- )
|
2008-02-06 14:47:19 -05:00
|
|
|
>r [ swap >c call c> drop ] curry r> ifcc ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: cleanup ( try cleanup-always cleanup-error -- )
|
2007-12-29 12:35:51 -05:00
|
|
|
over >r compose [ dip rethrow ] curry
|
2008-01-12 14:09:49 -05:00
|
|
|
recover r> call ; inline
|
2007-09-20 18:09:08 -04:00
|
|
|
|
|
|
|
: attempt-all ( seq quot -- obj )
|
|
|
|
[
|
|
|
|
[ [ , f ] compose [ , drop t ] recover ] curry all?
|
|
|
|
] { } make peek swap [ rethrow ] when ; inline
|
|
|
|
|
2008-01-31 01:52:06 -05:00
|
|
|
GENERIC: dispose ( object -- )
|
|
|
|
|
|
|
|
: with-disposal ( object quot -- )
|
|
|
|
over [ dispose ] curry [ ] cleanup ; inline
|
|
|
|
|
2007-09-20 18:09:08 -04:00
|
|
|
TUPLE: condition restarts continuation ;
|
|
|
|
|
|
|
|
: <condition> ( error restarts cc -- condition )
|
|
|
|
{
|
|
|
|
set-delegate
|
|
|
|
set-condition-restarts
|
|
|
|
set-condition-continuation
|
|
|
|
} condition construct ;
|
|
|
|
|
|
|
|
: throw-restarts ( error restarts -- restart )
|
|
|
|
[ <condition> throw ] callcc1 2nip ;
|
|
|
|
|
|
|
|
: rethrow-restarts ( error restarts -- restart )
|
|
|
|
[ <condition> rethrow ] callcc1 2nip ;
|
|
|
|
|
|
|
|
TUPLE: restart name obj continuation ;
|
|
|
|
|
|
|
|
C: <restart> restart
|
|
|
|
|
|
|
|
: restart ( restart -- )
|
|
|
|
dup restart-obj swap restart-continuation continue-with ;
|
|
|
|
|
|
|
|
M: object compute-restarts drop { } ;
|
|
|
|
|
|
|
|
M: tuple compute-restarts delegate compute-restarts ;
|
|
|
|
|
|
|
|
M: condition compute-restarts
|
|
|
|
[ delegate compute-restarts ] keep
|
|
|
|
[ condition-restarts ] keep
|
|
|
|
condition-continuation
|
|
|
|
[ <restart> ] curry { } assoc>map
|
|
|
|
append ;
|
|
|
|
|
|
|
|
<PRIVATE
|
|
|
|
|
|
|
|
: init-error-handler ( -- )
|
|
|
|
V{ } clone set-catchstack
|
|
|
|
! VM calls on error
|
|
|
|
[
|
|
|
|
continuation error-continuation set-global rethrow
|
|
|
|
] 5 setenv
|
|
|
|
! VM adds this to kernel errors, so that user-space
|
|
|
|
! can identify them
|
|
|
|
"kernel-error" 6 setenv ;
|
|
|
|
|
|
|
|
PRIVATE>
|
2007-10-05 01:08:18 -04:00
|
|
|
|
|
|
|
! Debugging support
|
|
|
|
: with-walker-hook ( continuation -- )
|
|
|
|
[ swap set-walker-hook (continue) ] curry callcc1 ;
|
|
|
|
|
|
|
|
SYMBOL: break-hook
|
|
|
|
|
|
|
|
: break ( -- )
|
|
|
|
continuation callstack
|
|
|
|
over set-continuation-call
|
|
|
|
walker-hook [ (continue-with) ] [ break-hook get call ] if* ;
|
|
|
|
|
|
|
|
GENERIC: (step-into) ( obj -- )
|
|
|
|
|
|
|
|
M: wrapper (step-into) wrapped break ;
|
|
|
|
M: object (step-into) break ;
|
2007-10-07 18:17:14 -04:00
|
|
|
M: callable (step-into) \ break add* break ;
|