/src/moddable/xs/sources/xsError.c
Line | Count | Source (jump to first uncovered line) |
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 | 35.3k | { |
74 | 35.3k | txSlot* slot; |
75 | 35.3k | txSlot* prototype; |
76 | 35.3k | txSlot* instance; |
77 | 35.3k | #if mxExplicitResourceManagement |
78 | 35.3k | txSlot* property; |
79 | 35.3k | #endif |
80 | | |
81 | 35.3k | mxPush(mxObjectPrototype); |
82 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
83 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
84 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_UNKNOWN_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
85 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
86 | 35.3k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_Error_prototype_get_stack), mxCallback(fx_Error_prototype_set_stack), mxID(_stack), XS_DONT_ENUM_FLAG); |
87 | 35.3k | mxErrorPrototype = *the->stack; |
88 | 35.3k | prototype = fxBuildHostConstructor(the, mxCallback(fx_Error), 1, mxID(_Error)); |
89 | 35.3k | mxErrorConstructor = *the->stack; |
90 | 35.3k | #if mxErrorIsError |
91 | 35.3k | slot = fxLastProperty(the, prototype); |
92 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_isError), 1, mxID(_isError), XS_DONT_ENUM_FLAG); |
93 | 35.3k | #endif |
94 | 35.3k | mxPop(); |
95 | 35.3k | mxPush(mxErrorPrototype); |
96 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
97 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_AGGREGATE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
98 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
99 | 35.3k | mxAggregateErrorPrototype = *the->stack; |
100 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_AggregateError), 2, mxID(_AggregateError)); |
101 | 35.3k | instance->value.instance.prototype = prototype; |
102 | 35.3k | mxAggregateErrorConstructor = *the->stack; |
103 | 35.3k | mxPop(); |
104 | 35.3k | mxPush(mxErrorPrototype); |
105 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
106 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_EVAL_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
107 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
108 | 35.3k | mxEvalErrorPrototype = *the->stack; |
109 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_EvalError), 1, mxID(_EvalError)); |
110 | 35.3k | instance->value.instance.prototype = prototype; |
111 | 35.3k | mxEvalErrorConstructor = *the->stack; |
112 | 35.3k | mxPop(); |
113 | 35.3k | mxPush(mxErrorPrototype); |
114 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
115 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_RANGE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
116 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
117 | 35.3k | mxRangeErrorPrototype = *the->stack; |
118 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_RangeError), 1, mxID(_RangeError)); |
119 | 35.3k | instance->value.instance.prototype = prototype; |
120 | 35.3k | mxRangeErrorConstructor = *the->stack; |
121 | 35.3k | mxPop(); |
122 | 35.3k | mxPush(mxErrorPrototype); |
123 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
124 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_REFERENCE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
125 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
126 | 35.3k | mxReferenceErrorPrototype = *the->stack; |
127 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_ReferenceError), 1, mxID(_ReferenceError)); |
128 | 35.3k | instance->value.instance.prototype = prototype; |
129 | 35.3k | mxReferenceErrorConstructor = *the->stack; |
130 | 35.3k | mxPop(); |
131 | 35.3k | mxPush(mxErrorPrototype); |
132 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
133 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_SYNTAX_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
134 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
135 | 35.3k | mxSyntaxErrorPrototype = *the->stack; |
136 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_SyntaxError), 1, mxID(_SyntaxError)); |
137 | 35.3k | instance->value.instance.prototype = prototype; |
138 | 35.3k | mxSyntaxErrorConstructor = *the->stack; |
139 | 35.3k | mxPop(); |
140 | 35.3k | mxPush(mxErrorPrototype); |
141 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
142 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_TYPE_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
143 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
144 | 35.3k | mxTypeErrorPrototype = *the->stack; |
145 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_TypeError), 1, mxID(_TypeError)); |
146 | 35.3k | instance->value.instance.prototype = prototype; |
147 | 35.3k | mxTypeErrorConstructor = *the->stack; |
148 | 35.3k | mxPop(); |
149 | 35.3k | mxPush(mxErrorPrototype); |
150 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
151 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_URI_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
152 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
153 | 35.3k | mxURIErrorPrototype = *the->stack; |
154 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_URIError), 1, mxID(_URIError)); |
155 | 35.3k | instance->value.instance.prototype = prototype; |
156 | 35.3k | mxURIErrorConstructor = *the->stack; |
157 | 35.3k | mxPop(); |
158 | | |
159 | 35.3k | #if mxExplicitResourceManagement |
160 | 35.3k | mxPush(mxErrorPrototype); |
161 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
162 | 35.3k | slot = fxNextStringXProperty(the, slot, (txString)gxErrorNames[XS_SUPPRESSED_ERROR], mxID(_name), XS_DONT_ENUM_FLAG); |
163 | 35.3k | slot = fxNextStringXProperty(the, slot, "", mxID(_message), XS_DONT_ENUM_FLAG); |
164 | 35.3k | mxSuppressedErrorPrototype = *the->stack; |
165 | 35.3k | instance = fxBuildHostConstructor(the, mxCallback(fx_SuppressedError), 3, mxID(_SuppressedError)); |
166 | 35.3k | instance->value.instance.prototype = prototype; |
167 | 35.3k | mxSuppressedErrorConstructor = *the->stack; |
168 | 35.3k | mxPop(); |
169 | | |
170 | 35.3k | mxPush(mxObjectPrototype); |
171 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
172 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
173 | 35.3k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DisposableStack_prototype_get_disposed), C_NULL, mxID(_disposed), XS_DONT_ENUM_FLAG); |
174 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_adopt), 2, mxID(_adopt), XS_DONT_ENUM_FLAG); |
175 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_defer), 1, mxID(_defer), XS_DONT_ENUM_FLAG); |
176 | 35.3k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_dispose), 0, mxID(_dispose), XS_DONT_ENUM_FLAG); |
177 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_move), 0, mxID(_move), XS_DONT_ENUM_FLAG); |
178 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DisposableStack_prototype_use), 1, mxID(_use), XS_DONT_ENUM_FLAG); |
179 | 35.3k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_dispose), XS_DONT_ENUM_FLAG); |
180 | 35.3k | slot = fxNextStringXProperty(the, slot, "DisposableStack", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
181 | 35.3k | mxDisposableStackPrototype = *the->stack; |
182 | 35.3k | slot = fxBuildHostConstructor(the, mxCallback(fx_DisposableStack), 0, mxID(_DisposableStack)); |
183 | 35.3k | mxDisposableStackConstructor = *the->stack; |
184 | 35.3k | mxPop(); |
185 | | |
186 | 35.3k | mxPush(mxObjectPrototype); |
187 | 35.3k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
188 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Error_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG); |
189 | 35.3k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_get_disposed), C_NULL, mxID(_disposed), XS_DONT_ENUM_FLAG); |
190 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_adopt), 2, mxID(_adopt), XS_DONT_ENUM_FLAG); |
191 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_defer), 1, mxID(_defer), XS_DONT_ENUM_FLAG); |
192 | 35.3k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_disposeAsync), 0, mxID(_disposeAsync), XS_DONT_ENUM_FLAG); |
193 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_move), 0, mxID(_move), XS_DONT_ENUM_FLAG); |
194 | 35.3k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_AsyncDisposableStack_prototype_use), 1, mxID(_use), XS_DONT_ENUM_FLAG); |
195 | 35.3k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_asyncDispose), XS_DONT_ENUM_FLAG); |
196 | 35.3k | slot = fxNextStringXProperty(the, slot, "AsyncDisposableStack", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
197 | 35.3k | mxAsyncDisposableStackPrototype = *the->stack; |
198 | 35.3k | slot = fxBuildHostConstructor(the, mxCallback(fx_AsyncDisposableStack), 0, mxID(_AsyncDisposableStack)); |
199 | 35.3k | mxAsyncDisposableStackConstructor = *the->stack; |
200 | 35.3k | mxPop(); |
201 | 35.3k | #endif |
202 | 35.3k | } |
203 | | |
204 | | void fxCaptureErrorStack(txMachine* the, txSlot* internal, txSlot* frame) |
205 | 2.70M | { |
206 | 2.70M | txSlot* slot = internal->value.reference = fxNewSlot(the); |
207 | 2.70M | slot->kind = XS_INSTANCE_KIND; |
208 | 2.70M | slot->value.instance.garbage = C_NULL; |
209 | 2.70M | slot->value.instance.prototype = C_NULL; |
210 | 14.8M | while (frame->next) { |
211 | 12.1M | txSlot* environment = mxFrameToEnvironment(frame); |
212 | 12.1M | txSlot* function = frame + 3; |
213 | 12.1M | if (function->kind == XS_REFERENCE_KIND) { |
214 | 11.9M | function = function->value.reference; |
215 | 11.9M | if (mxIsFunction(function)) { |
216 | 11.9M | txSlot* name = mxBehaviorGetProperty(the, function, mxID(_name), 0, XS_OWN); |
217 | 11.9M | slot = slot->next = fxNewSlot(the); |
218 | 11.9M | slot->flag = XS_GET_ONLY; |
219 | 11.9M | slot->kind = XS_KEY_KIND; |
220 | 11.9M | slot->ID = environment->ID; |
221 | 11.9M | slot->value.key.string = C_NULL; |
222 | 11.9M | slot->value.key.sum = environment->value.environment.line; |
223 | 11.9M | if (name && ((name->kind == XS_STRING_KIND) || (name->kind == XS_STRING_X_KIND))) { |
224 | 11.9M | if (name->kind == XS_STRING_X_KIND) |
225 | 0 | slot->kind = XS_KEY_X_KIND; |
226 | 11.9M | slot->value.key.string = name->value.string; |
227 | 11.9M | } |
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 | 11.9M | } |
247 | 11.9M | } |
248 | 12.1M | frame = frame->next; |
249 | 12.1M | } |
250 | 2.70M | } |
251 | | |
252 | | void fx_Error(txMachine* the) |
253 | 300 | { |
254 | 300 | fx_Error_aux(the, XS_UNKNOWN_ERROR, 0); |
255 | 300 | } |
256 | | |
257 | | void fx_Error_isError(txMachine* the) |
258 | 93 | { |
259 | 93 | mxResult->kind = XS_BOOLEAN_KIND; |
260 | 93 | mxResult->value.boolean = 0; |
261 | 93 | if (mxArgc > 0) { |
262 | 91 | txSlot* instance = fxGetInstance(the, mxArgv(0)); |
263 | 91 | if (instance) { |
264 | 58 | txSlot* internal = instance->next; |
265 | 58 | if (internal && (internal->kind == XS_ERROR_KIND)) { |
266 | 30 | mxResult->value.boolean = 1; |
267 | 30 | } |
268 | 58 | } |
269 | 91 | } |
270 | 93 | } |
271 | | |
272 | | txSlot* fx_Error_aux(txMachine* the, txError error, txInteger i) |
273 | 630k | { |
274 | 630k | txSlot* instance; |
275 | 630k | txSlot* slot; |
276 | 630k | if (mxIsUndefined(mxTarget)) |
277 | 90 | mxPushSlot(mxFunction); |
278 | 630k | else |
279 | 630k | mxPushSlot(mxTarget); |
280 | 630k | fxGetPrototypeFromConstructor(the, &mxErrorPrototypes(error)); |
281 | 630k | instance = fxNewObjectInstance(the); |
282 | 630k | mxPullSlot(mxResult); |
283 | 630k | slot = instance->next = fxNewSlot(the); |
284 | 630k | slot->flag = XS_INTERNAL_FLAG; |
285 | 630k | slot->kind = XS_ERROR_KIND; |
286 | 630k | slot->value.error.info = C_NULL; |
287 | 630k | slot->value.error.which = error; |
288 | 630k | if (gxDefaults.captureErrorStack) |
289 | 630k | gxDefaults.captureErrorStack(the, slot, the->frame->next); |
290 | 630k | if ((mxArgc > i) && (mxArgv(i)->kind != XS_UNDEFINED_KIND)) { |
291 | 629k | fxToString(the, mxArgv(i)); |
292 | 629k | slot = fxNextSlotProperty(the, slot, mxArgv(i), mxID(_message), XS_DONT_ENUM_FLAG); |
293 | 629k | } |
294 | 630k | i++; |
295 | 630k | if ((mxArgc > i) && (mxArgv(i)->kind == XS_REFERENCE_KIND)) { |
296 | 2 | 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 | 2 | } |
303 | 630k | return slot; |
304 | 630k | } |
305 | | |
306 | | void fx_Error_toString(txMachine* the) |
307 | 344k | { |
308 | 344k | txSlot* name; |
309 | 344k | txSlot* message; |
310 | 344k | if (mxThis->kind != XS_REFERENCE_KIND) |
311 | 7 | mxTypeError("this: not an object"); |
312 | 344k | mxPushSlot(mxThis); |
313 | 344k | mxGetID(mxID(_name)); |
314 | 344k | if (the->stack->kind == XS_UNDEFINED_KIND) |
315 | 343k | fxStringX(the, the->stack, "Error"); |
316 | 813 | else |
317 | 813 | fxToString(the, the->stack); |
318 | 344k | name = the->stack; |
319 | 344k | mxPushSlot(mxThis); |
320 | 344k | mxGetID(mxID(_message)); |
321 | 344k | if (the->stack->kind == XS_UNDEFINED_KIND) |
322 | 343k | *the->stack = mxEmptyString; |
323 | 816 | else |
324 | 816 | fxToString(the, the->stack); |
325 | 344k | message = the->stack; |
326 | 344k | if (c_isEmpty(name->value.string)) |
327 | 3 | *mxResult = *message; |
328 | 344k | else if (c_isEmpty(message->value.string)) |
329 | 344k | *mxResult = *name; |
330 | 19 | else { |
331 | 19 | fxStringX(the, mxResult, ""); |
332 | 19 | fxConcatString(the, mxResult, name); |
333 | 19 | fxConcatStringC(the, mxResult, ": "); |
334 | 19 | fxConcatString(the, mxResult, message); |
335 | 19 | } |
336 | 344k | the->stack += 2; |
337 | 344k | } |
338 | | |
339 | | void fx_AggregateError(txMachine* the) |
340 | 538 | { |
341 | 538 | txSlot* stack = the->stack; |
342 | 538 | txSlot* property = fx_Error_aux(the, XS_AGGREGATE_ERROR, 1); |
343 | 538 | txSlot* array; |
344 | 538 | txSlot** address; |
345 | 538 | txIndex length = 0; |
346 | 538 | txSlot* iterator; |
347 | 538 | txSlot* next; |
348 | 538 | txSlot* value; |
349 | 538 | txSlot* slot; |
350 | | |
351 | 538 | mxPush(mxArrayPrototype); |
352 | 538 | array = fxNewArrayInstance(the); |
353 | 538 | fxNextSlotProperty(the, property, the->stack, mxID(_errors), XS_DONT_ENUM_FLAG); |
354 | 538 | address = &array->next->next; |
355 | 538 | mxTemporary(iterator); |
356 | 538 | mxTemporary(next); |
357 | 538 | fxGetIterator(the, mxArgv(0), iterator, next, 0); |
358 | 538 | mxTemporary(value); |
359 | 78.6k | while (fxIteratorNext(the, iterator, next, value)) { |
360 | 78.0k | mxTry(the) { |
361 | 78.0k | *address = slot = fxNewSlot(the); |
362 | 78.0k | slot->kind = value->kind; |
363 | 78.0k | slot->value = value->value; |
364 | 78.0k | address = &slot->next; |
365 | 78.0k | length++; |
366 | 78.0k | } |
367 | 78.0k | mxCatch(the) { |
368 | 0 | fxIteratorReturn(the, iterator, 1); |
369 | 0 | fxJump(the); |
370 | 0 | } |
371 | 78.0k | } |
372 | 538 | array->next->value.array.length = length; |
373 | 538 | fxCacheArray(the, array); |
374 | | |
375 | 538 | the->stack = stack; |
376 | 538 | } |
377 | | |
378 | | void fx_EvalError(txMachine* the) |
379 | 11 | { |
380 | 11 | fx_Error_aux(the, XS_EVAL_ERROR, 0); |
381 | 11 | } |
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 | 4 | { |
390 | 4 | fx_Error_aux(the, XS_REFERENCE_ERROR, 0); |
391 | 4 | } |
392 | | |
393 | | void fx_SyntaxError(txMachine* the) |
394 | 629k | { |
395 | 629k | fx_Error_aux(the, XS_SYNTAX_ERROR, 0); |
396 | 629k | } |
397 | | |
398 | | void fx_TypeError(txMachine* the) |
399 | 4 | { |
400 | 4 | fx_Error_aux(the, XS_TYPE_ERROR, 0); |
401 | 4 | } |
402 | | |
403 | | void fx_URIError(txMachine* the) |
404 | 4 | { |
405 | 4 | fx_Error_aux(the, XS_URI_ERROR, 0); |
406 | 4 | } |
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 | 1 | fxStringX(the, mxResult, ""); |
416 | 1 | mxPushSlot(mxThis); |
417 | 1 | mxGetID(mxID(_name)); |
418 | 1 | if (the->stack->kind != XS_UNDEFINED_KIND) { |
419 | 1 | fxToString(the, the->stack); |
420 | 1 | fxConcatString(the, mxResult, the->stack); |
421 | 1 | } |
422 | 0 | else |
423 | 0 | fxConcatStringC(the, mxResult, "Error"); |
424 | 1 | mxPop(); |
425 | 1 | mxPushSlot(mxThis); |
426 | 1 | mxGetID(mxID(_message)); |
427 | 1 | if (the->stack->kind != XS_UNDEFINED_KIND) { |
428 | 1 | fxToString(the, the->stack); |
429 | 1 | if (!c_isEmpty(the->stack->value.string)) { |
430 | 0 | fxConcatStringC(the, mxResult, ": "); |
431 | 0 | fxConcatString(the, mxResult, the->stack); |
432 | 0 | } |
433 | 1 | } |
434 | 1 | mxPop(); |
435 | 1 | slot = slot->value.reference; |
436 | 1 | if (slot) { |
437 | 1 | slot = slot->next; |
438 | 2 | while (slot) { |
439 | 1 | fxConcatStringC(the, mxResult, "\n at"); |
440 | 1 | 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 | 1 | fxConcatStringC(the, mxResult, " ("); |
445 | 1 | if (slot->ID != XS_NO_ID) { |
446 | 1 | fxIDToString(the, slot->ID, the->nameBuffer, sizeof(the->nameBuffer)); |
447 | 1 | fxConcatStringC(the, mxResult, the->nameBuffer); |
448 | 1 | fxConcatStringC(the, mxResult, ":"); |
449 | 1 | fxIntegerToString(the, (txInteger)slot->value.key.sum, the->nameBuffer, sizeof(the->nameBuffer)); |
450 | 1 | fxConcatStringC(the, mxResult, the->nameBuffer); |
451 | 1 | } |
452 | 1 | fxConcatStringC(the, mxResult, ")"); |
453 | 1 | slot = slot->next; |
454 | 1 | } |
455 | 1 | } |
456 | 1 | } |
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 | 46 | { |
496 | 46 | txSlot* property = fx_Error_aux(the, XS_SUPPRESSED_ERROR, 2); |
497 | 46 | property = fxNextSlotProperty(the, property, mxArgv(0), mxID(_error), XS_DONT_ENUM_FLAG); |
498 | 46 | property = fxNextSlotProperty(the, property, mxArgv(1), mxID(_suppressed), XS_DONT_ENUM_FLAG); |
499 | 46 | } |
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 | 298 | { |
506 | 298 | if (slot->kind == XS_REFERENCE_KIND) { |
507 | 222 | txSlot* instance = slot->value.reference; |
508 | 222 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_DISPOSABLE_STACK_KIND)) { |
509 | 165 | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
510 | 0 | mxTypeError("this: read-only DisposableStack instance"); |
511 | 165 | if (disposable && slot->value.disposableStack.disposed) |
512 | 20 | mxReferenceError("this: disposed DisposableStack instance"); |
513 | 145 | return instance; |
514 | 165 | } |
515 | 222 | } |
516 | 298 | mxTypeError("this: not a DisposableStack instance"); |
517 | 0 | return C_NULL; |
518 | 298 | } |
519 | | |
520 | | void fx_DisposableStack(txMachine* the) |
521 | 132k | { |
522 | 132k | txSlot* instance; |
523 | 132k | txSlot* property; |
524 | 132k | if (mxIsUndefined(mxTarget)) |
525 | 1 | mxTypeError("call: DisposableStack"); |
526 | 132k | mxPushSlot(mxTarget); |
527 | 132k | fxGetPrototypeFromConstructor(the, &mxDisposableStackPrototype); |
528 | 132k | instance = fxNewSlot(the); |
529 | 132k | instance->kind = XS_INSTANCE_KIND; |
530 | 132k | instance->value.instance.garbage = C_NULL; |
531 | 132k | instance->value.instance.prototype = the->stack->value.reference; |
532 | 132k | the->stack->kind = XS_REFERENCE_KIND; |
533 | 132k | the->stack->value.reference = instance; |
534 | 132k | mxPullSlot(mxResult); |
535 | 132k | property = instance->next = fxNewSlot(the); |
536 | 132k | property->flag = XS_INTERNAL_FLAG; |
537 | 132k | property->kind = XS_DISPOSABLE_STACK_KIND; |
538 | 132k | property->value.disposableStack.stack = C_NULL; |
539 | 132k | property->value.disposableStack.disposed = 0; |
540 | 132k | } |
541 | | |
542 | | void fx_DisposableStack_prototype_get_disposed(txMachine* the) |
543 | 18 | { |
544 | 18 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 0, 0); |
545 | 18 | txSlot* property = instance->next; |
546 | 18 | mxResult->value.boolean = property->value.disposableStack.disposed; |
547 | 18 | mxResult->kind = XS_BOOLEAN_KIND; |
548 | 18 | } |
549 | | |
550 | | void fx_DisposableStack_prototype_adopt(txMachine* the) |
551 | 64 | { |
552 | 64 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
553 | 64 | txSlot* property = instance->next; |
554 | 64 | if (mxArgc > 0) |
555 | 39 | mxPushSlot(mxArgv(0)); |
556 | 25 | else |
557 | 25 | mxPushUndefined(); |
558 | 64 | if (mxArgc > 1) |
559 | 38 | mxPushSlot(mxArgv(1)); |
560 | 26 | else |
561 | 26 | mxPushUndefined(); |
562 | 64 | fxDisposableStackPush(the, property); |
563 | 64 | property->value.disposableStack.stack->flag |= XS_BASE_FLAG; |
564 | 64 | mxPop(); |
565 | 64 | mxPullSlot(mxResult); |
566 | 64 | } |
567 | | |
568 | | void fx_DisposableStack_prototype_defer(txMachine* the) |
569 | 64 | { |
570 | 64 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
571 | 64 | txSlot* property = instance->next; |
572 | 64 | mxPushUndefined(); |
573 | 64 | if (mxArgc > 0) |
574 | 42 | mxPushSlot(mxArgv(0)); |
575 | 22 | else |
576 | 22 | mxPushUndefined(); |
577 | 64 | fxDisposableStackPush(the, property); |
578 | 64 | mxPop(); |
579 | 64 | mxPop(); |
580 | 64 | } |
581 | | |
582 | | void fx_DisposableStack_prototype_dispose(txMachine* the) |
583 | 46 | { |
584 | 46 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 0); |
585 | 46 | txSlot* property = instance->next; |
586 | 46 | txSlot* exception; |
587 | 46 | txBoolean selector = 1; |
588 | 46 | txSlot* slot; |
589 | 46 | if (property->value.disposableStack.disposed) |
590 | 4 | return; |
591 | 42 | property->value.disposableStack.disposed = 1; |
592 | 42 | mxTemporary(exception); |
593 | 42 | slot = property->value.disposableStack.stack; |
594 | 68 | while (slot) { |
595 | 26 | txSlot* dispose = slot; |
596 | 26 | txSlot* resource = slot->next; |
597 | 26 | mxTry(the) { |
598 | 26 | 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 | 22 | else { |
607 | 22 | mxPushSlot(resource); |
608 | 22 | mxPushSlot(dispose); |
609 | 22 | mxCall(); |
610 | 22 | mxRunCount(0); |
611 | 22 | mxPop(); |
612 | 22 | } |
613 | 26 | } |
614 | 26 | mxCatch(the) { |
615 | 14 | if (selector == 0) { |
616 | 9 | mxPush(mxSuppressedErrorConstructor); |
617 | 9 | mxNew(); |
618 | 9 | mxPush(mxException); |
619 | 9 | mxPushSlot(exception); |
620 | 9 | mxRunCount(2); |
621 | 9 | mxPullSlot(exception); |
622 | 9 | } |
623 | 5 | else { |
624 | 5 | *exception = mxException; |
625 | 5 | selector = 0; |
626 | 5 | } |
627 | 14 | mxException = mxUndefined; |
628 | 14 | } |
629 | 26 | slot = resource->next; |
630 | 26 | } |
631 | 42 | if (selector == 0) { |
632 | 5 | mxException.kind = exception->kind; |
633 | 5 | mxException.value = exception->value; |
634 | 5 | fxJump(the); |
635 | 5 | } |
636 | 42 | } |
637 | | |
638 | | void fx_DisposableStack_prototype_move(txMachine* the) |
639 | 31 | { |
640 | 31 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
641 | 31 | txSlot* property = instance->next; |
642 | 31 | txSlot* resultInstance; |
643 | 31 | txSlot* resultProperty; |
644 | 31 | mxPush(mxDisposableStackConstructor); |
645 | 31 | fxGetPrototypeFromConstructor(the, &mxDisposableStackPrototype); |
646 | 31 | resultInstance = fxNewSlot(the); |
647 | 31 | resultInstance->kind = XS_INSTANCE_KIND; |
648 | 31 | resultInstance->value.instance.garbage = C_NULL; |
649 | 31 | resultInstance->value.instance.prototype = the->stack->value.reference; |
650 | 31 | the->stack->kind = XS_REFERENCE_KIND; |
651 | 31 | the->stack->value.reference = resultInstance; |
652 | 31 | mxPullSlot(mxResult); |
653 | 31 | resultProperty = resultInstance->next = fxNewSlot(the); |
654 | 31 | resultProperty->flag = XS_INTERNAL_FLAG; |
655 | 31 | resultProperty->kind = XS_DISPOSABLE_STACK_KIND; |
656 | 31 | resultProperty->value.disposableStack.stack = property->value.disposableStack.stack; |
657 | 31 | resultProperty->value.disposableStack.disposed = 0; |
658 | 31 | property->value.disposableStack.stack = C_NULL; |
659 | 31 | property->value.disposableStack.disposed = 1; |
660 | 31 | } |
661 | | |
662 | | void fx_DisposableStack_prototype_use(txMachine* the) |
663 | 75 | { |
664 | 75 | txSlot* instance = fxCheckDisposableStackInstance(the, mxThis, 1, 1); |
665 | 75 | txSlot* property = instance->next; |
666 | 75 | txSlot* resource; |
667 | 75 | if (mxArgc > 0) |
668 | 31 | mxPushSlot(mxArgv(0)); |
669 | 44 | else |
670 | 44 | mxPushUndefined(); |
671 | 75 | resource = the->stack; |
672 | 75 | if (!mxIsNull(resource) && !mxIsUndefined(resource)) { |
673 | 24 | mxPushSlot(resource); |
674 | 24 | mxGetID(mxID(_Symbol_dispose)); |
675 | 24 | fxDisposableStackPush(the, property); |
676 | 24 | mxPop(); |
677 | 24 | } |
678 | 75 | mxPullSlot(mxResult); |
679 | 75 | } |
680 | | |
681 | | void fxDisposableStackPush(txMachine* the, txSlot* property) |
682 | 105 | { |
683 | 105 | txSlot* dispose = the->stack; |
684 | 105 | txSlot* resource = dispose + 1; |
685 | 105 | txSlot** address = &property->value.disposableStack.stack; |
686 | 105 | txSlot* slot; |
687 | 105 | if (!fxIsCallable(the, dispose)) |
688 | 59 | mxTypeError("dispose: not a function"); |
689 | | |
690 | 46 | slot = fxNewSlot(the); |
691 | 46 | slot->next = *address; |
692 | 46 | slot->kind = resource->kind; |
693 | 46 | slot->value = resource->value; |
694 | 46 | *address = slot; |
695 | | |
696 | 46 | slot = fxNewSlot(the); |
697 | 46 | slot->next = *address; |
698 | 46 | slot->kind = dispose->kind; |
699 | 46 | slot->value = dispose->value; |
700 | 46 | *address = slot; |
701 | 46 | } |
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 | 129 | { |
710 | 129 | if (slot->kind == XS_REFERENCE_KIND) { |
711 | 67 | txSlot* instance = slot->value.reference; |
712 | 67 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ASYNC_DISPOSABLE_STACK_KIND)) { |
713 | 16 | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
714 | 0 | mxTypeError("this: read-only AsyncDisposableStack instance"); |
715 | 16 | if (disposable && slot->value.disposableStack.disposed) |
716 | 0 | mxReferenceError("this: disposed AsyncDisposableStack instance"); |
717 | 16 | return instance; |
718 | 16 | } |
719 | 67 | } |
720 | 129 | mxTypeError("this: not a AsyncDisposableStack instance"); |
721 | 0 | return C_NULL; |
722 | 129 | } |
723 | | void fx_AsyncDisposableStack(txMachine* the) |
724 | 331k | { |
725 | 331k | txSlot* instance; |
726 | 331k | txSlot* property; |
727 | 331k | txSlot* function; |
728 | 331k | txSlot* home; |
729 | 331k | if (mxIsUndefined(mxTarget)) |
730 | 1 | mxTypeError("call: AsyncDisposableStack"); |
731 | 331k | mxPushSlot(mxTarget); |
732 | 331k | fxGetPrototypeFromConstructor(the, &mxAsyncDisposableStackPrototype); |
733 | 331k | instance = fxNewSlot(the); |
734 | 331k | instance->kind = XS_INSTANCE_KIND; |
735 | 331k | instance->value.instance.garbage = C_NULL; |
736 | 331k | instance->value.instance.prototype = the->stack->value.reference; |
737 | 331k | the->stack->kind = XS_REFERENCE_KIND; |
738 | 331k | the->stack->value.reference = instance; |
739 | 331k | mxPullSlot(mxResult); |
740 | 331k | property = instance->next = fxNewSlot(the); |
741 | 331k | property->flag = XS_INTERNAL_FLAG; |
742 | 331k | property->kind = XS_ASYNC_DISPOSABLE_STACK_KIND; |
743 | 331k | property->value.disposableStack.stack = C_NULL; |
744 | 331k | property->value.disposableStack.disposed = 0; |
745 | | |
746 | 331k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
747 | 331k | function = fxNewHostFunction(the, fxAsyncDisposableStackResolve, 1, XS_NO_ID, mxAsyncGeneratorResolveYieldProfileID); |
748 | 331k | home = mxFunctionInstanceHome(function); |
749 | 331k | home->value.home.object = instance; |
750 | 331k | property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
751 | 331k | mxPop(); |
752 | 331k | function = fxNewHostFunction(the, fxAsyncDisposableStackReject, 1, XS_NO_ID, mxAsyncGeneratorRejectYieldProfileID); |
753 | 331k | home = mxFunctionInstanceHome(function); |
754 | 331k | home->value.home.object = instance; |
755 | 331k | property = fxNextSlotProperty(the, property, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
756 | 331k | mxPop(); |
757 | 331k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
758 | 331k | property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
759 | 331k | } |
760 | | |
761 | | void fx_AsyncDisposableStack_prototype_get_disposed(txMachine* the) |
762 | 16 | { |
763 | 16 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 0, 0); |
764 | 16 | txSlot* property = instance->next; |
765 | 16 | mxResult->value.boolean = property->value.disposableStack.disposed; |
766 | 16 | mxResult->kind = XS_BOOLEAN_KIND; |
767 | 16 | } |
768 | | |
769 | | void fx_AsyncDisposableStack_prototype_adopt(txMachine* the) |
770 | 23 | { |
771 | 23 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
772 | 23 | txSlot* property = instance->next; |
773 | 23 | if (mxArgc > 0) |
774 | 0 | mxPushSlot(mxArgv(0)); |
775 | 23 | else |
776 | 23 | mxPushUndefined(); |
777 | 23 | if (mxArgc > 1) |
778 | 0 | mxPushSlot(mxArgv(1)); |
779 | 23 | else |
780 | 23 | mxPushUndefined(); |
781 | 23 | fxAsyncDisposableStackPush(the, property); |
782 | 23 | property->value.disposableStack.stack->flag |= XS_BASE_FLAG; |
783 | 23 | mxPop(); |
784 | 23 | mxPullSlot(mxResult); |
785 | 23 | } |
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 | 23 | { |
851 | 23 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
852 | 23 | txSlot* property = instance->next; |
853 | 23 | txSlot* resultInstance; |
854 | 23 | txSlot* resultProperty; |
855 | 23 | txSlot* function; |
856 | 23 | txSlot* home; |
857 | 23 | mxPush(mxAsyncDisposableStackConstructor); |
858 | 23 | fxGetPrototypeFromConstructor(the, &mxAsyncDisposableStackPrototype); |
859 | 23 | resultInstance = fxNewSlot(the); |
860 | 23 | resultInstance->kind = XS_INSTANCE_KIND; |
861 | 23 | resultInstance->value.instance.garbage = C_NULL; |
862 | 23 | resultInstance->value.instance.prototype = the->stack->value.reference; |
863 | 23 | the->stack->kind = XS_REFERENCE_KIND; |
864 | 23 | the->stack->value.reference = resultInstance; |
865 | 23 | mxPullSlot(mxResult); |
866 | 23 | resultProperty = resultInstance->next = fxNewSlot(the); |
867 | 23 | resultProperty->flag = XS_INTERNAL_FLAG; |
868 | 23 | resultProperty->kind = XS_ASYNC_DISPOSABLE_STACK_KIND; |
869 | 23 | resultProperty->value.disposableStack.stack = property->value.disposableStack.stack; |
870 | 23 | resultProperty->value.disposableStack.disposed = 0; |
871 | | |
872 | 23 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
873 | 23 | function = fxNewHostFunction(the, fxAsyncDisposableStackResolve, 1, XS_NO_ID, mxAsyncGeneratorResolveYieldProfileID); |
874 | 23 | home = mxFunctionInstanceHome(function); |
875 | 23 | home->value.home.object = resultInstance; |
876 | 23 | resultProperty = fxNextSlotProperty(the, resultProperty, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
877 | 23 | mxPop(); |
878 | 23 | function = fxNewHostFunction(the, fxAsyncDisposableStackReject, 1, XS_NO_ID, mxAsyncGeneratorRejectYieldProfileID); |
879 | 23 | home = mxFunctionInstanceHome(function); |
880 | 23 | home->value.home.object = resultInstance; |
881 | 23 | resultProperty = fxNextSlotProperty(the, resultProperty, the->stack, XS_NO_ID, XS_INTERNAL_FLAG); |
882 | 23 | mxPop(); |
883 | 23 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
884 | 23 | resultProperty = fxNextUndefinedProperty(the, resultProperty, XS_NO_ID, XS_INTERNAL_FLAG); |
885 | | |
886 | 23 | property->value.disposableStack.stack = C_NULL; |
887 | 23 | property->value.disposableStack.disposed = 1; |
888 | 23 | } |
889 | | |
890 | | void fx_AsyncDisposableStack_prototype_use(txMachine* the) |
891 | 44 | { |
892 | 44 | txSlot* instance = fxCheckAsyncDisposableStackInstance(the, mxThis, 1, 1); |
893 | 44 | txSlot* property = instance->next; |
894 | 44 | txSlot* resource; |
895 | 44 | if (mxArgc > 0) |
896 | 14 | mxPushSlot(mxArgv(0)); |
897 | 30 | else |
898 | 30 | mxPushUndefined(); |
899 | 44 | resource = the->stack; |
900 | 44 | if (!mxIsNull(resource) && !mxIsUndefined(resource)) { |
901 | 14 | mxPushSlot(resource); |
902 | 14 | mxGetID(mxID(_Symbol_asyncDispose)); |
903 | 14 | if (!fxIsCallable(the, the->stack)) { |
904 | 14 | mxPop(); |
905 | 14 | mxPushSlot(resource); |
906 | 14 | mxGetID(mxID(_Symbol_dispose)); |
907 | 14 | } |
908 | 14 | fxAsyncDisposableStackPush(the, property); |
909 | 14 | mxPop(); |
910 | 14 | } |
911 | 44 | mxPullSlot(mxResult); |
912 | 44 | } |
913 | | |
914 | | void fxAsyncDisposableStackPush(txMachine* the, txSlot* property) |
915 | 14 | { |
916 | 14 | txSlot* dispose = the->stack; |
917 | 14 | txSlot* resource = dispose + 1; |
918 | 14 | txSlot** address = &property->value.disposableStack.stack; |
919 | 14 | txSlot* slot; |
920 | 14 | if (!fxIsCallable(the, dispose)) |
921 | 14 | 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 | | |