xbintsc 0.3.81 → 0.3.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/README.zh-CN.md +12 -4
- package/dist/src/ast/common.d.ts +23 -0
- package/dist/src/cli/main.js +68 -24
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +5 -1
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +50 -0
- package/dist/src/codegen/generator/context.js +124 -13
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/debug.d.ts +33 -0
- package/dist/src/codegen/generator/debug.js +97 -0
- package/dist/src/codegen/generator/debug.js.map +1 -0
- package/dist/src/codegen/generator/expressions/assignment.js +9 -5
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
- package/dist/src/codegen/generator/expressions/operators.js +35 -9
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -2
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/generator.d.ts +3 -1
- package/dist/src/codegen/generator/generator.js +3 -1
- package/dist/src/codegen/generator/generator.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +76 -6
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/numeric.d.ts +26 -0
- package/dist/src/codegen/generator/numeric.js +127 -0
- package/dist/src/codegen/generator/numeric.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +17 -0
- package/dist/src/codegen/generator/state.js +5 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/statements/dispatch.js +3 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +8 -2
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +7 -0
- package/dist/src/codegen/generator/tables.js +25 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/merge.js +41 -5
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +22 -3
- package/dist/src/driver/compiler.js +43 -57
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/fingerprint.d.ts +27 -0
- package/dist/src/driver/fingerprint.js +88 -0
- package/dist/src/driver/fingerprint.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +9 -2
- package/dist/src/driver/toolchain-provider.js +15 -15
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.d.ts +58 -1
- package/dist/src/driver/toolchain.js +169 -22
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/parser/expressions.js +20 -1
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/tests/cli/main.test.js +41 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/expressions.test.js +14 -3
- package/dist/tests/codegen/expressions.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +23 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +49 -2
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/driver/toolchain.test.js +62 -3
- package/dist/tests/driver/toolchain.test.js.map +1 -1
- package/dist/tests/e2e/child-process.test.d.ts +10 -0
- package/dist/tests/e2e/child-process.test.js +59 -0
- package/dist/tests/e2e/child-process.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +47 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/error-stack.test.d.ts +9 -0
- package/dist/tests/e2e/error-stack.test.js +94 -0
- package/dist/tests/e2e/error-stack.test.js.map +1 -0
- package/dist/tests/e2e/string-concat.test.d.ts +9 -0
- package/dist/tests/e2e/string-concat.test.js +102 -0
- package/dist/tests/e2e/string-concat.test.js.map +1 -0
- package/dist/tests/helpers.d.ts +9 -0
- package/dist/tests/helpers.js +26 -3
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +7 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/version.test.d.ts +1 -0
- package/dist/tests/version.test.js +24 -0
- package/dist/tests/version.test.js.map +1 -0
- package/doc/DESIGN.md +20 -12
- package/doc/ai/cli.md +2 -0
- package/doc/ai/contributing.md +7 -1
- package/doc/ai/language-support.md +4 -4
- package/doc/ai/troubleshooting.md +39 -2
- package/doc/ai/zh-CN/cli.md +2 -0
- package/doc/ai/zh-CN/contributing.md +6 -2
- package/doc/ai/zh-CN/language-support.md +4 -4
- package/doc/ai/zh-CN/troubleshooting.md +35 -2
- package/doc/implemented.md +3 -3
- package/doc/requirements.md +13 -4
- package/doc/unimplemented.md +11 -10
- package/doc/zh-CN/DESIGN.md +15 -9
- package/doc/zh-CN/implemented.md +3 -3
- package/doc/zh-CN/requirements.md +12 -3
- package/doc/zh-CN/unimplemented.md +10 -9
- package/package.json +3 -1
- package/runtime/ext_node/buffer/parts/construction.inc +2 -2
- package/runtime/ext_node/buffer/parts/methods.inc +1 -1
- package/runtime/ext_node/buffer/parts/search.inc +1 -1
- package/runtime/ext_node/child_process/child_process.c +25 -0
- package/runtime/ext_node/fs/fd_ops.c +1 -1
- package/runtime/rt.h +17 -1
- package/runtime/rt_internal.h +47 -4
- package/runtime/xt_alloc.c +14 -2
- package/runtime/xt_bigint/conversions.inc +1 -1
- package/runtime/xt_builtins.c +136 -14
- package/runtime/xt_containers/access.inc +17 -16
- package/runtime/xt_containers/objects.inc +4 -3
- package/runtime/xt_io/exception.inc +171 -2
- package/runtime/xt_io/inspect.inc +15 -13
- package/runtime/xt_io.c +5 -0
- package/runtime/xt_stdlib/arrays.inc +2 -2
- package/runtime/xt_stdlib/dispatch.inc +2 -2
- package/runtime/xt_stdlib/strings.inc +33 -21
- package/runtime/xt_stdlib2/array-statics.inc +2 -1
- package/runtime/xt_stdlib2/arrays.inc +1 -1
- package/runtime/xt_stdlib2/error.inc +22 -6
- package/runtime/xt_stdlib2/json.inc +3 -2
- package/runtime/xt_stdlib2/number-string-statics.inc +3 -1
- package/runtime/xt_stdlib2/regexp-match.inc +48 -33
- package/runtime/xt_stdlib2/strings.inc +23 -14
- package/runtime/xt_symbol.c +1 -1
- package/runtime/xt_values/comparison.inc +2 -2
- package/runtime/xt_values/constructors.inc +10 -5
- package/runtime/xt_values/conversions.inc +4 -3
- package/runtime/xt_values/strings.inc +78 -4
- package/scripts/bench.ts +172 -0
- package/scripts/build-runtime.ts +2 -1
- package/scripts/check-version.ts +53 -0
- package/src/ast/common.ts +23 -0
- package/src/cli/main.ts +68 -26
- package/src/codegen/generator/calls/invocation.ts +5 -0
- package/src/codegen/generator/context.ts +129 -18
- package/src/codegen/generator/debug.ts +132 -0
- package/src/codegen/generator/expressions/assignment.ts +9 -5
- package/src/codegen/generator/expressions/operators.ts +47 -8
- package/src/codegen/generator/expressions/primary.ts +5 -2
- package/src/codegen/generator/generator.ts +18 -2
- package/src/codegen/generator/module.ts +78 -6
- package/src/codegen/generator/numeric.ts +158 -0
- package/src/codegen/generator/state.ts +22 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -1
- package/src/codegen/generator/statements/dispatch.ts +3 -0
- package/src/codegen/generator/statements/variables.ts +8 -2
- package/src/codegen/generator/tables.ts +26 -0
- package/src/driver/bundler/merge.ts +39 -5
- package/src/driver/compiler.ts +62 -55
- package/src/driver/fingerprint.ts +85 -0
- package/src/driver/toolchain-provider.ts +17 -16
- package/src/driver/toolchain.ts +210 -21
- package/src/parser/expressions.ts +20 -1
|
@@ -322,7 +322,7 @@ xt_value xt_call_method(xt_value target, xt_value name, int32_t argc, xt_value *
|
|
|
322
322
|
/* Bound functions report `name` as "bound <target>" and reduce `length`
|
|
323
323
|
* by the number of pre-bound arguments, like the specification. */
|
|
324
324
|
xt_function *targetFn = (xt_function *)XT_GET_PTR(target);
|
|
325
|
-
const char *base = targetFn->name ? targetFn->name
|
|
325
|
+
const char *base = targetFn->name ? xt_string_bytes(targetFn->name) : "";
|
|
326
326
|
char boundName[256];
|
|
327
327
|
snprintf(boundName, sizeof(boundName), "bound %s", base);
|
|
328
328
|
int32_t prebound = argc > 1 ? argc - 1 : 0;
|
|
@@ -336,7 +336,7 @@ xt_value xt_call_method(xt_value target, xt_value name, int32_t argc, xt_value *
|
|
|
336
336
|
if (strcmp(method, "toString") == 0) {
|
|
337
337
|
/* Source text is not retained; report a native-style representation. */
|
|
338
338
|
xt_function *self = (xt_function *)XT_GET_PTR(target);
|
|
339
|
-
const char *selfName = self->name ? self->name
|
|
339
|
+
const char *selfName = self->name ? xt_string_bytes(self->name) : "";
|
|
340
340
|
char buffer[256];
|
|
341
341
|
snprintf(buffer, sizeof(buffer), "function %s() { [native code] }", selfName);
|
|
342
342
|
return xt_string_from_cstr(buffer);
|
|
@@ -4,8 +4,10 @@ static int32_t xt_string_find(xt_string *haystack, xt_string *needle, int32_t fr
|
|
|
4
4
|
if (from < 0) from = 0;
|
|
5
5
|
if ((uint32_t)from > haystack->length) return -1;
|
|
6
6
|
if (needle->length == 0) return from;
|
|
7
|
+
const char *hay = xt_string_bytes(haystack);
|
|
8
|
+
const char *need = xt_string_bytes(needle);
|
|
7
9
|
for (uint32_t i = (uint32_t)from; i + needle->length <= haystack->length; i++) {
|
|
8
|
-
if (memcmp(
|
|
10
|
+
if (memcmp(hay + i, need, needle->length) == 0) return (int32_t)i;
|
|
9
11
|
}
|
|
10
12
|
return -1;
|
|
11
13
|
}
|
|
@@ -15,7 +17,7 @@ static xt_value xt_string_char_at(xt_value value, xt_value indexValue) {
|
|
|
15
17
|
if (!s) return xt_string_from_cstr("");
|
|
16
18
|
int32_t index = xt_to_int32(indexValue);
|
|
17
19
|
if (index < 0 || (uint32_t)index >= s->length) return xt_string_from_cstr("");
|
|
18
|
-
return xt_string_new(s
|
|
20
|
+
return xt_string_new(xt_string_bytes(s) + index, 1);
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
static xt_value xt_string_char_code_at(xt_value value, xt_value indexValue) {
|
|
@@ -23,7 +25,7 @@ static xt_value xt_string_char_code_at(xt_value value, xt_value indexValue) {
|
|
|
23
25
|
if (!s) return xt_number(NAN);
|
|
24
26
|
int32_t index = xt_to_int32(indexValue);
|
|
25
27
|
if (index < 0 || (uint32_t)index >= s->length) return xt_number(NAN);
|
|
26
|
-
return xt_number((double)(unsigned char)s
|
|
28
|
+
return xt_number((double)(unsigned char)xt_string_bytes(s)[index]);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
static xt_value xt_string_index_of(xt_value value, xt_value needleValue, xt_value fromValue) {
|
|
@@ -41,7 +43,7 @@ static xt_value xt_string_slice(xt_value value, xt_value startValue, xt_value en
|
|
|
41
43
|
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
42
44
|
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
43
45
|
xt_normalize_slice(len, &start, &end);
|
|
44
|
-
return xt_string_new(s
|
|
46
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)(end - start));
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
static xt_value xt_string_substring(xt_value value, xt_value startValue, xt_value endValue) {
|
|
@@ -59,7 +61,7 @@ static xt_value xt_string_substring(xt_value value, xt_value startValue, xt_valu
|
|
|
59
61
|
start = end;
|
|
60
62
|
end = swap;
|
|
61
63
|
}
|
|
62
|
-
return xt_string_new(s
|
|
64
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)(end - start));
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
static xt_value xt_string_substr(xt_value value, xt_value startValue, xt_value lengthValue) {
|
|
@@ -73,7 +75,7 @@ static xt_value xt_string_substr(xt_value value, xt_value startValue, xt_value l
|
|
|
73
75
|
int32_t length = lengthValue == XT_UNDEFINED ? len - start : xt_to_int32(lengthValue);
|
|
74
76
|
if (length < 0) length = 0;
|
|
75
77
|
if (start + length > len) length = len - start;
|
|
76
|
-
return xt_string_new(s
|
|
78
|
+
return xt_string_new(xt_string_bytes(s) + start, (size_t)length);
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
static xt_value xt_string_split(xt_value value, xt_value separatorValue, xt_value limitValue) {
|
|
@@ -87,21 +89,23 @@ static xt_value xt_string_split(xt_value value, xt_value separatorValue, xt_valu
|
|
|
87
89
|
return result;
|
|
88
90
|
}
|
|
89
91
|
xt_string *sep = xt_as_string(xt_to_string(separatorValue));
|
|
92
|
+
const char *bytes = xt_string_bytes(s);
|
|
93
|
+
const char *sepBytes = xt_string_bytes(sep);
|
|
90
94
|
if (sep->length == 0) {
|
|
91
|
-
for (uint32_t i = 0; i < s->length; i++) xt_array_push(result, xt_string_new(
|
|
95
|
+
for (uint32_t i = 0; i < s->length; i++) xt_array_push(result, xt_string_new(bytes + i, 1));
|
|
92
96
|
} else {
|
|
93
97
|
uint32_t start = 0;
|
|
94
98
|
uint32_t i = 0;
|
|
95
99
|
while (i + sep->length <= s->length) {
|
|
96
|
-
if (memcmp(
|
|
97
|
-
xt_array_push(result, xt_string_new(
|
|
100
|
+
if (memcmp(bytes + i, sepBytes, sep->length) == 0) {
|
|
101
|
+
xt_array_push(result, xt_string_new(bytes + start, i - start));
|
|
98
102
|
i += sep->length;
|
|
99
103
|
start = i;
|
|
100
104
|
} else {
|
|
101
105
|
i++;
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
xt_array_push(result, xt_string_new(
|
|
108
|
+
xt_array_push(result, xt_string_new(bytes + start, s->length - start));
|
|
105
109
|
}
|
|
106
110
|
xt_array *array = xt_as_array(result);
|
|
107
111
|
if ((int64_t)array->length > limit) array->length = (uint32_t)limit;
|
|
@@ -112,9 +116,11 @@ static xt_value xt_string_case(xt_value value, int upper) {
|
|
|
112
116
|
xt_string *s = xt_as_string(value);
|
|
113
117
|
if (!s) return value;
|
|
114
118
|
xt_string *out = xt_string_alloc(s->length);
|
|
119
|
+
const char *bytes = xt_string_bytes(s);
|
|
120
|
+
char *mutable = xt_string_mutable(out);
|
|
115
121
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
116
|
-
unsigned char c = (unsigned char)
|
|
117
|
-
|
|
122
|
+
unsigned char c = (unsigned char)bytes[i];
|
|
123
|
+
mutable[i] = (char)(upper ? toupper((int)c) : tolower((int)c));
|
|
118
124
|
}
|
|
119
125
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
120
126
|
}
|
|
@@ -122,11 +128,12 @@ static xt_value xt_string_case(xt_value value, int upper) {
|
|
|
122
128
|
static xt_value xt_string_trim(xt_value value) {
|
|
123
129
|
xt_string *s = xt_as_string(value);
|
|
124
130
|
if (!s) return value;
|
|
131
|
+
const char *bytes = xt_string_bytes(s);
|
|
125
132
|
uint32_t start = 0;
|
|
126
133
|
uint32_t end = s->length;
|
|
127
|
-
while (start < end && isspace((unsigned char)
|
|
128
|
-
while (end > start && isspace((unsigned char)
|
|
129
|
-
return xt_string_new(
|
|
134
|
+
while (start < end && isspace((unsigned char)bytes[start])) start++;
|
|
135
|
+
while (end > start && isspace((unsigned char)bytes[end - 1])) end--;
|
|
136
|
+
return xt_string_new(bytes + start, end - start);
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
static xt_value xt_string_replace(xt_value value, xt_value searchValue, xt_value replacementValue) {
|
|
@@ -137,11 +144,14 @@ static xt_value xt_string_replace(xt_value value, xt_value searchValue, xt_value
|
|
|
137
144
|
xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
|
|
138
145
|
int32_t at = xt_string_find(s, search, 0);
|
|
139
146
|
if (at < 0) return value;
|
|
147
|
+
const char *text = xt_string_bytes(s);
|
|
148
|
+
const char *repl = xt_string_bytes(replacement);
|
|
140
149
|
size_t total = s->length - search->length + replacement->length;
|
|
141
150
|
xt_string *out = xt_string_alloc(total);
|
|
142
|
-
|
|
143
|
-
memcpy(
|
|
144
|
-
memcpy(
|
|
151
|
+
char *mutable = xt_string_mutable(out);
|
|
152
|
+
memcpy(mutable, text, (size_t)at);
|
|
153
|
+
memcpy(mutable + at, repl, replacement->length);
|
|
154
|
+
memcpy(mutable + at + replacement->length, text + at + search->length,
|
|
145
155
|
s->length - (size_t)at - search->length);
|
|
146
156
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
147
157
|
}
|
|
@@ -155,7 +165,9 @@ static xt_value xt_string_repeat(xt_value value, xt_value countValue) {
|
|
|
155
165
|
return XT_UNDEFINED;
|
|
156
166
|
}
|
|
157
167
|
xt_string *out = xt_string_alloc((size_t)s->length * (size_t)count);
|
|
158
|
-
|
|
168
|
+
const char *bytes = xt_string_bytes(s);
|
|
169
|
+
char *mutable = xt_string_mutable(out);
|
|
170
|
+
for (int32_t i = 0; i < count; i++) memcpy(mutable + (size_t)i * s->length, bytes, s->length);
|
|
159
171
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
160
172
|
}
|
|
161
173
|
|
|
@@ -164,7 +176,7 @@ static xt_value xt_string_starts_with(xt_value value, xt_value searchValue) {
|
|
|
164
176
|
if (!s) return XT_FALSE;
|
|
165
177
|
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
166
178
|
if (search->length > s->length) return XT_FALSE;
|
|
167
|
-
return xt_bool(memcmp(s
|
|
179
|
+
return xt_bool(memcmp(xt_string_bytes(s), xt_string_bytes(search), search->length) == 0);
|
|
168
180
|
}
|
|
169
181
|
|
|
170
182
|
static xt_value xt_string_ends_with(xt_value value, xt_value searchValue) {
|
|
@@ -172,7 +184,7 @@ static xt_value xt_string_ends_with(xt_value value, xt_value searchValue) {
|
|
|
172
184
|
if (!s) return XT_FALSE;
|
|
173
185
|
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
174
186
|
if (search->length > s->length) return XT_FALSE;
|
|
175
|
-
return xt_bool(memcmp(s
|
|
187
|
+
return xt_bool(memcmp(xt_string_bytes(s) + s->length - search->length, xt_string_bytes(search), search->length) == 0);
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
static xt_value xt_string_concat_args(xt_value value, int32_t argc, xt_value *argv) {
|
|
@@ -18,8 +18,9 @@ xt_value xt_array_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
18
18
|
}
|
|
19
19
|
} else if (XT_IS_STRING(source)) {
|
|
20
20
|
xt_string *s = xt_as_string(source);
|
|
21
|
+
const char *bytes = xt_string_bytes(s);
|
|
21
22
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
22
|
-
xt_value item = xt_string_new(
|
|
23
|
+
xt_value item = xt_string_new(bytes + i, 1);
|
|
23
24
|
if (XT_IS_FUNCTION(mapper)) { xt_value args[2] = {item, xt_number((double)i)}; item = xt_closure_call(mapper, 2, args); }
|
|
24
25
|
xt_array_push(out, item);
|
|
25
26
|
}
|
|
@@ -46,7 +46,7 @@ static int xt_array_default_compare(xt_value a, xt_value b) {
|
|
|
46
46
|
xt_string *sa = xt_as_string(xt_to_string(a));
|
|
47
47
|
xt_string *sb = xt_as_string(xt_to_string(b));
|
|
48
48
|
uint32_t n = sa->length < sb->length ? sa->length : sb->length;
|
|
49
|
-
int cmp = n ? memcmp(sa
|
|
49
|
+
int cmp = n ? memcmp(xt_string_bytes(sa), xt_string_bytes(sb), n) : 0;
|
|
50
50
|
if (cmp != 0) return cmp < 0 ? -1 : 1;
|
|
51
51
|
if (sa->length == sb->length) return 0;
|
|
52
52
|
return sa->length < sb->length ? -1 : 1;
|
|
@@ -50,6 +50,15 @@ xt_value xt_error_prototype(xt_value nameValue) {
|
|
|
50
50
|
return xt_error_proto_for(name);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/* Capture `Error.stack` into the object's private field (not a property, so it
|
|
54
|
+
* stays out of Object.keys/JSON.stringify, like V8's own non-enumerable stack). */
|
|
55
|
+
static void xt_error_capture_stack(xt_value error, const char *name, xt_value message) {
|
|
56
|
+
if (!XT_IS_OBJECT(error)) return;
|
|
57
|
+
xt_string *text = xt_as_string(xt_to_string(message));
|
|
58
|
+
xt_value stack = xt_stack_capture(name, text ? xt_string_bytes(text) : "");
|
|
59
|
+
((xt_object *)XT_GET_PTR(error))->error_stack = stack;
|
|
60
|
+
}
|
|
61
|
+
|
|
53
62
|
static xt_value xt_make_error(const char *name, int32_t argc, xt_value *argv) {
|
|
54
63
|
if (!xt_error_is_family(name)) name = "Error";
|
|
55
64
|
xt_value error = xt_object_new();
|
|
@@ -64,9 +73,10 @@ static xt_value xt_make_error(const char *name, int32_t argc, xt_value *argv) {
|
|
|
64
73
|
} else {
|
|
65
74
|
message = xt_arg_at(argc, argv, 0);
|
|
66
75
|
}
|
|
76
|
+
xt_value messageValue = message == XT_UNDEFINED ? xt_string_from_cstr("") : message;
|
|
67
77
|
xt_object_set(error, xt_string_from_cstr("name"), xt_string_from_cstr(name));
|
|
68
|
-
xt_object_set(error, xt_string_from_cstr("message"),
|
|
69
|
-
|
|
78
|
+
xt_object_set(error, xt_string_from_cstr("message"), messageValue);
|
|
79
|
+
xt_error_capture_stack(error, name, messageValue);
|
|
70
80
|
return error;
|
|
71
81
|
}
|
|
72
82
|
|
|
@@ -110,10 +120,10 @@ xt_value xt_error_to_string(xt_value error) {
|
|
|
110
120
|
if (ms->length == 0) return nameStr;
|
|
111
121
|
size_t total = ns->length + 2 + ms->length;
|
|
112
122
|
char *buffer = (char *)malloc(total + 1);
|
|
113
|
-
memcpy(buffer, ns
|
|
123
|
+
memcpy(buffer, xt_string_bytes(ns), ns->length);
|
|
114
124
|
buffer[ns->length] = ':';
|
|
115
125
|
buffer[ns->length + 1] = ' ';
|
|
116
|
-
memcpy(buffer + ns->length + 2, ms
|
|
126
|
+
memcpy(buffer + ns->length + 2, xt_string_bytes(ms), ms->length);
|
|
117
127
|
buffer[total] = '\0';
|
|
118
128
|
xt_value result = xt_string_new(buffer, total);
|
|
119
129
|
free(buffer);
|
|
@@ -159,6 +169,11 @@ xt_value xt_error_init(xt_value thisValue, xt_value nameValue, int32_t argc,
|
|
|
159
169
|
xt_value *argv) {
|
|
160
170
|
const char *name = XT_IS_STRING(nameValue) ? xt_string_data(nameValue) : "Error";
|
|
161
171
|
if (!xt_error_is_family(name)) name = "Error";
|
|
172
|
+
/* `class MyError extends Error` allocates a plain object first; mark it as an
|
|
173
|
+
* Error so `.stack` and the error-specific property access apply. */
|
|
174
|
+
if (XT_IS_OBJECT(thisValue)) {
|
|
175
|
+
((xt_object *)XT_GET_PTR(thisValue))->header.kind = XT_OBJECT_KIND_ERROR;
|
|
176
|
+
}
|
|
162
177
|
xt_object_set(thisValue, xt_string_from_cstr("name"), xt_string_from_cstr(name));
|
|
163
178
|
xt_value message;
|
|
164
179
|
if (strcmp(name, "AggregateError") == 0) {
|
|
@@ -167,7 +182,8 @@ xt_value xt_error_init(xt_value thisValue, xt_value nameValue, int32_t argc,
|
|
|
167
182
|
} else {
|
|
168
183
|
message = xt_arg_at(argc, argv, 0);
|
|
169
184
|
}
|
|
170
|
-
|
|
171
|
-
|
|
185
|
+
xt_value messageValue = message == XT_UNDEFINED ? xt_string_from_cstr("") : message;
|
|
186
|
+
xt_object_set(thisValue, xt_string_from_cstr("message"), messageValue);
|
|
187
|
+
xt_error_capture_stack(thisValue, name, messageValue);
|
|
172
188
|
return thisValue;
|
|
173
189
|
}
|
|
@@ -120,7 +120,7 @@ xt_value xt_json_parse(int32_t argc, xt_value *argv) {
|
|
|
120
120
|
xt_value input = xt_to_string(xt_arg_at(argc, argv, 0));
|
|
121
121
|
xt_string *s = xt_as_string(input);
|
|
122
122
|
if (!s) return XT_UNDEFINED;
|
|
123
|
-
xt_json_cursor cursor = {s
|
|
123
|
+
xt_json_cursor cursor = {xt_string_bytes(s), s->length, 0};
|
|
124
124
|
return xt_json_parse_value(&cursor);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -193,9 +193,10 @@ static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_va
|
|
|
193
193
|
}
|
|
194
194
|
if (XT_IS_STRING(value)) {
|
|
195
195
|
xt_string *s = xt_as_string(value);
|
|
196
|
+
const char *bytes = xt_string_bytes(s);
|
|
196
197
|
*out = xt_add(*out, xt_string_from_cstr("\""));
|
|
197
198
|
for (uint32_t i = 0; i < s->length; i++) {
|
|
198
|
-
char ch =
|
|
199
|
+
char ch = bytes[i];
|
|
199
200
|
if (ch == '"') *out = xt_add(*out, xt_string_from_cstr("\\\""));
|
|
200
201
|
else if (ch == '\\') *out = xt_add(*out, xt_string_from_cstr("\\\\"));
|
|
201
202
|
else if (ch == '\n') *out = xt_add(*out, xt_string_from_cstr("\\n"));
|
|
@@ -43,6 +43,7 @@ xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
43
43
|
if (!fn) return XT_UNDEFINED;
|
|
44
44
|
if (strcmp(fn, "fromCharCode") == 0 || strcmp(fn, "fromCodePoint") == 0) {
|
|
45
45
|
xt_string *out = xt_string_alloc((size_t)argc * 4 + 1);
|
|
46
|
+
char *mutable = xt_string_mutable(out);
|
|
46
47
|
size_t length = 0;
|
|
47
48
|
for (int32_t i = 0; i < argc; i++) {
|
|
48
49
|
unsigned code = (unsigned)xt_to_int32(argv[i]);
|
|
@@ -52,9 +53,10 @@ xt_value xt_string_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
|
52
53
|
else if (code < 0x800) { buffer[bytes++] = (char)(0xC0 | (code >> 6)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
53
54
|
else if (code < 0x10000) { buffer[bytes++] = (char)(0xE0 | (code >> 12)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
54
55
|
else { buffer[bytes++] = (char)(0xF0 | (code >> 18)); buffer[bytes++] = (char)(0x80 | ((code >> 12) & 0x3F)); buffer[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); buffer[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
55
|
-
memcpy(
|
|
56
|
+
memcpy(mutable + length, buffer, (size_t)bytes);
|
|
56
57
|
length += (size_t)bytes;
|
|
57
58
|
}
|
|
59
|
+
mutable[length] = '\0';
|
|
58
60
|
out->length = (uint32_t)length;
|
|
59
61
|
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
60
62
|
}
|
|
@@ -109,8 +109,11 @@ static int xt_regexp_run(xt_value regexpValue, xt_value input, int32_t start,
|
|
|
109
109
|
if ((uint32_t)start > text->length) return 0;
|
|
110
110
|
int flags = REG_EXTENDED;
|
|
111
111
|
xt_string *f = xt_as_string(regexp->flags);
|
|
112
|
-
if (f)
|
|
113
|
-
|
|
112
|
+
if (f) {
|
|
113
|
+
const char *flagBytes = xt_string_bytes(f);
|
|
114
|
+
for (uint32_t i = 0; i < f->length; i++) if (flagBytes[i] == 'i') flags |= REG_ICASE;
|
|
115
|
+
}
|
|
116
|
+
char *translated = xt_regexp_translate_js(xt_string_bytes(pattern), jsGroups, groupCount);
|
|
114
117
|
if (!translated) return 0;
|
|
115
118
|
regex_t compiled;
|
|
116
119
|
if (regcomp(&compiled, translated, flags) != 0) {
|
|
@@ -118,7 +121,7 @@ static int xt_regexp_run(xt_value regexpValue, xt_value input, int32_t start,
|
|
|
118
121
|
return 0;
|
|
119
122
|
}
|
|
120
123
|
free(translated);
|
|
121
|
-
int ok = regexec(&compiled, text
|
|
124
|
+
int ok = regexec(&compiled, xt_string_bytes(text) + start, nmatch, matches, 0) == 0;
|
|
122
125
|
regfree(&compiled);
|
|
123
126
|
if (!ok) return 0;
|
|
124
127
|
for (size_t i = 0; i < nmatch; i++) {
|
|
@@ -142,7 +145,8 @@ static int xt_regexp_is_global(xt_value regexpValue) {
|
|
|
142
145
|
xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
|
|
143
146
|
xt_string *f = xt_as_string(regexp->flags);
|
|
144
147
|
if (!f) return 0;
|
|
145
|
-
|
|
148
|
+
const char *flags = xt_string_bytes(f);
|
|
149
|
+
for (uint32_t i = 0; i < f->length; i++) if (flags[i] == 'g') return 1;
|
|
146
150
|
return 0;
|
|
147
151
|
}
|
|
148
152
|
|
|
@@ -154,7 +158,7 @@ static int xt_regexp_js_group_count(xt_value regexpValue) {
|
|
|
154
158
|
int count = (int)pattern->length + 1;
|
|
155
159
|
int *groups = (int *)malloc(sizeof(int) * (size_t)count);
|
|
156
160
|
int groupCount = 0;
|
|
157
|
-
char *translated = xt_regexp_translate_js(pattern
|
|
161
|
+
char *translated = xt_regexp_translate_js(xt_string_bytes(pattern), groups, &groupCount);
|
|
158
162
|
free(translated);
|
|
159
163
|
int total = 0;
|
|
160
164
|
for (int i = 0; i < groupCount; i++) if (groups[i] > total) total = groups[i];
|
|
@@ -177,6 +181,7 @@ xt_value xt_regexp_exec(xt_value target, xt_value input) {
|
|
|
177
181
|
if (!matches || !groups) { free(matches); free(groups); return XT_NULL; }
|
|
178
182
|
xt_value textValue = xt_to_string(input);
|
|
179
183
|
xt_string *text = xt_as_string(textValue);
|
|
184
|
+
const char *textBytes = xt_string_bytes(text);
|
|
180
185
|
int groupCount = 0;
|
|
181
186
|
if (!xt_regexp_run(target, input, 0, matches, cap, groups, &groupCount)) {
|
|
182
187
|
free(matches);
|
|
@@ -186,13 +191,13 @@ xt_value xt_regexp_exec(xt_value target, xt_value input) {
|
|
|
186
191
|
int jsTotal = 0;
|
|
187
192
|
for (int i = 0; i < groupCount; i++) if (groups[i] > jsTotal) jsTotal = groups[i];
|
|
188
193
|
xt_value out = xt_array_new(0, NULL);
|
|
189
|
-
xt_array_push(out, xt_string_new(
|
|
194
|
+
xt_array_push(out, xt_string_new(textBytes + matches[0].rm_so, (int64_t)(matches[0].rm_eo - matches[0].rm_so)));
|
|
190
195
|
for (int g = 1; g <= jsTotal; g++) {
|
|
191
196
|
xt_value groupValue = XT_UNDEFINED;
|
|
192
197
|
for (int i = 0; i < groupCount; i++) {
|
|
193
198
|
if (groups[i] != g) continue;
|
|
194
199
|
if (matches[i + 1].rm_so >= 0) {
|
|
195
|
-
groupValue = xt_string_new(
|
|
200
|
+
groupValue = xt_string_new(textBytes + matches[i + 1].rm_so, (int64_t)(matches[i + 1].rm_eo - matches[i + 1].rm_so));
|
|
196
201
|
}
|
|
197
202
|
break;
|
|
198
203
|
}
|
|
@@ -212,6 +217,7 @@ xt_value xt_regexp_match(xt_value input, xt_value regexp) {
|
|
|
212
217
|
if (!xt_regexp_is_global(regexp)) return xt_regexp_exec(regexp, input);
|
|
213
218
|
xt_value textValue = xt_to_string(input);
|
|
214
219
|
xt_string *text = xt_as_string(textValue);
|
|
220
|
+
const char *textBytes = xt_string_bytes(text);
|
|
215
221
|
xt_value results = xt_array_new(0, NULL);
|
|
216
222
|
int32_t cursor = 0;
|
|
217
223
|
int found = 0;
|
|
@@ -220,7 +226,7 @@ xt_value xt_regexp_match(xt_value input, xt_value regexp) {
|
|
|
220
226
|
int32_t end = 0;
|
|
221
227
|
if (!xt_regexp_find(regexp, input, cursor, &start, &end)) break;
|
|
222
228
|
found = 1;
|
|
223
|
-
xt_array_push(results, xt_string_new(
|
|
229
|
+
xt_array_push(results, xt_string_new(textBytes + start, (int64_t)(end - start)));
|
|
224
230
|
cursor = end > start ? end : end + 1;
|
|
225
231
|
}
|
|
226
232
|
return found ? results : XT_NULL;
|
|
@@ -241,10 +247,11 @@ static void xt_regexp_append(char **out, size_t *length, size_t *capacity, const
|
|
|
241
247
|
static void xt_regexp_append_group(char **out, size_t *length, size_t *capacity,
|
|
242
248
|
xt_string *text, regmatch_t *matches, int *groups,
|
|
243
249
|
int groupCount, int group) {
|
|
250
|
+
const char *textBytes = xt_string_bytes(text);
|
|
244
251
|
for (int i = 0; i < groupCount; i++) {
|
|
245
252
|
if (groups[i] != group) continue;
|
|
246
253
|
if (matches[i + 1].rm_so >= 0) {
|
|
247
|
-
xt_regexp_append(out, length, capacity,
|
|
254
|
+
xt_regexp_append(out, length, capacity, textBytes + matches[i + 1].rm_so,
|
|
248
255
|
(size_t)(matches[i + 1].rm_eo - matches[i + 1].rm_so));
|
|
249
256
|
}
|
|
250
257
|
return;
|
|
@@ -255,32 +262,34 @@ static void xt_regexp_expand_replacement(char **out, size_t *length, size_t *cap
|
|
|
255
262
|
xt_string *replacement, xt_string *text,
|
|
256
263
|
regmatch_t *matches, int *groups, int groupCount,
|
|
257
264
|
int jsTotal) {
|
|
265
|
+
const char *repl = xt_string_bytes(replacement);
|
|
266
|
+
const char *textBytes = xt_string_bytes(text);
|
|
258
267
|
size_t start = (size_t)matches[0].rm_so;
|
|
259
268
|
size_t end = (size_t)matches[0].rm_eo;
|
|
260
269
|
for (size_t i = 0; i < replacement->length; i++) {
|
|
261
|
-
char c =
|
|
270
|
+
char c = repl[i];
|
|
262
271
|
if (c != '$' || i + 1 >= replacement->length) {
|
|
263
272
|
xt_regexp_append(out, length, capacity, &c, 1);
|
|
264
273
|
continue;
|
|
265
274
|
}
|
|
266
|
-
char next =
|
|
275
|
+
char next = repl[i + 1];
|
|
267
276
|
if (next == '$') {
|
|
268
277
|
xt_regexp_append(out, length, capacity, "$", 1);
|
|
269
278
|
i++;
|
|
270
279
|
} else if (next == '&') {
|
|
271
|
-
xt_regexp_append(out, length, capacity,
|
|
280
|
+
xt_regexp_append(out, length, capacity, textBytes + start, end - start);
|
|
272
281
|
i++;
|
|
273
282
|
} else if (next == '`') {
|
|
274
|
-
xt_regexp_append(out, length, capacity,
|
|
283
|
+
xt_regexp_append(out, length, capacity, textBytes, start);
|
|
275
284
|
i++;
|
|
276
285
|
} else if (next == '\'') {
|
|
277
|
-
xt_regexp_append(out, length, capacity,
|
|
286
|
+
xt_regexp_append(out, length, capacity, textBytes + end, text->length - end);
|
|
278
287
|
i++;
|
|
279
288
|
} else if (next >= '0' && next <= '9') {
|
|
280
289
|
int value = next - '0';
|
|
281
290
|
int digits = 1;
|
|
282
|
-
if (i + 2 < replacement->length &&
|
|
283
|
-
int two = value * 10 + (
|
|
291
|
+
if (i + 2 < replacement->length && repl[i + 2] >= '0' && repl[i + 2] <= '9') {
|
|
292
|
+
int two = value * 10 + (repl[i + 2] - '0');
|
|
284
293
|
if (two <= jsTotal) { value = two; digits = 2; }
|
|
285
294
|
}
|
|
286
295
|
if (value >= 1 && value <= jsTotal) {
|
|
@@ -299,6 +308,7 @@ static void xt_regexp_expand_replacement(char **out, size_t *length, size_t *cap
|
|
|
299
308
|
xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replacementValue) {
|
|
300
309
|
xt_string *text = xt_as_string(xt_to_string(value));
|
|
301
310
|
if (!text) return value;
|
|
311
|
+
const char *textBytes = xt_string_bytes(text);
|
|
302
312
|
int global = xt_regexp_is_global(regexpValue);
|
|
303
313
|
int useFunction = XT_IS_FUNCTION(replacementValue);
|
|
304
314
|
xt_string *replacement = NULL;
|
|
@@ -324,18 +334,18 @@ xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replac
|
|
|
324
334
|
if (!xt_regexp_run(regexpValue, value, cursor, matches, cap, groups, &groupCount)) break;
|
|
325
335
|
int32_t start = (int32_t)matches[0].rm_so;
|
|
326
336
|
int32_t end = (int32_t)matches[0].rm_eo;
|
|
327
|
-
xt_regexp_append(&out, &length, &capacity,
|
|
337
|
+
xt_regexp_append(&out, &length, &capacity, textBytes + cursor, (size_t)(start - cursor));
|
|
328
338
|
if (useFunction) {
|
|
329
339
|
/* Accumulate in an `xt_array` so the earlier match/group strings stay
|
|
330
340
|
reachable while later groups (and the callback itself) allocate. */
|
|
331
341
|
xt_value argArray = xt_array_new(0, NULL);
|
|
332
|
-
xt_array_push(argArray, xt_string_new(
|
|
342
|
+
xt_array_push(argArray, xt_string_new(textBytes + start, (int64_t)(end - start)));
|
|
333
343
|
for (int g = 1; g <= jsTotal; g++) {
|
|
334
344
|
xt_value groupValue = XT_UNDEFINED;
|
|
335
345
|
for (int i = 0; i < groupCount; i++) {
|
|
336
346
|
if (groups[i] != g) continue;
|
|
337
347
|
if (matches[i + 1].rm_so >= 0) {
|
|
338
|
-
groupValue = xt_string_new(
|
|
348
|
+
groupValue = xt_string_new(textBytes + matches[i + 1].rm_so, (int64_t)(matches[i + 1].rm_eo - matches[i + 1].rm_so));
|
|
339
349
|
}
|
|
340
350
|
break;
|
|
341
351
|
}
|
|
@@ -345,7 +355,7 @@ xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replac
|
|
|
345
355
|
xt_array_push(argArray, xt_to_string(value));
|
|
346
356
|
xt_value produced = xt_closure_call(replacementValue, jsTotal + 3, xt_as_array(argArray)->items);
|
|
347
357
|
xt_string *producedText = xt_as_string(xt_to_string(produced));
|
|
348
|
-
if (producedText) xt_regexp_append(&out, &length, &capacity, producedText
|
|
358
|
+
if (producedText) xt_regexp_append(&out, &length, &capacity, xt_string_bytes(producedText), producedText->length);
|
|
349
359
|
} else {
|
|
350
360
|
xt_regexp_expand_replacement(&out, &length, &capacity, replacement, text, matches, groups, groupCount, jsTotal);
|
|
351
361
|
}
|
|
@@ -355,7 +365,7 @@ xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replac
|
|
|
355
365
|
} else {
|
|
356
366
|
/* Zero-width match: copy one byte so the scan always progresses. */
|
|
357
367
|
if (cursor >= (int32_t)text->length) break;
|
|
358
|
-
xt_regexp_append(&out, &length, &capacity,
|
|
368
|
+
xt_regexp_append(&out, &length, &capacity, textBytes + cursor, 1);
|
|
359
369
|
cursor++;
|
|
360
370
|
}
|
|
361
371
|
if (!global) break;
|
|
@@ -367,7 +377,7 @@ xt_value xt_regexp_replace(xt_value value, xt_value regexpValue, xt_value replac
|
|
|
367
377
|
return value;
|
|
368
378
|
}
|
|
369
379
|
size_t tail = text->length - (size_t)cursor;
|
|
370
|
-
xt_regexp_append(&out, &length, &capacity,
|
|
380
|
+
xt_regexp_append(&out, &length, &capacity, textBytes + cursor, tail);
|
|
371
381
|
xt_value result = xt_string_new(out, (int64_t)length);
|
|
372
382
|
free(out);
|
|
373
383
|
free(matches);
|
|
@@ -381,6 +391,7 @@ xt_value xt_regexp_split(xt_value value, xt_value regexpValue, xt_value limitVal
|
|
|
381
391
|
xt_value result = xt_array_new(0, NULL);
|
|
382
392
|
xt_string *text = xt_as_string(xt_to_string(value));
|
|
383
393
|
if (!text) return result;
|
|
394
|
+
const char *textBytes = xt_string_bytes(text);
|
|
384
395
|
int64_t limit = limitValue == XT_UNDEFINED ? 0x7fffffff : (int64_t)xt_to_int32(limitValue);
|
|
385
396
|
if (limit <= 0) return result;
|
|
386
397
|
xt_regexp *regexp = (xt_regexp *)XT_GET_PTR(regexpValue);
|
|
@@ -400,14 +411,14 @@ xt_value xt_regexp_split(xt_value value, xt_value regexpValue, xt_value limitVal
|
|
|
400
411
|
int32_t end = (int32_t)matches[0].rm_eo;
|
|
401
412
|
if (start != q) { q++; continue; }
|
|
402
413
|
if (end == p) { q++; continue; }
|
|
403
|
-
xt_array_push(result, xt_string_new(
|
|
414
|
+
xt_array_push(result, xt_string_new(textBytes + p, (int64_t)(q - p)));
|
|
404
415
|
if ((int64_t)xt_as_array(result)->length >= limit) { free(matches); free(groups); return result; }
|
|
405
416
|
for (int g = 1; g <= jsTotal; g++) {
|
|
406
417
|
xt_value groupValue = XT_UNDEFINED;
|
|
407
418
|
for (int i = 0; i < groupCount; i++) {
|
|
408
419
|
if (groups[i] != g) continue;
|
|
409
420
|
if (matches[i + 1].rm_so >= 0) {
|
|
410
|
-
groupValue = xt_string_new(
|
|
421
|
+
groupValue = xt_string_new(textBytes + matches[i + 1].rm_so, (int64_t)(matches[i + 1].rm_eo - matches[i + 1].rm_so));
|
|
411
422
|
}
|
|
412
423
|
break;
|
|
413
424
|
}
|
|
@@ -418,7 +429,7 @@ xt_value xt_regexp_split(xt_value value, xt_value regexpValue, xt_value limitVal
|
|
|
418
429
|
q = p;
|
|
419
430
|
}
|
|
420
431
|
if ((int64_t)xt_as_array(result)->length < limit) {
|
|
421
|
-
xt_array_push(result, xt_string_new(
|
|
432
|
+
xt_array_push(result, xt_string_new(textBytes + p, (int64_t)(len - p)));
|
|
422
433
|
}
|
|
423
434
|
free(matches);
|
|
424
435
|
free(groups);
|
|
@@ -431,16 +442,20 @@ xt_value xt_regexp_get_property(xt_value target, xt_value key) {
|
|
|
431
442
|
if (!XT_IS_STRING(key)) return XT_UNDEFINED;
|
|
432
443
|
xt_string *k = xt_as_string(key);
|
|
433
444
|
xt_string *f = xt_as_string(regexp->flags);
|
|
445
|
+
const char *keyBytes = xt_string_bytes(k);
|
|
434
446
|
int flag = 0;
|
|
435
|
-
if (k->length == 6 && memcmp(
|
|
436
|
-
if (k->length == 5 && memcmp(
|
|
437
|
-
if (k->length == 9 && memcmp(
|
|
438
|
-
if (k->length == 6 && memcmp(
|
|
439
|
-
else if (k->length == 10 && memcmp(
|
|
440
|
-
else if (k->length == 9 && memcmp(
|
|
441
|
-
else if (k->length == 6 && memcmp(
|
|
447
|
+
if (k->length == 6 && memcmp(keyBytes, "source", 6) == 0) return regexp->source;
|
|
448
|
+
if (k->length == 5 && memcmp(keyBytes, "flags", 5) == 0) return regexp->flags;
|
|
449
|
+
if (k->length == 9 && memcmp(keyBytes, "lastIndex", 9) == 0) return xt_number(0);
|
|
450
|
+
if (k->length == 6 && memcmp(keyBytes, "global", 6) == 0) flag = 'g';
|
|
451
|
+
else if (k->length == 10 && memcmp(keyBytes, "ignoreCase", 10) == 0) flag = 'i';
|
|
452
|
+
else if (k->length == 9 && memcmp(keyBytes, "multiline", 9) == 0) flag = 'm';
|
|
453
|
+
else if (k->length == 6 && memcmp(keyBytes, "sticky", 6) == 0) flag = 'y';
|
|
442
454
|
if (flag) {
|
|
443
|
-
if (f)
|
|
455
|
+
if (f) {
|
|
456
|
+
const char *flags = xt_string_bytes(f);
|
|
457
|
+
for (uint32_t i = 0; i < f->length; i++) if (flags[i] == flag) return XT_TRUE;
|
|
458
|
+
}
|
|
444
459
|
return XT_FALSE;
|
|
445
460
|
}
|
|
446
461
|
return XT_UNDEFINED;
|