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.
Files changed (201) hide show
  1. package/README.md +22 -22
  2. package/README.zh-CN.md +20 -19
  3. package/bin/xbintsc.js +1 -2
  4. package/dist/src/cli/main.js +8 -5
  5. package/dist/src/cli/main.js.map +1 -1
  6. package/dist/src/codegen/generator/state.js +8 -0
  7. package/dist/src/codegen/generator/state.js.map +1 -1
  8. package/dist/src/codegen/generator/tables.d.ts +5 -6
  9. package/dist/src/codegen/generator/tables.js +13 -6
  10. package/dist/src/codegen/generator/tables.js.map +1 -1
  11. package/dist/src/driver/bundler/graph.d.ts +8 -0
  12. package/dist/src/driver/bundler/graph.js +85 -0
  13. package/dist/src/driver/bundler/graph.js.map +1 -0
  14. package/dist/src/driver/bundler/merge.d.ts +11 -0
  15. package/dist/src/driver/bundler/merge.js +288 -0
  16. package/dist/src/driver/bundler/merge.js.map +1 -0
  17. package/dist/src/driver/bundler/resolve.d.ts +12 -0
  18. package/dist/src/driver/bundler/resolve.js +246 -0
  19. package/dist/src/driver/bundler/resolve.js.map +1 -0
  20. package/dist/src/driver/bundler/symbols.d.ts +15 -0
  21. package/dist/src/driver/bundler/symbols.js +51 -0
  22. package/dist/src/driver/bundler/symbols.js.map +1 -0
  23. package/dist/src/driver/bundler/types.d.ts +36 -0
  24. package/dist/src/driver/bundler/types.js +5 -0
  25. package/dist/src/driver/bundler/types.js.map +1 -0
  26. package/dist/src/driver/index.d.ts +1 -2
  27. package/dist/src/driver/index.js +1 -2
  28. package/dist/src/driver/index.js.map +1 -1
  29. package/dist/src/driver/modules.d.ts +9 -16
  30. package/dist/src/driver/modules.js +8 -644
  31. package/dist/src/driver/modules.js.map +1 -1
  32. package/dist/src/driver/paths.d.ts +0 -9
  33. package/dist/src/driver/paths.js +0 -31
  34. package/dist/src/driver/paths.js.map +1 -1
  35. package/dist/src/driver/toolchain-provider.d.ts +10 -10
  36. package/dist/src/driver/toolchain-provider.js +9 -38
  37. package/dist/src/driver/toolchain-provider.js.map +1 -1
  38. package/dist/src/driver/toolchain.js +8 -2
  39. package/dist/src/driver/toolchain.js.map +1 -1
  40. package/dist/src/extensions/catalog.js +2 -1
  41. package/dist/src/extensions/catalog.js.map +1 -1
  42. package/dist/src/extensions/gui/index.d.ts +24 -0
  43. package/dist/src/extensions/gui/index.js +101 -0
  44. package/dist/src/extensions/gui/index.js.map +1 -0
  45. package/dist/src/extensions/native.d.ts +2 -3
  46. package/dist/src/extensions/native.js +2 -3
  47. package/dist/src/extensions/native.js.map +1 -1
  48. package/dist/tests/driver/paths.test.js +1 -9
  49. package/dist/tests/driver/paths.test.js.map +1 -1
  50. package/dist/tests/driver/toolchain-provider.test.js +12 -79
  51. package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
  52. package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
  53. package/dist/tests/e2e/compile-basics.test.js +134 -0
  54. package/dist/tests/e2e/compile-basics.test.js.map +1 -0
  55. package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
  56. package/dist/tests/e2e/compile-builtins.test.js +191 -0
  57. package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
  58. package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
  59. package/dist/tests/e2e/compile-control-flow.test.js +190 -0
  60. package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
  61. package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
  62. package/dist/tests/e2e/compile-modules.test.js +48 -0
  63. package/dist/tests/e2e/compile-modules.test.js.map +1 -0
  64. package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
  65. package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
  66. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
  67. package/dist/tests/e2e/differential-helpers.d.ts +12 -0
  68. package/dist/tests/e2e/differential-helpers.js +16 -0
  69. package/dist/tests/e2e/differential-helpers.js.map +1 -0
  70. package/dist/tests/e2e/differential-language.test.d.ts +4 -0
  71. package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
  72. package/dist/tests/e2e/differential-language.test.js.map +1 -0
  73. package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
  74. package/dist/tests/e2e/differential-symbols.test.js +92 -0
  75. package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
  76. package/dist/tests/e2e/differential-values.test.d.ts +4 -0
  77. package/dist/tests/e2e/differential-values.test.js +197 -0
  78. package/dist/tests/e2e/differential-values.test.js.map +1 -0
  79. package/dist/tests/e2e/gui.test.d.ts +12 -0
  80. package/dist/tests/e2e/gui.test.js +493 -0
  81. package/dist/tests/e2e/gui.test.js.map +1 -0
  82. package/dist/tests/e2e/native-extensions.test.d.ts +4 -5
  83. package/dist/tests/e2e/native-extensions.test.js +6 -7
  84. package/dist/tests/e2e/native-extensions.test.js.map +1 -1
  85. package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
  86. package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
  87. package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
  88. package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
  89. package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
  90. package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
  91. package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
  92. package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
  93. package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
  94. package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
  95. package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
  96. package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
  97. package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
  98. package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
  99. package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
  100. package/dist/tests/e2e/timers.test.d.ts +7 -0
  101. package/dist/tests/e2e/timers.test.js +63 -0
  102. package/dist/tests/e2e/timers.test.js.map +1 -0
  103. package/package.json +2 -2
  104. package/runtime/ext_gui/css.cpp +743 -0
  105. package/runtime/ext_gui/css.h +98 -0
  106. package/runtime/ext_gui/document.cpp +264 -0
  107. package/runtime/ext_gui/document.h +89 -0
  108. package/runtime/ext_gui/dom.cpp +472 -0
  109. package/runtime/ext_gui/dom.h +71 -0
  110. package/runtime/ext_gui/gui.cpp +457 -0
  111. package/runtime/ext_gui/gui_engine.h +81 -0
  112. package/runtime/ext_gui/image.cpp +125 -0
  113. package/runtime/ext_gui/image.h +42 -0
  114. package/runtime/ext_gui/layout.cpp +748 -0
  115. package/runtime/ext_gui/layout.h +93 -0
  116. package/runtime/ext_gui/paint.cpp +137 -0
  117. package/runtime/ext_gui/paint.h +75 -0
  118. package/runtime/ext_gui/renderer.cpp +959 -0
  119. package/runtime/ext_gui/renderer.h +68 -0
  120. package/runtime/ext_gui/stb_image.h +7988 -0
  121. package/runtime/ext_gui/style.cpp +771 -0
  122. package/runtime/ext_gui/style.h +117 -0
  123. package/runtime/ext_gui/text.cpp +378 -0
  124. package/runtime/ext_gui/text.h +78 -0
  125. package/runtime/ext_gui/window.cpp +405 -0
  126. package/runtime/ext_node/fs/fs_common.h +13 -527
  127. package/runtime/ext_node/fs/meta_ops.c +3 -3
  128. package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
  129. package/runtime/ext_node/fs/parts/builtins.inc +69 -0
  130. package/runtime/ext_node/fs/parts/dir.inc +47 -0
  131. package/runtime/ext_node/fs/parts/encoding.inc +186 -0
  132. package/runtime/ext_node/fs/parts/errors.inc +66 -0
  133. package/runtime/ext_node/fs/parts/flags.inc +39 -0
  134. package/runtime/ext_node/fs/parts/platform.inc +86 -0
  135. package/runtime/ext_node/fs/parts/promisify.inc +15 -0
  136. package/runtime/ext_node/fs/parts/time.inc +9 -0
  137. package/runtime/rt.h +36 -4
  138. package/runtime/rt_internal.h +10 -23
  139. package/runtime/xt_builtins.c +4 -0
  140. package/runtime/xt_containers/access.inc +168 -0
  141. package/runtime/xt_containers/arrays.inc +108 -0
  142. package/runtime/xt_containers/boxes.inc +11 -0
  143. package/runtime/xt_containers/objects.inc +326 -0
  144. package/runtime/xt_containers.c +8 -618
  145. package/runtime/xt_ext.h +0 -1
  146. package/runtime/xt_io/base64.inc +87 -0
  147. package/runtime/xt_io/console.inc +119 -0
  148. package/runtime/xt_io/exception.inc +142 -0
  149. package/runtime/xt_io/inspect.inc +212 -0
  150. package/runtime/xt_io.c +11 -556
  151. package/runtime/xt_loop.c +262 -24
  152. package/runtime/xt_regex/api.inc +58 -0
  153. package/runtime/xt_regex/helpers.inc +68 -0
  154. package/runtime/xt_regex/matcher.inc +248 -0
  155. package/runtime/xt_regex/parser.inc +236 -0
  156. package/runtime/xt_regex/types.inc +58 -0
  157. package/runtime/xt_regex.h +9 -672
  158. package/runtime/xt_stdlib2/helpers.inc +2 -4
  159. package/runtime/xt_values/arithmetic.inc +150 -0
  160. package/runtime/xt_values/comparison.inc +112 -0
  161. package/runtime/xt_values/constructors.inc +41 -0
  162. package/runtime/xt_values/conversions.inc +115 -0
  163. package/runtime/xt_values/number-format.inc +180 -0
  164. package/runtime/xt_values/strings.inc +22 -0
  165. package/runtime/xt_values.c +10 -626
  166. package/scripts/build-gui.ts +317 -0
  167. package/scripts/build-runtime.ts +7 -8
  168. package/scripts/coverage-runtime.ts +4 -4
  169. package/scripts/package-release.ts +12 -84
  170. package/src/cli/main.ts +8 -4
  171. package/src/codegen/generator/state.ts +8 -0
  172. package/src/codegen/generator/tables.ts +13 -6
  173. package/src/driver/bundler/graph.ts +95 -0
  174. package/src/driver/bundler/merge.ts +312 -0
  175. package/src/driver/bundler/resolve.ts +240 -0
  176. package/src/driver/bundler/symbols.ts +55 -0
  177. package/src/driver/bundler/types.ts +37 -0
  178. package/src/driver/index.ts +1 -9
  179. package/src/driver/modules.ts +9 -693
  180. package/src/driver/paths.ts +0 -31
  181. package/src/driver/toolchain-provider.ts +12 -45
  182. package/src/driver/toolchain.ts +7 -2
  183. package/src/extensions/catalog.ts +2 -1
  184. package/src/extensions/gui/index.ts +107 -0
  185. package/src/extensions/native.ts +2 -3
  186. package/dist/src/driver/toolchain-download.d.ts +0 -50
  187. package/dist/src/driver/toolchain-download.js +0 -102
  188. package/dist/src/driver/toolchain-download.js.map +0 -1
  189. package/dist/tests/driver/toolchain-download.test.d.ts +0 -1
  190. package/dist/tests/driver/toolchain-download.test.js +0 -53
  191. package/dist/tests/driver/toolchain-download.test.js.map +0 -1
  192. package/dist/tests/e2e/compile.test.d.ts +0 -8
  193. package/dist/tests/e2e/compile.test.js +0 -893
  194. package/dist/tests/e2e/compile.test.js.map +0 -1
  195. package/dist/tests/e2e/differential.test.d.ts +0 -7
  196. package/dist/tests/e2e/differential.test.js.map +0 -1
  197. package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
  198. package/dist/tests/e2e/runtime-coverage.test.js +0 -646
  199. package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
  200. package/scripts/fetch-toolchain.ts +0 -101
  201. 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, but MinGW-w64 (the vendored toolchain) and every Unix libc define
22
- * it. Alias the Windows pointer-sized signed integer so the runtime's POSIX
23
- * shims compile unchanged across toolchains. */
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);
@@ -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
- /* Call `_setjmp` the way the active `<setjmp.h>` declares it. The two Windows
228
- * C runtimes differ:
227
+ /* Save a try frame with clang's `_setjmp` built-in.
229
228
  *
230
- * - MSVC/UCRT declares `_setjmp(jmp_buf)` with one visible argument and lets
231
- * clang treat it as a built-in that injects the caller's frame address
232
- * (`@llvm.frameaddress(0)`) as a hidden second argument. Writing the frame
233
- * by hand is a compile error ("too many arguments to function call").
234
- * - MinGW-w64 (the vendored llvm-mingw toolchain) declares
235
- * `_setjmp(jmp_buf, void *frame)` itself, so the frame must be passed
236
- * explicitly -- exactly what its own `setjmp` macro does.
237
- *
238
- * The generated IR emits the two-argument form, because it is already IR and
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
 
@@ -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);