xbintsc 0.3.14 → 0.3.16
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 +22 -22
- package/README.zh-CN.md +20 -19
- package/bin/xbintsc.js +1 -2
- package/dist/src/cli/main.js +8 -5
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +5 -6
- package/dist/src/codegen/generator/tables.js +13 -6
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/graph.d.ts +8 -0
- package/dist/src/driver/bundler/graph.js +85 -0
- package/dist/src/driver/bundler/graph.js.map +1 -0
- package/dist/src/driver/bundler/merge.d.ts +11 -0
- package/dist/src/driver/bundler/merge.js +288 -0
- package/dist/src/driver/bundler/merge.js.map +1 -0
- package/dist/src/driver/bundler/resolve.d.ts +12 -0
- package/dist/src/driver/bundler/resolve.js +246 -0
- package/dist/src/driver/bundler/resolve.js.map +1 -0
- package/dist/src/driver/bundler/symbols.d.ts +15 -0
- package/dist/src/driver/bundler/symbols.js +51 -0
- package/dist/src/driver/bundler/symbols.js.map +1 -0
- package/dist/src/driver/bundler/types.d.ts +36 -0
- package/dist/src/driver/bundler/types.js +5 -0
- package/dist/src/driver/bundler/types.js.map +1 -0
- package/dist/src/driver/index.d.ts +1 -2
- package/dist/src/driver/index.js +1 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/modules.d.ts +9 -16
- package/dist/src/driver/modules.js +8 -644
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/paths.d.ts +0 -9
- package/dist/src/driver/paths.js +0 -31
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/toolchain-provider.d.ts +10 -10
- package/dist/src/driver/toolchain-provider.js +9 -38
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.js +8 -2
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/catalog.js +2 -1
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/index.d.ts +24 -0
- package/dist/src/extensions/gui/index.js +101 -0
- package/dist/src/extensions/gui/index.js.map +1 -0
- package/dist/src/extensions/native.d.ts +2 -3
- package/dist/src/extensions/native.js +2 -3
- package/dist/src/extensions/native.js.map +1 -1
- package/dist/tests/driver/paths.test.js +1 -9
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +12 -79
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
- package/dist/tests/e2e/compile-basics.test.js +134 -0
- package/dist/tests/e2e/compile-basics.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
- package/dist/tests/e2e/compile-builtins.test.js +191 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
- package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
- package/dist/tests/e2e/compile-control-flow.test.js +190 -0
- package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
- package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
- package/dist/tests/e2e/compile-modules.test.js +48 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
- package/dist/tests/e2e/differential-helpers.d.ts +12 -0
- package/dist/tests/e2e/differential-helpers.js +16 -0
- package/dist/tests/e2e/differential-helpers.js.map +1 -0
- package/dist/tests/e2e/differential-language.test.d.ts +4 -0
- package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
- package/dist/tests/e2e/differential-language.test.js.map +1 -0
- package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
- package/dist/tests/e2e/differential-symbols.test.js +92 -0
- package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.d.ts +4 -0
- package/dist/tests/e2e/differential-values.test.js +197 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -0
- package/dist/tests/e2e/gui.test.d.ts +12 -0
- package/dist/tests/e2e/gui.test.js +493 -0
- package/dist/tests/e2e/gui.test.js.map +1 -0
- package/dist/tests/e2e/native-extensions.test.d.ts +4 -5
- package/dist/tests/e2e/native-extensions.test.js +6 -7
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
- package/dist/tests/e2e/timers.test.d.ts +7 -0
- package/dist/tests/e2e/timers.test.js +63 -0
- package/dist/tests/e2e/timers.test.js.map +1 -0
- package/package.json +2 -2
- package/runtime/ext_gui/css.cpp +743 -0
- package/runtime/ext_gui/css.h +98 -0
- package/runtime/ext_gui/document.cpp +264 -0
- package/runtime/ext_gui/document.h +89 -0
- package/runtime/ext_gui/dom.cpp +472 -0
- package/runtime/ext_gui/dom.h +71 -0
- package/runtime/ext_gui/gui.cpp +457 -0
- package/runtime/ext_gui/gui_engine.h +81 -0
- package/runtime/ext_gui/image.cpp +125 -0
- package/runtime/ext_gui/image.h +42 -0
- package/runtime/ext_gui/layout.cpp +748 -0
- package/runtime/ext_gui/layout.h +93 -0
- package/runtime/ext_gui/paint.cpp +137 -0
- package/runtime/ext_gui/paint.h +75 -0
- package/runtime/ext_gui/renderer.cpp +959 -0
- package/runtime/ext_gui/renderer.h +68 -0
- package/runtime/ext_gui/stb_image.h +7988 -0
- package/runtime/ext_gui/style.cpp +771 -0
- package/runtime/ext_gui/style.h +117 -0
- package/runtime/ext_gui/text.cpp +378 -0
- package/runtime/ext_gui/text.h +78 -0
- package/runtime/ext_gui/window.cpp +405 -0
- package/runtime/ext_node/fs/fs_common.h +13 -527
- package/runtime/ext_node/fs/meta_ops.c +3 -3
- package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
- package/runtime/ext_node/fs/parts/builtins.inc +69 -0
- package/runtime/ext_node/fs/parts/dir.inc +47 -0
- package/runtime/ext_node/fs/parts/encoding.inc +186 -0
- package/runtime/ext_node/fs/parts/errors.inc +66 -0
- package/runtime/ext_node/fs/parts/flags.inc +39 -0
- package/runtime/ext_node/fs/parts/platform.inc +86 -0
- package/runtime/ext_node/fs/parts/promisify.inc +15 -0
- package/runtime/ext_node/fs/parts/time.inc +9 -0
- package/runtime/rt.h +36 -4
- package/runtime/rt_internal.h +10 -23
- package/runtime/xt_builtins.c +4 -0
- package/runtime/xt_containers/access.inc +168 -0
- package/runtime/xt_containers/arrays.inc +108 -0
- package/runtime/xt_containers/boxes.inc +11 -0
- package/runtime/xt_containers/objects.inc +326 -0
- package/runtime/xt_containers.c +8 -618
- package/runtime/xt_ext.h +0 -1
- package/runtime/xt_io/base64.inc +87 -0
- package/runtime/xt_io/console.inc +119 -0
- package/runtime/xt_io/exception.inc +142 -0
- package/runtime/xt_io/inspect.inc +212 -0
- package/runtime/xt_io.c +11 -556
- package/runtime/xt_loop.c +262 -24
- package/runtime/xt_regex/api.inc +58 -0
- package/runtime/xt_regex/helpers.inc +68 -0
- package/runtime/xt_regex/matcher.inc +248 -0
- package/runtime/xt_regex/parser.inc +236 -0
- package/runtime/xt_regex/types.inc +58 -0
- package/runtime/xt_regex.h +9 -672
- package/runtime/xt_stdlib2/helpers.inc +2 -4
- package/runtime/xt_values/arithmetic.inc +150 -0
- package/runtime/xt_values/comparison.inc +112 -0
- package/runtime/xt_values/constructors.inc +41 -0
- package/runtime/xt_values/conversions.inc +115 -0
- package/runtime/xt_values/number-format.inc +180 -0
- package/runtime/xt_values/strings.inc +22 -0
- package/runtime/xt_values.c +10 -626
- package/scripts/build-gui.ts +317 -0
- package/scripts/build-runtime.ts +7 -8
- package/scripts/coverage-runtime.ts +4 -4
- package/scripts/package-release.ts +12 -84
- package/src/cli/main.ts +8 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/tables.ts +13 -6
- package/src/driver/bundler/graph.ts +95 -0
- package/src/driver/bundler/merge.ts +312 -0
- package/src/driver/bundler/resolve.ts +240 -0
- package/src/driver/bundler/symbols.ts +55 -0
- package/src/driver/bundler/types.ts +37 -0
- package/src/driver/index.ts +1 -9
- package/src/driver/modules.ts +9 -693
- package/src/driver/paths.ts +0 -31
- package/src/driver/toolchain-provider.ts +12 -45
- package/src/driver/toolchain.ts +7 -2
- package/src/extensions/catalog.ts +2 -1
- package/src/extensions/gui/index.ts +107 -0
- package/src/extensions/native.ts +2 -3
- package/dist/src/driver/toolchain-download.d.ts +0 -50
- package/dist/src/driver/toolchain-download.js +0 -102
- package/dist/src/driver/toolchain-download.js.map +0 -1
- package/dist/tests/driver/toolchain-download.test.d.ts +0 -1
- package/dist/tests/driver/toolchain-download.test.js +0 -53
- package/dist/tests/driver/toolchain-download.test.js.map +0 -1
- package/dist/tests/e2e/compile.test.d.ts +0 -8
- package/dist/tests/e2e/compile.test.js +0 -893
- package/dist/tests/e2e/compile.test.js.map +0 -1
- package/dist/tests/e2e/differential.test.d.ts +0 -7
- package/dist/tests/e2e/differential.test.js.map +0 -1
- package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
- package/dist/tests/e2e/runtime-coverage.test.js +0 -646
- package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
- package/scripts/fetch-toolchain.ts +0 -101
- package/src/driver/toolchain-download.ts +0 -135
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* base64 globals (btoa/atob) */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
static const char xt_base64_alphabet[] =
|
|
6
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
7
|
+
|
|
8
|
+
xt_value xt_btoa(int32_t argc, xt_value *argv) {
|
|
9
|
+
const char *input = argc > 0 ? xt_string_data(xt_to_string(argv[0])) : "";
|
|
10
|
+
if (!input) input = "";
|
|
11
|
+
size_t length = strlen(input);
|
|
12
|
+
size_t outLength = ((length + 2) / 3) * 4;
|
|
13
|
+
char *buffer = (char *)malloc(outLength + 1);
|
|
14
|
+
if (!buffer) return xt_string_from_cstr("");
|
|
15
|
+
size_t i = 0, j = 0;
|
|
16
|
+
while (i + 2 < length) {
|
|
17
|
+
unsigned int n = ((unsigned char)input[i] << 16) | ((unsigned char)input[i + 1] << 8) |
|
|
18
|
+
(unsigned char)input[i + 2];
|
|
19
|
+
buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
|
|
20
|
+
buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
|
|
21
|
+
buffer[j++] = xt_base64_alphabet[(n >> 6) & 63];
|
|
22
|
+
buffer[j++] = xt_base64_alphabet[n & 63];
|
|
23
|
+
i += 3;
|
|
24
|
+
}
|
|
25
|
+
if (length - i == 1) {
|
|
26
|
+
unsigned int n = (unsigned char)input[i] << 16;
|
|
27
|
+
buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
|
|
28
|
+
buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
|
|
29
|
+
buffer[j++] = '=';
|
|
30
|
+
buffer[j++] = '=';
|
|
31
|
+
} else if (length - i == 2) {
|
|
32
|
+
unsigned int n = ((unsigned char)input[i] << 16) | ((unsigned char)input[i + 1] << 8);
|
|
33
|
+
buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
|
|
34
|
+
buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
|
|
35
|
+
buffer[j++] = xt_base64_alphabet[(n >> 6) & 63];
|
|
36
|
+
buffer[j++] = '=';
|
|
37
|
+
}
|
|
38
|
+
buffer[j] = 0;
|
|
39
|
+
xt_value result = xt_string_new(buffer, j);
|
|
40
|
+
free(buffer);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static int xt_base64_value(char c) {
|
|
45
|
+
if (c >= 'A' && c <= 'Z') return c - 'A';
|
|
46
|
+
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
|
47
|
+
if (c >= '0' && c <= '9') return c - '0' + 52;
|
|
48
|
+
if (c == '+') return 62;
|
|
49
|
+
if (c == '/') return 63;
|
|
50
|
+
return -1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
xt_value xt_atob(int32_t argc, xt_value *argv) {
|
|
54
|
+
const char *input = argc > 0 ? xt_string_data(xt_to_string(argv[0])) : "";
|
|
55
|
+
if (!input) input = "";
|
|
56
|
+
size_t length = strlen(input);
|
|
57
|
+
char *buffer = (char *)malloc(length / 4 * 3 + 1);
|
|
58
|
+
if (!buffer) return xt_string_from_cstr("");
|
|
59
|
+
size_t out = 0;
|
|
60
|
+
int values[4];
|
|
61
|
+
int count = 0;
|
|
62
|
+
for (size_t i = 0; i < length; i++) {
|
|
63
|
+
char c = input[i];
|
|
64
|
+
if (c == '=' || c == '\n' || c == '\r' || c == ' ' || c == '\t') {
|
|
65
|
+
if (c == '=') break;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
int value = xt_base64_value(c);
|
|
69
|
+
if (value < 0) continue;
|
|
70
|
+
values[count++] = value;
|
|
71
|
+
if (count == 4) {
|
|
72
|
+
buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
|
|
73
|
+
buffer[out++] = (char)(((values[1] & 15) << 4) | (values[2] >> 2));
|
|
74
|
+
buffer[out++] = (char)(((values[2] & 3) << 6) | values[3]);
|
|
75
|
+
count = 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (count == 2) {
|
|
79
|
+
buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
|
|
80
|
+
} else if (count == 3) {
|
|
81
|
+
buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
|
|
82
|
+
buffer[out++] = (char)(((values[1] & 15) << 4) | (values[2] >> 2));
|
|
83
|
+
}
|
|
84
|
+
xt_value result = xt_string_new(buffer, out);
|
|
85
|
+
free(buffer);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Console methods */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
void xt_console_info(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stdout); }
|
|
6
|
+
void xt_console_warn(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|
|
7
|
+
void xt_console_error(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|
|
8
|
+
|
|
9
|
+
xt_value xt_console_dir(int32_t argc, xt_value *argv) {
|
|
10
|
+
xt_console_write(argc, argv, stdout);
|
|
11
|
+
return XT_UNDEFINED;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
xt_value xt_console_trace(int32_t argc, xt_value *argv) {
|
|
15
|
+
fputs("Trace", stderr);
|
|
16
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
17
|
+
fputc(' ', stderr);
|
|
18
|
+
xt_inspect_top(argv[i], stderr);
|
|
19
|
+
}
|
|
20
|
+
fputc('\n', stderr);
|
|
21
|
+
return XT_UNDEFINED;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
xt_value xt_console_assert(int32_t argc, xt_value *argv) {
|
|
25
|
+
if (argc == 0 || !xt_truthy(argv[0])) {
|
|
26
|
+
fputs("Assertion failed", stderr);
|
|
27
|
+
if (argc > 1) fputs(":", stderr);
|
|
28
|
+
for (int32_t i = 1; i < argc; i++) {
|
|
29
|
+
fputc(' ', stderr);
|
|
30
|
+
xt_inspect_top(argv[i], stderr);
|
|
31
|
+
}
|
|
32
|
+
fputc('\n', stderr);
|
|
33
|
+
}
|
|
34
|
+
return XT_UNDEFINED;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#define XT_CONSOLE_MAX_LABELS 32
|
|
38
|
+
static char *xt_console_labels[XT_CONSOLE_MAX_LABELS];
|
|
39
|
+
static long xt_console_counts[XT_CONSOLE_MAX_LABELS];
|
|
40
|
+
static clock_t xt_console_timers[XT_CONSOLE_MAX_LABELS];
|
|
41
|
+
static int xt_console_label_count = 0;
|
|
42
|
+
static int xt_console_depth = 0;
|
|
43
|
+
|
|
44
|
+
static int xt_console_find_label(const char *label) {
|
|
45
|
+
for (int i = 0; i < xt_console_label_count; i++) {
|
|
46
|
+
if (strcmp(xt_console_labels[i], label) == 0) return i;
|
|
47
|
+
}
|
|
48
|
+
if (xt_console_label_count >= XT_CONSOLE_MAX_LABELS) return -1;
|
|
49
|
+
int index = xt_console_label_count++;
|
|
50
|
+
xt_console_labels[index] = (char *)malloc(strlen(label) + 1);
|
|
51
|
+
memcpy(xt_console_labels[index], label, strlen(label) + 1);
|
|
52
|
+
xt_console_counts[index] = 0;
|
|
53
|
+
xt_console_timers[index] = 0;
|
|
54
|
+
return index;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static const char *xt_console_label(int32_t argc, xt_value *argv) {
|
|
58
|
+
if (argc == 0) return "default";
|
|
59
|
+
return xt_string_data(xt_to_string(argv[0]));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
xt_value xt_console_count(int32_t argc, xt_value *argv) {
|
|
63
|
+
const char *label = xt_console_label(argc, argv);
|
|
64
|
+
int index = xt_console_find_label(label ? label : "default");
|
|
65
|
+
if (index < 0) return XT_UNDEFINED;
|
|
66
|
+
xt_console_counts[index]++;
|
|
67
|
+
printf("%s: %ld\n", xt_console_labels[index], xt_console_counts[index]);
|
|
68
|
+
return XT_UNDEFINED;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
xt_value xt_console_count_reset(int32_t argc, xt_value *argv) {
|
|
72
|
+
const char *label = xt_console_label(argc, argv);
|
|
73
|
+
int index = xt_console_find_label(label ? label : "default");
|
|
74
|
+
if (index >= 0) xt_console_counts[index] = 0;
|
|
75
|
+
return XT_UNDEFINED;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
xt_value xt_console_group(int32_t argc, xt_value *argv) {
|
|
79
|
+
xt_console_write(argc, argv, stdout);
|
|
80
|
+
xt_console_depth++;
|
|
81
|
+
return XT_UNDEFINED;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
xt_value xt_console_group_end(int32_t argc, xt_value *argv) {
|
|
85
|
+
(void)argc;
|
|
86
|
+
(void)argv;
|
|
87
|
+
if (xt_console_depth > 0) xt_console_depth--;
|
|
88
|
+
return XT_UNDEFINED;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
xt_value xt_console_table(int32_t argc, xt_value *argv) {
|
|
92
|
+
xt_console_write(argc, argv, stdout);
|
|
93
|
+
return XT_UNDEFINED;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
xt_value xt_console_time(int32_t argc, xt_value *argv) {
|
|
97
|
+
const char *label = xt_console_label(argc, argv);
|
|
98
|
+
int index = xt_console_find_label(label ? label : "default");
|
|
99
|
+
if (index >= 0) xt_console_timers[index] = clock();
|
|
100
|
+
return XT_UNDEFINED;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
xt_value xt_console_time_log(int32_t argc, xt_value *argv) {
|
|
104
|
+
const char *label = xt_console_label(argc, argv);
|
|
105
|
+
int index = xt_console_find_label(label ? label : "default");
|
|
106
|
+
if (index >= 0 && xt_console_timers[index] != 0) {
|
|
107
|
+
double ms = (double)(clock() - xt_console_timers[index]) * 1000.0 / CLOCKS_PER_SEC;
|
|
108
|
+
printf("%s: %.3fms\n", xt_console_labels[index], ms);
|
|
109
|
+
}
|
|
110
|
+
return XT_UNDEFINED;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
xt_value xt_console_time_end(int32_t argc, xt_value *argv) {
|
|
114
|
+
xt_console_time_log(argc, argv);
|
|
115
|
+
const char *label = xt_console_label(argc, argv);
|
|
116
|
+
int index = xt_console_find_label(label ? label : "default");
|
|
117
|
+
if (index >= 0) xt_console_timers[index] = 0;
|
|
118
|
+
return XT_UNDEFINED;
|
|
119
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Exceptions */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* `try`/`catch` is implemented with a stack of setjmp frames. The compiler
|
|
7
|
+
* allocates a frame with `xt_try_enter`, calls `_setjmp` on it, and pops it
|
|
8
|
+
* with `xt_try_leave`. `xt_throw` longjmps into the innermost frame when one
|
|
9
|
+
* is active, and only prints + exits when the exception is uncaught.
|
|
10
|
+
*/
|
|
11
|
+
static xt_try_frame *g_try_top = NULL;
|
|
12
|
+
|
|
13
|
+
/* Program arguments, captured once by `xt_set_program_args` from `main`. */
|
|
14
|
+
int32_t xt_program_argc = 0;
|
|
15
|
+
char **xt_program_argv = NULL;
|
|
16
|
+
|
|
17
|
+
#if defined(_WIN32)
|
|
18
|
+
/*
|
|
19
|
+
* The UCRT validates its low-level I/O arguments and, when one is out of
|
|
20
|
+
* range, calls the invalid-parameter handler. The default handler terminates
|
|
21
|
+
* the process through `_invoke_watson`, which fast-fails with exit status
|
|
22
|
+
* 0xC0000409. That makes POSIX-style calls such as `close(9999)` abort instead
|
|
23
|
+
* of reporting `EBADF`. Install a no-op handler so the CRT returns its normal
|
|
24
|
+
* error code (and sets `errno`) instead of crashing.
|
|
25
|
+
*/
|
|
26
|
+
static void __cdecl xt_noop_invalid_parameter_handler(const wchar_t *expression, const wchar_t *function_name,
|
|
27
|
+
const wchar_t *file_name, unsigned int line_number,
|
|
28
|
+
uintptr_t reserved) {
|
|
29
|
+
(void)expression;
|
|
30
|
+
(void)function_name;
|
|
31
|
+
(void)file_name;
|
|
32
|
+
(void)line_number;
|
|
33
|
+
(void)reserved;
|
|
34
|
+
}
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
void xt_set_program_args(int32_t argc, char **argv) {
|
|
38
|
+
#if defined(_WIN32)
|
|
39
|
+
/* Keep stdout/stderr in binary mode so `\n` is not translated to `\r\n`,
|
|
40
|
+
matching Node's output, and initialise Winsock before any extension uses
|
|
41
|
+
sockets (the generated `main` calls this before running the program). */
|
|
42
|
+
_setmode(_fileno(stdout), _O_BINARY);
|
|
43
|
+
_setmode(_fileno(stderr), _O_BINARY);
|
|
44
|
+
_set_invalid_parameter_handler(xt_noop_invalid_parameter_handler);
|
|
45
|
+
WSADATA wsaData;
|
|
46
|
+
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
47
|
+
#endif
|
|
48
|
+
xt_program_argc = argc;
|
|
49
|
+
xt_program_argv = argv;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* `import.meta` support. The compiler resolves module URLs at build time, but
|
|
54
|
+
* a self-hosted binary only knows where *it* lives, so `import.meta.url` is the
|
|
55
|
+
* executable's own `file://` URL (and `dirname`/`filename` its path parts).
|
|
56
|
+
* This lets the compiler locate an adjacent `runtime/` directory at run time.
|
|
57
|
+
*/
|
|
58
|
+
static xt_value xt_file_url(const char *path) {
|
|
59
|
+
char url[4300];
|
|
60
|
+
size_t j = 0;
|
|
61
|
+
const char *prefix = "file://";
|
|
62
|
+
for (; *prefix; prefix++) url[j++] = *prefix;
|
|
63
|
+
#if defined(_WIN32)
|
|
64
|
+
url[j++] = '/';
|
|
65
|
+
#endif
|
|
66
|
+
for (const char *p = path; *p && j < sizeof(url) - 1; p++) url[j++] = (*p == '\\') ? '/' : *p;
|
|
67
|
+
url[j] = 0;
|
|
68
|
+
return xt_string_from_cstr(url);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
xt_value xt_import_meta(xt_value name) {
|
|
72
|
+
const char *prop = xt_string_data(name);
|
|
73
|
+
const char *raw = (xt_program_argv && xt_program_argv[0]) ? xt_program_argv[0] : "";
|
|
74
|
+
char resolved[4096];
|
|
75
|
+
resolved[0] = 0;
|
|
76
|
+
if (raw[0]) {
|
|
77
|
+
#if defined(_WIN32)
|
|
78
|
+
if (_fullpath(resolved, raw, sizeof(resolved)) == NULL) resolved[0] = 0;
|
|
79
|
+
#else
|
|
80
|
+
if (realpath(raw, resolved) == NULL) resolved[0] = 0;
|
|
81
|
+
#endif
|
|
82
|
+
}
|
|
83
|
+
const char *abs = resolved[0] ? resolved : raw;
|
|
84
|
+
if (prop && strcmp(prop, "dirname") == 0) {
|
|
85
|
+
char dir[4096];
|
|
86
|
+
size_t n = strlen(abs);
|
|
87
|
+
if (n >= sizeof(dir)) n = sizeof(dir) - 1;
|
|
88
|
+
memcpy(dir, abs, n);
|
|
89
|
+
dir[n] = 0;
|
|
90
|
+
char *slash = strrchr(dir, '/');
|
|
91
|
+
#if defined(_WIN32)
|
|
92
|
+
char *back = strrchr(dir, '\\');
|
|
93
|
+
if (back && (!slash || back > slash)) slash = back;
|
|
94
|
+
#endif
|
|
95
|
+
if (slash) {
|
|
96
|
+
if (slash == dir) slash[1] = 0;
|
|
97
|
+
else *slash = 0;
|
|
98
|
+
}
|
|
99
|
+
return xt_string_from_cstr(dir);
|
|
100
|
+
}
|
|
101
|
+
if (prop && strcmp(prop, "filename") == 0) return xt_string_from_cstr(abs);
|
|
102
|
+
return xt_file_url(abs);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void *xt_try_enter(void) {
|
|
106
|
+
xt_try_frame *frame = (xt_try_frame *)calloc(1, sizeof(xt_try_frame));
|
|
107
|
+
if (!frame) abort();
|
|
108
|
+
frame->prev = g_try_top;
|
|
109
|
+
frame->exception = XT_UNDEFINED;
|
|
110
|
+
g_try_top = frame;
|
|
111
|
+
return (void *)frame;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
xt_value xt_try_exception(void *framePtr) {
|
|
115
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
116
|
+
return frame ? frame->exception : XT_UNDEFINED;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void xt_try_leave(void *framePtr) {
|
|
120
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
121
|
+
if (frame && g_try_top == frame) {
|
|
122
|
+
g_try_top = frame->prev;
|
|
123
|
+
free(frame);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Save/restore the innermost try frame. Generators use this to swap their own
|
|
128
|
+
* exception stack in while they run on their private coroutine stack. */
|
|
129
|
+
void *xt_try_mark(void) { return (void *)g_try_top; }
|
|
130
|
+
|
|
131
|
+
void xt_try_restore(void *mark) { g_try_top = (xt_try_frame *)mark; }
|
|
132
|
+
|
|
133
|
+
void xt_throw(xt_value v) {
|
|
134
|
+
if (g_try_top) {
|
|
135
|
+
g_try_top->exception = v;
|
|
136
|
+
longjmp(g_try_top->buf, 1);
|
|
137
|
+
}
|
|
138
|
+
xt_value message = xt_to_string(v);
|
|
139
|
+
xt_string *s = xt_as_string(message);
|
|
140
|
+
fprintf(stderr, "Uncaught %s\n", s->data);
|
|
141
|
+
exit(1);
|
|
142
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Output and inspection */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
static void xt_print_value(xt_value v, FILE *out) {
|
|
6
|
+
if (XT_IS_STRING(v)) {
|
|
7
|
+
xt_string *s = xt_as_string(v);
|
|
8
|
+
fwrite(s->data, 1, s->length, out);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
xt_value text = xt_to_string(v);
|
|
12
|
+
xt_string *s = xt_as_string(text);
|
|
13
|
+
fwrite(s->data, 1, s->length, out);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
void xt_print(xt_value v) { xt_print_value(v, stdout); }
|
|
17
|
+
void xt_println(xt_value v) {
|
|
18
|
+
xt_print_value(v, stdout);
|
|
19
|
+
fputc('\n', stdout);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* console.log applies a Node-like inspection format: strings unquoted at the
|
|
24
|
+
* top level, arrays as `[ a, b ]` and objects as `{ key: value }`.
|
|
25
|
+
*
|
|
26
|
+
* Recursion tracks the ancestor chain so self-referential containers print
|
|
27
|
+
* Node's `[Circular *N]` marker instead of recursing forever. `N` is the
|
|
28
|
+
* 1-based position of the repeated container in the current path.
|
|
29
|
+
*/
|
|
30
|
+
#define XT_INSPECT_MAX_DEPTH 512
|
|
31
|
+
static const void *xt_inspect_stack[XT_INSPECT_MAX_DEPTH];
|
|
32
|
+
static int xt_inspect_depth = 0;
|
|
33
|
+
|
|
34
|
+
static int xt_inspect_seen(const void *ptr) {
|
|
35
|
+
for (int i = 0; i < xt_inspect_depth; i++) {
|
|
36
|
+
if (xt_inspect_stack[i] == ptr) return i + 1;
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static void xt_inspect_push(const void *ptr) {
|
|
42
|
+
if (xt_inspect_depth < XT_INSPECT_MAX_DEPTH) xt_inspect_stack[xt_inspect_depth++] = ptr;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static void xt_inspect_pop(void) {
|
|
46
|
+
if (xt_inspect_depth > 0) xt_inspect_depth--;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static int xt_inspect_identifier_key(xt_string *key) {
|
|
50
|
+
if (key->length == 0) return 0;
|
|
51
|
+
char c = key->data[0];
|
|
52
|
+
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$')) return 0;
|
|
53
|
+
for (uint32_t i = 1; i < key->length; i++) {
|
|
54
|
+
c = key->data[i];
|
|
55
|
+
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$')) return 0;
|
|
56
|
+
}
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Render a string the way `util.inspect` does inside a container: quoted,
|
|
61
|
+
* preferring whichever quote character needs fewer escapes. */
|
|
62
|
+
static void xt_inspect_string(xt_string *s, FILE *out) {
|
|
63
|
+
int hasSingle = 0;
|
|
64
|
+
int hasDouble = 0;
|
|
65
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
66
|
+
if (s->data[i] == '\'') hasSingle = 1;
|
|
67
|
+
else if (s->data[i] == '"') hasDouble = 1;
|
|
68
|
+
}
|
|
69
|
+
char quote = (hasSingle && !hasDouble) ? '"' : '\'';
|
|
70
|
+
fputc(quote, out);
|
|
71
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
72
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
73
|
+
switch (c) {
|
|
74
|
+
case '\\': fputs("\\\\", out); break;
|
|
75
|
+
case '\n': fputs("\\n", out); break;
|
|
76
|
+
case '\r': fputs("\\r", out); break;
|
|
77
|
+
case '\t': fputs("\\t", out); break;
|
|
78
|
+
case '\f': fputs("\\f", out); break;
|
|
79
|
+
case '\b': fputs("\\b", out); break;
|
|
80
|
+
case '\v': fputs("\\v", out); break;
|
|
81
|
+
default:
|
|
82
|
+
if (c == (unsigned char)quote) { fputc('\\', out); fputc(c, out); }
|
|
83
|
+
else if (c < 0x20) fprintf(out, "\\x%02x", c);
|
|
84
|
+
else fputc(c, out);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
fputc(quote, out);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static void xt_inspect(xt_value v, FILE *out, int nested) {
|
|
91
|
+
if (xt_is_symbol(v)) {
|
|
92
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(v));
|
|
93
|
+
fwrite(text->data, 1, text->length, out);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (XT_IS_BIGINT(v)) {
|
|
97
|
+
xt_value text = xt_bigint_to_decimal(v);
|
|
98
|
+
xt_string *s = xt_as_string(text);
|
|
99
|
+
fwrite(s->data, 1, s->length, out);
|
|
100
|
+
fputc('n', out);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (nested && XT_IS_STRING(v)) {
|
|
104
|
+
xt_inspect_string(xt_as_string(v), out);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (XT_IS_ARRAY(v)) {
|
|
108
|
+
xt_array *array = (xt_array *)XT_GET_PTR(v);
|
|
109
|
+
int seen = xt_inspect_seen(array);
|
|
110
|
+
if (seen > 0) {
|
|
111
|
+
fprintf(out, "[Circular *%d]", seen);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
|
|
115
|
+
fputs("[Array]", out);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
xt_inspect_push(array);
|
|
119
|
+
fputc('[', out);
|
|
120
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
121
|
+
if (i > 0) fputs(", ", out);
|
|
122
|
+
else fputc(' ', out);
|
|
123
|
+
xt_inspect(array->items[i], out, 1);
|
|
124
|
+
}
|
|
125
|
+
if (XT_IS_OBJECT(array->extra)) {
|
|
126
|
+
xt_object *extra = (xt_object *)XT_GET_PTR(array->extra);
|
|
127
|
+
for (uint32_t i = 0; i < extra->count; i++) {
|
|
128
|
+
if (array->length > 0 || i > 0) fputs(", ", out);
|
|
129
|
+
else fputc(' ', out);
|
|
130
|
+
xt_value key = extra->properties[i].key;
|
|
131
|
+
if (xt_is_symbol(key)) {
|
|
132
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
133
|
+
fwrite(text->data, 1, text->length, out);
|
|
134
|
+
} else {
|
|
135
|
+
xt_string *keyString = xt_as_string(key);
|
|
136
|
+
fwrite(keyString->data, 1, keyString->length, out);
|
|
137
|
+
}
|
|
138
|
+
fputs(": ", out);
|
|
139
|
+
xt_inspect(extra->properties[i].value, out, 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (array->length > 0 || (XT_IS_OBJECT(array->extra) && ((xt_object *)XT_GET_PTR(array->extra))->count > 0)) fputc(' ', out);
|
|
143
|
+
fputc(']', out);
|
|
144
|
+
xt_inspect_pop();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (XT_IS_OBJECT(v)) {
|
|
148
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(v);
|
|
149
|
+
int seen = xt_inspect_seen(obj);
|
|
150
|
+
if (seen > 0) {
|
|
151
|
+
fprintf(out, "[Circular *%d]", seen);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
|
|
155
|
+
fputs("[Object]", out);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
xt_inspect_push(obj);
|
|
159
|
+
fputc('{', out);
|
|
160
|
+
/* `util.inspect` lists string keys first, then symbol keys, in insertion
|
|
161
|
+
* order; symbol keys are printed without brackets. */
|
|
162
|
+
int written = 0;
|
|
163
|
+
for (int pass = 0; pass < 2; pass++) {
|
|
164
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
165
|
+
xt_value key = obj->properties[i].key;
|
|
166
|
+
int isSymbol = xt_is_symbol(key);
|
|
167
|
+
if ((pass == 0) == isSymbol) continue;
|
|
168
|
+
if (written > 0) fputs(", ", out);
|
|
169
|
+
else fputc(' ', out);
|
|
170
|
+
written++;
|
|
171
|
+
if (isSymbol) {
|
|
172
|
+
xt_string *text = xt_as_string(xt_symbol_to_string(key));
|
|
173
|
+
fwrite(text->data, 1, text->length, out);
|
|
174
|
+
} else {
|
|
175
|
+
xt_string *keyString = xt_as_string(key);
|
|
176
|
+
if (xt_inspect_identifier_key(keyString)) fwrite(keyString->data, 1, keyString->length, out);
|
|
177
|
+
else xt_inspect_string(keyString, out);
|
|
178
|
+
}
|
|
179
|
+
fputs(": ", out);
|
|
180
|
+
xt_inspect(obj->properties[i].value, out, 1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (written > 0) fputc(' ', out);
|
|
184
|
+
fputc('}', out);
|
|
185
|
+
xt_inspect_pop();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
xt_print_value(v, out);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* Inspect one top-level value; reset the ancestor chain so nested console
|
|
192
|
+
* calls (or a `longjmp` out of a throw) never leave stale state behind. */
|
|
193
|
+
static void xt_inspect_top(xt_value v, FILE *out) {
|
|
194
|
+
xt_inspect_depth = 0;
|
|
195
|
+
xt_inspect(v, out, 0);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void xt_console_log(int32_t argc, xt_value *argv) {
|
|
199
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
200
|
+
if (i > 0) fputc(' ', stdout);
|
|
201
|
+
xt_inspect_top(argv[i], stdout);
|
|
202
|
+
}
|
|
203
|
+
fputc('\n', stdout);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
static void xt_console_write(int32_t argc, xt_value *argv, FILE *out) {
|
|
207
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
208
|
+
if (i > 0) fputc(' ', out);
|
|
209
|
+
xt_inspect_top(argv[i], out);
|
|
210
|
+
}
|
|
211
|
+
fputc('\n', out);
|
|
212
|
+
}
|