]> gitweb.factorcode.org Git - factor.git/blob - core/continuations/continuations.factor
bfcca41587bb33f249cd85faecd130b4028901e3
[factor.git] / core / continuations / continuations.factor
1 ! Copyright (C) 2003, 2011 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays vectors kernel kernel.private sequences
4 namespaces make math splitting sorting quotations assocs
5 combinators combinators.private accessors words ;
6 IN: continuations
7
8 : with-datastack ( stack quot -- new-stack )
9     [
10         [ [ datastack ] dip swap [ { } like set-datastack ] dip ] dip
11         swap [ call datastack ] dip
12         swap [ set-datastack ] dip
13     ] (( stack quot -- new-stack )) call-effect-unsafe ;
14
15 SYMBOL: original-error
16 SYMBOL: error
17 SYMBOL: error-continuation
18 SYMBOL: error-thread
19 SYMBOL: restarts
20
21 <PRIVATE
22
23 : catchstack* ( -- catchstack )
24     1 context-object { vector } declare ; inline
25
26 ! We have to defeat some optimizations to make continuations work
27 : dummy-1 ( -- obj ) f ;
28 : dummy-2 ( obj -- obj ) ;
29
30 : catchstack ( -- catchstack ) catchstack* clone ; inline
31
32 : set-catchstack ( catchstack -- )
33     >vector 1 set-context-object ; inline
34
35 : init-catchstack ( -- ) f set-catchstack ;
36
37 PRIVATE>
38
39 TUPLE: continuation data call retain name catch ;
40
41 C: <continuation> continuation
42
43 : continuation ( -- continuation )
44     datastack callstack retainstack namestack catchstack
45     <continuation> ;
46
47 <PRIVATE
48
49 : >continuation< ( continuation -- data call retain name catch )
50     { [ data>> ] [ call>> ] [ retain>> ] [ name>> ] [ catch>> ] } cleave ;
51
52 PRIVATE>
53
54 : ifcc ( capture restore -- )
55     [ dummy-1 continuation ] 2dip [ dummy-2 ] prepose ?if ; inline
56
57 : callcc0 ( quot -- ) [ drop ] ifcc ; inline
58
59 : callcc1 ( quot -- obj ) [ ] ifcc ; inline
60
61 <PRIVATE
62
63 : (continue) ( continuation -- * )
64     [
65         >continuation<
66         set-catchstack
67         set-namestack
68         set-retainstack
69         [ set-datastack ] dip
70         set-callstack
71     ] (( continuation -- * )) call-effect-unsafe ;
72
73 PRIVATE>
74
75 : continue-with ( obj continuation -- * )
76     [
77         swap 4 set-special-object
78         >continuation<
79         set-catchstack
80         set-namestack
81         set-retainstack
82         [ set-datastack drop 4 special-object f 4 set-special-object f ] dip
83         set-callstack
84     ] (( obj continuation -- * )) call-effect-unsafe ;
85
86 : continue ( continuation -- * )
87     f swap continue-with ;
88
89 SYMBOL: return-continuation
90
91 : with-return ( quot -- )
92     [ [ return-continuation set ] prepose callcc0 ] with-scope ; inline
93
94 : return ( -- * )
95     return-continuation get continue ;
96
97 GENERIC: compute-restarts ( error -- seq )
98
99 <PRIVATE
100
101 : save-error ( error -- )
102     [ error set-global ]
103     [ compute-restarts restarts set-global ] bi ;
104
105 PRIVATE>
106
107 GENERIC: error-in-thread ( error thread -- * )
108
109 SYMBOL: thread-error-hook ! ( error thread -- )
110
111 thread-error-hook [ [ die ] ] initialize
112
113 M: object error-in-thread ( error thread -- * )
114     thread-error-hook get-global call( error thread -- * ) ;
115
116 : in-callback? ( -- ? ) 3 context-object ;
117
118 SYMBOL: callback-error-hook ! ( error -- * )
119
120 callback-error-hook [ [ die ] ] initialize
121
122 : rethrow ( error -- * )
123     dup save-error
124     catchstack* [
125         in-callback?
126         [ callback-error-hook get-global call( error -- * ) ]
127         [ 63 special-object error-in-thread ]
128         if
129     ] [ pop continue-with ] if-empty ;
130
131 : recover ( ..a try: ( ..a -- ..b ) recovery: ( ..a error -- ..b ) -- ..b )
132     [
133         [
134             [ catchstack* push ] dip
135             call
136             catchstack* pop*
137         ] curry
138     ] dip ifcc ; inline
139
140 : ignore-errors ( quot -- )
141     [ drop ] recover ; inline
142
143 : cleanup ( try cleanup-always cleanup-error -- )
144     [ compose [ dip rethrow ] curry recover ] [ drop ] 2bi call ; inline
145
146 ERROR: attempt-all-error ;
147
148 : attempt-all ( ... seq quot: ( ... elt -- ... obj ) -- ... obj )
149     over empty? [
150         attempt-all-error
151     ] [
152         [
153             [ [ , f ] compose [ , drop t ] recover ] curry all?
154         ] { } make last swap [ rethrow ] when
155     ] if ; inline
156
157 TUPLE: condition error restarts continuation ;
158
159 C: <condition> condition ( error restarts cc -- condition )
160
161 : throw-restarts ( error restarts -- restart )
162     [ <condition> throw ] callcc1 2nip ;
163
164 : rethrow-restarts ( error restarts -- restart )
165     [ <condition> rethrow ] callcc1 2nip ;
166
167 : throw-continue ( error -- )
168     { { "Continue" t } } throw-restarts drop ;
169
170 TUPLE: restart name obj continuation ;
171
172 C: <restart> restart
173
174 : restart ( restart -- * )
175     [ obj>> ] [ continuation>> ] bi continue-with ;
176
177 M: object compute-restarts drop { } ;
178
179 M: condition compute-restarts
180     [ error>> compute-restarts ]
181     [
182         [ restarts>> ]
183         [ continuation>> [ <restart> ] curry ] bi
184         { } assoc>map
185     ] bi append ;
186
187 <PRIVATE
188
189 : init-error-handler ( -- )
190     init-catchstack
191     ! VM calls on error
192     [
193         ! 63 = self
194         63 special-object error-thread set-global
195         continuation error-continuation set-global
196         [ original-error set-global ] [ rethrow ] bi
197     ] 5 set-special-object
198     ! VM adds this to kernel errors, so that user-space
199     ! can identify them
200     "kernel-error" 6 set-special-object ;
201
202 PRIVATE>