xbintsc 0.3.15 → 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 (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
package/runtime/xt_io.c CHANGED
@@ -20,6 +20,10 @@
20
20
  * exported `setjmp` symbol, whose Windows ABI is an incompatible two-argument
21
21
  * routine; on Linux/macOS `_setjmp` takes only the buffer and pairs with
22
22
  * `longjmp` (the XSI `_longjmp` does not exist on Windows).
23
+ *
24
+ * The implementation is grouped by functional area under `xt_io/` and
25
+ * `#include`d here as a single translation unit, so the exception frame state
26
+ * and inspection helpers stay `static` while each file stays focused.
23
27
  */
24
28
 
25
29
  #include "rt_internal.h"
@@ -36,556 +40,7 @@
36
40
  #include <winsock2.h>
37
41
  #endif
38
42
 
39
- /* ------------------------------------------------------------------------- */
40
- /* Exceptions and output */
41
- /* ------------------------------------------------------------------------- */
42
-
43
- /*
44
- * `try`/`catch` is implemented with a stack of setjmp frames. The compiler
45
- * allocates a frame with `xt_try_enter`, calls `_setjmp` on it, and pops it
46
- * with `xt_try_leave`. `xt_throw` longjmps into the innermost frame when one
47
- * is active, and only prints + exits when the exception is uncaught.
48
- */
49
- static xt_try_frame *g_try_top = NULL;
50
-
51
- /* Program arguments, captured once by `xt_set_program_args` from `main`. */
52
- int32_t xt_program_argc = 0;
53
- char **xt_program_argv = NULL;
54
-
55
- #if defined(_WIN32)
56
- /*
57
- * The UCRT validates its low-level I/O arguments and, when one is out of
58
- * range, calls the invalid-parameter handler. The default handler terminates
59
- * the process through `_invoke_watson`, which fast-fails with exit status
60
- * 0xC0000409. That makes POSIX-style calls such as `close(9999)` abort instead
61
- * of reporting `EBADF`. Install a no-op handler so the CRT returns its normal
62
- * error code (and sets `errno`) instead of crashing.
63
- */
64
- static void __cdecl xt_noop_invalid_parameter_handler(const wchar_t *expression, const wchar_t *function_name,
65
- const wchar_t *file_name, unsigned int line_number,
66
- uintptr_t reserved) {
67
- (void)expression;
68
- (void)function_name;
69
- (void)file_name;
70
- (void)line_number;
71
- (void)reserved;
72
- }
73
- #endif
74
-
75
- void xt_set_program_args(int32_t argc, char **argv) {
76
- #if defined(_WIN32)
77
- /* Keep stdout/stderr in binary mode so `\n` is not translated to `\r\n`,
78
- matching Node's output, and initialise Winsock before any extension uses
79
- sockets (the generated `main` calls this before running the program). */
80
- _setmode(_fileno(stdout), _O_BINARY);
81
- _setmode(_fileno(stderr), _O_BINARY);
82
- _set_invalid_parameter_handler(xt_noop_invalid_parameter_handler);
83
- WSADATA wsaData;
84
- WSAStartup(MAKEWORD(2, 2), &wsaData);
85
- #endif
86
- xt_program_argc = argc;
87
- xt_program_argv = argv;
88
- }
89
-
90
- /*
91
- * `import.meta` support. The compiler resolves module URLs at build time, but
92
- * a self-hosted binary only knows where *it* lives, so `import.meta.url` is the
93
- * executable's own `file://` URL (and `dirname`/`filename` its path parts).
94
- * This lets the compiler locate an adjacent `runtime/` directory at run time.
95
- */
96
- static xt_value xt_file_url(const char *path) {
97
- char url[4300];
98
- size_t j = 0;
99
- const char *prefix = "file://";
100
- for (; *prefix; prefix++) url[j++] = *prefix;
101
- #if defined(_WIN32)
102
- url[j++] = '/';
103
- #endif
104
- for (const char *p = path; *p && j < sizeof(url) - 1; p++) url[j++] = (*p == '\\') ? '/' : *p;
105
- url[j] = 0;
106
- return xt_string_from_cstr(url);
107
- }
108
-
109
- xt_value xt_import_meta(xt_value name) {
110
- const char *prop = xt_string_data(name);
111
- const char *raw = (xt_program_argv && xt_program_argv[0]) ? xt_program_argv[0] : "";
112
- char resolved[4096];
113
- resolved[0] = 0;
114
- if (raw[0]) {
115
- #if defined(_WIN32)
116
- if (_fullpath(resolved, raw, sizeof(resolved)) == NULL) resolved[0] = 0;
117
- #else
118
- if (realpath(raw, resolved) == NULL) resolved[0] = 0;
119
- #endif
120
- }
121
- const char *abs = resolved[0] ? resolved : raw;
122
- if (prop && strcmp(prop, "dirname") == 0) {
123
- char dir[4096];
124
- size_t n = strlen(abs);
125
- if (n >= sizeof(dir)) n = sizeof(dir) - 1;
126
- memcpy(dir, abs, n);
127
- dir[n] = 0;
128
- char *slash = strrchr(dir, '/');
129
- #if defined(_WIN32)
130
- char *back = strrchr(dir, '\\');
131
- if (back && (!slash || back > slash)) slash = back;
132
- #endif
133
- if (slash) {
134
- if (slash == dir) slash[1] = 0;
135
- else *slash = 0;
136
- }
137
- return xt_string_from_cstr(dir);
138
- }
139
- if (prop && strcmp(prop, "filename") == 0) return xt_string_from_cstr(abs);
140
- return xt_file_url(abs);
141
- }
142
-
143
- void *xt_try_enter(void) {
144
- xt_try_frame *frame = (xt_try_frame *)calloc(1, sizeof(xt_try_frame));
145
- if (!frame) abort();
146
- frame->prev = g_try_top;
147
- frame->exception = XT_UNDEFINED;
148
- g_try_top = frame;
149
- return (void *)frame;
150
- }
151
-
152
- xt_value xt_try_exception(void *framePtr) {
153
- xt_try_frame *frame = (xt_try_frame *)framePtr;
154
- return frame ? frame->exception : XT_UNDEFINED;
155
- }
156
-
157
- void xt_try_leave(void *framePtr) {
158
- xt_try_frame *frame = (xt_try_frame *)framePtr;
159
- if (frame && g_try_top == frame) {
160
- g_try_top = frame->prev;
161
- free(frame);
162
- }
163
- }
164
-
165
- /* Save/restore the innermost try frame. Generators use this to swap their own
166
- * exception stack in while they run on their private coroutine stack. */
167
- void *xt_try_mark(void) { return (void *)g_try_top; }
168
-
169
- void xt_try_restore(void *mark) { g_try_top = (xt_try_frame *)mark; }
170
-
171
- void xt_throw(xt_value v) {
172
- if (g_try_top) {
173
- g_try_top->exception = v;
174
- longjmp(g_try_top->buf, 1);
175
- }
176
- xt_value message = xt_to_string(v);
177
- xt_string *s = xt_as_string(message);
178
- fprintf(stderr, "Uncaught %s\n", s->data);
179
- exit(1);
180
- }
181
-
182
- static void xt_print_value(xt_value v, FILE *out) {
183
- if (XT_IS_STRING(v)) {
184
- xt_string *s = xt_as_string(v);
185
- fwrite(s->data, 1, s->length, out);
186
- return;
187
- }
188
- xt_value text = xt_to_string(v);
189
- xt_string *s = xt_as_string(text);
190
- fwrite(s->data, 1, s->length, out);
191
- }
192
-
193
- void xt_print(xt_value v) { xt_print_value(v, stdout); }
194
- void xt_println(xt_value v) {
195
- xt_print_value(v, stdout);
196
- fputc('\n', stdout);
197
- }
198
-
199
- /*
200
- * console.log applies a Node-like inspection format: strings unquoted at the
201
- * top level, arrays as `[ a, b ]` and objects as `{ key: value }`.
202
- *
203
- * Recursion tracks the ancestor chain so self-referential containers print
204
- * Node's `[Circular *N]` marker instead of recursing forever. `N` is the
205
- * 1-based position of the repeated container in the current path.
206
- */
207
- #define XT_INSPECT_MAX_DEPTH 512
208
- static const void *xt_inspect_stack[XT_INSPECT_MAX_DEPTH];
209
- static int xt_inspect_depth = 0;
210
-
211
- static int xt_inspect_seen(const void *ptr) {
212
- for (int i = 0; i < xt_inspect_depth; i++) {
213
- if (xt_inspect_stack[i] == ptr) return i + 1;
214
- }
215
- return 0;
216
- }
217
-
218
- static void xt_inspect_push(const void *ptr) {
219
- if (xt_inspect_depth < XT_INSPECT_MAX_DEPTH) xt_inspect_stack[xt_inspect_depth++] = ptr;
220
- }
221
-
222
- static void xt_inspect_pop(void) {
223
- if (xt_inspect_depth > 0) xt_inspect_depth--;
224
- }
225
-
226
- static int xt_inspect_identifier_key(xt_string *key) {
227
- if (key->length == 0) return 0;
228
- char c = key->data[0];
229
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$')) return 0;
230
- for (uint32_t i = 1; i < key->length; i++) {
231
- c = key->data[i];
232
- if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '$')) return 0;
233
- }
234
- return 1;
235
- }
236
-
237
- /* Render a string the way `util.inspect` does inside a container: quoted,
238
- * preferring whichever quote character needs fewer escapes. */
239
- static void xt_inspect_string(xt_string *s, FILE *out) {
240
- int hasSingle = 0;
241
- int hasDouble = 0;
242
- for (uint32_t i = 0; i < s->length; i++) {
243
- if (s->data[i] == '\'') hasSingle = 1;
244
- else if (s->data[i] == '"') hasDouble = 1;
245
- }
246
- char quote = (hasSingle && !hasDouble) ? '"' : '\'';
247
- fputc(quote, out);
248
- for (uint32_t i = 0; i < s->length; i++) {
249
- unsigned char c = (unsigned char)s->data[i];
250
- switch (c) {
251
- case '\\': fputs("\\\\", out); break;
252
- case '\n': fputs("\\n", out); break;
253
- case '\r': fputs("\\r", out); break;
254
- case '\t': fputs("\\t", out); break;
255
- case '\f': fputs("\\f", out); break;
256
- case '\b': fputs("\\b", out); break;
257
- case '\v': fputs("\\v", out); break;
258
- default:
259
- if (c == (unsigned char)quote) { fputc('\\', out); fputc(c, out); }
260
- else if (c < 0x20) fprintf(out, "\\x%02x", c);
261
- else fputc(c, out);
262
- }
263
- }
264
- fputc(quote, out);
265
- }
266
-
267
- static void xt_inspect(xt_value v, FILE *out, int nested) {
268
- if (xt_is_symbol(v)) {
269
- xt_string *text = xt_as_string(xt_symbol_to_string(v));
270
- fwrite(text->data, 1, text->length, out);
271
- return;
272
- }
273
- if (XT_IS_BIGINT(v)) {
274
- xt_value text = xt_bigint_to_decimal(v);
275
- xt_string *s = xt_as_string(text);
276
- fwrite(s->data, 1, s->length, out);
277
- fputc('n', out);
278
- return;
279
- }
280
- if (nested && XT_IS_STRING(v)) {
281
- xt_inspect_string(xt_as_string(v), out);
282
- return;
283
- }
284
- if (XT_IS_ARRAY(v)) {
285
- xt_array *array = (xt_array *)XT_GET_PTR(v);
286
- int seen = xt_inspect_seen(array);
287
- if (seen > 0) {
288
- fprintf(out, "[Circular *%d]", seen);
289
- return;
290
- }
291
- if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
292
- fputs("[Array]", out);
293
- return;
294
- }
295
- xt_inspect_push(array);
296
- fputc('[', out);
297
- for (uint32_t i = 0; i < array->length; i++) {
298
- if (i > 0) fputs(", ", out);
299
- else fputc(' ', out);
300
- xt_inspect(array->items[i], out, 1);
301
- }
302
- if (XT_IS_OBJECT(array->extra)) {
303
- xt_object *extra = (xt_object *)XT_GET_PTR(array->extra);
304
- for (uint32_t i = 0; i < extra->count; i++) {
305
- if (array->length > 0 || i > 0) fputs(", ", out);
306
- else fputc(' ', out);
307
- xt_value key = extra->properties[i].key;
308
- if (xt_is_symbol(key)) {
309
- xt_string *text = xt_as_string(xt_symbol_to_string(key));
310
- fwrite(text->data, 1, text->length, out);
311
- } else {
312
- xt_string *keyString = xt_as_string(key);
313
- fwrite(keyString->data, 1, keyString->length, out);
314
- }
315
- fputs(": ", out);
316
- xt_inspect(extra->properties[i].value, out, 1);
317
- }
318
- }
319
- if (array->length > 0 || (XT_IS_OBJECT(array->extra) && ((xt_object *)XT_GET_PTR(array->extra))->count > 0)) fputc(' ', out);
320
- fputc(']', out);
321
- xt_inspect_pop();
322
- return;
323
- }
324
- if (XT_IS_OBJECT(v)) {
325
- xt_object *obj = (xt_object *)XT_GET_PTR(v);
326
- int seen = xt_inspect_seen(obj);
327
- if (seen > 0) {
328
- fprintf(out, "[Circular *%d]", seen);
329
- return;
330
- }
331
- if (xt_inspect_depth >= XT_INSPECT_MAX_DEPTH) {
332
- fputs("[Object]", out);
333
- return;
334
- }
335
- xt_inspect_push(obj);
336
- fputc('{', out);
337
- /* `util.inspect` lists string keys first, then symbol keys, in insertion
338
- * order; symbol keys are printed without brackets. */
339
- int written = 0;
340
- for (int pass = 0; pass < 2; pass++) {
341
- for (uint32_t i = 0; i < obj->count; i++) {
342
- xt_value key = obj->properties[i].key;
343
- int isSymbol = xt_is_symbol(key);
344
- if ((pass == 0) == isSymbol) continue;
345
- if (written > 0) fputs(", ", out);
346
- else fputc(' ', out);
347
- written++;
348
- if (isSymbol) {
349
- xt_string *text = xt_as_string(xt_symbol_to_string(key));
350
- fwrite(text->data, 1, text->length, out);
351
- } else {
352
- xt_string *keyString = xt_as_string(key);
353
- if (xt_inspect_identifier_key(keyString)) fwrite(keyString->data, 1, keyString->length, out);
354
- else xt_inspect_string(keyString, out);
355
- }
356
- fputs(": ", out);
357
- xt_inspect(obj->properties[i].value, out, 1);
358
- }
359
- }
360
- if (written > 0) fputc(' ', out);
361
- fputc('}', out);
362
- xt_inspect_pop();
363
- return;
364
- }
365
- xt_print_value(v, out);
366
- }
367
-
368
- /* Inspect one top-level value; reset the ancestor chain so nested console
369
- * calls (or a `longjmp` out of a throw) never leave stale state behind. */
370
- static void xt_inspect_top(xt_value v, FILE *out) {
371
- xt_inspect_depth = 0;
372
- xt_inspect(v, out, 0);
373
- }
374
-
375
- void xt_console_log(int32_t argc, xt_value *argv) {
376
- for (int32_t i = 0; i < argc; i++) {
377
- if (i > 0) fputc(' ', stdout);
378
- xt_inspect_top(argv[i], stdout);
379
- }
380
- fputc('\n', stdout);
381
- }
382
-
383
- static void xt_console_write(int32_t argc, xt_value *argv, FILE *out) {
384
- for (int32_t i = 0; i < argc; i++) {
385
- if (i > 0) fputc(' ', out);
386
- xt_inspect_top(argv[i], out);
387
- }
388
- fputc('\n', out);
389
- }
390
-
391
- void xt_console_info(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stdout); }
392
- void xt_console_warn(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
393
- void xt_console_error(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
394
-
395
- xt_value xt_console_dir(int32_t argc, xt_value *argv) {
396
- xt_console_write(argc, argv, stdout);
397
- return XT_UNDEFINED;
398
- }
399
-
400
- xt_value xt_console_trace(int32_t argc, xt_value *argv) {
401
- fputs("Trace", stderr);
402
- for (int32_t i = 0; i < argc; i++) {
403
- fputc(' ', stderr);
404
- xt_inspect_top(argv[i], stderr);
405
- }
406
- fputc('\n', stderr);
407
- return XT_UNDEFINED;
408
- }
409
-
410
- xt_value xt_console_assert(int32_t argc, xt_value *argv) {
411
- if (argc == 0 || !xt_truthy(argv[0])) {
412
- fputs("Assertion failed", stderr);
413
- if (argc > 1) fputs(":", stderr);
414
- for (int32_t i = 1; i < argc; i++) {
415
- fputc(' ', stderr);
416
- xt_inspect_top(argv[i], stderr);
417
- }
418
- fputc('\n', stderr);
419
- }
420
- return XT_UNDEFINED;
421
- }
422
-
423
- #define XT_CONSOLE_MAX_LABELS 32
424
- static char *xt_console_labels[XT_CONSOLE_MAX_LABELS];
425
- static long xt_console_counts[XT_CONSOLE_MAX_LABELS];
426
- static clock_t xt_console_timers[XT_CONSOLE_MAX_LABELS];
427
- static int xt_console_label_count = 0;
428
- static int xt_console_depth = 0;
429
-
430
- static int xt_console_find_label(const char *label) {
431
- for (int i = 0; i < xt_console_label_count; i++) {
432
- if (strcmp(xt_console_labels[i], label) == 0) return i;
433
- }
434
- if (xt_console_label_count >= XT_CONSOLE_MAX_LABELS) return -1;
435
- int index = xt_console_label_count++;
436
- xt_console_labels[index] = (char *)malloc(strlen(label) + 1);
437
- memcpy(xt_console_labels[index], label, strlen(label) + 1);
438
- xt_console_counts[index] = 0;
439
- xt_console_timers[index] = 0;
440
- return index;
441
- }
442
-
443
- static const char *xt_console_label(int32_t argc, xt_value *argv) {
444
- if (argc == 0) return "default";
445
- return xt_string_data(xt_to_string(argv[0]));
446
- }
447
-
448
- xt_value xt_console_count(int32_t argc, xt_value *argv) {
449
- const char *label = xt_console_label(argc, argv);
450
- int index = xt_console_find_label(label ? label : "default");
451
- if (index < 0) return XT_UNDEFINED;
452
- xt_console_counts[index]++;
453
- printf("%s: %ld\n", xt_console_labels[index], xt_console_counts[index]);
454
- return XT_UNDEFINED;
455
- }
456
-
457
- xt_value xt_console_count_reset(int32_t argc, xt_value *argv) {
458
- const char *label = xt_console_label(argc, argv);
459
- int index = xt_console_find_label(label ? label : "default");
460
- if (index >= 0) xt_console_counts[index] = 0;
461
- return XT_UNDEFINED;
462
- }
463
-
464
- xt_value xt_console_group(int32_t argc, xt_value *argv) {
465
- xt_console_write(argc, argv, stdout);
466
- xt_console_depth++;
467
- return XT_UNDEFINED;
468
- }
469
-
470
- xt_value xt_console_group_end(int32_t argc, xt_value *argv) {
471
- (void)argc;
472
- (void)argv;
473
- if (xt_console_depth > 0) xt_console_depth--;
474
- return XT_UNDEFINED;
475
- }
476
-
477
- xt_value xt_console_table(int32_t argc, xt_value *argv) {
478
- xt_console_write(argc, argv, stdout);
479
- return XT_UNDEFINED;
480
- }
481
-
482
- xt_value xt_console_time(int32_t argc, xt_value *argv) {
483
- const char *label = xt_console_label(argc, argv);
484
- int index = xt_console_find_label(label ? label : "default");
485
- if (index >= 0) xt_console_timers[index] = clock();
486
- return XT_UNDEFINED;
487
- }
488
-
489
- xt_value xt_console_time_log(int32_t argc, xt_value *argv) {
490
- const char *label = xt_console_label(argc, argv);
491
- int index = xt_console_find_label(label ? label : "default");
492
- if (index >= 0 && xt_console_timers[index] != 0) {
493
- double ms = (double)(clock() - xt_console_timers[index]) * 1000.0 / CLOCKS_PER_SEC;
494
- printf("%s: %.3fms\n", xt_console_labels[index], ms);
495
- }
496
- return XT_UNDEFINED;
497
- }
498
-
499
- xt_value xt_console_time_end(int32_t argc, xt_value *argv) {
500
- xt_console_time_log(argc, argv);
501
- const char *label = xt_console_label(argc, argv);
502
- int index = xt_console_find_label(label ? label : "default");
503
- if (index >= 0) xt_console_timers[index] = 0;
504
- return XT_UNDEFINED;
505
- }
506
-
507
- /* -- base64 globals (btoa/atob) ------------------------------------------- */
508
-
509
- static const char xt_base64_alphabet[] =
510
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
511
-
512
- xt_value xt_btoa(int32_t argc, xt_value *argv) {
513
- const char *input = argc > 0 ? xt_string_data(xt_to_string(argv[0])) : "";
514
- if (!input) input = "";
515
- size_t length = strlen(input);
516
- size_t outLength = ((length + 2) / 3) * 4;
517
- char *buffer = (char *)malloc(outLength + 1);
518
- if (!buffer) return xt_string_from_cstr("");
519
- size_t i = 0, j = 0;
520
- while (i + 2 < length) {
521
- unsigned int n = ((unsigned char)input[i] << 16) | ((unsigned char)input[i + 1] << 8) |
522
- (unsigned char)input[i + 2];
523
- buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
524
- buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
525
- buffer[j++] = xt_base64_alphabet[(n >> 6) & 63];
526
- buffer[j++] = xt_base64_alphabet[n & 63];
527
- i += 3;
528
- }
529
- if (length - i == 1) {
530
- unsigned int n = (unsigned char)input[i] << 16;
531
- buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
532
- buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
533
- buffer[j++] = '=';
534
- buffer[j++] = '=';
535
- } else if (length - i == 2) {
536
- unsigned int n = ((unsigned char)input[i] << 16) | ((unsigned char)input[i + 1] << 8);
537
- buffer[j++] = xt_base64_alphabet[(n >> 18) & 63];
538
- buffer[j++] = xt_base64_alphabet[(n >> 12) & 63];
539
- buffer[j++] = xt_base64_alphabet[(n >> 6) & 63];
540
- buffer[j++] = '=';
541
- }
542
- buffer[j] = 0;
543
- xt_value result = xt_string_new(buffer, j);
544
- free(buffer);
545
- return result;
546
- }
547
-
548
- static int xt_base64_value(char c) {
549
- if (c >= 'A' && c <= 'Z') return c - 'A';
550
- if (c >= 'a' && c <= 'z') return c - 'a' + 26;
551
- if (c >= '0' && c <= '9') return c - '0' + 52;
552
- if (c == '+') return 62;
553
- if (c == '/') return 63;
554
- return -1;
555
- }
556
-
557
- xt_value xt_atob(int32_t argc, xt_value *argv) {
558
- const char *input = argc > 0 ? xt_string_data(xt_to_string(argv[0])) : "";
559
- if (!input) input = "";
560
- size_t length = strlen(input);
561
- char *buffer = (char *)malloc(length / 4 * 3 + 1);
562
- if (!buffer) return xt_string_from_cstr("");
563
- size_t out = 0;
564
- int values[4];
565
- int count = 0;
566
- for (size_t i = 0; i < length; i++) {
567
- char c = input[i];
568
- if (c == '=' || c == '\n' || c == '\r' || c == ' ' || c == '\t') {
569
- if (c == '=') break;
570
- continue;
571
- }
572
- int value = xt_base64_value(c);
573
- if (value < 0) continue;
574
- values[count++] = value;
575
- if (count == 4) {
576
- buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
577
- buffer[out++] = (char)(((values[1] & 15) << 4) | (values[2] >> 2));
578
- buffer[out++] = (char)(((values[2] & 3) << 6) | values[3]);
579
- count = 0;
580
- }
581
- }
582
- if (count == 2) {
583
- buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
584
- } else if (count == 3) {
585
- buffer[out++] = (char)((values[0] << 2) | (values[1] >> 4));
586
- buffer[out++] = (char)(((values[1] & 15) << 4) | (values[2] >> 2));
587
- }
588
- xt_value result = xt_string_new(buffer, out);
589
- free(buffer);
590
- return result;
591
- }
43
+ #include "xt_io/exception.inc"
44
+ #include "xt_io/inspect.inc"
45
+ #include "xt_io/console.inc"
46
+ #include "xt_io/base64.inc"