xbintsc 0.3.15 → 0.3.18

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 (156) hide show
  1. package/dist/src/cli/main.js +4 -4
  2. package/dist/src/cli/main.js.map +1 -1
  3. package/dist/src/codegen/generator/state.js +8 -0
  4. package/dist/src/codegen/generator/state.js.map +1 -1
  5. package/dist/src/codegen/generator/tables.js +8 -0
  6. package/dist/src/codegen/generator/tables.js.map +1 -1
  7. package/dist/src/driver/bundler/graph.d.ts +8 -0
  8. package/dist/src/driver/bundler/graph.js +85 -0
  9. package/dist/src/driver/bundler/graph.js.map +1 -0
  10. package/dist/src/driver/bundler/merge.d.ts +11 -0
  11. package/dist/src/driver/bundler/merge.js +288 -0
  12. package/dist/src/driver/bundler/merge.js.map +1 -0
  13. package/dist/src/driver/bundler/resolve.d.ts +12 -0
  14. package/dist/src/driver/bundler/resolve.js +246 -0
  15. package/dist/src/driver/bundler/resolve.js.map +1 -0
  16. package/dist/src/driver/bundler/symbols.d.ts +15 -0
  17. package/dist/src/driver/bundler/symbols.js +51 -0
  18. package/dist/src/driver/bundler/symbols.js.map +1 -0
  19. package/dist/src/driver/bundler/types.d.ts +36 -0
  20. package/dist/src/driver/bundler/types.js +5 -0
  21. package/dist/src/driver/bundler/types.js.map +1 -0
  22. package/dist/src/driver/modules.d.ts +9 -16
  23. package/dist/src/driver/modules.js +8 -644
  24. package/dist/src/driver/modules.js.map +1 -1
  25. package/dist/src/extensions/catalog.js +2 -1
  26. package/dist/src/extensions/catalog.js.map +1 -1
  27. package/dist/src/extensions/gui/index.d.ts +24 -0
  28. package/dist/src/extensions/gui/index.js +101 -0
  29. package/dist/src/extensions/gui/index.js.map +1 -0
  30. package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
  31. package/dist/tests/e2e/compile-basics.test.js +134 -0
  32. package/dist/tests/e2e/compile-basics.test.js.map +1 -0
  33. package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
  34. package/dist/tests/e2e/compile-builtins.test.js +191 -0
  35. package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
  36. package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
  37. package/dist/tests/e2e/compile-control-flow.test.js +190 -0
  38. package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
  39. package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
  40. package/dist/tests/e2e/compile-modules.test.js +48 -0
  41. package/dist/tests/e2e/compile-modules.test.js.map +1 -0
  42. package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
  43. package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
  44. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
  45. package/dist/tests/e2e/differential-helpers.d.ts +12 -0
  46. package/dist/tests/e2e/differential-helpers.js +16 -0
  47. package/dist/tests/e2e/differential-helpers.js.map +1 -0
  48. package/dist/tests/e2e/differential-language.test.d.ts +4 -0
  49. package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
  50. package/dist/tests/e2e/differential-language.test.js.map +1 -0
  51. package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
  52. package/dist/tests/e2e/differential-symbols.test.js +92 -0
  53. package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
  54. package/dist/tests/e2e/differential-values.test.d.ts +4 -0
  55. package/dist/tests/e2e/differential-values.test.js +197 -0
  56. package/dist/tests/e2e/differential-values.test.js.map +1 -0
  57. package/dist/tests/e2e/gui.test.d.ts +12 -0
  58. package/dist/tests/e2e/gui.test.js +493 -0
  59. package/dist/tests/e2e/gui.test.js.map +1 -0
  60. package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
  61. package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
  62. package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
  63. package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
  64. package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
  65. package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
  66. package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
  67. package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
  68. package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
  69. package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
  70. package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
  71. package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
  72. package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
  73. package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
  74. package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
  75. package/dist/tests/e2e/timers.test.d.ts +7 -0
  76. package/dist/tests/e2e/timers.test.js +63 -0
  77. package/dist/tests/e2e/timers.test.js.map +1 -0
  78. package/package.json +2 -1
  79. package/runtime/ext_gui/css.cpp +743 -0
  80. package/runtime/ext_gui/css.h +98 -0
  81. package/runtime/ext_gui/document.cpp +264 -0
  82. package/runtime/ext_gui/document.h +89 -0
  83. package/runtime/ext_gui/dom.cpp +472 -0
  84. package/runtime/ext_gui/dom.h +71 -0
  85. package/runtime/ext_gui/gui.cpp +457 -0
  86. package/runtime/ext_gui/gui_engine.h +81 -0
  87. package/runtime/ext_gui/image.cpp +125 -0
  88. package/runtime/ext_gui/image.h +42 -0
  89. package/runtime/ext_gui/layout.cpp +748 -0
  90. package/runtime/ext_gui/layout.h +93 -0
  91. package/runtime/ext_gui/paint.cpp +137 -0
  92. package/runtime/ext_gui/paint.h +75 -0
  93. package/runtime/ext_gui/renderer.cpp +959 -0
  94. package/runtime/ext_gui/renderer.h +68 -0
  95. package/runtime/ext_gui/stb_image.h +7988 -0
  96. package/runtime/ext_gui/style.cpp +771 -0
  97. package/runtime/ext_gui/style.h +117 -0
  98. package/runtime/ext_gui/text.cpp +378 -0
  99. package/runtime/ext_gui/text.h +78 -0
  100. package/runtime/ext_gui/window.cpp +405 -0
  101. package/runtime/ext_node/fs/fs_common.h +13 -527
  102. package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
  103. package/runtime/ext_node/fs/parts/builtins.inc +69 -0
  104. package/runtime/ext_node/fs/parts/dir.inc +47 -0
  105. package/runtime/ext_node/fs/parts/encoding.inc +186 -0
  106. package/runtime/ext_node/fs/parts/errors.inc +66 -0
  107. package/runtime/ext_node/fs/parts/flags.inc +39 -0
  108. package/runtime/ext_node/fs/parts/platform.inc +86 -0
  109. package/runtime/ext_node/fs/parts/promisify.inc +15 -0
  110. package/runtime/ext_node/fs/parts/time.inc +9 -0
  111. package/runtime/rt.h +33 -0
  112. package/runtime/xt_builtins.c +4 -0
  113. package/runtime/xt_containers/access.inc +168 -0
  114. package/runtime/xt_containers/arrays.inc +108 -0
  115. package/runtime/xt_containers/boxes.inc +11 -0
  116. package/runtime/xt_containers/objects.inc +326 -0
  117. package/runtime/xt_containers.c +8 -618
  118. package/runtime/xt_io/base64.inc +87 -0
  119. package/runtime/xt_io/console.inc +119 -0
  120. package/runtime/xt_io/exception.inc +142 -0
  121. package/runtime/xt_io/inspect.inc +212 -0
  122. package/runtime/xt_io.c +8 -553
  123. package/runtime/xt_loop.c +262 -24
  124. package/runtime/xt_regex/api.inc +58 -0
  125. package/runtime/xt_regex/helpers.inc +68 -0
  126. package/runtime/xt_regex/matcher.inc +248 -0
  127. package/runtime/xt_regex/parser.inc +236 -0
  128. package/runtime/xt_regex/types.inc +58 -0
  129. package/runtime/xt_regex.h +9 -672
  130. package/runtime/xt_values/arithmetic.inc +150 -0
  131. package/runtime/xt_values/comparison.inc +112 -0
  132. package/runtime/xt_values/constructors.inc +41 -0
  133. package/runtime/xt_values/conversions.inc +115 -0
  134. package/runtime/xt_values/number-format.inc +180 -0
  135. package/runtime/xt_values/strings.inc +22 -0
  136. package/runtime/xt_values.c +10 -626
  137. package/scripts/build-gui.ts +317 -0
  138. package/src/cli/main.ts +4 -3
  139. package/src/codegen/generator/state.ts +8 -0
  140. package/src/codegen/generator/tables.ts +8 -0
  141. package/src/driver/bundler/graph.ts +95 -0
  142. package/src/driver/bundler/merge.ts +312 -0
  143. package/src/driver/bundler/resolve.ts +240 -0
  144. package/src/driver/bundler/symbols.ts +55 -0
  145. package/src/driver/bundler/types.ts +37 -0
  146. package/src/driver/modules.ts +9 -693
  147. package/src/extensions/catalog.ts +2 -1
  148. package/src/extensions/gui/index.ts +107 -0
  149. package/dist/tests/e2e/compile.test.d.ts +0 -8
  150. package/dist/tests/e2e/compile.test.js +0 -893
  151. package/dist/tests/e2e/compile.test.js.map +0 -1
  152. package/dist/tests/e2e/differential.test.d.ts +0 -7
  153. package/dist/tests/e2e/differential.test.js.map +0 -1
  154. package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
  155. package/dist/tests/e2e/runtime-coverage.test.js +0 -646
  156. package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
