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.
- package/dist/src/cli/main.js +4 -4
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +8 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/graph.d.ts +8 -0
- package/dist/src/driver/bundler/graph.js +85 -0
- package/dist/src/driver/bundler/graph.js.map +1 -0
- package/dist/src/driver/bundler/merge.d.ts +11 -0
- package/dist/src/driver/bundler/merge.js +288 -0
- package/dist/src/driver/bundler/merge.js.map +1 -0
- package/dist/src/driver/bundler/resolve.d.ts +12 -0
- package/dist/src/driver/bundler/resolve.js +246 -0
- package/dist/src/driver/bundler/resolve.js.map +1 -0
- package/dist/src/driver/bundler/symbols.d.ts +15 -0
- package/dist/src/driver/bundler/symbols.js +51 -0
- package/dist/src/driver/bundler/symbols.js.map +1 -0
- package/dist/src/driver/bundler/types.d.ts +36 -0
- package/dist/src/driver/bundler/types.js +5 -0
- package/dist/src/driver/bundler/types.js.map +1 -0
- package/dist/src/driver/modules.d.ts +9 -16
- package/dist/src/driver/modules.js +8 -644
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/extensions/catalog.js +2 -1
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/index.d.ts +24 -0
- package/dist/src/extensions/gui/index.js +101 -0
- package/dist/src/extensions/gui/index.js.map +1 -0
- package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
- package/dist/tests/e2e/compile-basics.test.js +134 -0
- package/dist/tests/e2e/compile-basics.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
- package/dist/tests/e2e/compile-builtins.test.js +191 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
- package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
- package/dist/tests/e2e/compile-control-flow.test.js +190 -0
- package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
- package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
- package/dist/tests/e2e/compile-modules.test.js +48 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
- package/dist/tests/e2e/differential-helpers.d.ts +12 -0
- package/dist/tests/e2e/differential-helpers.js +16 -0
- package/dist/tests/e2e/differential-helpers.js.map +1 -0
- package/dist/tests/e2e/differential-language.test.d.ts +4 -0
- package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
- package/dist/tests/e2e/differential-language.test.js.map +1 -0
- package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
- package/dist/tests/e2e/differential-symbols.test.js +92 -0
- package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.d.ts +4 -0
- package/dist/tests/e2e/differential-values.test.js +197 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -0
- package/dist/tests/e2e/gui.test.d.ts +12 -0
- package/dist/tests/e2e/gui.test.js +493 -0
- package/dist/tests/e2e/gui.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
- package/dist/tests/e2e/timers.test.d.ts +7 -0
- package/dist/tests/e2e/timers.test.js +63 -0
- package/dist/tests/e2e/timers.test.js.map +1 -0
- package/package.json +2 -1
- package/runtime/ext_gui/css.cpp +743 -0
- package/runtime/ext_gui/css.h +98 -0
- package/runtime/ext_gui/document.cpp +264 -0
- package/runtime/ext_gui/document.h +89 -0
- package/runtime/ext_gui/dom.cpp +472 -0
- package/runtime/ext_gui/dom.h +71 -0
- package/runtime/ext_gui/gui.cpp +457 -0
- package/runtime/ext_gui/gui_engine.h +81 -0
- package/runtime/ext_gui/image.cpp +125 -0
- package/runtime/ext_gui/image.h +42 -0
- package/runtime/ext_gui/layout.cpp +748 -0
- package/runtime/ext_gui/layout.h +93 -0
- package/runtime/ext_gui/paint.cpp +137 -0
- package/runtime/ext_gui/paint.h +75 -0
- package/runtime/ext_gui/renderer.cpp +959 -0
- package/runtime/ext_gui/renderer.h +68 -0
- package/runtime/ext_gui/stb_image.h +7988 -0
- package/runtime/ext_gui/style.cpp +771 -0
- package/runtime/ext_gui/style.h +117 -0
- package/runtime/ext_gui/text.cpp +378 -0
- package/runtime/ext_gui/text.h +78 -0
- package/runtime/ext_gui/window.cpp +405 -0
- package/runtime/ext_node/fs/fs_common.h +13 -527
- package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
- package/runtime/ext_node/fs/parts/builtins.inc +69 -0
- package/runtime/ext_node/fs/parts/dir.inc +47 -0
- package/runtime/ext_node/fs/parts/encoding.inc +186 -0
- package/runtime/ext_node/fs/parts/errors.inc +66 -0
- package/runtime/ext_node/fs/parts/flags.inc +39 -0
- package/runtime/ext_node/fs/parts/platform.inc +86 -0
- package/runtime/ext_node/fs/parts/promisify.inc +15 -0
- package/runtime/ext_node/fs/parts/time.inc +9 -0
- package/runtime/rt.h +33 -0
- package/runtime/xt_builtins.c +4 -0
- package/runtime/xt_containers/access.inc +168 -0
- package/runtime/xt_containers/arrays.inc +108 -0
- package/runtime/xt_containers/boxes.inc +11 -0
- package/runtime/xt_containers/objects.inc +326 -0
- package/runtime/xt_containers.c +8 -618
- package/runtime/xt_io/base64.inc +87 -0
- package/runtime/xt_io/console.inc +119 -0
- package/runtime/xt_io/exception.inc +142 -0
- package/runtime/xt_io/inspect.inc +212 -0
- package/runtime/xt_io.c +8 -553
- package/runtime/xt_loop.c +262 -24
- package/runtime/xt_regex/api.inc +58 -0
- package/runtime/xt_regex/helpers.inc +68 -0
- package/runtime/xt_regex/matcher.inc +248 -0
- package/runtime/xt_regex/parser.inc +236 -0
- package/runtime/xt_regex/types.inc +58 -0
- package/runtime/xt_regex.h +9 -672
- package/runtime/xt_values/arithmetic.inc +150 -0
- package/runtime/xt_values/comparison.inc +112 -0
- package/runtime/xt_values/constructors.inc +41 -0
- package/runtime/xt_values/conversions.inc +115 -0
- package/runtime/xt_values/number-format.inc +180 -0
- package/runtime/xt_values/strings.inc +22 -0
- package/runtime/xt_values.c +10 -626
- package/scripts/build-gui.ts +317 -0
- package/src/cli/main.ts +4 -3
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/tables.ts +8 -0
- package/src/driver/bundler/graph.ts +95 -0
- package/src/driver/bundler/merge.ts +312 -0
- package/src/driver/bundler/resolve.ts +240 -0
- package/src/driver/bundler/symbols.ts +55 -0
- package/src/driver/bundler/types.ts +37 -0
- package/src/driver/modules.ts +9 -693
- package/src/extensions/catalog.ts +2 -1
- package/src/extensions/gui/index.ts +107 -0
- package/dist/tests/e2e/compile.test.d.ts +0 -8
- package/dist/tests/e2e/compile.test.js +0 -893
- package/dist/tests/e2e/compile.test.js.map +0 -1
- package/dist/tests/e2e/differential.test.d.ts +0 -7
- package/dist/tests/e2e/differential.test.js.map +0 -1
- package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
- package/dist/tests/e2e/runtime-coverage.test.js +0 -646
- package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
|
@@ -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);
|
package/runtime/xt_builtins.c
CHANGED
|
@@ -301,6 +301,10 @@ XT_BUILTIN_TRAMPOLINE(xt_builtin_value_encodeURIComponent, xt_encode_uri_compone
|
|
|
301
301
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_encodeURI, xt_encode_uri)
|
|
302
302
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_decodeURIComponent, xt_decode_uri_component)
|
|
303
303
|
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_decodeURI, xt_decode_uri)
|
|
304
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setTimeout, xt_set_timeout)
|
|
305
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearTimeout, xt_clear_timeout)
|
|
306
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_setInterval, xt_set_interval)
|
|
307
|
+
XT_BUILTIN_TRAMPOLINE(xt_builtin_value_clearInterval, xt_clear_interval)
|
|
304
308
|
|
|
305
309
|
xt_value xt_in(xt_value key, xt_value value) {
|
|
306
310
|
if (XT_IS_OBJECT(value)) return xt_object_has(value, key);
|
|
@@ -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
|
+
}
|