xbintsc 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/ast/expressions.d.ts +8 -0
- package/dist/src/binder/binder.js +1 -0
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/references.d.ts +1 -1
- package/dist/src/binder/references.js +34 -5
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/binder/types.d.ts +4 -0
- package/dist/src/binder/types.js.map +1 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +9 -1
- package/dist/src/codegen/generator/calls/access.js +146 -13
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.d.ts +1 -0
- package/dist/src/codegen/generator/calls/closures.js +25 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +12 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/calls/literals.js +12 -4
- package/dist/src/codegen/generator/calls/literals.js.map +1 -1
- package/dist/src/codegen/generator/calls/super.js +4 -7
- package/dist/src/codegen/generator/calls/super.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +21 -2
- package/dist/src/codegen/generator/context.js +42 -5
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.js +1 -3
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.d.ts +3 -1
- package/dist/src/codegen/generator/expressions/primary.js +99 -1
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.js +25 -15
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.d.ts +15 -0
- package/dist/src/codegen/generator/state.js +28 -1
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +3 -1
- package/dist/src/codegen/generator/statements/control-flow.js +85 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +15 -6
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/loops.d.ts +3 -0
- package/dist/src/codegen/generator/statements/loops.js +25 -11
- package/dist/src/codegen/generator/statements/loops.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +41 -1
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +1 -1
- package/dist/src/driver/compiler.js +33 -1
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.d.ts +4 -3
- package/dist/src/driver/modules.js +61 -4
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/toolchain.js +1 -1
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.js +4 -0
- package/dist/src/parser/declarations/classes.js.map +1 -1
- package/dist/src/parser/declarations/type-members.js.map +1 -1
- package/dist/src/parser/expressions.d.ts +2 -1
- package/dist/src/parser/expressions.js +10 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/helpers.js +2 -2
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +79 -6
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/parser.js +0 -1
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/statements.d.ts +1 -0
- package/dist/src/parser/statements.js +13 -1
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/src/parser/types.js +2 -2
- package/dist/src/parser/types.js.map +1 -1
- package/dist/tests/ast/factory.test.d.ts +1 -0
- package/dist/tests/ast/factory.test.js +35 -0
- package/dist/tests/ast/factory.test.js.map +1 -0
- package/dist/tests/ast/visitor.test.d.ts +1 -0
- package/dist/tests/ast/visitor.test.js +53 -0
- package/dist/tests/ast/visitor.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +109 -9
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/closures.test.d.ts +1 -0
- package/dist/tests/codegen/closures.test.js +32 -0
- package/dist/tests/codegen/closures.test.js.map +1 -0
- package/dist/tests/codegen/expressions.test.d.ts +1 -0
- package/dist/tests/codegen/expressions.test.js +149 -0
- package/dist/tests/codegen/expressions.test.js.map +1 -0
- package/dist/tests/codegen/llvm.test.js +14 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/codegen/values.test.d.ts +1 -0
- package/dist/tests/codegen/values.test.js +48 -0
- package/dist/tests/codegen/values.test.js.map +1 -0
- package/dist/tests/diagnostics/diagnostic.test.d.ts +1 -0
- package/dist/tests/diagnostics/diagnostic.test.js +117 -0
- package/dist/tests/diagnostics/diagnostic.test.js.map +1 -0
- package/dist/tests/diagnostics/source.test.d.ts +1 -0
- package/dist/tests/diagnostics/source.test.js +58 -0
- package/dist/tests/diagnostics/source.test.js.map +1 -0
- package/dist/tests/driver/modules.test.d.ts +1 -0
- package/dist/tests/driver/modules.test.js +140 -0
- package/dist/tests/driver/modules.test.js.map +1 -0
- package/dist/tests/driver/paths.test.js +17 -1
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/runtime-lib.test.d.ts +1 -0
- package/dist/tests/driver/runtime-lib.test.js +19 -0
- package/dist/tests/driver/runtime-lib.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +91 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +11 -1
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +14 -1
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +465 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/differential.test.d.ts +7 -0
- package/dist/tests/e2e/differential.test.js +581 -0
- package/dist/tests/e2e/differential.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +21 -0
- package/dist/tests/e2e/harness.js +26 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/extensions/node.test.d.ts +1 -0
- package/dist/tests/extensions/node.test.js +32 -0
- package/dist/tests/extensions/node.test.js.map +1 -0
- package/dist/tests/lexer/identifiers.test.d.ts +1 -0
- package/dist/tests/lexer/identifiers.test.js +13 -0
- package/dist/tests/lexer/identifiers.test.js.map +1 -0
- package/dist/tests/lexer/numbers.test.d.ts +1 -0
- package/dist/tests/lexer/numbers.test.js +23 -0
- package/dist/tests/lexer/numbers.test.js.map +1 -0
- package/dist/tests/lexer/strings.test.d.ts +1 -0
- package/dist/tests/lexer/strings.test.js +72 -0
- package/dist/tests/lexer/strings.test.js.map +1 -0
- package/dist/tests/parser/declarations.test.d.ts +1 -0
- package/dist/tests/parser/declarations.test.js +70 -0
- package/dist/tests/parser/declarations.test.js.map +1 -0
- package/dist/tests/parser/expressions.test.d.ts +1 -0
- package/dist/tests/parser/expressions.test.js +47 -0
- package/dist/tests/parser/expressions.test.js.map +1 -0
- package/dist/tests/parser/helpers.test.d.ts +1 -0
- package/dist/tests/parser/helpers.test.js +58 -0
- package/dist/tests/parser/helpers.test.js.map +1 -0
- package/dist/tests/parser/literals.test.d.ts +1 -0
- package/dist/tests/parser/literals.test.js +70 -0
- package/dist/tests/parser/literals.test.js.map +1 -0
- package/dist/tests/parser/module-syntax.test.d.ts +1 -0
- package/dist/tests/parser/module-syntax.test.js +91 -0
- package/dist/tests/parser/module-syntax.test.js.map +1 -0
- package/dist/tests/parser/statements.test.d.ts +1 -0
- package/dist/tests/parser/statements.test.js +85 -0
- package/dist/tests/parser/statements.test.js.map +1 -0
- package/dist/tests/parser/type-members.test.d.ts +1 -0
- package/dist/tests/parser/type-members.test.js +86 -0
- package/dist/tests/parser/type-members.test.js.map +1 -0
- package/dist/tests/parser/types.test.d.ts +1 -0
- package/dist/tests/parser/types.test.js +143 -0
- package/dist/tests/parser/types.test.js.map +1 -0
- package/package.json +6 -1
- package/runtime/ext_node/fs/fs_ops.c +36 -1
- package/runtime/rt.h +17 -0
- package/runtime/rt_internal.h +88 -2
- package/runtime/xt_builtins.c +174 -6
- package/runtime/xt_containers.c +234 -42
- package/runtime/xt_generator.c +304 -0
- package/runtime/xt_io.c +170 -30
- package/runtime/xt_promise.c +6 -1
- package/runtime/xt_regex.h +105 -35
- package/runtime/xt_stdlib/dispatch.inc +255 -4
- package/runtime/xt_stdlib/strings.inc +17 -13
- package/runtime/xt_stdlib2/arrays.inc +126 -19
- package/runtime/xt_stdlib2/date.inc +9 -2
- package/runtime/xt_stdlib2/error.inc +162 -12
- package/runtime/xt_stdlib2/helpers.inc +4 -0
- package/runtime/xt_stdlib2/json.inc +19 -6
- package/runtime/xt_stdlib2/number-string-statics.inc +1 -1
- package/runtime/xt_stdlib2/numbers.inc +4 -5
- package/runtime/xt_stdlib2/objects.inc +29 -0
- package/runtime/xt_stdlib2/regexp-match.inc +293 -51
- package/runtime/xt_stdlib2/set.inc +58 -2
- package/runtime/xt_stdlib2/strings.inc +38 -0
- package/runtime/xt_symbol.c +149 -0
- package/runtime/xt_values.c +221 -15
- package/scripts/build-runtime.ts +1 -1
- package/src/ast/expressions.ts +8 -0
- package/src/binder/binder.ts +1 -1
- package/src/binder/references.ts +47 -4
- package/src/binder/types.ts +4 -0
- package/src/cli/main.ts +1 -2
- package/src/codegen/generator/calls/access.ts +158 -13
- package/src/codegen/generator/calls/closures.ts +24 -0
- package/src/codegen/generator/calls/invocation.ts +11 -1
- package/src/codegen/generator/calls/literals.ts +10 -4
- package/src/codegen/generator/calls/super.ts +6 -9
- package/src/codegen/generator/context.ts +44 -7
- package/src/codegen/generator/expressions/assignment.ts +1 -3
- package/src/codegen/generator/expressions/primary.ts +108 -2
- package/src/codegen/generator/generator.ts +0 -1
- package/src/codegen/generator/module.ts +24 -18
- package/src/codegen/generator/state.ts +44 -1
- package/src/codegen/generator/statements/control-flow.ts +86 -0
- package/src/codegen/generator/statements/dispatch.ts +18 -6
- package/src/codegen/generator/statements/loops.ts +29 -11
- package/src/codegen/generator/tables.ts +44 -1
- package/src/driver/compiler.ts +32 -2
- package/src/driver/modules.ts +64 -4
- package/src/driver/toolchain.ts +1 -1
- package/src/lexer/scanner.ts +0 -1
- package/src/parser/declarations/classes.ts +4 -0
- package/src/parser/declarations/type-members.ts +0 -2
- package/src/parser/expressions.ts +13 -1
- package/src/parser/helpers.ts +2 -2
- package/src/parser/literals.ts +82 -7
- package/src/parser/modules.ts +0 -1
- package/src/parser/parser.ts +0 -1
- package/src/parser/statements.ts +14 -0
- package/src/parser/types.ts +2 -2
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — stackful generators.
|
|
3
|
+
*
|
|
4
|
+
* A generator function object carries `is_generator`. Calling it does not run
|
|
5
|
+
* the body; it creates an `xt_generator` that owns a private stack. `.next()`
|
|
6
|
+
* switches onto that stack, where the body runs until it calls `xt_yield`,
|
|
7
|
+
* which switches back. Because the body keeps a real call stack, `try`,
|
|
8
|
+
* `finally` and nested loops work across suspension points without a state
|
|
9
|
+
* machine transform.
|
|
10
|
+
*
|
|
11
|
+
* POSIX uses `ucontext` (`swapcontext`); Windows uses fibers. The generator's
|
|
12
|
+
* exception stack is swapped alongside it so a `throw` inside the body still
|
|
13
|
+
* targets the body's own `try` frames.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#define _XOPEN_SOURCE 700
|
|
17
|
+
|
|
18
|
+
#include "rt_internal.h"
|
|
19
|
+
|
|
20
|
+
#include <stdlib.h>
|
|
21
|
+
#include <string.h>
|
|
22
|
+
|
|
23
|
+
#if defined(__APPLE__)
|
|
24
|
+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
#ifdef _WIN32
|
|
28
|
+
#include <windows.h>
|
|
29
|
+
#else
|
|
30
|
+
#include <ucontext.h>
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
typedef struct xt_generator {
|
|
34
|
+
xt_header header;
|
|
35
|
+
xt_value function;
|
|
36
|
+
xt_value this_value;
|
|
37
|
+
xt_value *args;
|
|
38
|
+
int32_t argc;
|
|
39
|
+
xt_value sent; /* value passed by the most recent resume */
|
|
40
|
+
xt_value result; /* yielded / returned value, or a thrown exception */
|
|
41
|
+
/* Value pulled by `xt_iter_has` and consumed by `xt_iter_value`. */
|
|
42
|
+
xt_value iter_value;
|
|
43
|
+
int resume_kind; /* 0 = next, 1 = throw, 2 = return */
|
|
44
|
+
int started;
|
|
45
|
+
int done;
|
|
46
|
+
int threw;
|
|
47
|
+
int booted;
|
|
48
|
+
void *saved_try_top;
|
|
49
|
+
#ifdef _WIN32
|
|
50
|
+
void *fiber;
|
|
51
|
+
void *caller_fiber;
|
|
52
|
+
#else
|
|
53
|
+
ucontext_t ctx;
|
|
54
|
+
ucontext_t caller;
|
|
55
|
+
char *stack;
|
|
56
|
+
#endif
|
|
57
|
+
} xt_generator;
|
|
58
|
+
|
|
59
|
+
/* The generator whose coroutine is running, if any. */
|
|
60
|
+
static xt_generator *g_active_generator = NULL;
|
|
61
|
+
/* Filled in just before a coroutine is first entered (POSIX has no portable
|
|
62
|
+
* way to pass a pointer to `makecontext`). */
|
|
63
|
+
static xt_generator *g_boot_generator = NULL;
|
|
64
|
+
#ifdef _WIN32
|
|
65
|
+
static void *g_main_fiber = NULL;
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
int xt_is_generator(xt_value value) {
|
|
69
|
+
if (!XT_IS_OBJECT(value)) return 0;
|
|
70
|
+
return ((xt_header *)XT_GET_PTR(value))->kind == XT_OBJECT_KIND_GENERATOR;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static xt_generator *xt_as_generator(xt_value value) {
|
|
74
|
+
if (!xt_is_generator(value)) return NULL;
|
|
75
|
+
return (xt_generator *)XT_GET_PTR(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static xt_value xt_generator_result_object(xt_value value, int done) {
|
|
79
|
+
xt_value result = xt_object_new();
|
|
80
|
+
xt_object_set(result, xt_string_from_cstr("value"), value);
|
|
81
|
+
xt_object_set(result, xt_string_from_cstr("done"), xt_bool(done));
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static void xt_generator_suspend(xt_generator *gen) {
|
|
86
|
+
gen->saved_try_top = xt_try_mark();
|
|
87
|
+
#ifdef _WIN32
|
|
88
|
+
SwitchToFiber(gen->caller_fiber);
|
|
89
|
+
#else
|
|
90
|
+
swapcontext(&gen->ctx, &gen->caller);
|
|
91
|
+
#endif
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Runs on the generator's private stack. */
|
|
95
|
+
static void xt_generator_run(xt_generator *gen) {
|
|
96
|
+
void *boundary = xt_try_enter();
|
|
97
|
+
if (xt_try_setjmp(boundary) == 0) {
|
|
98
|
+
xt_function *function = (xt_function *)XT_GET_PTR(gen->function);
|
|
99
|
+
gen->result = function->code(gen->this_value, gen->function, gen->argc, gen->args);
|
|
100
|
+
gen->threw = 0;
|
|
101
|
+
} else {
|
|
102
|
+
gen->result = xt_try_exception(boundary);
|
|
103
|
+
gen->threw = 1;
|
|
104
|
+
}
|
|
105
|
+
gen->done = 1;
|
|
106
|
+
xt_generator_suspend(gen);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#ifndef _WIN32
|
|
110
|
+
static void xt_generator_entry(void) {
|
|
111
|
+
xt_generator *gen = g_boot_generator;
|
|
112
|
+
g_boot_generator = NULL;
|
|
113
|
+
xt_generator_run(gen);
|
|
114
|
+
}
|
|
115
|
+
#else
|
|
116
|
+
static void CALLBACK xt_generator_entry(void *param) {
|
|
117
|
+
xt_generator_run((xt_generator *)param);
|
|
118
|
+
}
|
|
119
|
+
#endif
|
|
120
|
+
|
|
121
|
+
static void xt_generator_boot(xt_generator *gen) {
|
|
122
|
+
#ifdef _WIN32
|
|
123
|
+
if (!g_main_fiber) g_main_fiber = ConvertThreadToFiber(NULL);
|
|
124
|
+
gen->fiber = CreateFiber(1 << 20, xt_generator_entry, gen);
|
|
125
|
+
if (!gen->fiber) abort();
|
|
126
|
+
#else
|
|
127
|
+
size_t size = 1 << 20;
|
|
128
|
+
gen->stack = (char *)malloc(size);
|
|
129
|
+
if (!gen->stack) abort();
|
|
130
|
+
if (getcontext(&gen->ctx) != 0) abort();
|
|
131
|
+
gen->ctx.uc_stack.ss_sp = gen->stack;
|
|
132
|
+
gen->ctx.uc_stack.ss_size = size;
|
|
133
|
+
gen->ctx.uc_link = NULL;
|
|
134
|
+
g_boot_generator = gen;
|
|
135
|
+
makecontext(&gen->ctx, xt_generator_entry, 0);
|
|
136
|
+
#endif
|
|
137
|
+
gen->booted = 1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Release the private stack once the coroutine has finished. The generator
|
|
141
|
+
* object itself stays valid; later `.next()` calls just report `done`. */
|
|
142
|
+
static void xt_generator_dispose(xt_generator *gen) {
|
|
143
|
+
#ifdef _WIN32
|
|
144
|
+
if (gen->fiber) {
|
|
145
|
+
DeleteFiber(gen->fiber);
|
|
146
|
+
gen->fiber = NULL;
|
|
147
|
+
}
|
|
148
|
+
gen->caller_fiber = NULL;
|
|
149
|
+
#else
|
|
150
|
+
if (gen->stack) {
|
|
151
|
+
free(gen->stack);
|
|
152
|
+
gen->stack = NULL;
|
|
153
|
+
}
|
|
154
|
+
#endif
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static void xt_generator_resume(xt_generator *gen) {
|
|
158
|
+
if (!gen->booted) xt_generator_boot(gen);
|
|
159
|
+
xt_generator *previous = g_active_generator;
|
|
160
|
+
g_active_generator = gen;
|
|
161
|
+
void *caller_try = xt_try_mark();
|
|
162
|
+
xt_try_restore(gen->saved_try_top);
|
|
163
|
+
#ifdef _WIN32
|
|
164
|
+
gen->caller_fiber = GetCurrentFiber();
|
|
165
|
+
SwitchToFiber(gen->fiber);
|
|
166
|
+
#else
|
|
167
|
+
swapcontext(&gen->caller, &gen->ctx);
|
|
168
|
+
#endif
|
|
169
|
+
gen->saved_try_top = xt_try_mark();
|
|
170
|
+
xt_try_restore(caller_try);
|
|
171
|
+
if (gen->done) xt_generator_dispose(gen);
|
|
172
|
+
g_active_generator = previous;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
xt_value xt_generator_new(xt_value function, xt_value thisValue, int32_t argc, xt_value *argv) {
|
|
176
|
+
xt_generator *gen = (xt_generator *)xt_alloc(sizeof(xt_generator), XT_OBJECT_KIND_GENERATOR);
|
|
177
|
+
gen->function = function;
|
|
178
|
+
gen->this_value = thisValue;
|
|
179
|
+
gen->argc = argc;
|
|
180
|
+
gen->result = XT_UNDEFINED;
|
|
181
|
+
gen->sent = XT_UNDEFINED;
|
|
182
|
+
gen->iter_value = XT_UNDEFINED;
|
|
183
|
+
if (argc > 0 && argv) {
|
|
184
|
+
gen->args = (xt_value *)malloc(sizeof(xt_value) * (size_t)argc);
|
|
185
|
+
if (!gen->args) abort();
|
|
186
|
+
memcpy(gen->args, argv, sizeof(xt_value) * (size_t)argc);
|
|
187
|
+
}
|
|
188
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, gen);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
xt_value xt_generator_next(xt_value generator, xt_value sent) {
|
|
192
|
+
xt_generator *gen = xt_as_generator(generator);
|
|
193
|
+
if (!gen) {
|
|
194
|
+
xt_throw(xt_string_from_cstr("TypeError: not a generator"));
|
|
195
|
+
return XT_UNDEFINED;
|
|
196
|
+
}
|
|
197
|
+
if (gen->done) return xt_generator_result_object(XT_UNDEFINED, 1);
|
|
198
|
+
gen->sent = sent;
|
|
199
|
+
gen->resume_kind = 0;
|
|
200
|
+
xt_generator_resume(gen);
|
|
201
|
+
if (gen->done) {
|
|
202
|
+
if (gen->threw) xt_throw(gen->result);
|
|
203
|
+
return xt_generator_result_object(gen->result, 1);
|
|
204
|
+
}
|
|
205
|
+
return xt_generator_result_object(gen->result, 0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
xt_value xt_generator_throw(xt_value generator, xt_value error) {
|
|
209
|
+
xt_generator *gen = xt_as_generator(generator);
|
|
210
|
+
if (!gen) {
|
|
211
|
+
xt_throw(xt_string_from_cstr("TypeError: not a generator"));
|
|
212
|
+
return XT_UNDEFINED;
|
|
213
|
+
}
|
|
214
|
+
if (gen->done) {
|
|
215
|
+
xt_throw(error);
|
|
216
|
+
return XT_UNDEFINED;
|
|
217
|
+
}
|
|
218
|
+
gen->sent = error;
|
|
219
|
+
gen->resume_kind = 1;
|
|
220
|
+
xt_generator_resume(gen);
|
|
221
|
+
if (gen->done) {
|
|
222
|
+
if (gen->threw) xt_throw(gen->result);
|
|
223
|
+
return xt_generator_result_object(gen->result, 1);
|
|
224
|
+
}
|
|
225
|
+
return xt_generator_result_object(gen->result, 0);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
xt_value xt_generator_return(xt_value generator, xt_value value) {
|
|
229
|
+
xt_generator *gen = xt_as_generator(generator);
|
|
230
|
+
if (!gen) {
|
|
231
|
+
xt_throw(xt_string_from_cstr("TypeError: not a generator"));
|
|
232
|
+
return XT_UNDEFINED;
|
|
233
|
+
}
|
|
234
|
+
/* Abandon the coroutine without resuming: finally blocks are not run. */
|
|
235
|
+
gen->done = 1;
|
|
236
|
+
gen->threw = 0;
|
|
237
|
+
gen->result = value;
|
|
238
|
+
xt_generator_dispose(gen);
|
|
239
|
+
return xt_generator_result_object(value, 1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* Suspend the running generator with `value`; returns the value the caller
|
|
243
|
+
* passes to the next resume (`next(v)` / `throw(e)` / `return(v)`). */
|
|
244
|
+
xt_value xt_yield(xt_value value) {
|
|
245
|
+
xt_generator *gen = g_active_generator;
|
|
246
|
+
if (!gen || gen->done) return XT_UNDEFINED;
|
|
247
|
+
gen->result = value;
|
|
248
|
+
xt_generator_suspend(gen);
|
|
249
|
+
if (gen->resume_kind == 1) {
|
|
250
|
+
xt_throw(gen->sent);
|
|
251
|
+
return XT_UNDEFINED;
|
|
252
|
+
}
|
|
253
|
+
if (gen->resume_kind == 2) {
|
|
254
|
+
gen->done = 1;
|
|
255
|
+
gen->threw = 0;
|
|
256
|
+
gen->result = gen->sent;
|
|
257
|
+
xt_generator_suspend(gen);
|
|
258
|
+
return XT_UNDEFINED;
|
|
259
|
+
}
|
|
260
|
+
return gen->sent;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* `yield* delegate`: relay every value the delegate produces. */
|
|
264
|
+
xt_value xt_yield_star(xt_value delegate) {
|
|
265
|
+
xt_value nextName = xt_string_from_cstr("next");
|
|
266
|
+
int usesNext = XT_IS_FUNCTION(xt_get(delegate, nextName));
|
|
267
|
+
/* A plain iterable (`[Symbol.iterator]` but no `next`) resolves through the
|
|
268
|
+
* iteration protocol; arrays/strings/Map/Set keep their index protocol. */
|
|
269
|
+
if (!usesNext) delegate = xt_iter_open(delegate);
|
|
270
|
+
xt_value sent = XT_UNDEFINED;
|
|
271
|
+
int32_t index = 0;
|
|
272
|
+
for (;;) {
|
|
273
|
+
xt_value value;
|
|
274
|
+
int done;
|
|
275
|
+
if (usesNext) {
|
|
276
|
+
xt_value step = xt_call_method(delegate, nextName, 1, &sent);
|
|
277
|
+
done = xt_truthy(xt_get(step, xt_string_from_cstr("done")));
|
|
278
|
+
value = xt_get(step, xt_string_from_cstr("value"));
|
|
279
|
+
} else {
|
|
280
|
+
xt_value position = xt_number((double)index);
|
|
281
|
+
if (!xt_truthy(xt_iter_has(delegate, position))) return XT_UNDEFINED;
|
|
282
|
+
value = xt_iter_value(delegate, position);
|
|
283
|
+
index++;
|
|
284
|
+
done = 0;
|
|
285
|
+
}
|
|
286
|
+
if (done) return value;
|
|
287
|
+
sent = xt_yield(value);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* `for...of` step for generators: pull and cache the next value. */
|
|
292
|
+
int xt_generator_has_next(xt_value generator) {
|
|
293
|
+
xt_generator *gen = xt_as_generator(generator);
|
|
294
|
+
if (!gen || gen->done) return 0;
|
|
295
|
+
xt_value step = xt_generator_next(generator, XT_UNDEFINED);
|
|
296
|
+
if (xt_truthy(xt_get(step, xt_string_from_cstr("done")))) return 0;
|
|
297
|
+
gen->iter_value = xt_get(step, xt_string_from_cstr("value"));
|
|
298
|
+
return 1;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
xt_value xt_generator_iter_value(xt_value generator) {
|
|
302
|
+
xt_generator *gen = xt_as_generator(generator);
|
|
303
|
+
return gen ? gen->iter_value : XT_UNDEFINED;
|
|
304
|
+
}
|
package/runtime/xt_io.c
CHANGED
|
@@ -7,15 +7,17 @@
|
|
|
7
7
|
*
|
|
8
8
|
* The generated IR calls `_setjmp` with two arguments — the jmp_buf and the
|
|
9
9
|
* caller's frame address (`@llvm.frameaddress(0)`) — paired with `longjmp`
|
|
10
|
-
* here. This is exactly what clang lowers a C `_setjmp(buf)` call to on MSVC
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `
|
|
14
|
-
*
|
|
15
|
-
* (
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
10
|
+
* here. This is exactly what clang lowers a C `_setjmp(buf)` call to on MSVC:
|
|
11
|
+
* on Windows the UCRT `_setjmp` stores that frame in `_JUMP_BUFFER.Frame` and
|
|
12
|
+
* `longjmp` passes it to `RtlUnwind` to run the unwind, so omitting it makes
|
|
13
|
+
* `longjmp` unwind to a bogus target (`STATUS_BAD_FUNCTION_TABLE`,
|
|
14
|
+
* 0xC00000FF). Because the generated call is IR it must pass the frame
|
|
15
|
+
* explicitly; the C runtime (see `xt_try_setjmp`) instead follows whatever
|
|
16
|
+
* the active `<setjmp.h>` declares -- one argument on MSVC (clang injects the
|
|
17
|
+
* frame) and two on MinGW-w64. `_setjmp` is used
|
|
18
|
+
* rather than the exported `setjmp` symbol, whose Windows ABI is an
|
|
19
|
+
* incompatible two-argument routine; on Linux/macOS `_setjmp` takes only the
|
|
20
|
+
* buffer and pairs with `longjmp` (the XSI `_longjmp` does not exist on
|
|
19
21
|
* Windows).
|
|
20
22
|
*/
|
|
21
23
|
|
|
@@ -43,12 +45,6 @@
|
|
|
43
45
|
* with `xt_try_leave`. `xt_throw` longjmps into the innermost frame when one
|
|
44
46
|
* is active, and only prints + exits when the exception is uncaught.
|
|
45
47
|
*/
|
|
46
|
-
typedef struct xt_try_frame {
|
|
47
|
-
jmp_buf buf;
|
|
48
|
-
struct xt_try_frame *prev;
|
|
49
|
-
xt_value exception;
|
|
50
|
-
} xt_try_frame;
|
|
51
|
-
|
|
52
48
|
static xt_try_frame *g_try_top = NULL;
|
|
53
49
|
|
|
54
50
|
/* Program arguments, captured once by `xt_set_program_args` from `main`. */
|
|
@@ -138,9 +134,18 @@ xt_value xt_try_exception(void *framePtr) {
|
|
|
138
134
|
|
|
139
135
|
void xt_try_leave(void *framePtr) {
|
|
140
136
|
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
141
|
-
if (frame && g_try_top == frame)
|
|
137
|
+
if (frame && g_try_top == frame) {
|
|
138
|
+
g_try_top = frame->prev;
|
|
139
|
+
free(frame);
|
|
140
|
+
}
|
|
142
141
|
}
|
|
143
142
|
|
|
143
|
+
/* Save/restore the innermost try frame. Generators use this to swap their own
|
|
144
|
+
* exception stack in while they run on their private coroutine stack. */
|
|
145
|
+
void *xt_try_mark(void) { return (void *)g_try_top; }
|
|
146
|
+
|
|
147
|
+
void xt_try_restore(void *mark) { g_try_top = (xt_try_frame *)mark; }
|
|
148
|
+
|
|
144
149
|
void xt_throw(xt_value v) {
|
|
145
150
|
if (g_try_top) {
|
|
146
151
|
g_try_top->exception = v;
|
|
@@ -172,8 +177,77 @@ void xt_println(xt_value v) {
|
|
|
172
177
|
/*
|
|
173
178
|
* console.log applies a Node-like inspection format: strings unquoted at the
|
|
174
179
|
* top level, arrays as `[ a, b ]` and objects as `{ key: value }`.
|
|
180
|
+
*
|
|
181
|
+
* Recursion tracks the ancestor chain so self-referential containers print
|
|
182
|
+
* Node's `[Circular *N]` marker instead of recursing forever. `N` is the
|
|
183
|
+
* 1-based position of the repeated container in the current path.
|
|
175
184
|
*/
|
|
176
|
-
|
|
185
|
+
#define XT_INSPECT_MAX_DEPTH 512
|
|
186
|
+
static const void *xt_inspect_stack[XT_INSPECT_MAX_DEPTH];
|
|
187
|
+
static int xt_inspect_depth = 0;
|
|
188
|
+
|
|
189
|
+
static int xt_inspect_seen(const void *ptr) {
|
|
190
|
+
for (int i = 0; i < xt_inspect_depth; i++) {
|
|
191
|
+
if (xt_inspect_stack[i] == ptr) return i + 1;
|
|
192
|
+
}
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static void xt_inspect_push(const void *ptr) {
|
|
197
|
+
if (xt_inspect_depth < XT_INSPECT_MAX_DEPTH) xt_inspect_stack[xt_inspect_depth++] = ptr;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static void xt_inspect_pop(void) {
|
|
201
|
+
if (xt_inspect_depth > 0) xt_inspect_depth--;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static int xt_inspect_identifier_key(xt_string *key) {
|
|
205
|
+
if (key->length == 0) return 0;
|
|
206
|
+
char c = key->data[0];
|
|
207
|
+
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$')) return 0;
|
|
208
|
+
for (uint32_t i = 1; i < key->length; i++) {
|
|
209
|
+
c = key->data[i];
|
|
210
|
+
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$')) return 0;
|
|
211
|
+
}
|
|
212
|
+
return 1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* Render a string the way `util.inspect` does inside a container: quoted,
|
|
216
|
+
* preferring whichever quote character needs fewer escapes. */
|
|
217
|
+
static void xt_inspect_string(xt_string *s, FILE *out) {
|
|
218
|
+
int hasSingle = 0;
|
|
219
|
+
int hasDouble = 0;
|
|
220
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
221
|
+
if (s->data[i] == '\'') hasSingle = 1;
|
|
222
|
+
else if (s->data[i] == '"') hasDouble = 1;
|
|
223
|
+
}
|
|
224
|
+
char quote = (hasSingle && !hasDouble) ? '"' : '\'';
|
|
225
|
+
fputc(quote, out);
|
|
226
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
227
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
228
|
+
switch (c) {
|
|
229
|
+
case '\\': fputs("\\\\", out); break;
|
|
230
|
+
case '\n': fputs("\\n", out); break;
|
|
231
|
+
case '\r': fputs("\\r", out); break;
|
|
232
|
+
case '\t': fputs("\\t", out); break;
|
|
233
|
+
case '\f': fputs("\\f", out); break;
|
|
234
|
+
case '\b': fputs("\\b", out); break;
|
|
235
|
+
case '\v': fputs("\\v", out); break;
|
|
236
|
+
default:
|
|
237
|
+
if (c == (unsigned char)quote) { fputc('\\', out); fputc(c, out); }
|
|
238
|
+
else if (c < 0x20) fprintf(out, "\\x%02x", c);
|
|
239
|
+
else fputc(c, out);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
fputc(quote, out);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
static void xt_inspect(xt_value v, FILE *out, int nested) {
|
|
246
|
+
if (xt_is_symbol(v)) {
|
|
247
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(v));
|
|
248
|
+
fwrite(text->data, 1, text->length, out);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
177
251
|
if (XT_IS_BIGINT(v)) {
|
|
178
252
|
xt_value text = xt_bigint_to_decimal(v);
|
|
179
253
|
xt_string *s = xt_as_string(text);
|
|
@@ -181,39 +255,105 @@ static void xt_inspect(xt_value v, FILE *out) {
|
|
|
181
255
|
fputc('n', out);
|
|
182
256
|
return;
|
|
183
257
|
}
|
|
258
|
+
if (nested && XT_IS_STRING(v)) {
|
|
259
|
+
xt_inspect_string(xt_as_string(v), out);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
184
262
|
if (XT_IS_ARRAY(v)) {
|
|
185
263
|
xt_array *array = (xt_array *)XT_GET_PTR(v);
|
|
264
|
+
int seen = xt_inspect_seen(array);
|
|
265
|
+
if (seen > 0) {
|
|
266
|
+
fprintf(out, "[Circular *%d]", seen);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
|
|
270
|
+
fputs("[Array]", out);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
xt_inspect_push(array);
|
|
186
274
|
fputc('[', out);
|
|
187
275
|
for (uint32_t i = 0; i < array->length; i++) {
|
|
188
276
|
if (i > 0) fputs(", ", out);
|
|
189
277
|
else fputc(' ', out);
|
|
190
|
-
xt_inspect(array->items[i], out);
|
|
278
|
+
xt_inspect(array->items[i], out, 1);
|
|
279
|
+
}
|
|
280
|
+
if (XT_IS_OBJECT(array->extra)) {
|
|
281
|
+
xt_object *extra = (xt_object *)XT_GET_PTR(array->extra);
|
|
282
|
+
for (uint32_t i = 0; i < extra->count; i++) {
|
|
283
|
+
if (array->length > 0 || i > 0) fputs(", ", out);
|
|
284
|
+
else fputc(' ', out);
|
|
285
|
+
xt_value key = extra->properties[i].key;
|
|
286
|
+
if (xt_is_symbol(key)) {
|
|
287
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
288
|
+
fwrite(text->data, 1, text->length, out);
|
|
289
|
+
} else {
|
|
290
|
+
xt_string *keyString = xt_as_string(key);
|
|
291
|
+
fwrite(keyString->data, 1, keyString->length, out);
|
|
292
|
+
}
|
|
293
|
+
fputs(": ", out);
|
|
294
|
+
xt_inspect(extra->properties[i].value, out, 1);
|
|
295
|
+
}
|
|
191
296
|
}
|
|
192
|
-
if (array->length > 0) fputc(' ', out);
|
|
297
|
+
if (array->length > 0 || (XT_IS_OBJECT(array->extra) && ((xt_object *)XT_GET_PTR(array->extra))->count > 0)) fputc(' ', out);
|
|
193
298
|
fputc(']', out);
|
|
299
|
+
xt_inspect_pop();
|
|
194
300
|
return;
|
|
195
301
|
}
|
|
196
302
|
if (XT_IS_OBJECT(v)) {
|
|
197
303
|
xt_object *obj = (xt_object *)XT_GET_PTR(v);
|
|
304
|
+
int seen = xt_inspect_seen(obj);
|
|
305
|
+
if (seen > 0) {
|
|
306
|
+
fprintf(out, "[Circular *%d]", seen);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
|
|
310
|
+
fputs("[Object]", out);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
xt_inspect_push(obj);
|
|
198
314
|
fputc('{', out);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
315
|
+
/* `util.inspect` lists string keys first, then symbol keys, in insertion
|
|
316
|
+
* order; symbol keys are printed without brackets. */
|
|
317
|
+
int written = 0;
|
|
318
|
+
for (int pass = 0; pass < 2; pass++) {
|
|
319
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
320
|
+
xt_value key = obj->properties[i].key;
|
|
321
|
+
int isSymbol = xt_is_symbol(key);
|
|
322
|
+
if ((pass == 0) == isSymbol) continue;
|
|
323
|
+
if (written > 0) fputs(", ", out);
|
|
324
|
+
else fputc(' ', out);
|
|
325
|
+
written++;
|
|
326
|
+
if (isSymbol) {
|
|
327
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
328
|
+
fwrite(text->data, 1, text->length, out);
|
|
329
|
+
} else {
|
|
330
|
+
xt_string *keyString = xt_as_string(key);
|
|
331
|
+
if (xt_inspect_identifier_key(keyString)) fwrite(keyString->data, 1, keyString->length, out);
|
|
332
|
+
else xt_inspect_string(keyString, out);
|
|
333
|
+
}
|
|
334
|
+
fputs(": ", out);
|
|
335
|
+
xt_inspect(obj->properties[i].value, out, 1);
|
|
336
|
+
}
|
|
205
337
|
}
|
|
206
|
-
if (
|
|
338
|
+
if (written > 0) fputc(' ', out);
|
|
207
339
|
fputc('}', out);
|
|
340
|
+
xt_inspect_pop();
|
|
208
341
|
return;
|
|
209
342
|
}
|
|
210
343
|
xt_print_value(v, out);
|
|
211
344
|
}
|
|
212
345
|
|
|
346
|
+
/* Inspect one top-level value; reset the ancestor chain so nested console
|
|
347
|
+
* calls (or a `longjmp` out of a throw) never leave stale state behind. */
|
|
348
|
+
static void xt_inspect_top(xt_value v, FILE *out) {
|
|
349
|
+
xt_inspect_depth = 0;
|
|
350
|
+
xt_inspect(v, out, 0);
|
|
351
|
+
}
|
|
352
|
+
|
|
213
353
|
void xt_console_log(int32_t argc, xt_value *argv) {
|
|
214
354
|
for (int32_t i = 0; i < argc; i++) {
|
|
215
355
|
if (i > 0) fputc(' ', stdout);
|
|
216
|
-
|
|
356
|
+
xt_inspect_top(argv[i], stdout);
|
|
217
357
|
}
|
|
218
358
|
fputc('\n', stdout);
|
|
219
359
|
}
|
|
@@ -221,7 +361,7 @@ void xt_console_log(int32_t argc, xt_value *argv) {
|
|
|
221
361
|
static void xt_console_write(int32_t argc, xt_value *argv, FILE *out) {
|
|
222
362
|
for (int32_t i = 0; i < argc; i++) {
|
|
223
363
|
if (i > 0) fputc(' ', out);
|
|
224
|
-
|
|
364
|
+
xt_inspect_top(argv[i], out);
|
|
225
365
|
}
|
|
226
366
|
fputc('\n', out);
|
|
227
367
|
}
|
|
@@ -239,7 +379,7 @@ xt_value xt_console_trace(int32_t argc, xt_value *argv) {
|
|
|
239
379
|
fputs("Trace", stderr);
|
|
240
380
|
for (int32_t i = 0; i < argc; i++) {
|
|
241
381
|
fputc(' ', stderr);
|
|
242
|
-
|
|
382
|
+
xt_inspect_top(argv[i], stderr);
|
|
243
383
|
}
|
|
244
384
|
fputc('\n', stderr);
|
|
245
385
|
return XT_UNDEFINED;
|
|
@@ -251,7 +391,7 @@ xt_value xt_console_assert(int32_t argc, xt_value *argv) {
|
|
|
251
391
|
if (argc > 1) fputs(":", stderr);
|
|
252
392
|
for (int32_t i = 1; i < argc; i++) {
|
|
253
393
|
fputc(' ', stderr);
|
|
254
|
-
|
|
394
|
+
xt_inspect_top(argv[i], stderr);
|
|
255
395
|
}
|
|
256
396
|
fputc('\n', stderr);
|
|
257
397
|
}
|
package/runtime/xt_promise.c
CHANGED
|
@@ -210,6 +210,7 @@ xt_value xt_promise_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
210
210
|
if (XT_IS_ARRAY(iterable)) {
|
|
211
211
|
xt_array *array = xt_as_array(iterable);
|
|
212
212
|
int anyRejected = 0;
|
|
213
|
+
xt_value reasons = xt_array_new(0, NULL);
|
|
213
214
|
for (uint32_t i = 0; i < array->length; i++) {
|
|
214
215
|
xt_value item = array->items[i];
|
|
215
216
|
xt_promise *inner = xt_is_promise(item) ? xt_as_promise(item) : NULL;
|
|
@@ -224,6 +225,7 @@ xt_value xt_promise_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
224
225
|
if (rejected) {
|
|
225
226
|
if (strcmp(fn, "any") == 0) {
|
|
226
227
|
anyRejected++;
|
|
228
|
+
xt_array_push(reasons, inner->value);
|
|
227
229
|
continue;
|
|
228
230
|
}
|
|
229
231
|
xt_promise_settle(result, XT_PROMISE_REJECTED, inner->value);
|
|
@@ -237,7 +239,10 @@ xt_value xt_promise_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
237
239
|
xt_array_push(values, settled);
|
|
238
240
|
}
|
|
239
241
|
if (strcmp(fn, "any") == 0 && anyRejected > 0) {
|
|
240
|
-
|
|
242
|
+
xt_value ctorArgv[2];
|
|
243
|
+
ctorArgv[0] = reasons;
|
|
244
|
+
ctorArgv[1] = xt_string_from_cstr("All promises were rejected");
|
|
245
|
+
xt_promise_settle(result, XT_PROMISE_REJECTED, xt_aggregate_error_ctor(2, ctorArgv));
|
|
241
246
|
return xt_promise_value(result);
|
|
242
247
|
}
|
|
243
248
|
}
|