xbintsc 0.2.8 → 0.3.1
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 +17 -2
- package/README.zh-CN.md +16 -2
- package/bin/xbintsc.js +49 -10
- package/dist/src/ast/expressions.d.ts +2 -0
- package/dist/src/binder/binder.d.ts +24 -98
- package/dist/src/binder/binder.js +13 -559
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +16 -0
- package/dist/src/binder/declarations.js +168 -0
- package/dist/src/binder/declarations.js.map +1 -0
- package/dist/src/binder/helpers.d.ts +11 -0
- package/dist/src/binder/helpers.js +46 -0
- package/dist/src/binder/helpers.js.map +1 -0
- package/dist/src/binder/references.d.ts +21 -0
- package/dist/src/binder/references.js +349 -0
- package/dist/src/binder/references.js.map +1 -0
- package/dist/src/binder/types.d.ts +114 -0
- package/dist/src/binder/types.js +27 -0
- package/dist/src/binder/types.js.map +1 -0
- package/dist/src/cli/main.d.ts +1 -0
- package/dist/src/cli/main.js +40 -0
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +13 -0
- package/dist/src/codegen/generator/calls/access.js +115 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -0
- package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
- package/dist/src/codegen/generator/calls/closures.js +50 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -0
- package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
- package/dist/src/codegen/generator/calls/invocation.js +242 -0
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
- package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
- package/dist/src/codegen/generator/calls/literals.js +69 -0
- package/dist/src/codegen/generator/calls/literals.js.map +1 -0
- package/dist/src/codegen/generator/calls/super.d.ts +10 -0
- package/dist/src/codegen/generator/calls/super.js +47 -0
- package/dist/src/codegen/generator/calls/super.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +15 -24
- package/dist/src/codegen/generator/calls.js +15 -482
- package/dist/src/codegen/generator/calls.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +1 -1
- package/dist/src/codegen/generator/context.js +2 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
- package/dist/src/codegen/generator/expressions/assignment.js +203 -0
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
- package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
- package/dist/src/codegen/generator/expressions/operators.js +163 -0
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
- package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
- package/dist/src/codegen/generator/expressions/primary.js +260 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +11 -21
- package/dist/src/codegen/generator/expressions.js +11 -494
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +16 -4
- package/dist/src/codegen/generator/module.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/statements/control-flow.d.ts +14 -0
- package/dist/src/codegen/generator/statements/control-flow.js +199 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
- package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
- package/dist/src/codegen/generator/statements/dispatch.js +100 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
- package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
- package/dist/src/codegen/generator/statements/loops.js +152 -0
- package/dist/src/codegen/generator/statements/loops.js.map +1 -0
- package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
- package/dist/src/codegen/generator/statements/variables.js +146 -0
- package/dist/src/codegen/generator/statements/variables.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +13 -21
- package/dist/src/codegen/generator/statements.js +13 -568
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +7 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/codegen/values.d.ts +17 -17
- package/dist/src/codegen/values.js +21 -57
- package/dist/src/codegen/values.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +1 -0
- package/dist/src/diagnostics/diagnostic.js +1 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/diagnostics/source.d.ts +1 -1
- package/dist/src/diagnostics/source.js +7 -12
- package/dist/src/diagnostics/source.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +4 -0
- package/dist/src/driver/compiler.js +51 -16
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +5 -2
- package/dist/src/driver/index.js +5 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/paths.d.ts +20 -0
- package/dist/src/driver/paths.js +49 -0
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +18 -0
- package/dist/src/driver/runtime-lib.js +31 -0
- package/dist/src/driver/runtime-lib.js.map +1 -0
- package/dist/src/driver/toolchain-download.d.ts +50 -0
- package/dist/src/driver/toolchain-download.js +76 -0
- package/dist/src/driver/toolchain-download.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +33 -0
- package/dist/src/driver/toolchain-provider.js +71 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -0
- package/dist/src/driver/toolchain.d.ts +9 -4
- package/dist/src/driver/toolchain.js +6 -10
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +4 -2
- package/dist/src/extensions/node/child_process/index.js +4 -2
- package/dist/src/extensions/node/child_process/index.js.map +1 -1
- package/dist/src/extensions/node/events/index.d.ts +10 -0
- package/dist/src/extensions/node/events/index.js +22 -0
- package/dist/src/extensions/node/events/index.js.map +1 -0
- package/dist/src/extensions/node/index.js +6 -0
- package/dist/src/extensions/node/index.js.map +1 -1
- package/dist/src/extensions/node/querystring/index.d.ts +10 -0
- package/dist/src/extensions/node/querystring/index.js +25 -0
- package/dist/src/extensions/node/querystring/index.js.map +1 -0
- package/dist/src/extensions/node/util/index.d.ts +11 -0
- package/dist/src/extensions/node/util/index.js +41 -0
- package/dist/src/extensions/node/util/index.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +6 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
- package/dist/src/lexer/scanner/identifiers.js +33 -0
- package/dist/src/lexer/scanner/identifiers.js.map +1 -0
- package/dist/src/lexer/scanner/numbers.d.ts +10 -0
- package/dist/src/lexer/scanner/numbers.js +89 -0
- package/dist/src/lexer/scanner/numbers.js.map +1 -0
- package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
- package/dist/src/lexer/scanner/punctuation.js +151 -0
- package/dist/src/lexer/scanner/punctuation.js.map +1 -0
- package/dist/src/lexer/scanner/regex.d.ts +11 -0
- package/dist/src/lexer/scanner/regex.js +69 -0
- package/dist/src/lexer/scanner/regex.js.map +1 -0
- package/dist/src/lexer/scanner/strings.d.ts +13 -0
- package/dist/src/lexer/scanner/strings.js +118 -0
- package/dist/src/lexer/scanner/strings.js.map +1 -0
- package/dist/src/lexer/scanner.d.ts +20 -27
- package/dist/src/lexer/scanner.js +11 -415
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.d.ts +14 -0
- package/dist/src/parser/declarations/classes.js +191 -0
- package/dist/src/parser/declarations/classes.js.map +1 -0
- package/dist/src/parser/declarations/functions.d.ts +17 -0
- package/dist/src/parser/declarations/functions.js +241 -0
- package/dist/src/parser/declarations/functions.js.map +1 -0
- package/dist/src/parser/declarations/type-members.d.ts +16 -0
- package/dist/src/parser/declarations/type-members.js +156 -0
- package/dist/src/parser/declarations/type-members.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +13 -24
- package/dist/src/parser/declarations.js +13 -571
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/helpers.js +13 -4
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +10 -1
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +24 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +3 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/paths.test.d.ts +1 -0
- package/dist/tests/driver/paths.test.js +26 -0
- package/dist/tests/driver/paths.test.js.map +1 -0
- package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-download.test.js +38 -0
- package/dist/tests/driver/toolchain-download.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +37 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
- package/dist/tests/e2e/compile-node.test.d.ts +7 -0
- package/dist/tests/e2e/compile-node.test.js +123 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -0
- package/dist/tests/e2e/compile.test.d.ts +4 -1
- package/dist/tests/e2e/compile.test.js +90 -130
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.d.ts +36 -0
- package/dist/tests/e2e/harness.js +64 -0
- package/dist/tests/e2e/harness.js.map +1 -0
- package/dist/tests/e2e/node-modules.test.js +60 -0
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/extensions/registry.test.js +4 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/package.json +5 -3
- package/runtime/ext_node/buffer/buffer.c +12 -552
- package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
- package/runtime/ext_node/buffer/parts/construction.inc +60 -0
- package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
- package/runtime/ext_node/buffer/parts/methods.inc +135 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
- package/runtime/ext_node/buffer/parts/search.inc +86 -0
- package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
- package/runtime/ext_node/child_process/child_process.c +37 -3
- package/runtime/ext_node/events/events.c +285 -0
- package/runtime/ext_node/http/http.c +11 -736
- package/runtime/ext_node/http/parts/client.inc +290 -0
- package/runtime/ext_node/http/parts/helpers.inc +45 -0
- package/runtime/ext_node/http/parts/prototypes.inc +57 -0
- package/runtime/ext_node/http/parts/response.inc +149 -0
- package/runtime/ext_node/http/parts/server.inc +133 -0
- package/runtime/ext_node/http/parts/string-builder.inc +58 -0
- package/runtime/ext_node/net/net.c +12 -504
- package/runtime/ext_node/net/parts/construction.inc +22 -0
- package/runtime/ext_node/net/parts/platform.inc +60 -0
- package/runtime/ext_node/net/parts/prototypes.inc +35 -0
- package/runtime/ext_node/net/parts/read-loop.inc +58 -0
- package/runtime/ext_node/net/parts/server.inc +131 -0
- package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
- package/runtime/ext_node/net/parts/static-api.inc +93 -0
- package/runtime/ext_node/querystring/querystring.c +251 -0
- package/runtime/ext_node/util/util.c +456 -0
- package/runtime/rt.h +8 -2
- package/runtime/rt_internal.h +34 -0
- package/runtime/xt_bigint/arithmetic.inc +135 -0
- package/runtime/xt_bigint/bits.inc +98 -0
- package/runtime/xt_bigint/bitwise.inc +103 -0
- package/runtime/xt_bigint/compare.inc +30 -0
- package/runtime/xt_bigint/conversions.inc +51 -0
- package/runtime/xt_bigint/division.inc +85 -0
- package/runtime/xt_bigint/format.inc +145 -0
- package/runtime/xt_bigint/helpers.inc +92 -0
- package/runtime/xt_bigint/magnitude.inc +88 -0
- package/runtime/xt_bigint/public.inc +59 -0
- package/runtime/xt_bigint/small-arithmetic.inc +58 -0
- package/runtime/xt_bigint.c +42 -0
- package/runtime/xt_builtins.c +40 -5
- package/runtime/xt_io.c +7 -0
- package/runtime/xt_stdlib/arrays.inc +161 -0
- package/runtime/xt_stdlib/dispatch.inc +116 -0
- package/runtime/xt_stdlib/helpers.inc +23 -0
- package/runtime/xt_stdlib/math.inc +72 -0
- package/runtime/xt_stdlib/strings.inc +178 -0
- package/runtime/xt_stdlib.c +10 -549
- package/runtime/xt_stdlib2/array-statics.inc +37 -0
- package/runtime/xt_stdlib2/arrays.inc +189 -0
- package/runtime/xt_stdlib2/container.inc +23 -0
- package/runtime/xt_stdlib2/date.inc +72 -0
- package/runtime/xt_stdlib2/error.inc +22 -0
- package/runtime/xt_stdlib2/helpers.inc +43 -0
- package/runtime/xt_stdlib2/json.inc +213 -0
- package/runtime/xt_stdlib2/map.inc +95 -0
- package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
- package/runtime/xt_stdlib2/numbers.inc +38 -0
- package/runtime/xt_stdlib2/objects.inc +41 -0
- package/runtime/xt_stdlib2/regexp-match.inc +204 -0
- package/runtime/xt_stdlib2/regexp.inc +20 -0
- package/runtime/xt_stdlib2/set.inc +105 -0
- package/runtime/xt_stdlib2/strings.inc +94 -0
- package/runtime/xt_stdlib2.c +19 -1278
- package/runtime/xt_values.c +155 -12
- package/scripts/build-runtime.ts +109 -0
- package/scripts/fetch-toolchain.ts +101 -0
- package/scripts/package-release.ts +192 -0
- package/src/ast/expressions.ts +2 -0
- package/src/binder/binder.ts +40 -725
- package/src/binder/declarations.ts +203 -0
- package/src/binder/helpers.ts +47 -0
- package/src/binder/references.ts +410 -0
- package/src/binder/types.ts +134 -0
- package/src/cli/main.ts +43 -0
- package/src/codegen/generator/calls/access.ts +139 -0
- package/src/codegen/generator/calls/closures.ts +60 -0
- package/src/codegen/generator/calls/invocation.ts +282 -0
- package/src/codegen/generator/calls/literals.ts +77 -0
- package/src/codegen/generator/calls/super.ts +61 -0
- package/src/codegen/generator/calls.ts +30 -552
- package/src/codegen/generator/context.ts +2 -2
- package/src/codegen/generator/expressions/assignment.ts +226 -0
- package/src/codegen/generator/expressions/operators.ts +182 -0
- package/src/codegen/generator/expressions/primary.ts +304 -0
- package/src/codegen/generator/expressions.ts +22 -553
- package/src/codegen/generator/module.ts +14 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/statements/control-flow.ts +225 -0
- package/src/codegen/generator/statements/dispatch.ts +122 -0
- package/src/codegen/generator/statements/loops.ts +173 -0
- package/src/codegen/generator/statements/variables.ts +152 -0
- package/src/codegen/generator/statements.ts +26 -612
- package/src/codegen/generator/tables.ts +7 -0
- package/src/codegen/values.ts +22 -57
- package/src/diagnostics/diagnostic.ts +1 -0
- package/src/diagnostics/source.ts +7 -12
- package/src/driver/compiler.ts +61 -18
- package/src/driver/index.ts +17 -2
- package/src/driver/paths.ts +54 -0
- package/src/driver/runtime-lib.ts +32 -0
- package/src/driver/toolchain-download.ts +108 -0
- package/src/driver/toolchain-provider.ts +91 -0
- package/src/driver/toolchain.ts +29 -11
- package/src/extensions/node/child_process/index.ts +4 -2
- package/src/extensions/node/events/index.ts +27 -0
- package/src/extensions/node/index.ts +6 -0
- package/src/extensions/node/querystring/index.ts +29 -0
- package/src/extensions/node/util/index.ts +48 -0
- package/src/extensions/registry.ts +6 -0
- package/src/index.ts +1 -0
- package/src/lexer/scanner/identifiers.ts +37 -0
- package/src/lexer/scanner/numbers.ts +84 -0
- package/src/lexer/scanner/punctuation.ts +132 -0
- package/src/lexer/scanner/regex.ts +79 -0
- package/src/lexer/scanner/strings.ts +128 -0
- package/src/lexer/scanner.ts +35 -401
- package/src/parser/declarations/classes.ts +215 -0
- package/src/parser/declarations/functions.ts +254 -0
- package/src/parser/declarations/type-members.ts +181 -0
- package/src/parser/declarations.ts +32 -609
- package/src/parser/helpers.ts +13 -6
- package/src/parser/literals.ts +10 -1
- package/scripts/build-runtime.mjs +0 -55
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/* -- array methods -------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
static xt_value xt_array_at(xt_value value, xt_value indexValue) {
|
|
4
|
+
xt_array *array = xt_as_array(value);
|
|
5
|
+
if (!array) return XT_UNDEFINED;
|
|
6
|
+
int32_t index = indexValue == XT_UNDEFINED ? 0 : xt_to_int32(indexValue);
|
|
7
|
+
if (index < 0) index += (int32_t)array->length;
|
|
8
|
+
if (index < 0 || (uint32_t)index >= array->length) return XT_UNDEFINED;
|
|
9
|
+
return array->items[index];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static xt_value xt_array_find(xt_value value, xt_value fn, int mode) {
|
|
13
|
+
xt_array *array = xt_as_array(value);
|
|
14
|
+
if (!array) return (mode == 0 || mode == 2) ? XT_UNDEFINED : xt_number(-1);
|
|
15
|
+
int reverse = (mode == 2 || mode == 3);
|
|
16
|
+
for (uint32_t step = 0; step < array->length; step++) {
|
|
17
|
+
int32_t i = reverse ? (int32_t)(array->length - 1 - step) : (int32_t)step;
|
|
18
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
19
|
+
if (xt_truthy(xt_closure_call(fn, 3, args))) return (mode == 0 || mode == 2) ? array->items[i] : xt_number((double)i);
|
|
20
|
+
}
|
|
21
|
+
return (mode == 0 || mode == 2) ? XT_UNDEFINED : xt_number(-1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static xt_value xt_array_quantifier(xt_value value, xt_value fn, int every) {
|
|
25
|
+
xt_array *array = xt_as_array(value);
|
|
26
|
+
if (!array) return xt_bool(every ? 1 : 0);
|
|
27
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
28
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
29
|
+
int ok = xt_truthy(xt_closure_call(fn, 3, args));
|
|
30
|
+
if (every && !ok) return XT_FALSE;
|
|
31
|
+
if (!every && ok) return XT_TRUE;
|
|
32
|
+
}
|
|
33
|
+
return xt_bool(every ? 1 : 0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static int xt_array_compare_values(xt_value a, xt_value b) {
|
|
37
|
+
if (xt_truthy(xt_gt(a, b))) return 1;
|
|
38
|
+
if (xt_truthy(xt_lt(a, b))) return -1;
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static xt_value xt_array_sort(xt_value value, xt_value fn) {
|
|
43
|
+
xt_array *array = xt_as_array(value);
|
|
44
|
+
if (!array || array->length < 2) return value;
|
|
45
|
+
int hasFn = XT_IS_FUNCTION(fn);
|
|
46
|
+
for (uint32_t i = 1; i < array->length; i++) {
|
|
47
|
+
xt_value key = array->items[i];
|
|
48
|
+
int32_t j = (int32_t)i - 1;
|
|
49
|
+
while (j >= 0) {
|
|
50
|
+
int cmp;
|
|
51
|
+
if (hasFn) {
|
|
52
|
+
xt_value args[2] = {array->items[j], key};
|
|
53
|
+
cmp = (int)xt_to_number(xt_closure_call(fn, 2, args));
|
|
54
|
+
} else {
|
|
55
|
+
cmp = xt_array_compare_values(array->items[j], key);
|
|
56
|
+
}
|
|
57
|
+
if (cmp <= 0) break;
|
|
58
|
+
array->items[j + 1] = array->items[j];
|
|
59
|
+
j--;
|
|
60
|
+
}
|
|
61
|
+
array->items[j + 1] = key;
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static void xt_array_flatten_into(xt_value out, xt_value value, int depth) {
|
|
67
|
+
xt_array *array = xt_as_array(value);
|
|
68
|
+
if (!array) { xt_array_push(out, value); return; }
|
|
69
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
70
|
+
if (depth > 0 && XT_IS_ARRAY(array->items[i])) xt_array_flatten_into(out, array->items[i], depth - 1);
|
|
71
|
+
else xt_array_push(out, array->items[i]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static xt_value xt_array_flat_map(xt_value value, xt_value fn) {
|
|
76
|
+
xt_array *array = xt_as_array(value);
|
|
77
|
+
xt_value out = xt_array_new(0, NULL);
|
|
78
|
+
if (!array) return out;
|
|
79
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
80
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
81
|
+
xt_value mapped = xt_closure_call(fn, 3, args);
|
|
82
|
+
if (XT_IS_ARRAY(mapped)) {
|
|
83
|
+
xt_array *m = xt_as_array(mapped);
|
|
84
|
+
for (uint32_t j = 0; j < m->length; j++) xt_array_push(out, m->items[j]);
|
|
85
|
+
} else xt_array_push(out, mapped);
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static xt_value xt_array_last_index_of(xt_value value, xt_value needle, xt_value fromValue) {
|
|
91
|
+
xt_array *array = xt_as_array(value);
|
|
92
|
+
if (!array) return xt_number(-1);
|
|
93
|
+
int32_t from = fromValue == XT_UNDEFINED ? (int32_t)array->length - 1 : xt_to_int32(fromValue);
|
|
94
|
+
if (from < 0) from += (int32_t)array->length;
|
|
95
|
+
if (from >= (int32_t)array->length) from = (int32_t)array->length - 1;
|
|
96
|
+
for (int32_t i = from; i >= 0; i--) if (xt_value_equals(array->items[i], needle)) return xt_number((double)i);
|
|
97
|
+
return xt_number(-1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static xt_value xt_array_fill(xt_value value, xt_value fillValue, xt_value startValue, xt_value endValue) {
|
|
101
|
+
xt_array *array = xt_as_array(value);
|
|
102
|
+
if (!array) return value;
|
|
103
|
+
int32_t len = (int32_t)array->length;
|
|
104
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
105
|
+
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
106
|
+
if (start < 0) start += len;
|
|
107
|
+
if (end < 0) end += len;
|
|
108
|
+
if (start < 0) start = 0;
|
|
109
|
+
if (end > len) end = len;
|
|
110
|
+
for (int32_t i = start; i < end; i++) array->items[i] = fillValue;
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static xt_value xt_array_copy_within(xt_value value, xt_value targetValue, xt_value startValue, xt_value endValue) {
|
|
115
|
+
xt_array *array = xt_as_array(value);
|
|
116
|
+
if (!array) return value;
|
|
117
|
+
int32_t len = (int32_t)array->length;
|
|
118
|
+
int32_t target = xt_to_int32(targetValue == XT_UNDEFINED ? xt_number(0) : targetValue);
|
|
119
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
120
|
+
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
121
|
+
if (target < 0) target += len;
|
|
122
|
+
if (start < 0) start += len;
|
|
123
|
+
if (end < 0) end += len;
|
|
124
|
+
if (target < 0 || start < 0 || target >= len || start >= len) return value;
|
|
125
|
+
if (end > len) end = len;
|
|
126
|
+
int32_t count = end - start;
|
|
127
|
+
if (count > len - target) count = len - target;
|
|
128
|
+
if (count <= 0) return value;
|
|
129
|
+
memmove(array->items + target, array->items + start, sizeof(xt_value) * (size_t)count);
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
xt_value xt_ext_array_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
|
|
134
|
+
*handled = 1;
|
|
135
|
+
if (strcmp(method, "at") == 0) return xt_array_at(target, xt_arg_at(argc, argv, 0));
|
|
136
|
+
if (strcmp(method, "find") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 0);
|
|
137
|
+
if (strcmp(method, "findIndex") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 1);
|
|
138
|
+
if (strcmp(method, "findLast") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 2);
|
|
139
|
+
if (strcmp(method, "findLastIndex") == 0) return xt_array_find(target, xt_arg_at(argc, argv, 0), 3);
|
|
140
|
+
if (strcmp(method, "some") == 0) return xt_array_quantifier(target, xt_arg_at(argc, argv, 0), 0);
|
|
141
|
+
if (strcmp(method, "every") == 0) return xt_array_quantifier(target, xt_arg_at(argc, argv, 0), 1);
|
|
142
|
+
if (strcmp(method, "sort") == 0) return xt_array_sort(target, xt_arg_at(argc, argv, 0));
|
|
143
|
+
if (strcmp(method, "flat") == 0) {
|
|
144
|
+
double depth = xt_arg_at(argc, argv, 0) == XT_UNDEFINED ? 1 : xt_to_number(argv[0]);
|
|
145
|
+
if (depth < 0) depth = 0;
|
|
146
|
+
xt_value out = xt_array_new(0, NULL);
|
|
147
|
+
xt_array_flatten_into(out, target, (int)depth);
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
if (strcmp(method, "flatMap") == 0) return xt_array_flat_map(target, xt_arg_at(argc, argv, 0));
|
|
151
|
+
if (strcmp(method, "lastIndexOf") == 0) return xt_array_last_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
152
|
+
if (strcmp(method, "fill") == 0) return xt_array_fill(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), xt_arg_at(argc, argv, 2));
|
|
153
|
+
if (strcmp(method, "copyWithin") == 0) return xt_array_copy_within(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), xt_arg_at(argc, argv, 2));
|
|
154
|
+
if (strcmp(method, "reduceRight") == 0) {
|
|
155
|
+
xt_array *array = xt_as_array(target);
|
|
156
|
+
if (!array) return XT_UNDEFINED;
|
|
157
|
+
xt_value fn = xt_arg_at(argc, argv, 0);
|
|
158
|
+
int32_t i = (int32_t)array->length - 1;
|
|
159
|
+
xt_value acc;
|
|
160
|
+
if (argc >= 2) acc = argv[1];
|
|
161
|
+
else if (array->length > 0) acc = array->items[i--];
|
|
162
|
+
else { xt_throw(xt_string_from_cstr("TypeError: Reduce of empty array with no initial value")); return XT_UNDEFINED; }
|
|
163
|
+
for (; i >= 0; i--) {
|
|
164
|
+
xt_value args[4] = {acc, array->items[i], xt_number((double)i), target};
|
|
165
|
+
acc = xt_closure_call(fn, 4, args);
|
|
166
|
+
}
|
|
167
|
+
return acc;
|
|
168
|
+
}
|
|
169
|
+
if (strcmp(method, "toString") == 0) return xt_call_method(target, xt_string_from_cstr("join"), 0, NULL);
|
|
170
|
+
if (strcmp(method, "keys") == 0 || strcmp(method, "values") == 0 || strcmp(method, "entries") == 0) {
|
|
171
|
+
xt_array *array = xt_as_array(target);
|
|
172
|
+
xt_value out = xt_array_new(0, NULL);
|
|
173
|
+
if (!array) return out;
|
|
174
|
+
int key = strcmp(method, "keys") == 0;
|
|
175
|
+
int entries = strcmp(method, "entries") == 0;
|
|
176
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
177
|
+
if (entries) {
|
|
178
|
+
xt_value pair = xt_array_new(0, NULL);
|
|
179
|
+
xt_array_push(pair, xt_number((double)i));
|
|
180
|
+
xt_array_push(pair, array->items[i]);
|
|
181
|
+
xt_array_push(out, pair);
|
|
182
|
+
} else if (key) xt_array_push(out, xt_number((double)i));
|
|
183
|
+
else xt_array_push(out, array->items[i]);
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
*handled = 0;
|
|
188
|
+
return XT_UNDEFINED;
|
|
189
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
xt_value xt_ext_container_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
|
|
2
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(target);
|
|
3
|
+
if (obj->header.kind == XT_OBJECT_KIND_MAP) return xt_map_method(target, method, argc, argv, handled);
|
|
4
|
+
if (obj->header.kind == XT_OBJECT_KIND_SET) return xt_set_method(target, method, argc, argv, handled);
|
|
5
|
+
if (obj->header.kind == XT_OBJECT_KIND_DATE) return xt_date_method(target, method, argc, argv, handled);
|
|
6
|
+
if (obj->header.kind == XT_OBJECT_KIND_REGEXP) {
|
|
7
|
+
xt_regexp *regexp = (xt_regexp *)obj;
|
|
8
|
+
*handled = 1;
|
|
9
|
+
if (strcmp(method, "test") == 0) return xt_regexp_test(target, xt_arg_at(argc, argv, 0));
|
|
10
|
+
if (strcmp(method, "exec") == 0) return xt_regexp_exec(target, xt_arg_at(argc, argv, 0));
|
|
11
|
+
if (strcmp(method, "toString") == 0) {
|
|
12
|
+
xt_value out = xt_string_from_cstr("/");
|
|
13
|
+
out = xt_add(out, regexp->source);
|
|
14
|
+
out = xt_add(out, xt_string_from_cstr("/"));
|
|
15
|
+
out = xt_add(out, regexp->flags);
|
|
16
|
+
return out;
|
|
17
|
+
}
|
|
18
|
+
*handled = 0;
|
|
19
|
+
return XT_UNDEFINED;
|
|
20
|
+
}
|
|
21
|
+
*handled = 0;
|
|
22
|
+
return XT_UNDEFINED;
|
|
23
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/* -- Date ----------------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
int xt_is_date(xt_value value) {
|
|
4
|
+
return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_DATE;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
xt_value xt_date_ctor(int32_t argc, xt_value *argv) {
|
|
8
|
+
xt_date *date = (xt_date *)xt_alloc(sizeof(xt_date), XT_OBJECT_KIND_DATE);
|
|
9
|
+
if (argc == 0) date->time = (double)time(NULL) * 1000.0;
|
|
10
|
+
else if (argc == 1) date->time = XT_IS_STRING(argv[0]) ? 0.0 : xt_to_number(argv[0]);
|
|
11
|
+
else {
|
|
12
|
+
struct tm tm;
|
|
13
|
+
memset(&tm, 0, sizeof(tm));
|
|
14
|
+
tm.tm_year = xt_to_int32(argv[0]) - 1900;
|
|
15
|
+
tm.tm_mon = xt_to_int32(argv[1]);
|
|
16
|
+
tm.tm_mday = argc > 2 ? xt_to_int32(argv[2]) : 1;
|
|
17
|
+
tm.tm_hour = argc > 3 ? xt_to_int32(argv[3]) : 0;
|
|
18
|
+
tm.tm_min = argc > 4 ? xt_to_int32(argv[4]) : 0;
|
|
19
|
+
tm.tm_sec = argc > 5 ? xt_to_int32(argv[5]) : 0;
|
|
20
|
+
tm.tm_isdst = -1;
|
|
21
|
+
date->time = (double)mktime(&tm) * 1000.0;
|
|
22
|
+
}
|
|
23
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, date);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
xt_value xt_date_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
27
|
+
const char *fn = xt_string_data(name);
|
|
28
|
+
if (!fn) return XT_UNDEFINED;
|
|
29
|
+
if (strcmp(fn, "now") == 0) return xt_number((double)time(NULL) * 1000.0);
|
|
30
|
+
if (strcmp(fn, "parse") == 0) return xt_number(0);
|
|
31
|
+
if (strcmp(fn, "UTC") == 0) {
|
|
32
|
+
struct tm tm;
|
|
33
|
+
memset(&tm, 0, sizeof(tm));
|
|
34
|
+
tm.tm_year = xt_to_int32(xt_arg_at(argc, argv, 0)) - 1900;
|
|
35
|
+
tm.tm_mon = xt_to_int32(xt_arg_at(argc, argv, 1));
|
|
36
|
+
tm.tm_mday = argc > 2 ? xt_to_int32(xt_arg_at(argc, argv, 2)) : 1;
|
|
37
|
+
return xt_number((double)xt_timegm(&tm) * 1000.0);
|
|
38
|
+
}
|
|
39
|
+
return XT_UNDEFINED;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static xt_value xt_date_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
|
|
43
|
+
*handled = 1;
|
|
44
|
+
xt_date *date = (xt_date *)XT_GET_PTR(target);
|
|
45
|
+
time_t seconds = (time_t)(date->time / 1000.0);
|
|
46
|
+
struct tm tm;
|
|
47
|
+
xt_gmtime_r(&seconds, &tm);
|
|
48
|
+
if (strcmp(method, "getTime") == 0 || strcmp(method, "valueOf") == 0) return xt_number(date->time);
|
|
49
|
+
const char *name = method;
|
|
50
|
+
char utc[32];
|
|
51
|
+
if (strncmp(method, "getUTC", 6) == 0) {
|
|
52
|
+
snprintf(utc, sizeof(utc), "get%s", method + 6);
|
|
53
|
+
name = utc;
|
|
54
|
+
}
|
|
55
|
+
if (strcmp(name, "getFullYear") == 0) return xt_number(tm.tm_year + 1900);
|
|
56
|
+
if (strcmp(name, "getMonth") == 0) return xt_number(tm.tm_mon);
|
|
57
|
+
if (strcmp(name, "getDate") == 0) return xt_number(tm.tm_mday);
|
|
58
|
+
if (strcmp(name, "getDay") == 0) return xt_number(tm.tm_wday);
|
|
59
|
+
if (strcmp(name, "getHours") == 0) return xt_number(tm.tm_hour);
|
|
60
|
+
if (strcmp(name, "getMinutes") == 0) return xt_number(tm.tm_min);
|
|
61
|
+
if (strcmp(name, "getSeconds") == 0) return xt_number(tm.tm_sec);
|
|
62
|
+
if (strcmp(name, "getMilliseconds") == 0) return xt_number(fmod(date->time, 1000.0));
|
|
63
|
+
if (strcmp(method, "toISOString") == 0) {
|
|
64
|
+
char buffer[64];
|
|
65
|
+
snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", tm.tm_year + 1900, tm.tm_mon + 1,
|
|
66
|
+
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)fmod(date->time, 1000.0));
|
|
67
|
+
return xt_string_from_cstr(buffer);
|
|
68
|
+
}
|
|
69
|
+
if (strcmp(method, "toJSON") == 0 || strcmp(method, "toString") == 0) return xt_call_method(target, xt_string_from_cstr("toISOString"), 0, NULL);
|
|
70
|
+
*handled = 0;
|
|
71
|
+
return XT_UNDEFINED;
|
|
72
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
xt_value xt_error_ctor(int32_t argc, xt_value *argv) {
|
|
2
|
+
xt_value error = xt_object_new();
|
|
3
|
+
xt_value name = xt_arg_at(argc, argv, 1);
|
|
4
|
+
xt_value message = xt_arg_at(argc, argv, 0);
|
|
5
|
+
xt_object_set(error, xt_string_from_cstr("name"),
|
|
6
|
+
name == XT_UNDEFINED ? xt_string_from_cstr("Error") : name);
|
|
7
|
+
xt_object_set(error, xt_string_from_cstr("message"),
|
|
8
|
+
message == XT_UNDEFINED ? xt_string_from_cstr("") : message);
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* `super(message)` inside a subclass of the builtin `Error`: initialize the
|
|
13
|
+
* already-allocated instance instead of creating a fresh object. */
|
|
14
|
+
xt_value xt_error_init(xt_value thisValue, int32_t argc, xt_value *argv) {
|
|
15
|
+
xt_value name = xt_arg_at(argc, argv, 1);
|
|
16
|
+
xt_value message = xt_arg_at(argc, argv, 0);
|
|
17
|
+
xt_object_set(thisValue, xt_string_from_cstr("name"),
|
|
18
|
+
name == XT_UNDEFINED ? xt_string_from_cstr("Error") : name);
|
|
19
|
+
xt_object_set(thisValue, xt_string_from_cstr("message"),
|
|
20
|
+
message == XT_UNDEFINED ? xt_string_from_cstr("") : message);
|
|
21
|
+
return thisValue;
|
|
22
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `timegm` and `gmtime_r` are POSIX extensions that Windows' CRT does not
|
|
3
|
+
* provide. MinGW-w64 (the bundled Windows toolchain) is affected too: its
|
|
4
|
+
* <time.h> only exposes `gmtime_r` when `_POSIX_C_SOURCE` is set and has no
|
|
5
|
+
* `timegm` at all, so wrap the MSVC-style equivalents for every `_WIN32` build.
|
|
6
|
+
*/
|
|
7
|
+
#if defined(_WIN32)
|
|
8
|
+
static time_t xt_timegm(struct tm *tm) { return (time_t)_mkgmtime64(tm); }
|
|
9
|
+
static struct tm *xt_gmtime_r(const time_t *timer, struct tm *buf) {
|
|
10
|
+
return gmtime_s(buf, timer) == 0 ? buf : NULL;
|
|
11
|
+
}
|
|
12
|
+
#else
|
|
13
|
+
static time_t xt_timegm(struct tm *tm) { return timegm(tm); }
|
|
14
|
+
static struct tm *xt_gmtime_r(const time_t *timer, struct tm *buf) { return gmtime_r(timer, buf); }
|
|
15
|
+
#endif
|
|
16
|
+
|
|
17
|
+
int xt_value_equals(xt_value a, xt_value b) {
|
|
18
|
+
if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
|
|
19
|
+
double x = xt_to_double(a);
|
|
20
|
+
double y = xt_to_double(b);
|
|
21
|
+
if (isnan(x) && isnan(y)) return 1;
|
|
22
|
+
return x == y;
|
|
23
|
+
}
|
|
24
|
+
return xt_truthy(xt_seq(a, b));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static xt_value xt_number_to_radix(double value, int radix) {
|
|
28
|
+
if (radix < 2 || radix > 36 || value != floor(value) || fabs(value) > 9.0e15) {
|
|
29
|
+
return xt_to_string(xt_number(value));
|
|
30
|
+
}
|
|
31
|
+
int negative = value < 0;
|
|
32
|
+
unsigned long long n = (unsigned long long)(negative ? -value : value);
|
|
33
|
+
static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
34
|
+
char buffer[80];
|
|
35
|
+
int pos = 0;
|
|
36
|
+
if (n == 0) buffer[pos++] = '0';
|
|
37
|
+
while (n > 0) { buffer[pos++] = digits[n % (unsigned)radix]; n /= (unsigned)radix; }
|
|
38
|
+
char out[80];
|
|
39
|
+
int o = 0;
|
|
40
|
+
if (negative) out[o++] = '-';
|
|
41
|
+
while (pos > 0) out[o++] = buffer[--pos];
|
|
42
|
+
return xt_string_new(out, (size_t)o);
|
|
43
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* -- JSON ----------------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
typedef struct { const char *data; size_t length; size_t pos; } xt_json_cursor;
|
|
4
|
+
|
|
5
|
+
static void xt_json_skip_ws(xt_json_cursor *c) {
|
|
6
|
+
while (c->pos < c->length) {
|
|
7
|
+
char ch = c->data[c->pos];
|
|
8
|
+
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') c->pos++;
|
|
9
|
+
else break;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static xt_value xt_json_parse_value(xt_json_cursor *c);
|
|
14
|
+
|
|
15
|
+
static xt_value xt_json_parse_string(xt_json_cursor *c) {
|
|
16
|
+
c->pos++;
|
|
17
|
+
size_t capacity = 32, length = 0;
|
|
18
|
+
char *out = (char *)malloc(capacity);
|
|
19
|
+
if (!out) abort();
|
|
20
|
+
while (c->pos < c->length) {
|
|
21
|
+
char ch = c->data[c->pos++];
|
|
22
|
+
if (ch == '"') break;
|
|
23
|
+
if (ch == '\\' && c->pos < c->length) {
|
|
24
|
+
char esc = c->data[c->pos++];
|
|
25
|
+
if (esc == 'n') ch = '\n';
|
|
26
|
+
else if (esc == 't') ch = '\t';
|
|
27
|
+
else if (esc == 'r') ch = '\r';
|
|
28
|
+
else if (esc == 'b') ch = '\b';
|
|
29
|
+
else if (esc == 'f') ch = '\f';
|
|
30
|
+
else if (esc == 'u') {
|
|
31
|
+
unsigned code = 0;
|
|
32
|
+
for (int i = 0; i < 4 && c->pos < c->length; i++) {
|
|
33
|
+
char h = c->data[c->pos++];
|
|
34
|
+
code <<= 4;
|
|
35
|
+
if (h >= '0' && h <= '9') code |= (unsigned)(h - '0');
|
|
36
|
+
else if (h >= 'a' && h <= 'f') code |= (unsigned)(h - 'a' + 10);
|
|
37
|
+
else if (h >= 'A' && h <= 'F') code |= (unsigned)(h - 'A' + 10);
|
|
38
|
+
}
|
|
39
|
+
if (code >= 0x80) {
|
|
40
|
+
char tmp[4];
|
|
41
|
+
int bytes = 0;
|
|
42
|
+
if (code < 0x800) { tmp[bytes++] = (char)(0xC0 | (code >> 6)); tmp[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
43
|
+
else { tmp[bytes++] = (char)(0xE0 | (code >> 12)); tmp[bytes++] = (char)(0x80 | ((code >> 6) & 0x3F)); tmp[bytes++] = (char)(0x80 | (code & 0x3F)); }
|
|
44
|
+
if (length + (size_t)bytes + 1 > capacity) { capacity = (length + (size_t)bytes + 1) * 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
|
|
45
|
+
memcpy(out + length, tmp, (size_t)bytes);
|
|
46
|
+
length += (size_t)bytes;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
ch = (char)code;
|
|
50
|
+
} else ch = esc;
|
|
51
|
+
}
|
|
52
|
+
if (length + 2 > capacity) { capacity *= 2; out = (char *)realloc(out, capacity); if (!out) abort(); }
|
|
53
|
+
out[length++] = ch;
|
|
54
|
+
}
|
|
55
|
+
xt_value result = xt_string_new(out, length);
|
|
56
|
+
free(out);
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static xt_value xt_json_parse_number(xt_json_cursor *c) {
|
|
61
|
+
size_t start = c->pos;
|
|
62
|
+
if (c->pos < c->length && (c->data[c->pos] == '-' || c->data[c->pos] == '+')) c->pos++;
|
|
63
|
+
while (c->pos < c->length && (isdigit((unsigned char)c->data[c->pos]) || c->data[c->pos] == '.' ||
|
|
64
|
+
c->data[c->pos] == 'e' || c->data[c->pos] == 'E' ||
|
|
65
|
+
c->data[c->pos] == '+' || c->data[c->pos] == '-')) c->pos++;
|
|
66
|
+
char buffer[64];
|
|
67
|
+
size_t n = c->pos - start;
|
|
68
|
+
if (n >= sizeof(buffer)) n = sizeof(buffer) - 1;
|
|
69
|
+
memcpy(buffer, c->data + start, n);
|
|
70
|
+
buffer[n] = '\0';
|
|
71
|
+
return xt_number(strtod(buffer, NULL));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static xt_value xt_json_parse_value(xt_json_cursor *c) {
|
|
75
|
+
xt_json_skip_ws(c);
|
|
76
|
+
if (c->pos >= c->length) return XT_UNDEFINED;
|
|
77
|
+
char ch = c->data[c->pos];
|
|
78
|
+
if (ch == '"') return xt_json_parse_string(c);
|
|
79
|
+
if (ch == '{') {
|
|
80
|
+
c->pos++;
|
|
81
|
+
xt_value object = xt_object_new();
|
|
82
|
+
xt_json_skip_ws(c);
|
|
83
|
+
if (c->pos < c->length && c->data[c->pos] == '}') { c->pos++; return object; }
|
|
84
|
+
for (;;) {
|
|
85
|
+
xt_json_skip_ws(c);
|
|
86
|
+
if (c->pos >= c->length || c->data[c->pos] != '"') break;
|
|
87
|
+
xt_value key = xt_json_parse_string(c);
|
|
88
|
+
xt_json_skip_ws(c);
|
|
89
|
+
if (c->pos < c->length && c->data[c->pos] == ':') c->pos++;
|
|
90
|
+
xt_value value = xt_json_parse_value(c);
|
|
91
|
+
xt_object_set(object, key, value);
|
|
92
|
+
xt_json_skip_ws(c);
|
|
93
|
+
if (c->pos < c->length && c->data[c->pos] == ',') { c->pos++; continue; }
|
|
94
|
+
if (c->pos < c->length && c->data[c->pos] == '}') c->pos++;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
return object;
|
|
98
|
+
}
|
|
99
|
+
if (ch == '[') {
|
|
100
|
+
c->pos++;
|
|
101
|
+
xt_value array = xt_array_new(0, NULL);
|
|
102
|
+
xt_json_skip_ws(c);
|
|
103
|
+
if (c->pos < c->length && c->data[c->pos] == ']') { c->pos++; return array; }
|
|
104
|
+
for (;;) {
|
|
105
|
+
xt_array_push(array, xt_json_parse_value(c));
|
|
106
|
+
xt_json_skip_ws(c);
|
|
107
|
+
if (c->pos < c->length && c->data[c->pos] == ',') { c->pos++; continue; }
|
|
108
|
+
if (c->pos < c->length && c->data[c->pos] == ']') c->pos++;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
return array;
|
|
112
|
+
}
|
|
113
|
+
if (c->pos + 4 <= c->length && memcmp(c->data + c->pos, "true", 4) == 0) { c->pos += 4; return XT_TRUE; }
|
|
114
|
+
if (c->pos + 5 <= c->length && memcmp(c->data + c->pos, "false", 5) == 0) { c->pos += 5; return XT_FALSE; }
|
|
115
|
+
if (c->pos + 4 <= c->length && memcmp(c->data + c->pos, "null", 4) == 0) { c->pos += 4; return XT_NULL; }
|
|
116
|
+
return xt_json_parse_number(c);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
xt_value xt_json_parse(int32_t argc, xt_value *argv) {
|
|
120
|
+
xt_value input = xt_to_string(xt_arg_at(argc, argv, 0));
|
|
121
|
+
xt_string *s = xt_as_string(input);
|
|
122
|
+
if (!s) return XT_UNDEFINED;
|
|
123
|
+
xt_json_cursor cursor = {s->data, s->length, 0};
|
|
124
|
+
return xt_json_parse_value(&cursor);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_value *out);
|
|
128
|
+
|
|
129
|
+
static void xt_json_indent(xt_value *out, int indent, int depth) {
|
|
130
|
+
if (indent <= 0) return;
|
|
131
|
+
*out = xt_add(*out, xt_string_from_cstr("\n"));
|
|
132
|
+
for (int i = 0; i < indent * depth; i++) *out = xt_add(*out, xt_string_from_cstr(" "));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static void xt_json_stringify_array(xt_value value, int indent, int depth, xt_value *out) {
|
|
136
|
+
xt_array *array = xt_as_array(value);
|
|
137
|
+
if (!array || array->length == 0) { *out = xt_add(*out, xt_string_from_cstr("[]")); return; }
|
|
138
|
+
*out = xt_add(*out, xt_string_from_cstr("["));
|
|
139
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
140
|
+
if (i > 0) *out = xt_add(*out, xt_string_from_cstr(","));
|
|
141
|
+
xt_json_indent(out, indent, depth + 1);
|
|
142
|
+
xt_json_stringify_value(array->items[i], indent, depth + 1, out);
|
|
143
|
+
}
|
|
144
|
+
xt_json_indent(out, indent, depth);
|
|
145
|
+
*out = xt_add(*out, xt_string_from_cstr("]"));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static void xt_json_stringify_object(xt_value value, int indent, int depth, xt_value *out) {
|
|
149
|
+
xt_value keys = xt_object_keys(value);
|
|
150
|
+
xt_array *array = xt_as_array(keys);
|
|
151
|
+
if (!array || array->length == 0) { *out = xt_add(*out, xt_string_from_cstr("{}")); return; }
|
|
152
|
+
*out = xt_add(*out, xt_string_from_cstr("{"));
|
|
153
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
154
|
+
if (i > 0) *out = xt_add(*out, xt_string_from_cstr(","));
|
|
155
|
+
xt_json_indent(out, indent, depth + 1);
|
|
156
|
+
xt_value key = array->items[i];
|
|
157
|
+
*out = xt_add(*out, xt_string_from_cstr("\""));
|
|
158
|
+
*out = xt_add(*out, key);
|
|
159
|
+
*out = xt_add(*out, xt_string_from_cstr("\":"));
|
|
160
|
+
if (indent > 0) *out = xt_add(*out, xt_string_from_cstr(" "));
|
|
161
|
+
xt_json_stringify_value(xt_object_get(value, key), indent, depth + 1, out);
|
|
162
|
+
}
|
|
163
|
+
xt_json_indent(out, indent, depth);
|
|
164
|
+
*out = xt_add(*out, xt_string_from_cstr("}"));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static void xt_json_stringify_value(xt_value value, int indent, int depth, xt_value *out) {
|
|
168
|
+
if (value == XT_UNDEFINED || value == XT_NULL || XT_IS_FUNCTION(value)) {
|
|
169
|
+
*out = xt_add(*out, xt_string_from_cstr("null"));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (XT_IS_BIGINT(value)) {
|
|
173
|
+
xt_throw(xt_string_from_cstr("TypeError: Do not know how to serialize a BigInt"));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (XT_IS_BOOL(value)) { *out = xt_add(*out, value == XT_TRUE ? xt_string_from_cstr("true") : xt_string_from_cstr("false")); return; }
|
|
177
|
+
if (XT_IS_NUMBER(value)) {
|
|
178
|
+
double d = xt_to_double(value);
|
|
179
|
+
if (!isfinite(d)) *out = xt_add(*out, xt_string_from_cstr("null"));
|
|
180
|
+
else *out = xt_add(*out, xt_to_string(value));
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (XT_IS_STRING(value)) {
|
|
184
|
+
xt_string *s = xt_as_string(value);
|
|
185
|
+
*out = xt_add(*out, xt_string_from_cstr("\""));
|
|
186
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
187
|
+
char ch = s->data[i];
|
|
188
|
+
if (ch == '"') *out = xt_add(*out, xt_string_from_cstr("\\\""));
|
|
189
|
+
else if (ch == '\\') *out = xt_add(*out, xt_string_from_cstr("\\\\"));
|
|
190
|
+
else if (ch == '\n') *out = xt_add(*out, xt_string_from_cstr("\\n"));
|
|
191
|
+
else if (ch == '\r') *out = xt_add(*out, xt_string_from_cstr("\\r"));
|
|
192
|
+
else if (ch == '\t') *out = xt_add(*out, xt_string_from_cstr("\\t"));
|
|
193
|
+
else *out = xt_add(*out, xt_string_new(&ch, 1));
|
|
194
|
+
}
|
|
195
|
+
*out = xt_add(*out, xt_string_from_cstr("\""));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (XT_IS_ARRAY(value)) { xt_json_stringify_array(value, indent, depth, out); return; }
|
|
199
|
+
if (XT_IS_OBJECT(value)) { xt_json_stringify_object(value, indent, depth, out); return; }
|
|
200
|
+
*out = xt_add(*out, xt_string_from_cstr("null"));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
xt_value xt_json_stringify(int32_t argc, xt_value *argv) {
|
|
204
|
+
int indent = 0;
|
|
205
|
+
xt_value space = xt_arg_at(argc, argv, 1);
|
|
206
|
+
if (XT_IS_NUMBER(space)) indent = xt_to_int32(space);
|
|
207
|
+
else if (XT_IS_STRING(space)) indent = (int)((xt_string *)XT_GET_PTR(space))->length;
|
|
208
|
+
if (indent < 0) indent = 0;
|
|
209
|
+
if (indent > 10) indent = 10;
|
|
210
|
+
xt_value out = xt_string_from_cstr("");
|
|
211
|
+
xt_json_stringify_value(xt_arg_at(argc, argv, 0), indent, 0, &out);
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* -- Map ------------------------------------------------------------------ */
|
|
2
|
+
|
|
3
|
+
int xt_is_map(xt_value value) {
|
|
4
|
+
return XT_IS_OBJECT(value) && ((xt_object *)XT_GET_PTR(value))->header.kind == XT_OBJECT_KIND_MAP;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
int32_t xt_map_size(xt_value value) {
|
|
8
|
+
if (!xt_is_map(value)) return 0;
|
|
9
|
+
return (int32_t)((xt_map *)XT_GET_PTR(value))->count;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static int32_t xt_map_index(xt_map *map, xt_value key) {
|
|
13
|
+
for (uint32_t i = 0; i < map->count; i++) if (xt_value_equals(map->keys[i], key)) return (int32_t)i;
|
|
14
|
+
return -1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static void xt_map_set(xt_map *map, xt_value key, xt_value value) {
|
|
18
|
+
int32_t index = xt_map_index(map, key);
|
|
19
|
+
if (index >= 0) { map->values[index] = value; return; }
|
|
20
|
+
if (map->count >= map->capacity) {
|
|
21
|
+
uint32_t capacity = map->capacity == 0 ? 8 : map->capacity * 2;
|
|
22
|
+
map->keys = (xt_value *)realloc(map->keys, sizeof(xt_value) * capacity);
|
|
23
|
+
map->values = (xt_value *)realloc(map->values, sizeof(xt_value) * capacity);
|
|
24
|
+
if (!map->keys || !map->values) abort();
|
|
25
|
+
map->capacity = capacity;
|
|
26
|
+
}
|
|
27
|
+
map->keys[map->count] = key;
|
|
28
|
+
map->values[map->count] = value;
|
|
29
|
+
map->count++;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static int xt_map_delete(xt_map *map, xt_value key) {
|
|
33
|
+
int32_t index = xt_map_index(map, key);
|
|
34
|
+
if (index < 0) return 0;
|
|
35
|
+
for (uint32_t i = (uint32_t)index + 1; i < map->count; i++) {
|
|
36
|
+
map->keys[i - 1] = map->keys[i];
|
|
37
|
+
map->values[i - 1] = map->values[i];
|
|
38
|
+
}
|
|
39
|
+
map->count--;
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
xt_value xt_map_ctor(int32_t argc, xt_value *argv) {
|
|
44
|
+
xt_map *map = (xt_map *)xt_alloc(sizeof(xt_map), XT_OBJECT_KIND_MAP);
|
|
45
|
+
map->keys = NULL; map->values = NULL; map->count = 0; map->capacity = 0;
|
|
46
|
+
xt_value iterable = xt_arg_at(argc, argv, 0);
|
|
47
|
+
if (XT_IS_ARRAY(iterable)) {
|
|
48
|
+
xt_array *array = xt_as_array(iterable);
|
|
49
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
50
|
+
xt_array *pair = xt_as_array(array->items[i]);
|
|
51
|
+
if (pair && pair->length >= 2) xt_map_set(map, pair->items[0], pair->items[1]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, map);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static xt_value xt_map_method(xt_value target, const char *method, int32_t argc, xt_value *argv, int *handled) {
|
|
58
|
+
*handled = 1;
|
|
59
|
+
xt_map *map = (xt_map *)XT_GET_PTR(target);
|
|
60
|
+
if (strcmp(method, "set") == 0) { xt_map_set(map, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1)); return target; }
|
|
61
|
+
if (strcmp(method, "get") == 0) {
|
|
62
|
+
int32_t index = xt_map_index(map, xt_arg_at(argc, argv, 0));
|
|
63
|
+
return index >= 0 ? map->values[index] : XT_UNDEFINED;
|
|
64
|
+
}
|
|
65
|
+
if (strcmp(method, "has") == 0) return xt_bool(xt_map_index(map, xt_arg_at(argc, argv, 0)) >= 0);
|
|
66
|
+
if (strcmp(method, "delete") == 0) return xt_bool(xt_map_delete(map, xt_arg_at(argc, argv, 0)));
|
|
67
|
+
if (strcmp(method, "clear") == 0) { map->count = 0; return XT_UNDEFINED; }
|
|
68
|
+
if (strcmp(method, "forEach") == 0) {
|
|
69
|
+
xt_value fn = xt_arg_at(argc, argv, 0);
|
|
70
|
+
for (uint32_t i = 0; i < map->count; i++) { xt_value args[3] = {map->values[i], map->keys[i], target}; xt_closure_call(fn, 3, args); }
|
|
71
|
+
return XT_UNDEFINED;
|
|
72
|
+
}
|
|
73
|
+
if (strcmp(method, "keys") == 0) {
|
|
74
|
+
xt_value out = xt_array_new(0, NULL);
|
|
75
|
+
for (uint32_t i = 0; i < map->count; i++) xt_array_push(out, map->keys[i]);
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
if (strcmp(method, "values") == 0) {
|
|
79
|
+
xt_value out = xt_array_new(0, NULL);
|
|
80
|
+
for (uint32_t i = 0; i < map->count; i++) xt_array_push(out, map->values[i]);
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
if (strcmp(method, "entries") == 0) {
|
|
84
|
+
xt_value out = xt_array_new(0, NULL);
|
|
85
|
+
for (uint32_t i = 0; i < map->count; i++) {
|
|
86
|
+
xt_value pair = xt_array_new(0, NULL);
|
|
87
|
+
xt_array_push(pair, map->keys[i]);
|
|
88
|
+
xt_array_push(pair, map->values[i]);
|
|
89
|
+
xt_array_push(out, pair);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
*handled = 0;
|
|
94
|
+
return XT_UNDEFINED;
|
|
95
|
+
}
|