/src/moddable/xs/sources/xsError.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2025 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | static txSlot* fx_Error_aux(txMachine* the, txError error, txInteger i); |
41 | | |
42 | | const int gxErrorWhichPrototypeStackIndex[XS_ERROR_COUNT] ICACHE_FLASH_ATTR = { |
43 | | mxErrorPrototypeStackIndex, |
44 | | mxErrorPrototypeStackIndex, |
45 | | mxEvalErrorPrototypeStackIndex, |
46 | | mxRangeErrorPrototypeStackIndex, |
47 | | mxReferenceErrorPrototypeStackIndex, |
48 | | mxSyntaxErrorPrototypeStackIndex, |
49 | | mxTypeErrorPrototypeStackIndex, |
50 | | mxURIErrorPrototypeStackIndex, |
51 | | mxAggregateErrorPrototypeStackIndex, |
52 | | #if mxExplicitResourceManagement |
53 | | mxSuppressedErrorPrototypeStackIndex, |
54 | | #else |
55 | | mxErrorPrototypeStackIndex, |
56 | | #endif |
57 | | }; |
58 | | |
59 | | const char *const gxErrorNames[XS_ERROR_COUNT] ICACHE_FLASH_ATTR = { |
60 | | "no error", |
61 | | "Error", |
62 | | "EvalError", |
63 | | "RangeError", |
64 | | "ReferenceError", |
65 | | "SyntaxError", |
66 | | "TypeError", |
67 | | "URIError", |
68 | | "AggregateError", |
69 | | "SuppressedError" |
70 | | }; |
71 | | |
72 | | void fxBuildError(txMachine* the) |
73 | 27.5k | { |
74 | 27.5k | txSlot* slot; |
75 | 27.5k | txSlot* prototype; |
76 | 27.5k | txSlot* instance; |
77 | 27.5k | #if mxExplicitResourceManagement |
78 | 27.5k | txSlot* property; |
79 | 27.5k | #endif |
80 | | |
81 | 27.5k | mxPush(mxObjectPrototype); |
82 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
83 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
84 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_UNKNOWN_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
85 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
86 | 27.5k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_Error_prototype_get_stack), mxCallback(fx_Error_prototype_set_stack), mxID(_stack), XS_DONT_ENUM_FLAG); |
87 | 27.5k | mxErrorPrototype = *the->stack; |
88 | 27.5k | prototype = fxBuildHostConstructor(the, mxCallback(fx_Error), 1, mxID(_Error)); |
89 | 27.5k | mxErrorConstructor = *the->stack; |
90 | 27.5k | #if mxErrorIsError |
91 | 27.5k | slot = fxLastProperty(the, prototype); |
92 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_isError), 1, mxID(_isError), XS_DONT_ENUM_FLAG); |
93 | 27.5k | #endif |
94 | 27.5k | mxPop(); |
95 | 27.5k | mxPush(mxErrorPrototype); |
96 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
97 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_AGGREGATE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
98 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
99 | 27.5k | mxAggregateErrorPrototype = *the->stack; |
100 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_AggregateError), 2, mxID(_AggregateError)); |
101 | 27.5k | instance->value.instance.prototype = prototype; |
102 | 27.5k | mxAggregateErrorConstructor = *the->stack; |
103 | 27.5k | mxPop(); |
104 | 27.5k | mxPush(mxErrorPrototype); |
105 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
106 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_EVAL_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
107 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
108 | 27.5k | mxEvalErrorPrototype = *the->stack; |
109 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_EvalError), 1, mxID(_EvalError)); |
110 | 27.5k | instance->value.instance.prototype = prototype; |
111 | 27.5k | mxEvalErrorConstructor = *the->stack; |
112 | 27.5k | mxPop(); |
113 | 27.5k | mxPush(mxErrorPrototype); |
114 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
115 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_RANGE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
116 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
117 | 27.5k | mxRangeErrorPrototype = *the->stack; |
118 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_RangeError), 1, mxID(_RangeError)); |
119 | 27.5k | instance->value.instance.prototype = prototype; |
120 | 27.5k | mxRangeErrorConstructor = *the->stack; |
121 | 27.5k | mxPop(); |
122 | 27.5k | mxPush(mxErrorPrototype); |
123 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
124 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_REFERENCE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
125 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
126 | 27.5k | mxReferenceErrorPrototype = *the->stack; |
127 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_ReferenceError), 1, mxID(_ReferenceError)); |
128 | 27.5k | instance->value.instance.prototype = prototype; |
129 | 27.5k | mxReferenceErrorConstructor = *the->stack; |
130 | 27.5k | mxPop(); |
131 | 27.5k | mxPush(mxErrorPrototype); |
132 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
133 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_SYNTAX_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
134 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
135 | 27.5k | mxSyntaxErrorPrototype = *the->stack; |
136 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_SyntaxError), 1, mxID(_SyntaxError)); |
137 | 27.5k | instance->value.instance.prototype = prototype; |
138 | 27.5k | mxSyntaxErrorConstructor = *the->stack; |
139 | 27.5k | mxPop(); |
140 | 27.5k | mxPush(mxErrorPrototype); |
141 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
142 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_TYPE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
143 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
144 | 27.5k | mxTypeErrorPrototype = *the->stack; |
145 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_TypeError), 1, mxID(_TypeError)); |
146 | 27.5k | instance->value.instance.prototype = prototype; |
147 | 27.5k | mxTypeErrorConstructor = *the->stack; |
148 | 27.5k | mxPop(); |
149 | 27.5k | mxPush(mxErrorPrototype); |
150 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
151 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_URI_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
152 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
153 | 27.5k | mxURIErrorPrototype = *the->stack; |
154 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_URIError), 1, mxID(_URIError)); |
155 | 27.5k | instance->value.instance.prototype = prototype; |
156 | 27.5k | mxURIErrorConstructor = *the->stack; |
157 | 27.5k | mxPop(); |
158 | | |
159 | 27.5k | #if mxExplicitResourceManagement |
160 | 27.5k | mxPush(mxErrorPrototype); |
161 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
162 | 27.5k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_SUPPRESSED_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
163 | 27.5k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
164 | 27.5k | mxSuppressedErrorPrototype = *the->stack; |
165 | 27.5k | instance = fxBuildHostConstructor(the, mxCallback(fx_SuppressedError), 3, mxID(_SuppressedError)); |
166 | 27.5k | instance->value.instance.prototype = prototype; |
167 | 27.5k | mxSuppressedErrorConstructor = *the->stack; |
168 | 27.5k | mxPop(); |
169 | | |
170 | 27.5k | mxPush(mxObjectPrototype); |
171 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
172 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
173 | 27.5k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DisposableStack_prototype_get_disposed), C_NULL, mxID(_disposed), XS_DONT_ENUM_FLAG); |
174 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_adopt), 2, mxID(_adopt), XS_DONT_ENUM_FLAG); |
175 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_defer), 1, mxID(_defer), XS_DONT_ENUM_FLAG); |
176 | 27.5k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_dispose), 0, mxID(_dispose), XS_DONT_ENUM_FLAG); |
177 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_move), 0, mxID(_move), XS_DONT_ENUM_FLAG); |
178 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_use), 1, mxID(_use), XS_DONT_ENUM_FLAG); |
179 | 27.5k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_dispose), XS_DONT_ENUM_FLAG); |
180 | 27.5k | slot = fxNextStringXProperty(the, slot, "DisposableStack", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
181 | 27.5k | mxDisposableStackPrototype = *the->stack; |
182 | 27.5k | slot = fxBuildHostConstructor(the, mxCallback(fx_DisposableStack), 0, mxID(_DisposableStack)); |
183 | 27.5k | mxDisposableStackConstructor = *the->stack; |
184 | 27.5k | mxPop(); |
185 | | |
186 | 27.5k | mxPush(mxObjectPrototype); |
187 | 27.5k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
188 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
189 | 27.5k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_get_disposed), C_NULL, mxID(_disposed), XS_DONT_ENUM_FLAG); |
190 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_adopt), 2, mxID(_adopt), XS_DONT_ENUM_FLAG); |
191 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_defer), 1, mxID(_defer), XS_DONT_ENUM_FLAG); |
192 | 27.5k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_disposeAsync), 0, mxID(_disposeAsync), XS_DONT_ENUM_FLAG); |
193 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_move), 0, mxID(_move), XS_DONT_ENUM_FLAG); |
194 | 27.5k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_use), 1, mxID(_use), XS_DONT_ENUM_FLAG); |
195 | 27.5k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_asyncDispose), XS_DONT_ENUM_FLAG); |
196 | 27.5k | slot = fxNextStringXProperty(the, slot, "AsyncDisposableStack", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
197 | 27.5k | mxAsyncDisposableStackPrototype = *the->stack; |
198 | 27.5k | slot = fxBuildHostConstructor(the, mxCallback(fx_AsyncDisposableStack), 0, mxID(_AsyncDisposableStack)); |
199 | 27.5k | mxAsyncDisposableStackConstructor = *the->stack; |
200 | 27.5k | mxPop(); |
201 | 27.5k | #endif |
202 | 27.5k | } |
203 | | |
204 | | void fxCaptureErrorStack(txMachine* the, txSlot* internal, txSlot* frame) |
205 | 1.68M | { |
206 | 1.68M | txSlot* slot = internal->value.reference = fxNewSlot(the); |
207 | 1.68M | slot->kind = XS_INSTANCE_KIND; |
208 | 1.68M | slot->value.instance.garbage = C_NULL; |
209 | 1.68M | slot->value.instance.prototype = C_NULL; |
210 | 30.1M | while (frame->next) { |
211 | 28.4M | txSlot* environment = mxFrameToEnvironment(frame); |
212 | 28.4M | txSlot* function = frame + 3; |
213 | 28.4M | if (function->kind == XS_REFERENCE_KIND) { |
214 | 28.4M | function = function->value.reference; |
215 | 28.4M | if (mxIsFunction(function)) { |
216 | 28.4M | txSlot* name = mxBehaviorGetProperty(the, function, mxID(_name), 0, XS_OWN); |
217 | 28.4M | slot = slot->next = fxNewSlot(the); |
218 | 28.4M | slot->flag = XS_GET_ONLY; |
219 | 28.4M | slot->kind = XS_KEY_KIND; |
220 | 28.4M | slot->ID = environment->ID; |
221 | 28.4M | slot->value.key.string = C_NULL; |
222 | 28.4M | slot->value.key.sum = environment->value.environment.line; |
223 | 28.4M | if (name && ((name->kind == XS_STRING_KIND) || (name->kind == XS_STRING_X_KIND))) { |
224 | 28.4M | if (name->kind == XS_STRING_X_KIND) |
225 | 0 | slot->kind = XS_KEY_X_KIND; |
226 | 28.4M | slot->value.key.string = name->value.string; |
227 | 28.4M | } |
228 | 0 | else { |
229 | 0 | txSlot* code = mxFunctionInstanceCode(function); |
230 | 0 | if (code->ID != XS_NO_ID) { |
231 | 0 | txSlot* key = fxGetKey(the, code->ID); |
232 | 0 | if ((key->kind == XS_KEY_KIND) || (key->kind == XS_KEY_X_KIND)) { |
233 | 0 | slot->value.key.string = key->value.key.string; |
234 | 0 | slot->kind = key->kind; |
235 | 0 | } |
236 | 0 | else if (key->kind == XS_REFERENCE_KIND) { |
237 | 0 | name = key->value.reference->next->next; |
238 | 0 | if (name && ((name->kind == XS_STRING_KIND) || (name->kind == XS_STRING_X_KIND))) { |
239 | 0 | if (name->kind == XS_STRING_X_KIND) |
240 | 0 | slot->kind = XS_KEY_X_KIND; |
241 | 0 | slot->value.key.string = name->value.string; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | } |
245 | 0 | } |
246 | 28.4M | } |
247 | 28.4M | } |
248 | 28.4M | frame = frame->next; |
249 | 28.4M | } |
250 | 1.68M | } |
251 | | |
252 | | void fx_Error(txMachine* the) |
253 | 56.2k | { |
254 | 56.2k | fx_Error_aux(the, XS_UNKNOWN_ERROR, 0); |
255 | 56.2k | } |
256 | | |
257 | | void fx_Error_isError(txMachine* the) |
258 | 268 | { |
259 | 268 | mxResult->kind = XS_BOOLEAN_KIND; |
260 | 268 | mxResult->value.boolean = 0; |
261 | 268 | if (mxArgc > 0) { |
262 | 230 | txSlot* instance = fxGetInstance(the, mxArgv(0)); |
263 | 230 | if (instance) { |
264 | 171 | txSlot* internal = instance->next; |
265 | 171 | if (internal && (internal->kind == XS_ERROR_KIND)) { |
266 | 142 | mxResult->value.boolean = 1; |
267 | 142 | } |
268 | 171 | } |
269 | 230 | } |
270 | 268 | } |
271 | | |
272 | | txSlot* fx_Error_aux(txMachine* the, txError error, txInteger i) |
273 | 374k | { |
274 | 374k | txSlot* instance; |
275 | 374k | txSlot* slot; |
276 | 374k | if (mxIsUndefined(mxTarget)) |
277 | 222 | mxPushSlot(mxFunction); |
278 | 373k | else |
279 | 373k | mxPushSlot(mxTarget); |
280 | 374k | fxGetPrototypeFromConstructor(the, &mxErrorPrototypes(error)); |
281 | 374k | instance = fxNewObjectInstance(the); |
282 | 374k | mxPullSlot(mxResult); |
283 | 374k | slot = instance->next = fxNewSlot(the); |
284 | 374k | slot->flag = XS_INTERNAL_FLAG; |
285 | 374k | slot->kind = XS_ERROR_KIND; |
286 | 374k | slot->value.error.info = C_NULL; |
287 | 374k | slot->value.error.which = error; |
288 | 374k | if (gxDefaults.captureErrorStack) |
289 | 374k | gxDefaults.captureErrorStack(the, slot, the->frame->next); |
290 | 374k | if ((mxArgc > i) && (mxArgv(i)->kind != XS_UNDEFINED_KIND)) { |
291 | 350k | fxToString(the, mxArgv(i)); |
292 | 350k | slot = fxNextSlotProperty(the, slot, mxArgv(i), mxID(_message), XS_DONT_ENUM_FLAG); |
293 | 350k | } |
294 | 374k | i++; |
295 | 374k | if ((mxArgc > i) && (mxArgv(i)->kind == XS_REFERENCE_KIND)) { |
296 | 32.5k | if (mxBehaviorHasProperty(the, mxArgv(i)->value.reference, mxID(_cause), 0)) { |
297 | 1 | mxPushSlot(mxArgv(i)); |
298 | 1 | mxGetID(mxID(_cause)); |
299 | 1 | slot = fxNextSlotProperty(the, slot, the->stack, mxID(_cause), XS_DONT_ENUM_FLAG); |
300 | 1 | mxPop(); |
301 | 1 | } |
302 | 32.5k | } |
303 | 374k | return slot; |
304 | 374k | } |
305 | | |
306 | | void fx_Error_toString(txMachine* the) |
307 | 185k | { |
308 | 185k | txSlot* name; |
309 | 185k | txSlot* message; |
310 | 185k | if (mxThis->kind != XS_REFERENCE_KIND) |
311 | 9 | mxTypeError("this: not an object"); |
312 | 185k | mxPushSlot(mxThis); |
313 | 185k | mxGetID(mxID(_name)); |
314 | 185k | if (the->stack->kind == XS_UNDEFINED_KIND) |
315 | 185k | fxStringX(the, the->stack, "Error"); |
316 | 118 | else |
317 | 118 | fxToString(the, the->stack); |
318 | 185k | name = the->stack; |
319 | 185k | mxPushSlot(mxThis); |
320 | 185k | mxGetID(mxID(_message)); |
321 | 185k | if (the->stack->kind == XS_UNDEFINED_KIND) |
322 | 185k | *the->stack = mxEmptyString; |
323 | 119 | else |
324 | 119 | fxToString(the, the->stack); |
325 | 185k | message = the->stack; |
326 | 185k | if (c_isEmpty(name->value.string)) |
327 | 3 | *mxResult = *message; |
328 | 185k | else if (c_isEmpty(message->value.string)) |
329 | 185k | *mxResult = *name; |
330 | 93 | else { |
331 | 93 | fxStringX(the, mxResult, ""); |
332 | 93 | fxConcatString(the, mxResult, name); |
333 | 93 | fxConcatStringC(the, mxResult, ": "); |
334 | 93 | fxConcatString(the, mxResult, message); |
335 | 93 | } |
336 | 185k | the->stack += 2; |
337 | 185k | } |
338 | | |
339 | | void fx_AggregateError(txMachine* the) |
340 | 101 | { |
341 | 101 | txSlot* stack = the->stack; |
342 | 101 | txSlot* property = fx_Error_aux(the, XS_AGGREGATE_ERROR, 1); |
343 | 101 | txSlot* array; |
344 | 101 | txSlot** address; |
345 | 101 | txIndex length = 0; |
346 | 101 | txSlot* iterator; |
347 | 101 | txSlot* next; |
348 | 101 | txSlot* value; |
349 | 101 | txSlot* slot; |
350 | | |
351 | 101 | mxPush(mxArrayPrototype); |
352 | 101 | array = fxNewArrayInstance(the); |
353 | 101 | fxNextSlotProperty(the, property, the->stack, mxID(_errors), XS_DONT_ENUM_FLAG); |
354 | 101 | address = &array->next->next; |
355 | 101 | mxTemporary(iterator); |
356 | 101 | mxTemporary(next); |
357 | 101 | fxGetIterator(the, mxArgv(0), iterator, next, 0); |
358 | 101 | mxTemporary(value); |
359 | 39.7k | while (fxIteratorNext(the, iterator, next, value)) { |
360 | 39.6k | mxTry(the) { |
361 | 39.6k | *address = slot = fxNewSlot(the); |
362 | 39.6k | slot->kind = value->kind; |
363 | 39.6k | slot->value = value->value; |
364 | 39.6k | address = &slot->next; |
365 | 39.6k | length++; |
366 | 39.6k | } |
367 | 39.6k | mxCatch(the) { |
368 | 0 | fxIteratorReturn(the, iterator, 1); |
369 | 0 | fxJump(the); |
370 | 0 | } |
371 | 39.6k | } |
372 | 101 | array->next->value.array.length = length; |
373 | 101 | fxCacheArray(the, array); |
374 | | |
375 | 101 | the->stack = stack; |
376 | 101 | } |
377 | | |
378 | | void fx_EvalError(txMachine* the) |
379 | 117 | { |
380 | 117 | fx_Error_aux(the, XS_EVAL_ERROR, 0); |
381 | 117 | } |
382 | | |
383 | | void fx_RangeError(txMachine* the) |
384 | 76 | { |
385 | 76 | fx_Error_aux(the, XS_RANGE_ERROR, 0); |
386 | 76 | } |
387 | | |
388 | | void fx_ReferenceError(txMachine* the) |
389 | 5 | { |
390 | 5 | fx_Error_aux(the, XS_REFERENCE_ERROR, 0); |
391 | 5 | } |
392 | | |
393 | | void fx_SyntaxError(txMachine* the) |
394 | 317k | { |
395 | 317k | fx_Error_aux(the, XS_SYNTAX_ERROR, 0); |
396 | 317k | } |
397 | | |
398 | | void fx_TypeError(txMachine* the) |
399 | 99 | { |
400 | 99 | fx_Error_aux(the, XS_TYPE_ERROR, 0); |
401 | 99 | } |
402 | | |
403 | | void fx_URIError(txMachine* the) |
404 | 5 | { |
405 | 5 | fx_Error_aux(the, XS_URI_ERROR, 0); |
406 | 5 | } |
407 | | |
408 | | void fx_Error_prototype_get_stack(txMachine* the) |
409 | 2 | { |
410 | 2 | txSlot* slot; |
411 | 2 | if (mxThis->kind != XS_REFERENCE_KIND) |
412 | 0 | mxTypeError("this: not an object"); |
413 | 2 | slot = mxThis->value.reference->next; |
414 | 2 | if (slot && (slot->kind == XS_ERROR_KIND)) { |
415 | 2 | fxStringX(the, mxResult, ""); |
416 | 2 | mxPushSlot(mxThis); |
417 | 2 | mxGetID(mxID(_name)); |
418 | 2 | if (the->stack->kind != XS_UNDEFINED_KIND) { |
419 | 2 | fxToString(the, the->stack); |
420 | 2 | fxConcatString(the, mxResult, the->stack); |
421 | 2 | } |
422 | 0 | else |
423 | 0 | fxConcatStringC(the, mxResult, "Error"); |
424 | 2 | mxPop(); |
425 | 2 | mxPushSlot(mxThis); |
426 | 2 | mxGetID(mxID(_message)); |
427 | 2 | if (the->stack->kind != XS_UNDEFINED_KIND) { |
428 | 2 | fxToString(the, the->stack); |
429 | 2 | if (!c_isEmpty(the->stack->value.string)) { |
430 | 1 | fxConcatStringC(the, mxResult, ": "); |
431 | 1 | fxConcatString(the, mxResult, the->stack); |
432 | 1 | } |
433 | 2 | } |
434 | 2 | mxPop(); |
435 | 2 | slot = slot->value.reference; |
436 | 2 | if (slot) { |
437 | 2 | slot = slot->next; |
438 | 4 | while (slot) { |
439 | 2 | fxConcatStringC(the, mxResult, "\n at"); |
440 | 2 | if ((slot->value.key.string != C_NULL) && (mxStringLength(slot->value.key.string))) { |
441 | 0 | fxConcatStringC(the, mxResult, " "); |
442 | 0 | fxConcatString(the, mxResult, slot); |
443 | 0 | } |
444 | 2 | fxConcatStringC(the, mxResult, " ("); |
445 | 2 | if (slot->ID != XS_NO_ID) { |
446 | 2 | fxIDToString(the, slot->ID, the->nameBuffer, sizeof(the->nameBuffer)); |
447 | 2 | fxConcatStringC(the, mxResult, the->nameBuffer); |
448 | 2 | fxConcatStringC(the, mxResult, ":"); |
449 | 2 | fxIntegerToString(the, (txInteger)slot->value.key.sum, the->nameBuffer, sizeof(the->nameBuffer)); |
450 | 2 | fxConcatStringC(the, mxResult, the->nameBuffer); |
451 | 2 | } |
452 | 2 | fxConcatStringC(the, mxResult, ")"); |
453 | 2 | slot = slot->next; |
454 | 2 | } |
455 | 2 | } |
456 | 2 | } |
457 | 2 | } |
458 | | |
459 | | void fx_Error_prototype_set_stack(txMachine* the) |
460 | 0 | { |
461 | 0 | if (mxThis->kind != XS_REFERENCE_KIND) |
462 | 0 | mxTypeError("this: not an object"); |
463 | 0 | if (mxArgc < 1) |
464 | 0 | mxTypeError("no value"); |
465 | 0 | mxPushSlot(mxArgv(0)); |
466 | 0 | mxPushSlot(mxThis); |
467 | 0 | mxDefineID(mxID(_stack), XS_NO_FLAG, XS_GET_ONLY); |
468 | 0 | mxPop(); |
469 | 0 | } |
470 | | |
471 | | static const txString gXSAbortStrings[] = { |
472 | | "debugger", |
473 | | "memory full", |
474 | | "JavaScript stack overflow", |
475 | | "fatal", |
476 | | "dead strip", |
477 | | "unhandled exception", |
478 | | "not enough keys", |
479 | | "too much computation", |
480 | | "unhandled rejection", |
481 | | "native stack overflow", |
482 | | }; |
483 | | |
484 | | txString fxAbortString(int status) |
485 | 0 | { |
486 | 0 | if ((status < 0) || (status >= (int)(sizeof(gXSAbortStrings) / sizeof(txString)))) |
487 | 0 | return "unknown"; |
488 | | |
489 | 0 | return gXSAbortStrings[status]; |
490 | 0 | } |
491 | | |
492 | | #if mxExplicitResourceManagement |
493 | | |
494 | | void fx_SuppressedError(txMachine* the) |
495 | 18 | { |
496 | 18 | txSlot* property = fx_Error_aux(the, XS_SUPPRESSED_ERROR, 2); |
497 | 18 | property = fxNextSlotProperty(the, property, mxArgv(0), mxID(_error), XS_DONT_ENUM_FLAG); |
498 | 18 | property = fxNextSlotProperty(the, property, mxArgv(1), mxID(_suppressed), XS_DONT_ENUM_FLAG); |
499 | 18 | } |
500 | | |
501 | | static txSlot* fxCheckDisposableStackInstance(txMachine* the, txSlot* slot, txBoolean mutable, txBoolean disposable); |
502 | | static void fxDisposableStackPush(txMachine* the, txSlot* property); |
503 | | |
504 | | txSlot* fxCheckDisposableStackInstance(txMachine* the, txSlot* slot, txBoolean mutable, txBoolean disposable) |
505 | 271 | { |
506 | 271 | if (slot->kind == XS_REFERENCE_KIND) { |
507 | 201 | txSlot* instance = slot->value.reference; |
508 | 201 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_DISPOSABLE_STACK_KIND)) { |
509 | 149 | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
510 | 0 | mxTypeError("this: read-only DisposableStack instance"); |
511 | 149 | if (disposable && slot->value.disposableStack.disposed) |
512 | 20 | mxReferenceError("this: disposed DisposableStack instance"); |
513 | 129 | return instance; |
514 | 149 | } |
515 | 201 | } |
516 | 271 | mxTypeError("this: not a DisposableStack instance"); |
517 | 0 | return C_NULL; |
518 | 271 | } |
519 | | |
520 | | void fx_DisposableStack(txMachine* the) |
521 | 817 | { |
522 | 817 | txSlot* instance; |
523 | 817 | txSlot* property; |
524 | 817 | if (mxIsUndefined(mxTarget)) |
525 | 1 | mxTypeError("call: DisposableStack"); |
526 | 816 | mxPushSlot(mxTarget); |
527 | 816 | fxGetPrototypeFromConstructor(the, &mxDisposableStackPrototype); |
528 | 816 | instance = fxNewSlot(the); |
529 | 816 | instance->kind = XS_INSTANCE_KIND; |
530 | 816 | instance->value.instance.garbage = C_NULL; |
531 | 816 | instance->value.instance.prototype = the->stack->value.reference; |
532 | 816 | the->stack->kind = XS_REFERENCE_KIND; |
533 | 816 | the->stack->value.reference = instance; |
534 | 816 | mxPullSlot(mxResult); |
535 | 816 | property = instance->next = fxNewSlot(the); |
536 | 816 | property->flag = XS_INTERNAL_FLAG; |
537 | 816 | property->kind = XS_DISPOSABLE_STACK_KIND; |
538 | 816 | property->value.disposableStack.stack = C_NULL; |
539 | 816 | property->value.disposableStack.disposed = 0; |
540 | 816 | } |
541 | | |
542 | | void fx_DisposableStack_prototype_get_disposed(txMachine* the) |
543 | 16 | { |
544 | 16 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 0, 0); |
545 | 16 | txSlot* property = instance->next; |
546 | 16 | mxResult->value.boolean = property->value.disposableStack.disposed; |
547 | 16 | mxResult->kind = XS_BOOLEAN_KIND; |
548 | 16 | } |
549 | | |
550 | | void fx_DisposableStack_prototype_adopt(txMachine* the) |
551 | 62 | { |
552 | 62 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
553 | 62 | txSlot* property = instance->next; |
554 | 62 | if (mxArgc > 0) |
555 | 42 | mxPushSlot(mxArgv(0)); |
556 | 20 | else |
557 | 20 | mxPushUndefined(); |
558 | 62 | if (mxArgc > 1) |
559 | 41 | mxPushSlot(mxArgv(1)); |
560 | 21 | else |
561 | 21 | mxPushUndefined(); |
562 | 62 | fxDisposableStackPush(the, property); |
563 | 62 | property->value.disposableStack.stack->flag |= XS_BASE_FLAG; |
564 | 62 | mxPop(); |
565 | 62 | mxPullSlot(mxResult); |
566 | 62 | } |
567 | | |
568 | | void fx_DisposableStack_prototype_defer(txMachine* the) |
569 | 55 | { |
570 | 55 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
571 | 55 | txSlot* property = instance->next; |
572 | 55 | mxPushUndefined(); |
573 | 55 | if (mxArgc > 0) |
574 | 29 | mxPushSlot(mxArgv(0)); |
575 | 26 | else |
576 | 26 | mxPushUndefined(); |
577 | 55 | fxDisposableStackPush(the, property); |
578 | 55 | mxPop(); |
579 | 55 | mxPop(); |
580 | 55 | } |
581 | | |
582 | | void fx_DisposableStack_prototype_dispose(txMachine* the) |
583 | 52 | { |
584 | 52 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 0); |
585 | 52 | txSlot* property = instance->next; |
586 | 52 | txSlot* exception; |
587 | 52 | txBoolean selector = 1; |
588 | 52 | txSlot* slot; |
589 | 52 | if (property->value.disposableStack.disposed) |
590 | 6 | return; |
591 | 46 | property->value.disposableStack.disposed = 1; |
592 | 46 | mxTemporary(exception); |
593 | 46 | slot = property->value.disposableStack.stack; |
594 | 62 | while (slot) { |
595 | 16 | txSlot* dispose = slot; |
596 | 16 | txSlot* resource = slot->next; |
597 | 16 | mxTry(the) { |
598 | 16 | if (dispose->flag & XS_BASE_FLAG) { |
599 | 4 | mxPushUndefined(); |
600 | 4 | mxPushSlot(dispose); |
601 | 4 | mxCall(); |
602 | 4 | mxPushSlot(resource); |
603 | 4 | mxRunCount(1); |
604 | 4 | mxPop(); |
605 | 4 | } |
606 | 12 | else { |
607 | 12 | mxPushSlot(resource); |
608 | 12 | mxPushSlot(dispose); |
609 | 12 | mxCall(); |
610 | 12 | mxRunCount(0); |
611 | 12 | mxPop(); |
612 | 12 | } |
613 | 16 | } |
614 | 16 | mxCatch(the) { |
615 | 5 | if (selector == 0) { |
616 | 2 | mxPush(mxSuppressedErrorConstructor); |
617 | 2 | mxNew(); |
618 | 2 | mxPush(mxException); |
619 | 2 | mxPushSlot(exception); |
620 | 2 | mxRunCount(2); |
621 | 2 | mxPullSlot(exception); |
622 | 2 | } |
623 | 3 | else { |
624 | 3 | *exception = mxException; |
625 | 3 | selector = 0; |
626 | 3 | } |
627 | 5 | mxException = mxUndefined; |
628 | 5 | } |
629 | 16 | slot = resource->next; |
630 | 16 | } |
631 | 46 | if (selector == 0) { |
632 | 3 | mxException.kind = exception->kind; |
633 | 3 | mxException.value = exception->value; |
634 | 3 | fxJump(the); |
635 | 3 | } |
636 | 46 | } |
637 | | |
638 | | void fx_DisposableStack_prototype_move(txMachine* the) |
639 | 20 | { |
640 | 20 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
641 | 20 | txSlot* property = instance->next; |
642 | 20 | txSlot* resultInstance; |
643 | 20 | txSlot* resultProperty; |
644 | 20 | mxPush(mxDisposableStackConstructor); |
645 | 20 | fxGetPrototypeFromConstructor(the, &mxDisposableStackPrototype); |
646 | 20 | resultInstance = fxNewSlot(the); |
647 | 20 | resultInstance->kind = XS_INSTANCE_KIND; |
648 | 20 | resultInstance->value.instance.garbage = C_NULL; |
649 | 20 | resultInstance->value.instance.prototype = the->stack->value.reference; |
650 | 20 | the->stack->kind = XS_REFERENCE_KIND; |
651 | 20 | the->stack->value.reference = resultInstance; |
652 | 20 | mxPullSlot(mxResult); |
653 | 20 | resultProperty = resultInstance->next = fxNewSlot(the); |
654 | 20 | resultProperty->flag = XS_INTERNAL_FLAG; |
655 | 20 | resultProperty->kind = XS_DISPOSABLE_STACK_KIND; |
656 | 20 | resultProperty->value.disposableStack.stack = property->value.disposableStack.stack; |
657 | 20 | resultProperty->value.disposableStack.disposed = 0; |
658 | 20 | property->value.disposableStack.stack = C_NULL; |
659 | 20 | property->value.disposableStack.disposed = 1; |
660 | 20 | } |
661 | | |
662 | | void fx_DisposableStack_prototype_use(txMachine* the) |
663 | 66 | { |
664 | 66 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
665 | 66 | txSlot* property = instance->next; |
666 | 66 | txSlot* resource; |
667 | 66 | if (mxArgc > 0) |
668 | 21 | mxPushSlot(mxArgv(0)); |
669 | 45 | else |
670 | 45 | mxPushUndefined(); |
671 | 66 | resource = the->stack; |
672 | 66 | if (!mxIsNull(resource) && !mxIsUndefined(resource)) { |
673 | 16 | mxPushSlot(resource); |
674 | 16 | mxGetID(mxID(_Symbol_dispose)); |
675 | 16 | fxDisposableStackPush(the, property); |
676 | 16 | mxPop(); |
677 | 16 | } |
678 | 66 | mxPullSlot(mxResult); |
679 | 66 | } |
680 | | |
681 | | void fxDisposableStackPush(txMachine* the, txSlot* property) |
682 | 88 | { |
683 | 88 | txSlot* dispose = the->stack; |
684 | 88 | txSlot* resource = dispose + 1; |
685 | 88 | txSlot** address = &property->value.disposableStack.stack; |
686 | 88 | txSlot* slot; |
687 | 88 | if (!fxIsCallable(the, dispose)) |
688 | 52 | mxTypeError("dispose: not a function"); |
689 | | |
690 | 36 | slot = fxNewSlot(the); |
691 | 36 | slot->next = *address; |
692 | 36 | slot->kind = resource->kind; |
693 | 36 | slot->value = resource->value; |
694 | 36 | *address = slot; |
695 | | |
696 | 36 | slot = fxNewSlot(the); |
697 | 36 | slot->next = *address; |
698 | 36 | slot->kind = dispose->kind; |
699 | 36 | slot->value = dispose->value; |
700 | 36 | *address = slot; |
701 | 36 | } |
702 | | |
703 | | static txSlot* fxCheckAsyncDisposableStackInstance(txMachine* the, txSlot* slot, txBoolean mutable, txBoolean disposable); |
704 | | static void fxAsyncDisposableStackPush(txMachine* the, txSlot* property); |
705 | | static void fxAsyncDisposableStackReject(txMachine* the); |
706 | | static void fxAsyncDisposableStackResolve(txMachine* the); |
707 | | |
708 | | txSlot* fxCheckAsyncDisposableStackInstance(txMachine* the, txSlot* slot, txBoolean mutable, txBoolean disposable) |
709 | 104 | { |
710 | 104 | if (slot->kind == XS_REFERENCE_KIND) { |
711 | 50 | txSlot* instance = slot->value.reference; |
712 | 50 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ASYNC_DISPOSABLE_STACK_KIND)) { |
713 | 12 | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
714 | 0 | mxTypeError("this: read-only AsyncDisposableStack instance"); |
715 | 12 | if (disposable && slot->value.disposableStack.disposed) |
716 | 0 | mxReferenceError("this: disposed AsyncDisposableStack instance"); |
717 | 12 | return instance; |
718 | 12 | } |
719 | 50 | } |
720 | 104 | mxTypeError("this: not a AsyncDisposableStack instance"); |
721 | 0 | return C_NULL; |
722 | 104 | } |
723 | | void fx_AsyncDisposableStack(txMachine* the) |
724 | 185k | { |
725 | 185k | txSlot* instance; |
726 | 185k | txSlot* property; |
727 | 185k | txSlot* function; |
728 | 185k | txSlot* home; |
729 | 185k | if (mxIsUndefined(mxTarget)) |
730 | 3 | mxTypeError("call: AsyncDisposableStack"); |
731 | 185k | mxPushSlot(mxTarget); |
732 | 185k | fxGetPrototypeFromConstructor(the, &mxAsyncDisposableStackPrototype); |
733 | 185k | instance = fxNewSlot(the); |
734 | 185k | instance->kind = XS_INSTANCE_KIND; |
735 | 185k | instance->value.instance.garbage = C_NULL; |
736 | 185k | instance->value.instance.prototype = the->stack->value.reference; |
737 | 185k | the->stack->kind = XS_REFERENCE_KIND; |
738 | 185k | the->stack->value.reference = instance; |
739 | 185k | mxPullSlot(mxResult); |
740 | 185k | property = instance->next = fxNewSlot(the); |
741 | 185k | property->flag = XS_INTERNAL_FLAG; |
742 | 185k | property->kind = XS_ASYNC_DISPOSABLE_STACK_KIND; |
743 | 185k | property->value.disposableStack.stack = C_NULL; |
744 | 185k | property->value.disposableStack.disposed = 0; |
745 | | |
746 | 185k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
747 | 185k | function = fxNewHostFunction(the, fxAsyncDisposableStackResolve, 1, XS_NO_ID, mxAsyncGeneratorResolveYieldProfileID); |
748 | 185k | home = mxFunctionInstanceHome(function); |
749 | 185k | home->value.home.object = instance; |
750 | 185k | property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
751 | 185k | mxPop(); |
752 | 185k | function = fxNewHostFunction(the, fxAsyncDisposableStackReject, 1, XS_NO_ID, mxAsyncGeneratorRejectYieldProfileID); |
753 | 185k | home = mxFunctionInstanceHome(function); |
754 | 185k | home->value.home.object = instance; |
755 | 185k | property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
756 | 185k | mxPop(); |
757 | 185k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
758 | 185k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
759 | 185k | } |
760 | | |
761 | | void fx_AsyncDisposableStack_prototype_get_disposed(txMachine* the) |
762 | 10 | { |
763 | 10 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 0, 0); |
764 | 10 | txSlot* property = instance->next; |
765 | 10 | mxResult->value.boolean = property->value.disposableStack.disposed; |
766 | 10 | mxResult->kind = XS_BOOLEAN_KIND; |
767 | 10 | } |
768 | | |
769 | | void fx_AsyncDisposableStack_prototype_adopt(txMachine* the) |
770 | 22 | { |
771 | 22 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
772 | 22 | txSlot* property = instance->next; |
773 | 22 | if (mxArgc > 0) |
774 | 0 | mxPushSlot(mxArgv(0)); |
775 | 22 | else |
776 | 22 | mxPushUndefined(); |
777 | 22 | if (mxArgc > 1) |
778 | 0 | mxPushSlot(mxArgv(1)); |
779 | 22 | else |
780 | 22 | mxPushUndefined(); |
781 | 22 | fxAsyncDisposableStackPush(the, property); |
782 | 22 | property->value.disposableStack.stack->flag |= XS_BASE_FLAG; |
783 | 22 | mxPop(); |
784 | 22 | mxPullSlot(mxResult); |
785 | 22 | } |
786 | | |
787 | | void fx_AsyncDisposableStack_prototype_defer(txMachine* the) |
788 | 23 | { |
789 | 23 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
790 | 23 | txSlot* property = instance->next; |
791 | 23 | mxPushUndefined(); |
792 | 23 | if (mxArgc > 0) |
793 | 0 | mxPushSlot(mxArgv(0)); |
794 | 23 | else |
795 | 23 | mxPushUndefined(); |
796 | 23 | fxAsyncDisposableStackPush(the, property); |
797 | 23 | mxPop(); |
798 | 23 | mxPop(); |
799 | 23 | } |
800 | | |
801 | | void fx_AsyncDisposableStack_prototype_disposeAsync(txMachine* the) |
802 | 0 | { |
803 | 0 | txSlot* promise; |
804 | 0 | txSlot* resolveFunction; |
805 | 0 | txSlot* rejectFunction; |
806 | |
|
807 | 0 | mxPush(mxPromisePrototype); |
808 | 0 | promise = fxNewPromiseInstance(the); |
809 | 0 | mxPullSlot(mxResult); |
810 | 0 | mxPromiseStatus(promise)->value.integer = mxPendingStatus; |
811 | 0 | fxPushPromiseFunctions(the, promise); |
812 | 0 | resolveFunction = the->stack + 1; |
813 | 0 | rejectFunction = the->stack; |
814 | 0 | mxTry(the) { |
815 | 0 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 0); |
816 | 0 | txSlot* property = instance->next; |
817 | 0 | if (property->value.disposableStack.disposed) { |
818 | 0 | mxPushUndefined(); |
819 | 0 | mxPushSlot(resolveFunction); |
820 | 0 | mxCall(); |
821 | 0 | mxPushUndefined(); |
822 | 0 | mxRunCount(1); |
823 | 0 | mxPop(); |
824 | 0 | } |
825 | 0 | else { |
826 | 0 | txSlot* exception = property->next; |
827 | 0 | txSlot* resolveStepFunction = exception->next; |
828 | 0 | txSlot* rejectStepFunction = resolveStepFunction->next; |
829 | 0 | property->value.disposableStack.disposed = 1; |
830 | 0 | property = rejectStepFunction->next; |
831 | 0 | property->kind = resolveFunction->kind; |
832 | 0 | property->value = resolveFunction->value; |
833 | 0 | property = property->next; |
834 | 0 | property->kind = rejectFunction->kind; |
835 | 0 | property->value = rejectFunction->value; |
836 | 0 | mxPushUndefined(); |
837 | 0 | mxPushSlot(resolveStepFunction); |
838 | 0 | mxCall(); |
839 | 0 | mxPushUndefined(); |
840 | 0 | mxRunCount(1); |
841 | 0 | mxPop(); |
842 | 0 | } |
843 | 0 | } |
844 | 0 | mxCatch(the) { |
845 | 0 | fxRejectException(the, rejectFunction); |
846 | 0 | } |
847 | 0 | } |
848 | | |
849 | | void fx_AsyncDisposableStack_prototype_move(txMachine* the) |
850 | 21 | { |
851 | 21 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
852 | 21 | txSlot* property = instance->next; |
853 | 21 | txSlot* resultInstance; |
854 | 21 | txSlot* resultProperty; |
855 | 21 | txSlot* function; |
856 | 21 | txSlot* home; |
857 | 21 | mxPush(mxAsyncDisposableStackConstructor); |
858 | 21 | fxGetPrototypeFromConstructor(the, &mxAsyncDisposableStackPrototype); |
859 | 21 | resultInstance = fxNewSlot(the); |
860 | 21 | resultInstance->kind = XS_INSTANCE_KIND; |
861 | 21 | resultInstance->value.instance.garbage = C_NULL; |
862 | 21 | resultInstance->value.instance.prototype = the->stack->value.reference; |
863 | 21 | the->stack->kind = XS_REFERENCE_KIND; |
864 | 21 | the->stack->value.reference = resultInstance; |
865 | 21 | mxPullSlot(mxResult); |
866 | 21 | resultProperty = resultInstance->next = fxNewSlot(the); |
867 | 21 | resultProperty->flag = XS_INTERNAL_FLAG; |
868 | 21 | resultProperty->kind = XS_ASYNC_DISPOSABLE_STACK_KIND; |
869 | 21 | resultProperty->value.disposableStack.stack = property->value.disposableStack.stack; |
870 | 21 | resultProperty->value.disposableStack.disposed = 0; |
871 | | |
872 | 21 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
873 | 21 | function = fxNewHostFunction(the, fxAsyncDisposableStackResolve, 1, XS_NO_ID, mxAsyncGeneratorResolveYieldProfileID); |
874 | 21 | home = mxFunctionInstanceHome(function); |
875 | 21 | home->value.home.object = resultInstance; |
876 | 21 | resultProperty = fxNextSlotProperty(the, resultProperty, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
877 | 21 | mxPop(); |
878 | 21 | function = fxNewHostFunction(the, fxAsyncDisposableStackReject, 1, XS_NO_ID, mxAsyncGeneratorRejectYieldProfileID); |
879 | 21 | home = mxFunctionInstanceHome(function); |
880 | 21 | home->value.home.object = resultInstance; |
881 | 21 | resultProperty = fxNextSlotProperty(the, resultProperty, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
882 | 21 | mxPop(); |
883 | 21 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
884 | 21 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
885 | | |
886 | 21 | property->value.disposableStack.stack = C_NULL; |
887 | 21 | property->value.disposableStack.disposed = 1; |
888 | 21 | } |
889 | | |
890 | | void fx_AsyncDisposableStack_prototype_use(txMachine* the) |
891 | 28 | { |
892 | 28 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
893 | 28 | txSlot* property = instance->next; |
894 | 28 | txSlot* resource; |
895 | 28 | if (mxArgc > 0) |
896 | 11 | mxPushSlot(mxArgv(0)); |
897 | 17 | else |
898 | 17 | mxPushUndefined(); |
899 | 28 | resource = the->stack; |
900 | 28 | if (!mxIsNull(resource) && !mxIsUndefined(resource)) { |
901 | 11 | mxPushSlot(resource); |
902 | 11 | mxGetID(mxID(_Symbol_asyncDispose)); |
903 | 11 | if (!fxIsCallable(the, the->stack)) { |
904 | 11 | mxPop(); |
905 | 11 | mxPushSlot(resource); |
906 | 11 | mxGetID(mxID(_Symbol_dispose)); |
907 | 11 | } |
908 | 11 | fxAsyncDisposableStackPush(the, property); |
909 | 11 | mxPop(); |
910 | 11 | } |
911 | 28 | mxPullSlot(mxResult); |
912 | 28 | } |
913 | | |
914 | | void fxAsyncDisposableStackPush(txMachine* the, txSlot* property) |
915 | 11 | { |
916 | 11 | txSlot* dispose = the->stack; |
917 | 11 | txSlot* resource = dispose + 1; |
918 | 11 | txSlot** address = &property->value.disposableStack.stack; |
919 | 11 | txSlot* slot; |
920 | 11 | if (!fxIsCallable(the, dispose)) |
921 | 11 | mxTypeError("dispose: no a function"); |
922 | | |
923 | 0 | slot = fxNewSlot(the); |
924 | 0 | slot->next = *address; |
925 | 0 | slot->kind = resource->kind; |
926 | 0 | slot->value = resource->value; |
927 | 0 | *address = slot; |
928 | | |
929 | 0 | slot = fxNewSlot(the); |
930 | 0 | slot->next = *address; |
931 | 0 | slot->kind = dispose->kind; |
932 | 0 | slot->value = dispose->value; |
933 | 0 | *address = slot; |
934 | 0 | } |
935 | | |
936 | | void fxAsyncDisposableStackReject(txMachine* the) |
937 | 0 | { |
938 | 0 | txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference); |
939 | 0 | txSlot* instance = slot->value.home.object; |
940 | 0 | txSlot* property = instance->next; |
941 | 0 | txSlot* exception = property->next; |
942 | | |
943 | 0 | if (mxIsUndefined(exception)) { |
944 | 0 | mxPushSlot(mxArgv(0)); |
945 | 0 | mxPullSlot(exception); |
946 | 0 | } |
947 | 0 | else { |
948 | 0 | mxPush(mxSuppressedErrorConstructor); |
949 | 0 | mxNew(); |
950 | 0 | mxPushSlot(mxArgv(0)); |
951 | 0 | mxPushSlot(exception); |
952 | 0 | mxRunCount(2); |
953 | 0 | mxPullSlot(exception); |
954 | 0 | } |
955 | 0 | fxAsyncDisposableStackResolve(the); |
956 | 0 | } |
957 | | |
958 | | void fxAsyncDisposableStackResolve(txMachine* the) |
959 | 0 | { |
960 | 0 | txSlot* slot = mxFunctionInstanceHome(mxFunction->value.reference); |
961 | 0 | txSlot* instance = slot->value.home.object; |
962 | 0 | txSlot* property = instance->next; |
963 | 0 | txSlot* exception = property->next; |
964 | 0 | txSlot* resolveStepFunction = exception->next; |
965 | 0 | txSlot* rejectStepFunction = resolveStepFunction->next; |
966 | 0 | txSlot* resolveFunction = rejectStepFunction->next; |
967 | 0 | txSlot* rejectFunction = resolveFunction->next; |
968 | |
|
969 | 0 | slot = property->value.disposableStack.stack; |
970 | 0 | if (slot) { |
971 | 0 | txSlot* dispose = slot; |
972 | 0 | txSlot* resource = slot->next; |
973 | 0 | property->value.disposableStack.stack = resource->next; |
974 | 0 | mxTry(the) { |
975 | 0 | mxPushUndefined(); |
976 | 0 | mxPush(mxPromiseConstructor); |
977 | 0 | if (dispose->flag & XS_BASE_FLAG) { |
978 | 0 | mxPushUndefined(); |
979 | 0 | mxPushSlot(dispose); |
980 | 0 | mxCall(); |
981 | 0 | mxPushSlot(resource); |
982 | 0 | mxRunCount(1); |
983 | 0 | } |
984 | 0 | else { |
985 | 0 | mxPushSlot(resource); |
986 | 0 | mxPushSlot(dispose); |
987 | 0 | mxCall(); |
988 | 0 | mxRunCount(0); |
989 | 0 | } |
990 | 0 | fx_Promise_resolveAux(the); |
991 | 0 | mxPop(); |
992 | 0 | mxPop(); |
993 | 0 | fxPromiseThen(the, the->stack->value.reference, resolveStepFunction, rejectStepFunction, C_NULL, C_NULL); |
994 | 0 | mxPop(); |
995 | 0 | } |
996 | 0 | mxCatch(the) { |
997 | 0 | mxPushUndefined(); |
998 | 0 | mxPushSlot(rejectStepFunction); |
999 | 0 | mxCall(); |
1000 | 0 | mxPush(mxException); |
1001 | 0 | mxException = mxUndefined; |
1002 | 0 | mxRunCount(1); |
1003 | 0 | mxPop(); |
1004 | 0 | } |
1005 | 0 | } |
1006 | 0 | else { |
1007 | 0 | if (mxIsUndefined(exception)) { |
1008 | 0 | mxPushUndefined(); |
1009 | 0 | mxPushSlot(resolveFunction); |
1010 | 0 | mxCall(); |
1011 | 0 | mxPushUndefined(); |
1012 | 0 | mxRunCount(1); |
1013 | 0 | mxPop(); |
1014 | 0 | } |
1015 | 0 | else { |
1016 | 0 | mxPushUndefined(); |
1017 | 0 | mxPushSlot(rejectFunction); |
1018 | 0 | mxCall(); |
1019 | 0 | mxPushSlot(exception); |
1020 | 0 | mxRunCount(1); |
1021 | 0 | mxPop(); |
1022 | 0 | } |
1023 | 0 | } |
1024 | 0 | } |
1025 | | |
1026 | | #endif |
1027 | | |
1028 | | |
1029 | | |
1030 | | |