@@ -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
@@ -241,6 +241,39 @@ void xt_loop_remove(int fd);
241
241
  void xt_run_event_loop(void);
242
242
  int xt_loop_has_work(void);
243
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
+
244
277
  /* -- global functions ------------------------------------------------------ */
245
278
  xt_value xt_parse_int(int32_t argc, xt_value *argv);
246
279
  xt_value xt_parse_float(int32_t argc, xt_value *argv);
@@ -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);
@@ -0,0 +1,168 @@
1
+ /* ------------------------------------------------------------------------- */
2
+ /* Generic member access */
3
+ /* ------------------------------------------------------------------------- */
4
+
5
+ /*
6
+ * Reading a property of `null` / `undefined` is a TypeError in JavaScript.
7
+ * Short-circuiting `?.` guards forbid reaching this point for a nullish
8
+ * receiver, so a non-optional access on a nullish base is a genuine bug in
9
+ * the compiled program (e.g. `o?.a.b` where `o.a` is null).
10
+ */
11
+ static void xt_throw_read_of_nullish(xt_value target, xt_value key) {
12
+ const char *base = target == XT_NULL ? "null" : "undefined";
13
+ char keybuf[128];
14
+ xt_string *k = XT_IS_STRING(key) ? xt_as_string(key) : xt_as_string(xt_to_string(key));
15
+ uint32_t n = k->length < sizeof(keybuf) - 1 ? k->length : (uint32_t)(sizeof(keybuf) - 1);
16
+ memcpy(keybuf, k->data, n);
17
+ keybuf[n] = 0;
18
+ char message[256];
19
+ snprintf(message, sizeof(message),
20
+ "TypeError: Cannot read properties of %s (reading '%s')", base, keybuf);
21
+ xt_throw(xt_string_from_cstr(message));
22
+ }
23
+
24
+ xt_value xt_get(xt_value target, xt_value key) {
25
+ if (target == XT_UNDEFINED || target == XT_NULL) xt_throw_read_of_nullish(target, key);
26
+ if (XT_IS_ARRAY(target)) {
27
+ /* `arr.length` must read the array's length, never an element. */
28
+ if (XT_IS_STRING(key)) {
29
+ xt_string *k = xt_as_string(key);
30
+ if (k->length == 6 && memcmp(k->data, "length", 6) == 0)
31
+ return xt_number((double)((xt_array *)XT_GET_PTR(target))->length);
32
+ /* Named (non-index) properties such as `raw`/`index`/`input`. */
33
+ uint32_t ignored = 0;
34
+ if (!xt_key_is_array_index(k, &ignored)) {
35
+ xt_value extra = xt_array_extra((xt_array *)XT_GET_PTR(target), 0);
36
+ if (extra != XT_UNDEFINED) {
37
+ xt_value value = xt_object_get(extra, key);
38
+ if (value != XT_UNDEFINED) return value;
39
+ }
40
+ /* Fall back to first-class built-in methods (`arr.map`). */
41
+ return xt_method_value(target, key);
42
+ }
43
+ return xt_array_get(target, key);
44
+ }
45
+ /* Symbol-keyed properties live in the side object too. */
46
+ if (xt_is_symbol(key)) {
47
+ xt_value extra = xt_array_extra((xt_array *)XT_GET_PTR(target), 0);
48
+ if (extra != XT_UNDEFINED) {
49
+ xt_value value = xt_object_get(extra, key);
50
+ if (value != XT_UNDEFINED) return value;
51
+ }
52
+ return xt_method_value(target, key);
53
+ }
54
+ return xt_array_get(target, key);
55
+ }
56
+ if (XT_IS_FUNCTION(target)) {
57
+ /* Functions expose own `name` / `length` (arity) properties. */
58
+ if (XT_IS_STRING(key)) {
59
+ xt_string *k = xt_as_string(key);
60
+ if (k->length == 6 && memcmp(k->data, "length", 6) == 0) {
61
+ int32_t arity = ((xt_function *)XT_GET_PTR(target))->arity;
62
+ return xt_number(arity >= 0 ? (double)arity : 0.0);
63
+ }
64
+ if (k->length == 4 && memcmp(k->data, "name", 4) == 0) {
65
+ xt_string *name = ((xt_function *)XT_GET_PTR(target))->name;
66
+ return name ? XT_FROM_PTR(XT_TAG_STRING, name) : xt_string_from_cstr("");
67
+ }
68
+ }
69
+ {
70
+ xt_value value = xt_object_get(target, key);
71
+ if (value != XT_UNDEFINED) return value;
72
+ return xt_method_value(target, key);
73
+ }
74
+ }
75
+ if (XT_IS_OBJECT(target)) {
76
+ /* Map/Set expose `.size`; promises, dates and regexps have their own
77
+ * getters implemented in the standard library. */
78
+ xt_object *obj = (xt_object *)XT_GET_PTR(target);
79
+ if (obj->header.kind == XT_OBJECT_KIND_SYMBOL) {
80
+ if (XT_IS_STRING(key)) {
81
+ xt_string *k = xt_as_string(key);
82
+ if (k->length == 11 && memcmp(k->data, "description", 11) == 0) {
83
+ return xt_symbol_description(target);
84
+ }
85
+ }
86
+ return xt_method_value(target, key);
87
+ }
88
+ if (obj->header.kind == XT_OBJECT_KIND_MAP || obj->header.kind == XT_OBJECT_KIND_SET) {
89
+ if (XT_IS_STRING(key)) {
90
+ xt_string *k = xt_as_string(key);
91
+ if (k->length == 4 && memcmp(k->data, "size", 4) == 0) {
92
+ int32_t size = obj->header.kind == XT_OBJECT_KIND_MAP ? xt_map_size(target) : xt_set_size(target);
93
+ return xt_number((double)size);
94
+ }
95
+ }
96
+ }
97
+ if (obj->header.kind == XT_OBJECT_KIND_REGEXP) {
98
+ xt_value regexpValue = xt_regexp_get_property(target, key);
99
+ if (regexpValue != XT_UNDEFINED) return regexpValue;
100
+ }
101
+ if (obj->header.kind == XT_OBJECT_KIND_ERROR && XT_IS_STRING(key)) {
102
+ xt_string *k = xt_as_string(key);
103
+ if (k->length == 5 && memcmp(k->data, "stack", 5) == 0) {
104
+ xt_value own = xt_object_get(target, key);
105
+ return own != XT_UNDEFINED ? own : xt_error_to_string(target);
106
+ }
107
+ }
108
+ {
109
+ xt_value value = xt_object_get(target, key);
110
+ if (value != XT_UNDEFINED) return value;
111
+ return xt_method_value(target, key);
112
+ }
113
+ }
114
+ if (XT_IS_STRING(target)) {
115
+ /* Property access on a string: `.length`, numeric indexing and built-in
116
+ * methods. */
117
+ xt_string *s = xt_as_string(target);
118
+ if (XT_IS_STRING(key)) {
119
+ xt_string *k = xt_as_string(key);
120
+ if (k->length == 6 && memcmp(k->data, "length", 6) == 0) return xt_number((double)s->length);
121
+ uint32_t index = 0;
122
+ if (xt_key_is_array_index(k, &index) && index < s->length) {
123
+ return xt_string_new(s->data + index, 1);
124
+ }
125
+ return xt_method_value(target, key);
126
+ }
127
+ if (XT_IS_NUMBER(key)) {
128
+ int32_t index = xt_to_int32(key);
129
+ if (index >= 0 && (uint32_t)index < s->length) return xt_string_new(s->data + index, 1);
130
+ }
131
+ return XT_UNDEFINED;
132
+ }
133
+ if (XT_IS_STRING(key) &&
134
+ (XT_IS_NUMBER(target) || XT_IS_BIGINT(target) || target == XT_TRUE || target == XT_FALSE)) {
135
+ return xt_method_value(target, key);
136
+ }
137
+ return XT_UNDEFINED;
138
+ }
139
+
140
+ xt_value xt_set(xt_value target, xt_value key, xt_value value) {
141
+ if (XT_IS_ARRAY(target)) {
142
+ /* Assigning `arr.length` truncates or extends the array. */
143
+ if (XT_IS_STRING(key)) {
144
+ xt_string *k = xt_as_string(key);
145
+ if (k->length == 6 && memcmp(k->data, "length", 6) == 0) {
146
+ xt_array *array = (xt_array *)XT_GET_PTR(target);
147
+ int32_t n = xt_to_int32(value);
148
+ if (n < 0) n = 0;
149
+ xt_array_reserve(array, (uint32_t)n);
150
+ for (uint32_t j = array->length; j < (uint32_t)n; j++) array->items[j] = XT_UNDEFINED;
151
+ array->length = (uint32_t)n;
152
+ return value;
153
+ }
154
+ uint32_t ignored = 0;
155
+ if (!xt_key_is_array_index(k, &ignored)) {
156
+ return xt_object_set(xt_array_extra((xt_array *)XT_GET_PTR(target), 1), key, value);
157
+ }
158
+ return xt_array_set(target, key, value);
159
+ }
160
+ if (xt_is_symbol(key)) {
161
+ return xt_object_set(xt_array_extra((xt_array *)XT_GET_PTR(target), 1), key, value);
162
+ }
163
+ return xt_array_set(target, key, value);
164
+ }
165
+ if (XT_IS_FUNCTION(target)) return xt_object_set(target, key, value);
166
+ if (XT_IS_OBJECT(target)) return xt_object_set(target, key, value);
167
+ return value;
168
+ }