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,186 @@
|
|
|
1
|
+
/* -- encoding helpers ----------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
static const char xt_fs_base64_alphabet[] =
|
|
4
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
5
|
+
|
|
6
|
+
/* Accepts a bare encoding string or an options object with `encoding`. */
|
|
7
|
+
static inline const char *xt_fs_encoding(xt_value options) {
|
|
8
|
+
if (XT_IS_STRING(options)) return xt_string_data(options);
|
|
9
|
+
if (XT_IS_OBJECT(options)) {
|
|
10
|
+
xt_value encoding = xt_object_get_cstr(options, "encoding");
|
|
11
|
+
if (XT_IS_STRING(encoding)) return xt_string_data(encoding);
|
|
12
|
+
}
|
|
13
|
+
return NULL;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static inline int xt_fs_is_hex(const char *encoding) {
|
|
17
|
+
return encoding && strcmp(encoding, "hex") == 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static inline int xt_fs_is_base64(const char *encoding) {
|
|
21
|
+
return encoding && strcmp(encoding, "base64") == 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static inline int xt_fs_is_base64url(const char *encoding) {
|
|
25
|
+
return encoding && strcmp(encoding, "base64url") == 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static inline int xt_fs_is_utf16(const char *encoding) {
|
|
29
|
+
return encoding && (strcmp(encoding, "utf16le") == 0 || strcmp(encoding, "ucs2") == 0 ||
|
|
30
|
+
strcmp(encoding, "ucs-2") == 0 || strcmp(encoding, "utf-16le") == 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static inline xt_value xt_fs_encode_hex(const unsigned char *data, size_t length) {
|
|
34
|
+
static const char digits[] = "0123456789abcdef";
|
|
35
|
+
char *buffer = (char *)malloc(length * 2 + 1);
|
|
36
|
+
if (!buffer) return xt_undefined();
|
|
37
|
+
for (size_t i = 0; i < length; i++) {
|
|
38
|
+
buffer[i * 2] = digits[data[i] >> 4];
|
|
39
|
+
buffer[i * 2 + 1] = digits[data[i] & 0x0f];
|
|
40
|
+
}
|
|
41
|
+
xt_value result = xt_string_new(buffer, length * 2);
|
|
42
|
+
free(buffer);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static inline xt_value xt_fs_encode_base64(const unsigned char *data, size_t length) {
|
|
47
|
+
size_t outLength = ((length + 2) / 3) * 4;
|
|
48
|
+
char *buffer = (char *)malloc(outLength + 1);
|
|
49
|
+
if (!buffer) return xt_undefined();
|
|
50
|
+
size_t i = 0, j = 0;
|
|
51
|
+
while (i + 2 < length) {
|
|
52
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8) | (uint32_t)data[i + 2];
|
|
53
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
54
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
55
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
56
|
+
buffer[j++] = xt_fs_base64_alphabet[n & 63];
|
|
57
|
+
i += 3;
|
|
58
|
+
}
|
|
59
|
+
if (length - i == 1) {
|
|
60
|
+
uint32_t n = (uint32_t)data[i] << 16;
|
|
61
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
62
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
63
|
+
buffer[j++] = '=';
|
|
64
|
+
buffer[j++] = '=';
|
|
65
|
+
} else if (length - i == 2) {
|
|
66
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8);
|
|
67
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
68
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
69
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
70
|
+
buffer[j++] = '=';
|
|
71
|
+
}
|
|
72
|
+
xt_value result = xt_string_new(buffer, j);
|
|
73
|
+
free(buffer);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Encode bytes for `readFileSync` according to `encoding` (default raw UTF-8). */
|
|
78
|
+
static inline xt_value xt_fs_encode_base64url(const unsigned char *data, size_t length) {
|
|
79
|
+
size_t outLength = ((length + 2) / 3) * 4 + 1;
|
|
80
|
+
char *buffer = (char *)malloc(outLength);
|
|
81
|
+
if (!buffer) return xt_undefined();
|
|
82
|
+
size_t i = 0, j = 0;
|
|
83
|
+
while (i + 2 < length) {
|
|
84
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8) | (uint32_t)data[i + 2];
|
|
85
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
86
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
87
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
88
|
+
buffer[j++] = xt_fs_base64_alphabet[n & 63];
|
|
89
|
+
i += 3;
|
|
90
|
+
}
|
|
91
|
+
if (length - i == 1) {
|
|
92
|
+
uint32_t n = (uint32_t)data[i] << 16;
|
|
93
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
94
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
95
|
+
} else if (length - i == 2) {
|
|
96
|
+
uint32_t n = ((uint32_t)data[i] << 16) | ((uint32_t)data[i + 1] << 8);
|
|
97
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 18) & 63];
|
|
98
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 12) & 63];
|
|
99
|
+
buffer[j++] = xt_fs_base64_alphabet[(n >> 6) & 63];
|
|
100
|
+
}
|
|
101
|
+
for (size_t k = 0; k < j; k++) {
|
|
102
|
+
if (buffer[k] == '+') buffer[k] = '-';
|
|
103
|
+
else if (buffer[k] == '/') buffer[k] = '_';
|
|
104
|
+
}
|
|
105
|
+
xt_value result = xt_string_new(buffer, j);
|
|
106
|
+
free(buffer);
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static inline xt_value xt_fs_encode_bytes(const unsigned char *data, size_t length, const char *encoding) {
|
|
111
|
+
if (xt_fs_is_hex(encoding)) return xt_fs_encode_hex(data, length);
|
|
112
|
+
if (xt_fs_is_base64(encoding)) return xt_fs_encode_base64(data, length);
|
|
113
|
+
if (xt_fs_is_base64url(encoding)) return xt_fs_encode_base64url(data, length);
|
|
114
|
+
return xt_string_new((const char *)data, length);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static inline int xt_fs_base64_value(char c) {
|
|
118
|
+
if (c >= 'A' && c <= 'Z') return c - 'A';
|
|
119
|
+
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
|
120
|
+
if (c >= '0' && c <= '9') return c - '0' + 52;
|
|
121
|
+
if (c == '+' || c == '-') return 62;
|
|
122
|
+
if (c == '/' || c == '_') return 63;
|
|
123
|
+
return -1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static inline int xt_fs_hex_value(char c) {
|
|
127
|
+
if (c >= '0' && c <= '9') return c - '0';
|
|
128
|
+
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
|
129
|
+
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
130
|
+
return -1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* Decode text for `writeFileSync` according to `encoding`. Returns a malloc'd
|
|
135
|
+
* byte buffer (never NULL unless allocation failed) and stores its length in
|
|
136
|
+
* `*outLength`; the caller frees it.
|
|
137
|
+
*/
|
|
138
|
+
static inline unsigned char *xt_fs_decode_text(const char *text, size_t length, const char *encoding, size_t *outLength) {
|
|
139
|
+
unsigned char *bytes = NULL;
|
|
140
|
+
if (xt_fs_is_base64(encoding) || xt_fs_is_base64url(encoding)) {
|
|
141
|
+
size_t capacity = (length / 4 + 1) * 3;
|
|
142
|
+
bytes = (unsigned char *)malloc(capacity + 1);
|
|
143
|
+
if (!bytes) return NULL;
|
|
144
|
+
size_t written = 0;
|
|
145
|
+
int accumulator = 0, bits = 0;
|
|
146
|
+
for (size_t i = 0; i < length; i++) {
|
|
147
|
+
if (text[i] == '=') break;
|
|
148
|
+
int value = xt_fs_base64_value(text[i]);
|
|
149
|
+
if (value < 0) continue;
|
|
150
|
+
accumulator = (accumulator << 6) | value;
|
|
151
|
+
bits += 6;
|
|
152
|
+
if (bits >= 8) {
|
|
153
|
+
bits -= 8;
|
|
154
|
+
bytes[written++] = (unsigned char)((accumulator >> bits) & 0xff);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
bytes[written] = '\0';
|
|
158
|
+
*outLength = written;
|
|
159
|
+
return bytes;
|
|
160
|
+
}
|
|
161
|
+
if (xt_fs_is_hex(encoding)) {
|
|
162
|
+
bytes = (unsigned char *)malloc(length / 2 + 1);
|
|
163
|
+
if (!bytes) return NULL;
|
|
164
|
+
size_t written = 0;
|
|
165
|
+
int high = -1;
|
|
166
|
+
for (size_t i = 0; i < length; i++) {
|
|
167
|
+
int value = xt_fs_hex_value(text[i]);
|
|
168
|
+
if (value < 0) continue;
|
|
169
|
+
if (high < 0) {
|
|
170
|
+
high = value;
|
|
171
|
+
} else {
|
|
172
|
+
bytes[written++] = (unsigned char)((high << 4) | value);
|
|
173
|
+
high = -1;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
bytes[written] = '\0';
|
|
177
|
+
*outLength = written;
|
|
178
|
+
return bytes;
|
|
179
|
+
}
|
|
180
|
+
bytes = (unsigned char *)malloc(length + 1);
|
|
181
|
+
if (!bytes) return NULL;
|
|
182
|
+
if (length > 0) memcpy(bytes, text, length);
|
|
183
|
+
bytes[length] = '\0';
|
|
184
|
+
*outLength = length;
|
|
185
|
+
return bytes;
|
|
186
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* -- errors --------------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/* Node's `err.code` for the errno values the fs module can raise. */
|
|
4
|
+
static inline const char *xt_fs_errno_name(int err) {
|
|
5
|
+
switch (err) {
|
|
6
|
+
case ENOENT: return "ENOENT";
|
|
7
|
+
case EACCES: return "EACCES";
|
|
8
|
+
case EEXIST: return "EEXIST";
|
|
9
|
+
case ENOTDIR: return "ENOTDIR";
|
|
10
|
+
case EISDIR: return "EISDIR";
|
|
11
|
+
case EPERM: return "EPERM";
|
|
12
|
+
case EINVAL: return "EINVAL";
|
|
13
|
+
case EBADF: return "EBADF";
|
|
14
|
+
case ENOSPC: return "ENOSPC";
|
|
15
|
+
case EROFS: return "EROFS";
|
|
16
|
+
case EMFILE: return "EMFILE";
|
|
17
|
+
#ifdef ENOTEMPTY
|
|
18
|
+
case ENOTEMPTY: return "ENOTEMPTY";
|
|
19
|
+
#endif
|
|
20
|
+
#ifdef ELOOP
|
|
21
|
+
case ELOOP: return "ELOOP";
|
|
22
|
+
#endif
|
|
23
|
+
#ifdef ENAMETOOLONG
|
|
24
|
+
case ENAMETOOLONG: return "ENAMETOOLONG";
|
|
25
|
+
#endif
|
|
26
|
+
#ifdef EXDEV
|
|
27
|
+
case EXDEV: return "EXDEV";
|
|
28
|
+
#endif
|
|
29
|
+
default: return "UNKNOWN";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Build a Node-shaped Error (`code`/`errno`/`syscall`/`path`/`message`). */
|
|
34
|
+
static inline xt_value xt_fs_error_object(int err, const char *syscall, const char *path) {
|
|
35
|
+
const char *code = xt_fs_errno_name(err);
|
|
36
|
+
char buffer[1024];
|
|
37
|
+
snprintf(buffer, sizeof(buffer), "%s: %s, %s '%s'", code, strerror(err), syscall ? syscall : "",
|
|
38
|
+
path ? path : "");
|
|
39
|
+
xt_value error = xt_object_new();
|
|
40
|
+
((xt_object *)XT_GET_PTR(error))->header.kind = XT_OBJECT_KIND_ERROR;
|
|
41
|
+
xt_object_set(error, xt_string_from_cstr("name"), xt_string_from_cstr("Error"));
|
|
42
|
+
xt_object_set(error, xt_string_from_cstr("message"), xt_string_from_cstr(buffer));
|
|
43
|
+
xt_object_set(error, xt_string_from_cstr("code"), xt_string_from_cstr(code));
|
|
44
|
+
xt_object_set(error, xt_string_from_cstr("errno"), xt_number((double)(-err)));
|
|
45
|
+
if (syscall) xt_object_set(error, xt_string_from_cstr("syscall"), xt_string_from_cstr(syscall));
|
|
46
|
+
if (path) xt_object_set(error, xt_string_from_cstr("path"), xt_string_from_cstr(path));
|
|
47
|
+
return error;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Raise `errno` (captured by the caller right after a failed syscall). */
|
|
51
|
+
static inline void xt_fs_raise_errno(int err, const char *syscall, const char *path) {
|
|
52
|
+
xt_throw(xt_fs_error_object(err, syscall, path));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static inline void xt_fs_raise_path(const char *syscall, const char *path) {
|
|
56
|
+
xt_fs_raise_errno(errno, syscall, path);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* Report a failed syscall. The fs module follows Node and *throws* a shaped
|
|
61
|
+
* Error (the runtime now has catchable exceptions), so callers must not rely
|
|
62
|
+
* on a return value after a failure.
|
|
63
|
+
*/
|
|
64
|
+
static inline void xt_fs_error(const char *action, const char *path) {
|
|
65
|
+
xt_fs_raise_errno(errno, action, path);
|
|
66
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* -- open-flag parsing ---------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
#if defined(_WIN32)
|
|
4
|
+
#define XT_FS_BINARY_FLAG _O_BINARY
|
|
5
|
+
#define XT_FS_RDONLY _O_RDONLY
|
|
6
|
+
#define XT_FS_WRONLY _O_WRONLY
|
|
7
|
+
#define XT_FS_RDWR _O_RDWR
|
|
8
|
+
#define XT_FS_CREAT _O_CREAT
|
|
9
|
+
#define XT_FS_TRUNC _O_TRUNC
|
|
10
|
+
#define XT_FS_APPEND _O_APPEND
|
|
11
|
+
#define XT_FS_EXCL _O_EXCL
|
|
12
|
+
#else
|
|
13
|
+
#define XT_FS_BINARY_FLAG 0
|
|
14
|
+
#define XT_FS_RDONLY O_RDONLY
|
|
15
|
+
#define XT_FS_WRONLY O_WRONLY
|
|
16
|
+
#define XT_FS_RDWR O_RDWR
|
|
17
|
+
#define XT_FS_CREAT O_CREAT
|
|
18
|
+
#define XT_FS_TRUNC O_TRUNC
|
|
19
|
+
#define XT_FS_APPEND O_APPEND
|
|
20
|
+
#define XT_FS_EXCL O_EXCL
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
/* Translate a Node flag string (`"r"`, `"w+"`, `"a"`, ...) or number. */
|
|
24
|
+
static inline int xt_fs_parse_flags(xt_value value) {
|
|
25
|
+
if (XT_IS_STRING(value)) {
|
|
26
|
+
const char *flag = xt_string_data(value);
|
|
27
|
+
if (!flag) return XT_FS_RDONLY | XT_FS_BINARY_FLAG;
|
|
28
|
+
int plus = strchr(flag, '+') != NULL;
|
|
29
|
+
int excl = strchr(flag, 'x') != NULL;
|
|
30
|
+
int base;
|
|
31
|
+
if (flag[0] == 'a') base = XT_FS_APPEND | XT_FS_CREAT;
|
|
32
|
+
else if (flag[0] == 'w') base = XT_FS_CREAT | XT_FS_TRUNC;
|
|
33
|
+
else base = 0; /* 'r' and the numeric path below */
|
|
34
|
+
base |= (plus || flag[0] == 'w' || flag[0] == 'a') ? XT_FS_RDWR : XT_FS_RDONLY;
|
|
35
|
+
if (excl) base |= XT_FS_EXCL;
|
|
36
|
+
return base | XT_FS_BINARY_FLAG;
|
|
37
|
+
}
|
|
38
|
+
return (int)xt_to_number(value) | XT_FS_BINARY_FLAG;
|
|
39
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* -- platform shims ------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
#if defined(_WIN32)
|
|
4
|
+
#include <direct.h>
|
|
5
|
+
#include <fcntl.h>
|
|
6
|
+
#include <io.h>
|
|
7
|
+
#include <sys/stat.h>
|
|
8
|
+
#include <sys/types.h>
|
|
9
|
+
|
|
10
|
+
/* Stat results are filled from Win32 directly. The CRT's `_stat` converts the
|
|
11
|
+
* FILETIME through the *local* time zone before producing `time_t`, so a time
|
|
12
|
+
* near the Unix epoch (e.g. `utimesSync(path, 1000, 2000)`) maps to 1969 on a
|
|
13
|
+
* machine west of UTC and the CRT reports an unrepresentable `st_mtime` (-1).
|
|
14
|
+
* Reading the Win32 FILETIME and converting it to Unix seconds in UTC like
|
|
15
|
+
* libuv/Node keeps the values exact and timezone independent. */
|
|
16
|
+
typedef struct {
|
|
17
|
+
long long st_size;
|
|
18
|
+
unsigned int st_mode;
|
|
19
|
+
unsigned int st_uid;
|
|
20
|
+
unsigned int st_gid;
|
|
21
|
+
unsigned int st_dev;
|
|
22
|
+
unsigned long long st_ino;
|
|
23
|
+
unsigned int st_nlink;
|
|
24
|
+
unsigned int st_rdev;
|
|
25
|
+
long long st_mtime; /* seconds since the Unix epoch */
|
|
26
|
+
long long st_atime;
|
|
27
|
+
long long st_ctime;
|
|
28
|
+
} xt_fs_stat_t;
|
|
29
|
+
|
|
30
|
+
int xt_fs_win_stat(const char *path, xt_fs_stat_t *out);
|
|
31
|
+
int xt_fs_win_lstat(const char *path, xt_fs_stat_t *out);
|
|
32
|
+
int xt_fs_win_fstat(int fd, xt_fs_stat_t *out);
|
|
33
|
+
#define xt_fs_stat_fn xt_fs_win_stat
|
|
34
|
+
#define xt_fs_lstat_fn xt_fs_win_lstat
|
|
35
|
+
#define xt_fs_fstat_fn xt_fs_win_fstat
|
|
36
|
+
#define xt_fs_access _access
|
|
37
|
+
#define xt_fs_mkdir_mode(path, mode) _mkdir(path)
|
|
38
|
+
#define xt_fs_mkdir_one(path) _mkdir(path)
|
|
39
|
+
#define xt_fs_rmdir_one(path) _rmdir(path)
|
|
40
|
+
#define XT_FS_OPEN _open
|
|
41
|
+
#define XT_FS_CLOSE _close
|
|
42
|
+
#define XT_FS_READ _read
|
|
43
|
+
#define XT_FS_WRITE _write
|
|
44
|
+
|
|
45
|
+
#ifndef S_ISREG
|
|
46
|
+
#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
|
47
|
+
#endif
|
|
48
|
+
#ifndef S_ISDIR
|
|
49
|
+
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
|
50
|
+
#endif
|
|
51
|
+
#ifndef S_ISLNK
|
|
52
|
+
#define S_ISLNK(m) 0
|
|
53
|
+
#endif
|
|
54
|
+
#ifndef S_ISFIFO
|
|
55
|
+
#define S_ISFIFO(m) 0
|
|
56
|
+
#endif
|
|
57
|
+
#ifndef S_ISSOCK
|
|
58
|
+
#define S_ISSOCK(m) 0
|
|
59
|
+
#endif
|
|
60
|
+
#ifndef S_ISBLK
|
|
61
|
+
#define S_ISBLK(m) 0
|
|
62
|
+
#endif
|
|
63
|
+
#ifndef S_ISCHR
|
|
64
|
+
#define S_ISCHR(m) (((m) & _S_IFMT) == _S_IFCHR)
|
|
65
|
+
#endif
|
|
66
|
+
#ifndef F_OK
|
|
67
|
+
#define F_OK 0
|
|
68
|
+
#endif
|
|
69
|
+
#else
|
|
70
|
+
#include <fcntl.h>
|
|
71
|
+
#include <sys/stat.h>
|
|
72
|
+
#include <sys/types.h>
|
|
73
|
+
#include <unistd.h>
|
|
74
|
+
|
|
75
|
+
typedef struct stat xt_fs_stat_t;
|
|
76
|
+
#define xt_fs_stat_fn stat
|
|
77
|
+
#define xt_fs_lstat_fn lstat
|
|
78
|
+
#define xt_fs_access access
|
|
79
|
+
#define xt_fs_mkdir_mode(path, mode) mkdir((path), (mode))
|
|
80
|
+
#define xt_fs_mkdir_one(path) mkdir(path, 0777)
|
|
81
|
+
#define xt_fs_rmdir_one(path) rmdir(path)
|
|
82
|
+
#define XT_FS_OPEN open
|
|
83
|
+
#define XT_FS_CLOSE close
|
|
84
|
+
#define XT_FS_READ read
|
|
85
|
+
#define XT_FS_WRITE write
|
|
86
|
+
#endif
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* -- promise wrapper ------------------------------------------------------ */
|
|
2
|
+
|
|
3
|
+
/* A promise wrapper over a synchronous builtin: an immediately settled
|
|
4
|
+
* promise that is rejected (rather than throwing) when the builtin raises. */
|
|
5
|
+
static inline xt_value xt_fs_promisify(xt_value (*fn)(int32_t, xt_value *), int32_t argc, xt_value *argv) {
|
|
6
|
+
void *frame = xt_try_enter();
|
|
7
|
+
if (xt_try_setjmp(frame) == 0) {
|
|
8
|
+
xt_value result = fn(argc, argv);
|
|
9
|
+
xt_try_leave(frame);
|
|
10
|
+
return xt_promise_resolve(result);
|
|
11
|
+
}
|
|
12
|
+
xt_value exception = xt_try_exception(frame);
|
|
13
|
+
xt_try_leave(frame);
|
|
14
|
+
return xt_promise_reject(exception);
|
|
15
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* -- time helpers --------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
/* Node accepts a Date or a number of seconds; Date stores milliseconds. */
|
|
4
|
+
static inline double xt_fs_time_seconds(xt_value value) {
|
|
5
|
+
if (XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_DATE) {
|
|
6
|
+
return ((xt_date *)XT_GET_PTR(value))->time / 1000.0;
|
|
7
|
+
}
|
|
8
|
+
return xt_to_number(value);
|
|
9
|
+
}
|
package/runtime/rt.h
CHANGED
|
@@ -18,10 +18,9 @@
|
|
|
18
18
|
#include <stdint.h>
|
|
19
19
|
|
|
20
20
|
/* POSIX `ssize_t` is not exposed by the MSVC/UCRT headers clang uses on
|
|
21
|
-
* Windows
|
|
22
|
-
*
|
|
23
|
-
|
|
24
|
-
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(_SSIZE_T_DEFINED)
|
|
21
|
+
* Windows (every Unix libc defines it). Alias the Windows pointer-sized signed
|
|
22
|
+
* integer so the runtime's POSIX shims compile unchanged. */
|
|
23
|
+
#if defined(_WIN32) && !defined(_SSIZE_T_DEFINED)
|
|
25
24
|
typedef intptr_t ssize_t;
|
|
26
25
|
#define _SSIZE_T_DEFINED
|
|
27
26
|
#endif
|
|
@@ -242,6 +241,39 @@ void xt_loop_remove(int fd);
|
|
|
242
241
|
void xt_run_event_loop(void);
|
|
243
242
|
int xt_loop_has_work(void);
|
|
244
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Run one iteration of the reactor, waiting up to `timeout_ms` for readiness
|
|
246
|
+
* (`< 0` blocks until an event arrives, `0` polls without sleeping), and then
|
|
247
|
+
* fire any timers that have come due. The wait is shortened to the nearest
|
|
248
|
+
* timer deadline so a timer-only program still sleeps. Returns the number of
|
|
249
|
+
* active watchers (descriptors plus timers) still registered, or a negative
|
|
250
|
+
* value when the wait itself failed.
|
|
251
|
+
*
|
|
252
|
+
* Hosts that own their main loop (a GUI toolkit, an embedder, ...) call this
|
|
253
|
+
* periodically instead of `xt_run_event_loop` so timers, sockets and promise
|
|
254
|
+
* microtasks keep draining between their own events. When there is no work it
|
|
255
|
+
* returns immediately, so a host with no I/O is unaffected.
|
|
256
|
+
*/
|
|
257
|
+
int xt_loop_poll(int timeout_ms);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* A host-provided main loop. When set, `xt_run_event_loop` delegates to it
|
|
261
|
+
* instead of blocking on `select(2)`. This lets an extension drive the process
|
|
262
|
+
* main loop (e.g. a window toolkit on the UI thread) while still pumping the
|
|
263
|
+
* reactor through `xt_loop_poll`. Call with `NULL` to restore the default.
|
|
264
|
+
*/
|
|
265
|
+
typedef void (*xt_main_loop_fn)(void);
|
|
266
|
+
void xt_loop_set_main(xt_main_loop_fn fn);
|
|
267
|
+
|
|
268
|
+
/* -- timers --------------------------------------------------------------- */
|
|
269
|
+
/* The JS timer globals, implemented on top of the reactor above. Each returns
|
|
270
|
+
* a numeric id (or `undefined` for the `clear*` pair); callbacks are ordinary
|
|
271
|
+
* closure values and extra arguments after the delay are forwarded to them. */
|
|
272
|
+
xt_value xt_set_timeout(int32_t argc, xt_value *argv);
|
|
273
|
+
xt_value xt_clear_timeout(int32_t argc, xt_value *argv);
|
|
274
|
+
xt_value xt_set_interval(int32_t argc, xt_value *argv);
|
|
275
|
+
xt_value xt_clear_interval(int32_t argc, xt_value *argv);
|
|
276
|
+
|
|
245
277
|
/* -- global functions ------------------------------------------------------ */
|
|
246
278
|
xt_value xt_parse_int(int32_t argc, xt_value *argv);
|
|
247
279
|
xt_value xt_parse_float(int32_t argc, xt_value *argv);
|
package/runtime/rt_internal.h
CHANGED
|
@@ -224,31 +224,18 @@ typedef struct xt_try_frame {
|
|
|
224
224
|
struct xt_try_frame *prev;
|
|
225
225
|
xt_value exception;
|
|
226
226
|
} xt_try_frame;
|
|
227
|
-
/*
|
|
228
|
-
* C runtimes differ:
|
|
227
|
+
/* Save a try frame with clang's `_setjmp` built-in.
|
|
229
228
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* clang will not rewrite it. On Windows ARM64 it names `_setjmpex` (and the
|
|
240
|
-
* entry stack pointer from `llvm.sponentry`) instead, matching clang's own
|
|
241
|
-
* lowering there. `_setjmp`/`_setjmpex` (rather than the `setjmp` macro) is
|
|
242
|
-
* used so it pairs with the plain `longjmp` in `xt_throw`. */
|
|
243
|
-
#if defined(_WIN32) && !defined(__MINGW32__)
|
|
244
|
-
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf)
|
|
245
|
-
#elif defined(_WIN32) && defined(__aarch64__)
|
|
246
|
-
#define xt_try_setjmp(framePtr) _setjmpex(((xt_try_frame *)(framePtr))->buf, __builtin_sponentry())
|
|
247
|
-
#elif defined(_WIN32)
|
|
248
|
-
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf, __builtin_frame_address(0))
|
|
249
|
-
#else
|
|
229
|
+
* The generated IR passes the frame explicitly because it is already IR and
|
|
230
|
+
* clang will not rewrite it. This C helper instead calls `_setjmp(buf)` and lets
|
|
231
|
+
* clang supply the frame: on Windows x64 it injects the caller's frame address
|
|
232
|
+
* (`@llvm.frameaddress(0)`) into `_JUMP_BUFFER.Frame` so `longjmp` can feed it
|
|
233
|
+
* to `RtlUnwind`; on Windows ARM64, where the UCRT has no `_setjmp`, it lowers
|
|
234
|
+
* the call to `_setjmpex` with the entry stack pointer (`@llvm.sponentry`). On
|
|
235
|
+
* Linux/macOS `_setjmp` takes only the buffer and pairs with `longjmp`.
|
|
236
|
+
* `_setjmp` is used rather than the exported `setjmp` symbol, whose Windows ABI
|
|
237
|
+
* is an incompatible two-argument routine. */
|
|
250
238
|
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf)
|
|
251
|
-
#endif
|
|
252
239
|
void *xt_try_mark(void);
|
|
253
240
|
void xt_try_restore(void *mark);
|
|
254
241
|
|
package/runtime/xt_builtins.c
CHANGED
|
@@ -301,6 +301,10 @@ XT_BUILTIN_TRAMPOLINE(xt_builtin_value_encodeURIComponent, xt_encode_uri_compone
|
|
|
301
301
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_encodeURI, xt_encode_uri)
|
|
302
302
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_decodeURIComponent, xt_decode_uri_component)
|
|
303
303
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_decodeURI, xt_decode_uri)
|
|
304
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setTimeout, xt_set_timeout)
|
|
305
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearTimeout, xt_clear_timeout)
|
|
306
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setInterval, xt_set_interval)
|
|
307
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearInterval, xt_clear_interval)
|
|
304
308
|
|
|
305
309
|
xt_value xt_in(xt_value key, xt_value value) {
|
|
306
310
|
if (XT_IS_OBJECT(value)) return xt_object_has(value, key);
|