1
1
local create = coroutine.create
2
2
local resume = coroutine.resume
3
3
local yield = coroutine.yield
4
- local unpack = table.unpack or unpack
4
+ local unpack0 = table.unpack or unpack
5
+
6
+ local unpack = function (t )
7
+ if t and # t > 0 then
8
+ return unpack0 (t )
9
+ end
10
+ end
5
11
6
12
local Eff
7
13
do
@@ -59,6 +65,27 @@ local is_eff_obj = function(obj)
59
65
return type (obj ) == " table" and (obj .cls == Eff .cls or obj .cls == Resend .cls )
60
66
end
61
67
68
+ local function get_effh (eff , effeffhs )
69
+ eff = tostring (eff )
70
+
71
+ for i = 1 , # effeffhs do
72
+ if tostring (effeffhs [i ][1 ]) == eff then
73
+ return effeffhs [i ][2 ]
74
+ end
75
+ end
76
+ end
77
+
78
+ local function handle_error_message (r )
79
+ if type (r ) == " string" and
80
+ (r :match (" attempt to yield from outside a coroutine" )
81
+ or r :match (" cannot resume dead coroutine" ))
82
+ then
83
+ return error (" continuation cannot be performed twice" )
84
+ else
85
+ return error (r )
86
+ end
87
+ end
88
+
62
89
local handler
63
90
handler = function (eff , vh , effh )
64
91
local is_the_eff = function (it )
@@ -72,7 +99,7 @@ handler = function(eff, vh, effh)
72
99
local continue
73
100
74
101
local rehandle = function (arg , k )
75
- return handler (eff , function (... ) return continue (gr , ... ) end , effh )(function ()
102
+ return handler (eff , function (args ) return continue (gr , unpack ( args ) ) end , effh )(function ()
76
103
return k (arg )
77
104
end )
78
105
end
@@ -108,14 +135,66 @@ handler = function(eff, vh, effh)
108
135
continue = function (co , arg )
109
136
local st , r = resume (co , arg )
110
137
if not st then
111
- if type (r ) == " string" and
112
- (r :match (" attempt to yield from outside a coroutine" )
113
- or r :match (" cannot resume dead coroutine" ))
114
- then
115
- return error (" continuation cannot be performed twice" )
138
+ return handle_error_message (r )
139
+ else
140
+ return handle (r )
141
+ end
142
+ end
143
+
144
+ return continue (gr , nil )
145
+ end
146
+ end
147
+
148
+ local handlers
149
+ handlers = function (vh , ...)
150
+ local effeffhs = {... }
151
+
152
+ return function (th )
153
+ local gr = create (th )
154
+
155
+ local handle
156
+ local continue
157
+
158
+ local rehandles = function (arg , k )
159
+ return handlers (function (...) return continue (gr , ... ) end , unpack (effeffhs ))(function ()
160
+ return k (arg )
161
+ end )
162
+ end
163
+
164
+ handle = function (r )
165
+ if not is_eff_obj (r ) then
166
+ return vh (r )
167
+ end
168
+
169
+ if r .cls == Eff .cls then
170
+ local effh = get_effh (r .eff , effeffhs )
171
+ if effh then
172
+ return effh (function (arg )
173
+ return continue (gr , arg )
174
+ end , unpack (r .arg ))
175
+ else
176
+ return Resend (r , function (arg )
177
+ return continue (gr , arg )
178
+ end )
179
+ end
180
+ elseif r .cls == Resend .cls then
181
+ local effh = get_effh (r .eff , effeffhs )
182
+ if effh then
183
+ return effh (function (arg )
184
+ return rehandles (arg , r .continue )
185
+ end , unpack (r .arg ))
116
186
else
117
- return error (r )
187
+ return Resend (r , function (arg )
188
+ return rehandles (arg , r .continue )
189
+ end )
118
190
end
191
+ end
192
+ end
193
+
194
+ continue = function (co , arg )
195
+ local st , r = resume (co , arg )
196
+ if not st then
197
+ return handle_error_message (r )
119
198
else
120
199
return handle (r )
121
200
end
@@ -125,9 +204,11 @@ handler = function(eff, vh, effh)
125
204
end
126
205
end
127
206
207
+
128
208
return {
129
209
Eff = Eff ,
130
210
perform = yield ,
131
211
handler = handler ,
212
+ handlers = handlers
132
213
}
133
214
0 commit comments