xbintsc 0.3.79 → 0.3.87
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/README.md +13 -5
- package/README.zh-CN.md +13 -6
- package/dist/src/ast/common.d.ts +23 -0
- package/dist/src/cli/main.js +68 -24
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +5 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +50 -0
- package/dist/src/codegen/generator/context.js +124 -13
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.d.ts +33 -0
- package/dist/src/codegen/generator/debug.js +97 -0
- package/dist/src/codegen/generator/debug.js.map +1 -0
- package/dist/src/codegen/generator/expressions/assignment.js +9 -5
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +35 -9
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -2
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.d.ts +3 -1
- package/dist/src/codegen/generator/generator.js +3 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +76 -6
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +26 -0
- package/dist/src/codegen/generator/numeric.js +127 -0
- package/dist/src/codegen/generator/numeric.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +17 -0
- package/dist/src/codegen/generator/state.js +5 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +3 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +8 -2
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +25 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +41 -5
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +22 -3
- package/dist/src/driver/compiler.js +49 -58
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.d.ts +27 -0
- package/dist/src/driver/fingerprint.js +88 -0
- package/dist/src/driver/fingerprint.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +9 -2
- package/dist/src/driver/toolchain-provider.js +15 -15
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +58 -1
- package/dist/src/driver/toolchain.js +169 -22
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/gui/index.js +10 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/parser/expressions.js +20 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/tests/cli/main.test.js +41 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/expressions.test.js +14 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +23 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +49 -2
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +62 -3
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.d.ts +10 -0
- package/dist/tests/e2e/child-process.test.js +59 -0
- package/dist/tests/e2e/child-process.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +47 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/error-stack.test.d.ts +9 -0
- package/dist/tests/e2e/error-stack.test.js +94 -0
- package/dist/tests/e2e/error-stack.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-svg.test.d.ts +21 -0
- package/dist/tests/e2e/gui-example-svg.test.js +105 -0
- package/dist/tests/e2e/gui-example-svg.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.d.ts +7 -0
- package/dist/tests/e2e/gui-transform.test.js +198 -0
- package/dist/tests/e2e/gui-transform.test.js.map +1 -0
- package/dist/tests/e2e/string-concat.test.d.ts +9 -0
- package/dist/tests/e2e/string-concat.test.js +102 -0
- package/dist/tests/e2e/string-concat.test.js.map +1 -0
- package/dist/tests/helpers.d.ts +9 -0
- package/dist/tests/helpers.js +26 -3
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +7 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/version.test.d.ts +1 -0
- package/dist/tests/version.test.js +24 -0
- package/dist/tests/version.test.js.map +1 -0
- package/doc/DESIGN.md +20 -12
- package/doc/ai/cli.md +7 -0
- package/doc/ai/contributing.md +7 -1
- package/doc/ai/extensions.md +5 -1
- package/doc/ai/language-support.md +4 -4
- package/doc/ai/troubleshooting.md +39 -2
- package/doc/ai/zh-CN/cli.md +2 -0
- package/doc/ai/zh-CN/contributing.md +6 -2
- package/doc/ai/zh-CN/extensions.md +5 -1
- package/doc/ai/zh-CN/language-support.md +4 -4
- package/doc/ai/zh-CN/troubleshooting.md +35 -2
- package/doc/gui/animation.md +53 -2
- package/doc/gui/api.md +1 -1
- package/doc/gui/dom.md +6 -1
- package/doc/gui/input.md +4 -1
- package/doc/gui/known-issues.md +16 -4
- package/doc/gui/layout.md +36 -0
- package/doc/gui/rendering.md +15 -0
- package/doc/gui.md +32 -3
- package/doc/implemented.md +4 -4
- package/doc/requirements.md +13 -4
- package/doc/unimplemented.md +11 -10
- package/doc/zh-CN/DESIGN.md +15 -9
- package/doc/zh-CN/gui/animation.md +49 -2
- package/doc/zh-CN/gui/api.md +1 -1
- package/doc/zh-CN/gui/dom.md +6 -1
- package/doc/zh-CN/gui/input.md +2 -0
- package/doc/zh-CN/gui/known-issues.md +12 -2
- package/doc/zh-CN/gui/layout.md +31 -0
- package/doc/zh-CN/gui/rendering.md +11 -0
- package/doc/zh-CN/gui.md +28 -3
- package/doc/zh-CN/implemented.md +4 -4
- package/doc/zh-CN/requirements.md +12 -3
- package/doc/zh-CN/unimplemented.md +10 -9
- package/package.json +3 -1
- package/runtime/ext_gui/document.cpp +21 -3
- package/runtime/ext_gui/document.h +4 -1
- package/runtime/ext_gui/dom_api_node.cpp +6 -4
- package/runtime/ext_gui/layout.cpp +78 -1
- package/runtime/ext_gui/layout.h +21 -0
- package/runtime/ext_gui/paint.cpp +48 -15
- package/runtime/ext_gui/paint.h +8 -2
- package/runtime/ext_gui/renderer.cpp +4 -2
- package/runtime/ext_gui/renderer_image.cpp +2 -1
- package/runtime/ext_gui/renderer_internal.h +6 -1
- package/runtime/ext_gui/renderer_text.cpp +37 -15
- package/runtime/ext_gui/style.h +10 -0
- package/runtime/ext_gui/style_print.cpp +6 -0
- package/runtime/ext_gui/style_values.cpp +43 -0
- package/runtime/ext_gui/transform.cpp +412 -0
- package/runtime/ext_gui/transform.h +112 -0
- package/runtime/ext_gui/window.cpp +6 -4
- package/runtime/ext_node/buffer/parts/construction.inc +2 -2
- package/runtime/ext_node/buffer/parts/methods.inc +1 -1
- package/runtime/ext_node/buffer/parts/search.inc +1 -1
- package/runtime/ext_node/child_process/child_process.c +25 -0
- package/runtime/ext_node/fs/fd_ops.c +1 -1
- package/runtime/rt.h +17 -1
- package/runtime/rt_internal.h +47 -4
- package/runtime/xt_alloc.c +14 -2
- package/runtime/xt_bigint/conversions.inc +1 -1
- package/runtime/xt_builtins.c +136 -14
- package/runtime/xt_containers/access.inc +17 -16
- package/runtime/xt_containers/objects.inc +4 -3
- package/runtime/xt_io/exception.inc +171 -2
- package/runtime/xt_io/inspect.inc +15 -13
- package/runtime/xt_io.c +5 -0
- package/runtime/xt_stdlib/arrays.inc +2 -2
- package/runtime/xt_stdlib/dispatch.inc +2 -2
- package/runtime/xt_stdlib/strings.inc +33 -21
- package/runtime/xt_stdlib2/array-statics.inc +2 -1
- package/runtime/xt_stdlib2/arrays.inc +1 -1
- package/runtime/xt_stdlib2/error.inc +22 -6
- package/runtime/xt_stdlib2/json.inc +3 -2
- package/runtime/xt_stdlib2/number-string-statics.inc +3 -1
- package/runtime/xt_stdlib2/regexp-match.inc +48 -33
- package/runtime/xt_stdlib2/strings.inc +23 -14
- package/runtime/xt_symbol.c +1 -1
- package/runtime/xt_values/comparison.inc +2 -2
- package/runtime/xt_values/constructors.inc +10 -5
- package/runtime/xt_values/conversions.inc +4 -3
- package/runtime/xt_values/strings.inc +78 -4
- package/scripts/bench.ts +172 -0
- package/scripts/build-runtime.ts +2 -1
- package/scripts/check-version.ts +53 -0
- package/src/ast/common.ts +23 -0
- package/src/cli/main.ts +68 -26
- package/src/codegen/generator/calls/invocation.ts +5 -0
- package/src/codegen/generator/context.ts +129 -18
- package/src/codegen/generator/debug.ts +132 -0
- package/src/codegen/generator/expressions/assignment.ts +9 -5
- package/src/codegen/generator/expressions/operators.ts +47 -8
- package/src/codegen/generator/expressions/primary.ts +5 -2
- package/src/codegen/generator/generator.ts +18 -2
- package/src/codegen/generator/module.ts +78 -6
- package/src/codegen/generator/numeric.ts +158 -0
- package/src/codegen/generator/state.ts +22 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -1
- package/src/codegen/generator/statements/dispatch.ts +3 -0
- package/src/codegen/generator/statements/variables.ts +8 -2
- package/src/codegen/generator/tables.ts +26 -0
- package/src/driver/bundler/merge.ts +39 -5
- package/src/driver/compiler.ts +68 -56
- package/src/driver/fingerprint.ts +85 -0
- package/src/driver/toolchain-provider.ts +17 -16
- package/src/driver/toolchain.ts +210 -21
- package/src/extensions/gui/index.ts +10 -2
- package/src/parser/expressions.ts +20 -1
|
@@ -14,6 +14,162 @@ static xt_try_frame *g_try_top = NULL;
|
|
|
14
14
|
int32_t xt_program_argc = 0;
|
|
15
15
|
char **xt_program_argv = NULL;
|
|
16
16
|
|
|
17
|
+
/* ------------------------------------------------------------------------- */
|
|
18
|
+
/* Shadow call stack */
|
|
19
|
+
/* ------------------------------------------------------------------------- */
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Compiled functions push one frame on entry and pop it before returning, so
|
|
23
|
+
* `Error` can capture a JavaScript-level stack without any debug metadata.
|
|
24
|
+
* Generator bodies are not tracked (they switch stacks and can be suspended
|
|
25
|
+
* indefinitely); a normal function called from a generator is tracked normally.
|
|
26
|
+
*
|
|
27
|
+
* `name`/`file` point into the module's static string constants; the runtime
|
|
28
|
+
* never frees them. The depth is trimmed when a `try` frame is left, so frames
|
|
29
|
+
* from calls unwound by a throw cannot leak into a later stack.
|
|
30
|
+
*/
|
|
31
|
+
#define XT_STACK_MAX_DEPTH 256
|
|
32
|
+
|
|
33
|
+
typedef struct {
|
|
34
|
+
const char *name;
|
|
35
|
+
const char *file;
|
|
36
|
+
int32_t line;
|
|
37
|
+
} xt_stack_entry;
|
|
38
|
+
|
|
39
|
+
static xt_stack_entry g_stack[XT_STACK_MAX_DEPTH];
|
|
40
|
+
static int32_t g_stack_depth = 0;
|
|
41
|
+
|
|
42
|
+
void xt_stack_push(const char *name, const char *file, int32_t line) {
|
|
43
|
+
if (g_stack_depth >= XT_STACK_MAX_DEPTH) return;
|
|
44
|
+
xt_stack_entry *entry = &g_stack[g_stack_depth++];
|
|
45
|
+
entry->name = name;
|
|
46
|
+
entry->file = file;
|
|
47
|
+
entry->line = line;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
void xt_stack_pop(void) {
|
|
51
|
+
if (g_stack_depth > 0) g_stack_depth--;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
int32_t xt_stack_depth(void) { return g_stack_depth; }
|
|
55
|
+
|
|
56
|
+
void xt_stack_set_line(int32_t line) {
|
|
57
|
+
/* Called just before an `Error` is constructed, so the innermost frame
|
|
58
|
+
* reports the construction line rather than the function's declaration. */
|
|
59
|
+
if (g_stack_depth > 0) g_stack[g_stack_depth - 1].line = line;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void xt_stack_trim(int32_t depth) {
|
|
63
|
+
if (depth < 0) depth = 0;
|
|
64
|
+
if (depth < g_stack_depth) g_stack_depth = depth;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static void xt_stack_append(char **buffer, size_t *length, size_t *capacity, const char *text) {
|
|
68
|
+
size_t count = strlen(text);
|
|
69
|
+
if (*length + count + 1 > *capacity) {
|
|
70
|
+
size_t next = *capacity ? *capacity : 256;
|
|
71
|
+
while (next < *length + count + 1) next *= 2;
|
|
72
|
+
char *grown = (char *)realloc(*buffer, next);
|
|
73
|
+
if (!grown) return;
|
|
74
|
+
*buffer = grown;
|
|
75
|
+
*capacity = next;
|
|
76
|
+
}
|
|
77
|
+
memcpy(*buffer + *length, text, count);
|
|
78
|
+
*length += count;
|
|
79
|
+
(*buffer)[*length] = 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
xt_value xt_stack_capture(const char *name, const char *message) {
|
|
83
|
+
const char *header = name && name[0] ? name : "Error";
|
|
84
|
+
char *buffer = NULL;
|
|
85
|
+
size_t length = 0;
|
|
86
|
+
size_t capacity = 0;
|
|
87
|
+
xt_stack_append(&buffer, &length, &capacity, header);
|
|
88
|
+
if (message && message[0]) {
|
|
89
|
+
xt_stack_append(&buffer, &length, &capacity, ": ");
|
|
90
|
+
xt_stack_append(&buffer, &length, &capacity, message);
|
|
91
|
+
}
|
|
92
|
+
xt_stack_append(&buffer, &length, &capacity, "\n");
|
|
93
|
+
for (int32_t index = g_stack_depth - 1; index >= 0; index--) {
|
|
94
|
+
const xt_stack_entry *entry = &g_stack[index];
|
|
95
|
+
char line[24];
|
|
96
|
+
xt_stack_append(&buffer, &length, &capacity, " at ");
|
|
97
|
+
xt_stack_append(&buffer, &length, &capacity, entry->name && entry->name[0] ? entry->name : "anonymous");
|
|
98
|
+
xt_stack_append(&buffer, &length, &capacity, " (");
|
|
99
|
+
xt_stack_append(&buffer, &length, &capacity, entry->file && entry->file[0] ? entry->file : "<anonymous>");
|
|
100
|
+
if (entry->line > 0) {
|
|
101
|
+
snprintf(line, sizeof(line), ":%d", (int)entry->line);
|
|
102
|
+
xt_stack_append(&buffer, &length, &capacity, line);
|
|
103
|
+
}
|
|
104
|
+
xt_stack_append(&buffer, &length, &capacity, ")\n");
|
|
105
|
+
}
|
|
106
|
+
xt_value result = xt_string_new(buffer ? buffer : "", length);
|
|
107
|
+
free(buffer);
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
xt_value xt_error_stack(xt_value error) {
|
|
112
|
+
if (!XT_IS_OBJECT(error)) return XT_UNDEFINED;
|
|
113
|
+
xt_object *object = (xt_object *)XT_GET_PTR(error);
|
|
114
|
+
if (object->header.kind != XT_OBJECT_KIND_ERROR) return XT_UNDEFINED;
|
|
115
|
+
return object->error_stack;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ------------------------------------------------------------------------- */
|
|
119
|
+
/* Fatal-signal diagnostics */
|
|
120
|
+
/* ------------------------------------------------------------------------- */
|
|
121
|
+
|
|
122
|
+
static char g_crash_report[16384];
|
|
123
|
+
|
|
124
|
+
static int xt_format_stack(char *out, size_t size) {
|
|
125
|
+
int written = 0;
|
|
126
|
+
for (int32_t index = g_stack_depth - 1; index >= 0 && written < (int)size; index--) {
|
|
127
|
+
const xt_stack_entry *entry = &g_stack[index];
|
|
128
|
+
int count = snprintf(out + written, size - (size_t)written, " at %s (%s:%d)\n",
|
|
129
|
+
entry->name && entry->name[0] ? entry->name : "anonymous",
|
|
130
|
+
entry->file && entry->file[0] ? entry->file : "<anonymous>", (int)entry->line);
|
|
131
|
+
if (count < 0) break;
|
|
132
|
+
written += count;
|
|
133
|
+
}
|
|
134
|
+
return written < (int)size ? written : (int)size - 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#if defined(_WIN32)
|
|
138
|
+
|
|
139
|
+
static LONG WINAPI xt_fatal_exception(EXCEPTION_POINTERS *info) {
|
|
140
|
+
unsigned long code =
|
|
141
|
+
info && info->ExceptionRecord ? (unsigned long)info->ExceptionRecord->ExceptionCode : 0UL;
|
|
142
|
+
int written = snprintf(g_crash_report, sizeof(g_crash_report), "\nxbintsc: fatal exception 0x%08lx\n", code);
|
|
143
|
+
written += xt_format_stack(g_crash_report + written, sizeof(g_crash_report) - (size_t)written);
|
|
144
|
+
_write(2, g_crash_report, (unsigned int)written);
|
|
145
|
+
_exit(1);
|
|
146
|
+
return EXCEPTION_EXECUTE_HANDLER;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
void xt_install_crash_handler(void) { SetUnhandledExceptionFilter(xt_fatal_exception); }
|
|
150
|
+
|
|
151
|
+
#else
|
|
152
|
+
|
|
153
|
+
static void xt_fatal_signal(int sig) {
|
|
154
|
+
int written = snprintf(g_crash_report, sizeof(g_crash_report), "\nxbintsc: fatal signal %d\n", sig);
|
|
155
|
+
written += xt_format_stack(g_crash_report + written, sizeof(g_crash_report) - (size_t)written);
|
|
156
|
+
ssize_t ignored = write(STDERR_FILENO, g_crash_report, (size_t)written);
|
|
157
|
+
(void)ignored;
|
|
158
|
+
_exit(128 + sig);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void xt_install_crash_handler(void) {
|
|
162
|
+
signal(SIGSEGV, xt_fatal_signal);
|
|
163
|
+
signal(SIGABRT, xt_fatal_signal);
|
|
164
|
+
signal(SIGFPE, xt_fatal_signal);
|
|
165
|
+
signal(SIGBUS, xt_fatal_signal);
|
|
166
|
+
#ifdef SIGILL
|
|
167
|
+
signal(SIGILL, xt_fatal_signal);
|
|
168
|
+
#endif
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#endif
|
|
172
|
+
|
|
17
173
|
#if defined(_WIN32)
|
|
18
174
|
/*
|
|
19
175
|
* The UCRT validates its low-level I/O arguments and, when one is out of
|
|
@@ -107,18 +263,23 @@ void *xt_try_enter(void) {
|
|
|
107
263
|
if (!frame) abort();
|
|
108
264
|
frame->prev = g_try_top;
|
|
109
265
|
frame->exception = XT_UNDEFINED;
|
|
266
|
+
frame->stack_depth = g_stack_depth;
|
|
110
267
|
g_try_top = frame;
|
|
111
268
|
return (void *)frame;
|
|
112
269
|
}
|
|
113
270
|
|
|
114
271
|
xt_value xt_try_exception(void *framePtr) {
|
|
115
272
|
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
116
|
-
|
|
273
|
+
if (!frame) return XT_UNDEFINED;
|
|
274
|
+
/* A throw longjmps past the calls it unwinds; drop their shadow frames. */
|
|
275
|
+
xt_stack_trim(frame->stack_depth);
|
|
276
|
+
return frame->exception;
|
|
117
277
|
}
|
|
118
278
|
|
|
119
279
|
void xt_try_leave(void *framePtr) {
|
|
120
280
|
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
121
281
|
if (frame && g_try_top == frame) {
|
|
282
|
+
xt_stack_trim(frame->stack_depth);
|
|
122
283
|
g_try_top = frame->prev;
|
|
123
284
|
free(frame);
|
|
124
285
|
}
|
|
@@ -135,8 +296,16 @@ void xt_throw(xt_value v) {
|
|
|
135
296
|
g_try_top->exception = v;
|
|
136
297
|
longjmp(g_try_top->buf, 1);
|
|
137
298
|
}
|
|
299
|
+
xt_value stack = xt_error_stack(v);
|
|
300
|
+
if (stack != XT_UNDEFINED) {
|
|
301
|
+
xt_string *text = xt_as_string(stack);
|
|
302
|
+
if (text) {
|
|
303
|
+
fprintf(stderr, "Uncaught %s\n", xt_string_bytes(text));
|
|
304
|
+
exit(1);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
138
307
|
xt_value message = xt_to_string(v);
|
|
139
308
|
xt_string *s = xt_as_string(message);
|
|
140
|
-
fprintf(stderr, "Uncaught %s\n", s
|
|
309
|
+
fprintf(stderr, "Uncaught %s\n", xt_string_bytes(s));
|
|
141
310
|
exit(1);
|
|
142
311
|
}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
static void xt_print_value(xt_value v, FILE *out) {
|
|
6
6
|
if (XT_IS_STRING(v)) {
|
|
7
7
|
xt_string *s = xt_as_string(v);
|
|
8
|
-
fwrite(s
|
|
8
|
+
fwrite(xt_string_bytes(s), 1, s->length, out);
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
xt_value text = xt_to_string(v);
|
|
12
12
|
xt_string *s = xt_as_string(text);
|
|
13
|
-
fwrite(s
|
|
13
|
+
fwrite(xt_string_bytes(s), 1, s->length, out);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
void xt_print(xt_value v) { xt_print_value(v, stdout); }
|
|
@@ -48,10 +48,11 @@ static void xt_inspect_pop(void) {
|
|
|
48
48
|
|
|
49
49
|
static int xt_inspect_identifier_key(xt_string *key) {
|
|
50
50
|
if (key->length == 0) return 0;
|
|
51
|
-
char
|
|
51
|
+
const char *bytes = xt_string_bytes(key);
|
|
52
|
+
char c = bytes[0];
|
|
52
53
|
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$')) return 0;
|
|
53
54
|
for (uint32_t i = 1; i < key->length; i++) {
|
|
54
|
-
c =
|
|
55
|
+
c = bytes[i];
|
|
55
56
|
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$')) return 0;
|
|
56
57
|
}
|
|
57
58
|
return 1;
|
|
@@ -60,16 +61,17 @@ static int xt_inspect_identifier_key(xt_string *key) {
|
|
|
60
61
|
/* Render a string the way `util.inspect` does inside a container: quoted,
|
|
61
62
|
* preferring whichever quote character needs fewer escapes. */
|
|
62
63
|
static void xt_inspect_string(xt_string *s, FILE *out) {
|
|
64
|
+
const char *bytes = xt_string_bytes(s);
|
|
63
65
|
int hasSingle = 0;
|
|
64
66
|
int hasDouble = 0;
|
|
65
67
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
66
|
-
if (
|
|
67
|
-
else if (
|
|
68
|
+
if (bytes[i] == '\'') hasSingle = 1;
|
|
69
|
+
else if (bytes[i] == '"') hasDouble = 1;
|
|
68
70
|
}
|
|
69
71
|
char quote = (hasSingle && !hasDouble) ? '"' : '\'';
|
|
70
72
|
fputc(quote, out);
|
|
71
73
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
72
|
-
unsigned char c = (unsigned char)
|
|
74
|
+
unsigned char c = (unsigned char)bytes[i];
|
|
73
75
|
switch (c) {
|
|
74
76
|
case '\\': fputs("\\\\", out); break;
|
|
75
77
|
case '\n': fputs("\\n", out); break;
|
|
@@ -90,13 +92,13 @@ static void xt_inspect_string(xt_string *s, FILE *out) {
|
|
|
90
92
|
static void xt_inspect(xt_value v, FILE *out, int nested) {
|
|
91
93
|
if (xt_is_symbol(v)) {
|
|
92
94
|
xt_string *text = xt_as_string(xt_symbol_to_string(v));
|
|
93
|
-
fwrite(text
|
|
95
|
+
fwrite(xt_string_bytes(text), 1, text->length, out);
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
96
98
|
if (XT_IS_BIGINT(v)) {
|
|
97
99
|
xt_value text = xt_bigint_to_decimal(v);
|
|
98
100
|
xt_string *s = xt_as_string(text);
|
|
99
|
-
fwrite(s
|
|
101
|
+
fwrite(xt_string_bytes(s), 1, s->length, out);
|
|
100
102
|
fputc('n', out);
|
|
101
103
|
return;
|
|
102
104
|
}
|
|
@@ -130,10 +132,10 @@ static void xt_inspect(xt_value v, FILE *out, int nested) {
|
|
|
130
132
|
xt_value key = extra->properties[i].key;
|
|
131
133
|
if (xt_is_symbol(key)) {
|
|
132
134
|
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
133
|
-
fwrite(text
|
|
135
|
+
fwrite(xt_string_bytes(text), 1, text->length, out);
|
|
134
136
|
} else {
|
|
135
137
|
xt_string *keyString = xt_as_string(key);
|
|
136
|
-
fwrite(keyString
|
|
138
|
+
fwrite(xt_string_bytes(keyString), 1, keyString->length, out);
|
|
137
139
|
}
|
|
138
140
|
fputs(": ", out);
|
|
139
141
|
xt_inspect(extra->properties[i].value, out, 1);
|
|
@@ -170,10 +172,10 @@ static void xt_inspect(xt_value v, FILE *out, int nested) {
|
|
|
170
172
|
written++;
|
|
171
173
|
if (isSymbol) {
|
|
172
174
|
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
173
|
-
fwrite(text
|
|
175
|
+
fwrite(xt_string_bytes(text), 1, text->length, out);
|
|
174
176
|
} else {
|
|
175
177
|
xt_string *keyString = xt_as_string(key);
|
|
176
|
-
if (xt_inspect_identifier_key(keyString)) fwrite(keyString
|
|
178
|
+
if (xt_inspect_identifier_key(keyString)) fwrite(xt_string_bytes(keyString), 1, keyString->length, out);
|
|
177
179
|
else xt_inspect_string(keyString, out);
|
|
178
180
|
}
|
|
179
181
|
fputs(": ", out);
|
package/runtime/xt_io.c
CHANGED
|
@@ -47,11 +47,11 @@ static xt_value xt_array_join(xt_value value, xt_value separator) {
|
|
|
47
47
|
if (!out) abort();
|
|
48
48
|
out[0] = '\0';
|
|
49
49
|
for (uint32_t i = 0; i < array->length; i++) {
|
|
50
|
-
if (i > 0) xt_buffer_append(&out, &length, &capacity, sep
|
|
50
|
+
if (i > 0) xt_buffer_append(&out, &length, &capacity, xt_string_bytes(sep), sep->length);
|
|
51
51
|
xt_value item = array->items[i];
|
|
52
52
|
if (item == XT_UNDEFINED || item == XT_NULL) continue;
|
|
53
53
|
xt_string *str = xt_as_string(xt_to_string(item));
|
|
54
|
-
xt_buffer_append(&out, &length, &capacity, str
|
|
54
|
+
xt_buffer_append(&out, &length, &capacity, xt_string_bytes(str), str->length);
|
|
55
55
|
}
|
|
56
56
|
xt_value result = xt_string_new(out, length);
|
|
57
57
|
free(out);
|
|
@@ -322,7 +322,7 @@ xt_value xt_call_method(xt_value target, xt_value name, int32_t argc, xt_value *
|
|
|
322
322
|
/* Bound functions report `name` as "bound <target>" and reduce `length`
|
|
323
323
|
* by the number of pre-bound arguments, like the specification. */
|
|
324
324
|
xt_function *targetFn = (xt_function *)XT_GET_PTR(target);
|
|
325
|
-
const char *base = targetFn->name ? targetFn->name
|
|
325
|
+
const char *base = targetFn->name ? xt_string_bytes(targetFn->name) : "";
|
|
326
326
|
char boundName[256];
|
|
327
327
|
snprintf(boundName, sizeof(boundName), "bound %s", base);
|
|
328
328
|
int32_t prebound = argc > 1 ? argc - 1 : 0;
|
|
@@ -336,7 +336,7 @@ xt_value xt_call_method(xt_value target, xt_value name, int32_t argc, xt_value *
|
|
|
336
336
|
if (strcmp(method, "toString") == 0) {
|
|
337
337
|
/* Source text is not retained; report a native-style representation. */
|
|
338
338
|
xt_function *self = (xt_function *)XT_GET_PTR(target);
|
|
339
|
-
const char *selfName = self->name ? self->name
|
|
339
|
+
const char *selfName = self->name ? xt_string_bytes(self->name) : "";
|
|
340
340
|
char buffer[256];
|
|
341
341
|
snprintf(buffer, sizeof(buffer), "function %s() { [native code] }", selfName);
|
|
342
342
|
return xt_string_from_cstr(buffer);
|
|
@@ -4,8 +4,10 @@ static int32_t xt_string_find(xt_string *haystack, xt_string *needle, int32_t fr
|
|
|
4
4
|
if (from < 0) from = 0;
|
|
5
5
|
if ((uint32_t)from > haystack->length) return -1;
|
|
6
6
|
if (needle->length == 0) return from;
|
|
7
|
+
const char *hay = xt_string_bytes(haystack);
|
|
8
|
+
const char *need = xt_string_bytes(needle);
|
|
7
9
|
for (uint32_t i = (uint32_t)from; i + needle->length <= haystack->length; i++) {
|
|
8
|
-
if (memcmp(
|
|
10
|
+
if (memcmp(hay + i, need, needle->length) == 0) return (int32_t)i;
|
|
9
11
|
}
|
|
10
12
|
return -1;
|
|
11
13
|
}
|
|
@@ -15,7 +17,7 @@ static xt_value xt_string_char_at(xt_value value, xt_value indexValue) {
|
|
|
15
17
|
if (!s) return xt_string_from_cstr("");
|
|
16
18
|
int32_t index = xt_to_int32(indexValue);
|
|
17
19
|
if (index < 0 || (uint32_t)index >= s->length) return xt_string_from_cstr("");
|
|
18
|
-
return xt_string_new(s
|
|
20
|
+
return xt_string_new(xt_string_bytes(s) + index, 1);
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
static xt_value xt_string_char_code_at(xt_value value, xt_value indexValue) {
|
|
@@ -23,7 +25,7 @@ static xt_value xt_string_char_code_at(xt_value value, xt_value indexValue) {
|
|
|
23
25
|
if (!s) return xt_number(NAN);
|
|
24
26
|
int32_t index = xt_to_int32(indexValue);
|
|
25
27
|
if (index < 0 || (uint32_t)index >= s->length) return xt_number(NAN);
|
|
26
|
-
return xt_number((double)(unsigned char)s
|
|
28
|
+
return xt_number((double)(unsigned char)xt_string_bytes(s)[index]);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
static xt_value xt_string_index_of(xt_value value, xt_value needleValue, xt_value fromValue) {
|
|
@@ -41,7 +43,7 @@ static xt_value xt_string_slice(xt_value value, xt_value startValue, xt_value en
|
|
|
41
43
|
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
42
44
|
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
43
45
|
xt_normalize_slice(len, &start, &end);
|
|
44
|
-
return xt_string_new(s
|
|
46
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)(end - start));
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
static xt_value xt_string_substring(xt_value value, xt_value startValue, xt_value endValue) {
|
|
@@ -59,7 +61,7 @@ static xt_value xt_string_substring(xt_value value, xt_value startValue, xt_valu
|
|
|
59
61
|
start = end;
|
|
60
62
|
end = swap;
|
|
61
63
|
}
|
|
62
|
-
return xt_string_new(s
|
|
64
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)(end - start));
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
static xt_value xt_string_substr(xt_value value, xt_value startValue, xt_value lengthValue) {
|
|
@@ -73,7 +75,7 @@ static xt_value xt_string_substr(xt_value value, xt_value startValue, xt_value l
|
|
|
73
75
|
int32_t length = lengthValue == XT_UNDEFINED ? len - start : xt_to_int32(lengthValue);
|
|
74
76
|
if (length < 0) length = 0;
|
|
75
77
|
if (start + length > len) length = len - start;
|
|
76
|
-
return xt_string_new(s
|
|
78
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)length);
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
static xt_value xt_string_split(xt_value value, xt_value separatorValue, xt_value limitValue) {
|
|
@@ -87,21 +89,23 @@ static xt_value xt_string_split(xt_value value, xt_value separatorValue, xt_valu
|
|
|
87
89
|
return result;
|
|
88
90
|
}
|
|
89
91
|
xt_string *sep = xt_as_string(xt_to_string(separatorValue));
|
|
92
|
+
const char *bytes = xt_string_bytes(s);
|
|
93
|
+
const char *sepBytes = xt_string_bytes(sep);
|
|
90
94
|
if (sep->length == 0) {
|
|
91
|
-
for (uint32_t i = 0; i < s->length; i++) xt_array_push(result, xt_string_new(
|
|
95
|
+
for (uint32_t i = 0; i < s->length; i++) xt_array_push(result, xt_string_new(bytes + i, 1));
|
|
92
96
|
} else {
|
|
93
97
|
uint32_t start = 0;
|
|
94
98
|
uint32_t i = 0;
|
|
95
99
|
while (i + sep->length <= s->length) {
|
|
96
|
-
if (memcmp(
|
|
97
|
-
xt_array_push(result, xt_string_new(
|
|
100
|
+
if (memcmp(bytes + i, sepBytes, sep->length) == 0) {
|
|
101
|
+
xt_array_push(result, xt_string_new(bytes + start, i - start));
|
|
98
102
|
i += sep->length;
|
|
99
103
|
start = i;
|
|
100
104
|
} else {
|
|
101
105
|
i++;
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
xt_array_push(result, xt_string_new(
|
|
108
|
+
xt_array_push(result, xt_string_new(bytes + start, s->length - start));
|
|
105
109
|
}
|
|
106
110
|
xt_array *array = xt_as_array(result);
|
|
107
111
|
if ((int64_t)array->length > limit) array->length = (uint32_t)limit;
|
|
@@ -112,9 +116,11 @@ static xt_value xt_string_case(xt_value value, int upper) {
|
|
|
112
116
|
xt_string *s = xt_as_string(value);
|
|
113
117
|
if (!s) return value;
|
|
114
118
|
xt_string *out = xt_string_alloc(s->length);
|
|
119
|
+
const char *bytes = xt_string_bytes(s);
|
|
120
|
+
char *mutable = xt_string_mutable(out);
|
|
115
121
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
116
|
-
unsigned char c = (unsigned char)
|
|
117
|
-
|
|
122
|
+
unsigned char c = (unsigned char)bytes[i];
|
|
123
|
+
mutable[i] = (char)(upper ? toupper((int)c) : tolower((int)c));
|
|
118
124
|
}
|
|
119
125
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
120
126
|
}
|
|
@@ -122,11 +128,12 @@ static xt_value xt_string_case(xt_value value, int upper) {
|
|
|
122
128
|
static xt_value xt_string_trim(xt_value value) {
|
|
123
129
|
xt_string *s = xt_as_string(value);
|
|
124
130
|
if (!s) return value;
|
|
131
|
+
const char *bytes = xt_string_bytes(s);
|
|
125
132
|
uint32_t start = 0;
|
|
126
133
|
uint32_t end = s->length;
|
|
127
|
-
while (start < end && isspace((unsigned char)
|
|
128
|
-
while (end > start && isspace((unsigned char)
|
|
129
|
-
return xt_string_new(
|
|
134
|
+
while (start < end && isspace((unsigned char)bytes[start])) start++;
|
|
135
|
+
while (end > start && isspace((unsigned char)bytes[end - 1])) end--;
|
|
136
|
+
return xt_string_new(bytes + start, end - start);
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
static xt_value xt_string_replace(xt_value value, xt_value searchValue, xt_value replacementValue) {
|
|
@@ -137,11 +144,14 @@ static xt_value xt_string_replace(xt_value value, xt_value searchValue, xt_value
|
|
|
137
144
|
xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
|
|
138
145
|
int32_t at = xt_string_find(s, search, 0);
|
|
139
146
|
if (at < 0) return value;
|
|
147
|
+
const char *text = xt_string_bytes(s);
|
|
148
|
+
const char *repl = xt_string_bytes(replacement);
|
|
140
149
|
size_t total = s->length - search->length + replacement->length;
|
|
141
150
|
xt_string *out = xt_string_alloc(total);
|
|
142
|
-
|
|
143
|
-
memcpy(
|
|
144
|
-
memcpy(
|
|
151
|
+
char *mutable = xt_string_mutable(out);
|
|
152
|
+
memcpy(mutable, text, (size_t)at);
|
|
153
|
+
memcpy(mutable + at, repl, replacement->length);
|
|
154
|
+
memcpy(mutable + at + replacement->length, text + at + search->length,
|
|
145
155
|
s->length - (size_t)at - search->length);
|
|
146
156
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
147
157
|
}
|
|
@@ -155,7 +165,9 @@ static xt_value xt_string_repeat(xt_value value, xt_value countValue) {
|
|
|
155
165
|
return XT_UNDEFINED;
|
|
156
166
|
}
|
|
157
167
|
xt_string *out = xt_string_alloc((size_t)s->length * (size_t)count);
|
|
158
|
-
|
|
168
|
+
const char *bytes = xt_string_bytes(s);
|
|
169
|
+
char *mutable = xt_string_mutable(out);
|
|
170
|
+
for (int32_t i = 0; i < count; i++) memcpy(mutable + (size_t)i * s->length, bytes, s->length);
|
|
159
171
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
160
172
|
}
|
|
161
173
|
|
|
@@ -164,7 +176,7 @@ static xt_value xt_string_starts_with(xt_value value, xt_value searchValue) {
|
|
|
164
176
|
if (!s) return XT_FALSE;
|
|
165
177
|
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
166
178
|
if (search->length > s->length) return XT_FALSE;
|
|
167
|
-
return xt_bool(memcmp(s
|
|
179
|
+
return xt_bool(memcmp(xt_string_bytes(s), xt_string_bytes(search), search->length) == 0);
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
static xt_value xt_string_ends_with(xt_value value, xt_value searchValue) {
|
|
@@ -172,7 +184,7 @@ static xt_value xt_string_ends_with(xt_value value, xt_value searchValue) {
|
|
|
172
184
|
if (!s) return XT_FALSE;
|
|
173
185
|
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
174
186
|
if (search->length > s->length) return XT_FALSE;
|
|
175
|
-
return xt_bool(memcmp(s
|
|
187
|
+
return xt_bool(memcmp(xt_string_bytes(s) + s->length - search->length, xt_string_bytes(search), search->length) == 0);
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
static xt_value xt_string_concat_args(xt_value value, int32_t argc, xt_value *argv) {
|
|
@@ -18,8 +18,9 @@ xt_value xt_array_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
18
18
|
}
|
|
19
19
|
} else if (XT_IS_STRING(source)) {
|
|
20
20
|
xt_string *s = xt_as_string(source);
|
|
21
|
+
const char *bytes = xt_string_bytes(s);
|
|
21
22
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
22
|
-
xt_value item = xt_string_new(
|
|
23
|
+
xt_value item = xt_string_new(bytes + i, 1);
|
|
23
24
|
if (XT_IS_FUNCTION(mapper)) { xt_value args[2] = {item, xt_number((double)i)}; item = xt_closure_call(mapper, 2, args); }
|
|
24
25
|
xt_array_push(out, item);
|
|
25
26
|
}
|
|
@@ -46,7 +46,7 @@ static int xt_array_default_compare(xt_value a, xt_value b) {
|
|
|
46
46
|
xt_string *sa = xt_as_string(xt_to_string(a));
|
|
47
47
|
xt_string *sb = xt_as_string(xt_to_string(b));
|
|
48
48
|
uint32_t n = sa->length < sb->length ? sa->length : sb->length;
|
|
49
|
-
int cmp = n ? memcmp(sa
|
|
49
|
+
int cmp = n ? memcmp(xt_string_bytes(sa), xt_string_bytes(sb), n) : 0;
|
|
50
50
|
if (cmp != 0) return cmp < 0 ? -1 : 1;
|
|
51
51
|
if (sa->length == sb->length) return 0;
|
|
52
52
|
return sa->length < sb->length ? -1 : 1;
|
|
@@ -50,6 +50,15 @@ xt_value xt_error_prototype(xt_value nameValue) {
|
|
|
50
50
|
return xt_error_proto_for(name);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* Capture `Error.stack` into the object's private field (not a property, so it
|
|
54
|
+
* stays out of Object.keys/JSON.stringify, like V8's own non-enumerable stack). */
|
|
55
|
+
static void xt_error_capture_stack(xt_value error, const char *name, xt_value message) {
|
|
56
|
+
if (!XT_IS_OBJECT(error)) return;
|
|
57
|
+
xt_string *text = xt_as_string(xt_to_string(message));
|
|
58
|
+
xt_value stack = xt_stack_capture(name, text ? xt_string_bytes(text) : "");
|
|
59
|
+
((xt_object *)XT_GET_PTR(error))->error_stack = stack;
|
|
60
|
+
}
|
|
61
|
+
|
|
53
62
|
static xt_value xt_make_error(const char *name, int32_t argc, xt_value *argv) {
|
|
54
63
|
if (!xt_error_is_family(name)) name = "Error";
|
|
55
64
|
xt_value error = xt_object_new();
|
|
@@ -64,9 +73,10 @@ static xt_value xt_make_error(const char *name, int32_t argc, xt_value *argv) {
|
|
|
64
73
|
} else {
|
|
65
74
|
message = xt_arg_at(argc, argv, 0);
|
|
66
75
|
}
|
|
76
|
+
xt_value messageValue = message == XT_UNDEFINED ? xt_string_from_cstr("") : message;
|
|
67
77
|
xt_object_set(error, xt_string_from_cstr("name"), xt_string_from_cstr(name));
|
|
68
|
-
xt_object_set(error, xt_string_from_cstr("message"),
|
|
69
|
-
|
|
78
|
+
xt_object_set(error, xt_string_from_cstr("message"), messageValue);
|
|
79
|
+
xt_error_capture_stack(error, name, messageValue);
|
|
70
80
|
return error;
|
|
71
81
|
}
|
|
72
82
|
|
|
@@ -110,10 +120,10 @@ xt_value xt_error_to_string(xt_value error) {
|
|
|
110
120
|
if (ms->length == 0) return nameStr;
|
|
111
121
|
size_t total = ns->length + 2 + ms->length;
|
|
112
122
|
char *buffer = (char *)malloc(total + 1);
|
|
113
|
-
memcpy(buffer, ns
|
|
123
|
+
memcpy(buffer, xt_string_bytes(ns), ns->length);
|
|
114
124
|
buffer[ns->length] = ':';
|
|
115
125
|
buffer[ns->length + 1] = ' ';
|
|
116
|
-
memcpy(buffer + ns->length + 2, ms
|
|
126
|
+
memcpy(buffer + ns->length + 2, xt_string_bytes(ms), ms->length);
|
|
117
127
|
buffer[total] = '\0';
|
|
118
128
|
xt_value result = xt_string_new(buffer, total);
|
|
119
129
|
free(buffer);
|
|
@@ -159,6 +169,11 @@ xt_value xt_error_init(xt_value thisValue, xt_value nameValue, int32_t argc,
|
|
|
159
169
|
xt_value *argv) {
|
|
160
170
|
const char *name = XT_IS_STRING(nameValue) ? xt_string_data(nameValue) : "Error";
|
|
161
171
|
if (!xt_error_is_family(name)) name = "Error";
|
|
172
|
+
/* `class MyError extends Error` allocates a plain object first; mark it as an
|
|
173
|
+
* Error so `.stack` and the error-specific property access apply. */
|
|
174
|
+
if (XT_IS_OBJECT(thisValue)) {
|
|
175
|
+
((xt_object *)XT_GET_PTR(thisValue))->header.kind = XT_OBJECT_KIND_ERROR;
|
|
176
|
+
}
|
|
162
177
|
xt_object_set(thisValue, xt_string_from_cstr("name"), xt_string_from_cstr(name));
|
|
163
178
|
xt_value message;
|
|
164
179
|
if (strcmp(name, "AggregateError") == 0) {
|
|
@@ -167,7 +182,8 @@ xt_value xt_error_init(xt_value thisValue, xt_value nameValue, int32_t argc,
|
|
|
167
182
|
} else {
|
|
168
183
|
message = xt_arg_at(argc, argv, 0);
|
|
169
184
|
}
|
|
170
|
-
|
|
171
|
-
|
|
185
|
+
xt_value messageValue = message == XT_UNDEFINED ? xt_string_from_cstr("") : message;
|
|
186
|
+
xt_object_set(thisValue, xt_string_from_cstr("message"), messageValue);
|
|
187
|
+
xt_error_capture_stack(thisValue, name, messageValue);
|
|
172
188
|
return thisValue;
|
|
173
189
|
}
|
|
@@ -120,7 +120,7 @@ xt_value xt_json_parse(int32_t argc, xt_value *argv) {
|
|
|
120
120
|
xt_value input = xt_to_string(xt_arg_at(argc, argv, 0));
|
|
121
121
|
xt_string *s = xt_as_string(input);
|
|
122
122
|
if (!s) return XT_UNDEFINED;
|
|
123
|
-
xt_json_cursor cursor = {s
|
|
123
|
+
xt_json_cursor cursor = {xt_string_bytes(s), s->length, 0};
|
|
124
124
|
return xt_json_parse_value(&cursor);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -193,9 +193,10 @@ static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_va
|
|
|
193
193
|
}
|
|
194
194
|
if (XT_IS_STRING(value)) {
|
|
195
195
|
xt_string *s = xt_as_string(value);
|
|
196
|
+
const char *bytes = xt_string_bytes(s);
|
|
196
197
|
*out = xt_add(*out, xt_string_from_cstr("\""));
|
|
197
198
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
198
|
-
char ch =
|
|
199
|
+
char ch = bytes[i];
|
|
199
200
|
if (ch == '"') *out = xt_add(*out, xt_string_from_cstr("\\\""));
|
|
200
201
|
else if (ch == '\\') *out = xt_add(*out, xt_string_from_cstr("\\\\"));
|
|
201
202
|
else if (ch == '\n') *out = xt_add(*out, xt_string_from_cstr("\\n"));
|
|
@@ -43,6 +43,7 @@ xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
43
43
|
if (!fn) return XT_UNDEFINED;
|
|
44
44
|
if (strcmp(fn, "fromCharCode") == 0 || strcmp(fn, "fromCodePoint") == 0) {
|
|
45
45
|
xt_string *out = xt_string_alloc((size_t)argc * 4 + 1);
|
|
46
|
+
char *mutable = xt_string_mutable(out);
|
|
46
47
|
size_t length = 0;
|
|
47
48
|
for (int32_t i = 0; i < argc; i++) {
|
|
48
49
|
unsigned code = (unsigned)xt_to_int32(argv[i]);
|
|
@@ -52,9 +53,10 @@ xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
52
53
|
else if (code < 0x800) { buffer[bytes++] = (char)(0xC0 | (code >> 6)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
53
54
|
else if (code < 0x10000) { buffer[bytes++] = (char)(0xE0 | (code >> 12)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
54
55
|
else { buffer[bytes++] = (char)(0xF0 | (code >> 18)); buffer[bytes++] = (char)(0x80 | ((code >> 12) & 0x3F)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
55
|
-
memcpy(
|
|
56
|
+
memcpy(mutable + length, buffer, (size_t)bytes);
|
|
56
57
|
length += (size_t)bytes;
|
|
57
58
|
}
|
|
59
|
+
mutable[length] = '\0';
|
|
58
60
|
out->length = (uint32_t)length;
|
|
59
61
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
60
62
|
}
|