xbintsc 0.3.81 → 0.5.6
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/AGENTS.md +8 -4
- package/README.md +16 -5
- package/README.zh-CN.md +14 -6
- 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/access.js +6 -2
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/closures.js +4 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +9 -4
- 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 +11 -3
- 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 -1
- package/dist/src/codegen/generator/module.js +82 -12
- 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 +9 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +2 -4
- 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 +16 -0
- package/dist/src/codegen/generator/tables.js +99 -2
- 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 +23 -4
- package/dist/src/driver/compiler.js +46 -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/closures.test.js +8 -0
- package/dist/tests/codegen/closures.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/async-await.test.d.ts +10 -0
- package/dist/tests/e2e/async-await.test.js +247 -0
- package/dist/tests/e2e/async-await.test.js.map +1 -0
- 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/runtime-coverage-globals.test.js +46 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -1
- 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/e2e/string-utf16.test.d.ts +6 -0
- package/dist/tests/e2e/string-utf16.test.js +133 -0
- package/dist/tests/e2e/string-utf16.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 +16 -8
- package/doc/ai/extensions.md +3 -2
- package/doc/ai/language-support.md +15 -12
- package/doc/ai/troubleshooting.md +43 -5
- package/doc/ai/zh-CN/cli.md +2 -0
- package/doc/ai/zh-CN/contributing.md +11 -7
- package/doc/ai/zh-CN/extensions.md +2 -1
- package/doc/ai/zh-CN/language-support.md +15 -12
- package/doc/ai/zh-CN/troubleshooting.md +38 -4
- package/doc/implemented.md +16 -13
- package/doc/requirements.md +13 -4
- package/doc/unimplemented.md +20 -18
- package/doc/zh-CN/DESIGN.md +15 -9
- package/doc/zh-CN/implemented.md +15 -12
- package/doc/zh-CN/requirements.md +12 -3
- package/doc/zh-CN/unimplemented.md +19 -17
- 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 +49 -1
- package/runtime/rt_internal.h +136 -4
- package/runtime/xt_alloc.c +20 -2
- package/runtime/xt_async.c +197 -0
- package/runtime/xt_bigint/conversions.inc +1 -1
- package/runtime/xt_builtins.c +169 -43
- package/runtime/xt_constructors.c +389 -0
- package/runtime/xt_containers/access.inc +61 -24
- package/runtime/xt_containers/arrays.inc +26 -2
- package/runtime/xt_containers/objects.inc +206 -8
- package/runtime/xt_coroutine.c +212 -0
- package/runtime/xt_generator.c +31 -162
- package/runtime/xt_io/exception.inc +171 -2
- package/runtime/xt_io/inspect.inc +48 -13
- package/runtime/xt_io.c +5 -0
- package/runtime/xt_promise.c +62 -17
- package/runtime/xt_stdlib/arrays.inc +2 -2
- package/runtime/xt_stdlib/dispatch.inc +20 -4
- package/runtime/xt_stdlib/strings.inc +98 -29
- package/runtime/xt_stdlib2/array-statics.inc +3 -2
- package/runtime/xt_stdlib2/arrays.inc +1 -1
- package/runtime/xt_stdlib2/error.inc +33 -6
- package/runtime/xt_stdlib2/json.inc +46 -16
- package/runtime/xt_stdlib2/number-string-statics.inc +24 -13
- package/runtime/xt_stdlib2/objects.inc +1 -1
- package/runtime/xt_stdlib2/regexp-match.inc +50 -35
- package/runtime/xt_stdlib2/set.inc +6 -0
- package/runtime/xt_stdlib2/strings.inc +81 -42
- package/runtime/xt_symbol.c +1 -1
- package/runtime/xt_typed_array/construction.inc +43 -2
- package/runtime/xt_typed_array.c +4 -0
- package/runtime/xt_values/comparison.inc +2 -2
- package/runtime/xt_values/constructors.inc +18 -5
- package/runtime/xt_values/conversions.inc +4 -3
- package/runtime/xt_values/strings.inc +94 -4
- package/runtime/xt_values/utf16.inc +340 -0
- package/runtime/xt_values.c +1 -0
- 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/access.ts +7 -2
- package/src/codegen/generator/calls/closures.ts +3 -0
- package/src/codegen/generator/calls/invocation.ts +9 -3
- 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 +11 -3
- package/src/codegen/generator/generator.ts +18 -2
- package/src/codegen/generator/module.ts +83 -13
- package/src/codegen/generator/numeric.ts +158 -0
- package/src/codegen/generator/state.ts +26 -0
- package/src/codegen/generator/statements/control-flow.ts +2 -3
- package/src/codegen/generator/statements/dispatch.ts +3 -0
- package/src/codegen/generator/statements/variables.ts +8 -2
- package/src/codegen/generator/tables.ts +110 -2
- package/src/driver/bundler/merge.ts +39 -5
- package/src/driver/compiler.ts +65 -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
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end tests for the lazy (rope/cons) string model.
|
|
3
|
+
*
|
|
4
|
+
* Concatenation above the eager-copy threshold produces an immutable cons node
|
|
5
|
+
* whose bytes are materialised on first observation. These tests exercise every
|
|
6
|
+
* kind of observation (length, slicing, searching, case changes, JSON, property
|
|
7
|
+
* keys) and keep chains reachable across a garbage collection.
|
|
8
|
+
*/
|
|
9
|
+
import { expect, it } from "vitest";
|
|
10
|
+
import { describeE2E } from "./harness.js";
|
|
11
|
+
describeE2E("lazy string concatenation", (harness) => {
|
|
12
|
+
const { runProgram, runProgramFull } = harness;
|
|
13
|
+
it("matches Node for append and prepend chains", () => {
|
|
14
|
+
const source = `
|
|
15
|
+
function build(n: number): string {
|
|
16
|
+
let text = "";
|
|
17
|
+
for (let i = 0; i < n; i++) text = text + "abcdefghijklmnopqrstuvwxyz".charAt(i % 26);
|
|
18
|
+
return text;
|
|
19
|
+
}
|
|
20
|
+
const text = build(2000);
|
|
21
|
+
console.log(text.length);
|
|
22
|
+
console.log(text.slice(0, 26));
|
|
23
|
+
console.log(text.slice(-26));
|
|
24
|
+
console.log(text.indexOf("xyz"));
|
|
25
|
+
console.log(text.lastIndexOf("abc"));
|
|
26
|
+
console.log(text.includes("mnop"));
|
|
27
|
+
console.log(text.split("def").length);
|
|
28
|
+
console.log(text.toUpperCase().slice(0, 26));
|
|
29
|
+
console.log(text.replace("abc", "ABC").slice(0, 26));
|
|
30
|
+
console.log(text.replaceAll("a", "!").slice(0, 26));
|
|
31
|
+
console.log(text === build(2000));
|
|
32
|
+
console.log(text.startsWith("abc"), text.endsWith("xyz"));
|
|
33
|
+
console.log(JSON.stringify(text.slice(0, 10)));
|
|
34
|
+
console.log(text.charCodeAt(5), text.at(-1));
|
|
35
|
+
|
|
36
|
+
let prepended = "";
|
|
37
|
+
for (let i = 0; i < 2000; i++) prepended = "x" + prepended;
|
|
38
|
+
console.log(prepended.length, prepended.slice(0, 3), prepended.slice(-3));
|
|
39
|
+
|
|
40
|
+
let mixed = "";
|
|
41
|
+
for (let i = 0; i < 200; i++) mixed += i;
|
|
42
|
+
console.log(mixed.length, mixed.slice(0, 12));
|
|
43
|
+
|
|
44
|
+
let templated = "";
|
|
45
|
+
for (let i = 0; i < 2000; i++) templated = \`\${templated}\${i % 10}\`;
|
|
46
|
+
console.log(templated.length, templated.slice(0, 12));
|
|
47
|
+
|
|
48
|
+
let key = "";
|
|
49
|
+
for (let i = 0; i < 40; i++) key += "k";
|
|
50
|
+
const holder: any = {};
|
|
51
|
+
holder[key] = "v";
|
|
52
|
+
console.log(holder[key], Object.keys(holder)[0].length);
|
|
53
|
+
console.log([text, prepended].join("|").length);
|
|
54
|
+
`;
|
|
55
|
+
harness.expectSameOutputAsNode(source, { name: "string_concat_chains" });
|
|
56
|
+
});
|
|
57
|
+
it("keeps cons nodes reachable across collections", () => {
|
|
58
|
+
const source = `
|
|
59
|
+
let text = "";
|
|
60
|
+
for (let i = 0; i < 2000; i++) text += "z";
|
|
61
|
+
const holder: any = { text: text };
|
|
62
|
+
const list: any[] = [text];
|
|
63
|
+
text = "";
|
|
64
|
+
|
|
65
|
+
/* Allocate and drop many objects to force collections while the rope is
|
|
66
|
+
reachable only through the object property and the array element. */
|
|
67
|
+
let junk: any = {};
|
|
68
|
+
for (let i = 0; i < 40000; i++) junk = { value: i };
|
|
69
|
+
junk = {};
|
|
70
|
+
const trigger = "x" + "y";
|
|
71
|
+
|
|
72
|
+
/* Reuse the freed memory before the rope is ever flattened. */
|
|
73
|
+
const reuse: any[] = [];
|
|
74
|
+
for (let i = 0; i < 5000; i++) reuse.push("a" + "b");
|
|
75
|
+
|
|
76
|
+
console.log(holder.text.length, holder.text === "z".repeat(2000));
|
|
77
|
+
console.log(list[0].length, list[0] === holder.text, reuse.length, trigger);
|
|
78
|
+
console.log(holder.text.slice(0, 2), holder.text.slice(-2), holder.text.toUpperCase().slice(0, 3));
|
|
79
|
+
`;
|
|
80
|
+
const result = runProgramFull(source, {
|
|
81
|
+
name: "string_concat_gc",
|
|
82
|
+
env: { XT_GC_THRESHOLD: "1048576" },
|
|
83
|
+
timeout: 60000,
|
|
84
|
+
});
|
|
85
|
+
expect(result.status).toBe(0);
|
|
86
|
+
expect(result.stdout.trim()).toBe("2000 true\n2000 true 5000 xy\nzz zz ZZZ");
|
|
87
|
+
});
|
|
88
|
+
it("flattens reused chains without mutating earlier results", () => {
|
|
89
|
+
const source = `
|
|
90
|
+
let prefix = "start-";
|
|
91
|
+
for (let i = 0; i < 200; i++) prefix += "p";
|
|
92
|
+
const first = prefix + "-first";
|
|
93
|
+
const second = prefix + "-second";
|
|
94
|
+
const prefixCopy = prefix.slice(0);
|
|
95
|
+
console.log(first.slice(-6), second.slice(-7));
|
|
96
|
+
console.log(prefix.length, first.length, second.length);
|
|
97
|
+
console.log(prefix === prefixCopy, prefix === first.slice(0, prefix.length));
|
|
98
|
+
`;
|
|
99
|
+
expect(runProgram(source)).toBe("-first -second\n206 212 213\ntrue true");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=string-concat.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-concat.test.js","sourceRoot":"","sources":["../../../tests/e2e/string-concat.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,WAAW,CAAC,2BAA2B,EAAE,CAAC,OAAO,EAAE,EAAE;IACnD,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAE/C,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwClB,CAAC;QACE,OAAO,CAAC,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBlB,CAAC;QACE,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE;YACpC,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,EAAE,eAAe,EAAE,SAAS,EAAE;YACnC,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,MAAM,GAAG;;;;;;;;;CASlB,CAAC;QACE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Differential coverage for JavaScript's UTF-16 string view over the runtime's
|
|
3
|
+
* UTF-8 storage: `length`, indexing, slicing, searching, splitting, padding,
|
|
4
|
+
* iteration, surrogate round-trips, JSON and RegExp offsets.
|
|
5
|
+
*/
|
|
6
|
+
import { expect, it } from "vitest";
|
|
7
|
+
import { describeE2E } from "./harness.js";
|
|
8
|
+
describeE2E("UTF-16 string semantics", (harness) => {
|
|
9
|
+
const { runProgram, expectSameOutputAsNode } = harness;
|
|
10
|
+
it("matches Node for length, indexing, slicing and searching", () => {
|
|
11
|
+
const source = `
|
|
12
|
+
const s = "中文😀aé";
|
|
13
|
+
const show = (v: unknown) => console.log(JSON.stringify(v));
|
|
14
|
+
show(s.length);
|
|
15
|
+
for (let i = 0; i < s.length; i++) show(s[i]);
|
|
16
|
+
for (let i = 0; i <= s.length; i++) show(s.codePointAt(i));
|
|
17
|
+
show(s.slice(0, 4));
|
|
18
|
+
show(s.slice(1, 5));
|
|
19
|
+
show(s.slice(2, 3));
|
|
20
|
+
show(s.slice(3, 4));
|
|
21
|
+
show(s.slice(-3));
|
|
22
|
+
show(s.substring(3, 1));
|
|
23
|
+
show(s.substring(1, 100));
|
|
24
|
+
show(s.substr(2, 2));
|
|
25
|
+
show(s.substr(-2));
|
|
26
|
+
show(s.charAt(2));
|
|
27
|
+
show(s.charCodeAt(2));
|
|
28
|
+
show(s.at(-1));
|
|
29
|
+
show(s.at(-5));
|
|
30
|
+
show(s.indexOf("😀"));
|
|
31
|
+
show(s.indexOf("a", 4));
|
|
32
|
+
show(s.indexOf("", 100));
|
|
33
|
+
show(s.lastIndexOf("中"));
|
|
34
|
+
show(s.lastIndexOf("😀", 3));
|
|
35
|
+
show(s.lastIndexOf("a", 2));
|
|
36
|
+
show(s.includes("😀"));
|
|
37
|
+
show(s.includes("文", 2));
|
|
38
|
+
show(s.startsWith("中文"));
|
|
39
|
+
show(s.startsWith("😀", 2));
|
|
40
|
+
show(s.endsWith("aé"));
|
|
41
|
+
show(s.endsWith("😀", 4));
|
|
42
|
+
show(s.split("😀"));
|
|
43
|
+
show(s.split("", 4));
|
|
44
|
+
show(s.split("a"));
|
|
45
|
+
show("😀".repeat(3));
|
|
46
|
+
show("x".padStart(4, "😀"));
|
|
47
|
+
show("x".padEnd(4, "😀"));
|
|
48
|
+
show("中".padStart(3, "ab"));
|
|
49
|
+
show("a😀b中".startsWith("😀", 2));
|
|
50
|
+
show("a😀b中".indexOf("😀", 2));
|
|
51
|
+
show("a😀b中".endsWith("a", 2));
|
|
52
|
+
show("a😀b中".lastIndexOf("😀", 2));
|
|
53
|
+
show("a😀b中".lastIndexOf("\\uDE00", 2));
|
|
54
|
+
show(s.length === 6);
|
|
55
|
+
`;
|
|
56
|
+
expectSameOutputAsNode(source, { name: "utf16_indexing" });
|
|
57
|
+
});
|
|
58
|
+
it("matches Node for iteration, keys, surrogate round-trips and JSON", () => {
|
|
59
|
+
const source = `
|
|
60
|
+
const s = "中文😀aé";
|
|
61
|
+
const show = (v: unknown) => console.log(JSON.stringify(v));
|
|
62
|
+
show([...s]);
|
|
63
|
+
show(Array.from(s));
|
|
64
|
+
show(Object.keys(s));
|
|
65
|
+
show(Object.values("😀"));
|
|
66
|
+
show(Object.entries("😀"));
|
|
67
|
+
const high = "\\uD83D";
|
|
68
|
+
const low = "\\uDE00";
|
|
69
|
+
show(high + low);
|
|
70
|
+
show((high + low).length);
|
|
71
|
+
show((high + low) === "😀");
|
|
72
|
+
show(String.fromCharCode(0x4e2d, 0xd83d, 0xde00));
|
|
73
|
+
show(String.fromCharCode(0x10000));
|
|
74
|
+
show(String.fromCodePoint(0x1f600));
|
|
75
|
+
show(String.fromCodePoint(0x4e2d));
|
|
76
|
+
show(JSON.stringify("\\uD83D"));
|
|
77
|
+
show(JSON.stringify("\\uDE00"));
|
|
78
|
+
show(JSON.stringify("\\uD83D\\uDE00"));
|
|
79
|
+
show(JSON.stringify("\\u{1F600}"));
|
|
80
|
+
show("\\u{1F600}".length);
|
|
81
|
+
show("\\u4e2d".length);
|
|
82
|
+
show(JSON.stringify(JSON.parse('"\\\\u4e2d\\\\ud83d\\\\ude00"')));
|
|
83
|
+
show(JSON.parse('"\\\\ud83d\\\\ude00"').length);
|
|
84
|
+
show(JSON.parse('"\\\\ud83d"').length);
|
|
85
|
+
let built = "";
|
|
86
|
+
for (const ch of s) built += ch;
|
|
87
|
+
show(built);
|
|
88
|
+
show(built === s);
|
|
89
|
+
let keys = "";
|
|
90
|
+
for (const key in "😀") keys += key;
|
|
91
|
+
show(keys);
|
|
92
|
+
show(JSON.stringify({ ..."😀" }));
|
|
93
|
+
show("a😀".replaceAll("", "-"));
|
|
94
|
+
show("a😀".replaceAll("😀", "中"));
|
|
95
|
+
show("a😀b".replace("", "-"));
|
|
96
|
+
`;
|
|
97
|
+
expectSameOutputAsNode(source, { name: "utf16_iteration_json" });
|
|
98
|
+
});
|
|
99
|
+
it("reports RegExp offsets in UTF-16 code units", () => {
|
|
100
|
+
const source = `
|
|
101
|
+
const show = (v: unknown) => console.log(JSON.stringify(v));
|
|
102
|
+
show("中😀x1".match(/1/)!.index);
|
|
103
|
+
show("中😀x".search(/x/));
|
|
104
|
+
show("中1".replace(/1/, (m: string, at: number) => String(at)));
|
|
105
|
+
show("a1b2".replace(/\\d/g, (m: string, at: number) => String(at)));
|
|
106
|
+
show("中1".replace(/1/, "#"));
|
|
107
|
+
show(JSON.stringify("中😀中".split(/😀/)));
|
|
108
|
+
`;
|
|
109
|
+
expectSameOutputAsNode(source, { name: "utf16_regex_offsets" });
|
|
110
|
+
});
|
|
111
|
+
it("normalizes surrogate pairs across lazy concatenation boundaries", () => {
|
|
112
|
+
const source = `
|
|
113
|
+
const prefix = "x".repeat(40);
|
|
114
|
+
const high = "\\uD83D";
|
|
115
|
+
const low = "\\uDE00";
|
|
116
|
+
const s = prefix + high + low;
|
|
117
|
+
const show = (v: unknown) => console.log(JSON.stringify(v));
|
|
118
|
+
show(s.length);
|
|
119
|
+
show(s.slice(-2));
|
|
120
|
+
show(s === prefix + "😀");
|
|
121
|
+
show(s.charCodeAt(40));
|
|
122
|
+
show(s.charCodeAt(41));
|
|
123
|
+
show(s.codePointAt(40));
|
|
124
|
+
show(s.endsWith("😀"));
|
|
125
|
+
show(s.indexOf("😀"));
|
|
126
|
+
`;
|
|
127
|
+
expectSameOutputAsNode(source, { name: "utf16_lazy_boundary" });
|
|
128
|
+
});
|
|
129
|
+
it("prints a lone surrogate as the replacement character", () => {
|
|
130
|
+
expect(runProgram('console.log("😀"[0], "中".length);', { name: "utf16_console" })).toBe("� 1");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=string-utf16.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-utf16.test.js","sourceRoot":"","sources":["../../../tests/e2e/string-utf16.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,WAAW,CAAC,yBAAyB,EAAE,CAAC,OAAO,EAAE,EAAE;IACjD,MAAM,EAAE,UAAU,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC;IAEvD,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4ClB,CAAC;QACE,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqClB,CAAC;QACE,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG;;;;;;;;CAQlB,CAAC;QACE,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;CAclB,CAAC;QACE,sBAAsB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,UAAU,CAAC,mCAAmC,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/tests/helpers.d.ts
CHANGED
|
@@ -18,9 +18,18 @@ export declare function bindSource(text: string): {
|
|
|
18
18
|
export declare function compileToIr(text: string, extensions?: ExtensionRegistry, target?: {
|
|
19
19
|
platform: string;
|
|
20
20
|
arch: string;
|
|
21
|
+
}, options?: {
|
|
22
|
+
readonly debug?: boolean;
|
|
21
23
|
}): {
|
|
22
24
|
ir: string;
|
|
23
25
|
binding: BindResult;
|
|
24
26
|
diagnostics: readonly Diagnostic[];
|
|
25
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* True when a *supported* clang is available. The end-to-end suites really
|
|
30
|
+
* compile and link native binaries, and the emitted IR needs clang >= 16, so a
|
|
31
|
+
* missing or too-old toolchain skips them instead of failing every case with an
|
|
32
|
+
* opaque-pointer error. `resolveToolchain` applies the same selection (and
|
|
33
|
+
* version gate) the driver uses, so the tests and the compiler agree.
|
|
34
|
+
*/
|
|
26
35
|
export declare function hasClang(): boolean;
|
package/dist/tests/helpers.js
CHANGED
|
@@ -7,7 +7,8 @@ import { Parser } from "../src/parser/parser.js";
|
|
|
7
7
|
import { bind } from "../src/binder/binder.js";
|
|
8
8
|
import { generate } from "../src/codegen/llvm.js";
|
|
9
9
|
import { createDefaultRegistry } from "../src/extensions/registry.js";
|
|
10
|
-
import {
|
|
10
|
+
import { MINIMUM_CLANG_MAJOR } from "../src/driver/toolchain.js";
|
|
11
|
+
import { resolveToolchain } from "../src/driver/toolchain-provider.js";
|
|
11
12
|
export function lex(text) {
|
|
12
13
|
const source = new SourceFile("test.ts", sourceTextBytes(text));
|
|
13
14
|
const diagnostics = new DiagnosticBag();
|
|
@@ -28,7 +29,7 @@ export function bindSource(text) {
|
|
|
28
29
|
const result = bind(file);
|
|
29
30
|
return { result, diagnostics: bag.diagnostics };
|
|
30
31
|
}
|
|
31
|
-
export function compileToIr(text, extensions, target) {
|
|
32
|
+
export function compileToIr(text, extensions, target, options = {}) {
|
|
32
33
|
const { file, diagnostics: parseDiagnostics } = parse(text);
|
|
33
34
|
const diagnostics = new DiagnosticBag();
|
|
34
35
|
diagnostics.addAll(parseDiagnostics);
|
|
@@ -37,10 +38,32 @@ export function compileToIr(text, extensions, target) {
|
|
|
37
38
|
builtins: registry.builtins(),
|
|
38
39
|
modules: registry.modules(),
|
|
39
40
|
...(target ? { target } : {}),
|
|
41
|
+
debug: options.debug === true,
|
|
40
42
|
});
|
|
41
43
|
return { ir, binding, diagnostics: diagnostics.diagnostics };
|
|
42
44
|
}
|
|
45
|
+
let cachedClangSupport;
|
|
46
|
+
/**
|
|
47
|
+
* True when a *supported* clang is available. The end-to-end suites really
|
|
48
|
+
* compile and link native binaries, and the emitted IR needs clang >= 16, so a
|
|
49
|
+
* missing or too-old toolchain skips them instead of failing every case with an
|
|
50
|
+
* opaque-pointer error. `resolveToolchain` applies the same selection (and
|
|
51
|
+
* version gate) the driver uses, so the tests and the compiler agree.
|
|
52
|
+
*/
|
|
43
53
|
export function hasClang() {
|
|
44
|
-
|
|
54
|
+
if (cachedClangSupport === undefined) {
|
|
55
|
+
try {
|
|
56
|
+
const version = resolveToolchain().version;
|
|
57
|
+
cachedClangSupport = version === undefined || version.major >= MINIMUM_CLANG_MAJOR;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
cachedClangSupport = false;
|
|
61
|
+
}
|
|
62
|
+
if (!cachedClangSupport) {
|
|
63
|
+
console.warn(`xbintsc: skipping end-to-end tests — clang ${MINIMUM_CLANG_MAJOR}+ was not found ` +
|
|
64
|
+
"(see doc/requirements.md, or set xbintsc_CLANG)");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return cachedClangSupport;
|
|
45
68
|
}
|
|
46
69
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../tests/helpers.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAErD,OAAO,EAAE,aAAa,EAAmB,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAmB,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAA0B,MAAM,+BAA+B,CAAC;AAC9F,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../tests/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,4 +44,11 @@ describe("assignment validation", () => {
|
|
|
44
44
|
expect(diagnostics.some((d) => d.code === DiagnosticCode.InvalidAssignmentTarget)).toBe(true);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
|
+
describe("unsupported syntax", () => {
|
|
48
|
+
it("reports new.target as an unsupported feature, not a syntax error", () => {
|
|
49
|
+
const { diagnostics } = parse("function F() { return new.target; }");
|
|
50
|
+
expect(diagnostics.map((d) => d.code)).toContain(DiagnosticCode.UnsupportedFeature);
|
|
51
|
+
expect(diagnostics.map((d) => d.code)).not.toContain(DiagnosticCode.UnexpectedToken);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
47
54
|
//# sourceMappingURL=expressions.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expressions.test.js","sourceRoot":"","sources":["../../../tests/parser/expressions.test.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAErE,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAQ,CAAC;IACvC,OAAO,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAC1D,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,yBAAyB,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,2BAA2B,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,+BAA+B,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,wBAAwB,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"expressions.test.js","sourceRoot":"","sources":["../../../tests/parser/expressions.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { COMPILER_VERSION } from "../src/driver/compiler.js";
|
|
4
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
5
|
+
describe("compiler version", () => {
|
|
6
|
+
it("matches package.json", () => {
|
|
7
|
+
expect(COMPILER_VERSION).toBe(packageJson.version);
|
|
8
|
+
});
|
|
9
|
+
it("is part of the incremental cache key", () => {
|
|
10
|
+
const source = readFileSync(new URL("../src/driver/compiler.ts", import.meta.url), "utf8");
|
|
11
|
+
expect(source).toMatch(/hashParts\(\[\s*COMPILER_VERSION,/);
|
|
12
|
+
});
|
|
13
|
+
it("is printed by `xbintsc version`", async () => {
|
|
14
|
+
const { run } = await import("../src/cli/main.js");
|
|
15
|
+
const lines = [];
|
|
16
|
+
const code = run(["version"], {
|
|
17
|
+
stdout: (text) => lines.push(text),
|
|
18
|
+
stderr: (text) => lines.push(text),
|
|
19
|
+
});
|
|
20
|
+
expect(code).toBe(0);
|
|
21
|
+
expect(lines.join("")).toContain(COMPILER_VERSION);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=version.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.test.js","sourceRoot":"","sources":["../../tests/version.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC3C,CAAC;AAEzB,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3F,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACnD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE;YAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAClC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/doc/DESIGN.md
CHANGED
|
@@ -41,16 +41,21 @@ xt_value fn(xt_value env, int32_t argc, xt_value *argv);
|
|
|
41
41
|
|
|
42
42
|
`env` threads captured variables by reference through boxes, so direct calls and
|
|
43
43
|
closure calls share a single code path. JavaScript semantics that are awkward to
|
|
44
|
-
inline (`+` coercion,
|
|
45
|
-
|
|
44
|
+
inline (`+` coercion, property access, inspection) are delegated to `@xt_*`
|
|
45
|
+
runtime calls. Numeric arithmetic and comparison are the exception: codegen emits
|
|
46
|
+
the double fast path inline (`numeric.ts`) and calls the runtime for the coercing
|
|
47
|
+
cases.
|
|
46
48
|
|
|
47
49
|
### Runtime
|
|
48
50
|
|
|
49
|
-
`runtime
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
stay
|
|
51
|
+
`runtime/` implements strings, objects, arrays, closures, arithmetic, comparison,
|
|
52
|
+
exceptions and Node-like `console.log` inspection. It is split by concern into
|
|
53
|
+
translation units (`xt_values.c`, `xt_containers.c`, `xt_stdlib.c`,
|
|
54
|
+
`xt_builtins.c`, `xt_io.c`, `xt_alloc.c`, …), each `#include`-ing its
|
|
55
|
+
implementation fragments (`.inc`) so files stay small without changing the link
|
|
56
|
+
surface. It uses a non-moving mark-sweep collector behind `xt_alloc` (explicit
|
|
57
|
+
roots, subsystem root providers and a conservative C-stack scan), so the
|
|
58
|
+
collector's internals stay isolated from the compiler.
|
|
54
59
|
|
|
55
60
|
### Replacing llc
|
|
56
61
|
|
|
@@ -103,15 +108,18 @@ found on `PATH` (the MSVC ABI when LLVM + the Visual Studio C++ build tools are
|
|
|
103
108
|
installed), and each manifest declares any platform-specific linker flags. See
|
|
104
109
|
`examples/extensions/` and `runtime/xt_ext.h` / `runtime/xt_ext.rs`.
|
|
105
110
|
|
|
106
|
-
## Self-hosting
|
|
111
|
+
## Self-hosting
|
|
107
112
|
|
|
108
|
-
The compiler itself
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
The compiler compiles itself: `xbintsc build src/cli/main.ts --ext node` produces
|
|
114
|
+
a working `xbintsc` binary, and the emitted IR is a fixpoint from the first
|
|
115
|
+
generation onward. CI builds those binaries for every supported platform and
|
|
116
|
+
checks the fixpoint. The runtime stays in C; rewriting it in TypeScript is an
|
|
117
|
+
option for later, not a prerequisite for self-hosting.
|
|
111
118
|
|
|
112
119
|
## Tests
|
|
113
120
|
|
|
114
121
|
Organised by module: `tests/lexer`, `tests/parser`, `tests/binder`,
|
|
115
122
|
`tests/codegen`, `tests/driver`, `tests/extensions`, `tests/cli`, `tests/e2e`.
|
|
116
|
-
When
|
|
123
|
+
When a supported clang (16+, the same version gate `build` applies) is present,
|
|
124
|
+
e2e tests really compile and run binaries; otherwise
|
|
117
125
|
they are skipped automatically.
|
package/doc/ai/cli.md
CHANGED
|
@@ -36,6 +36,8 @@ unknown command prints an error plus the help text and exits 1.
|
|
|
36
36
|
--app-id <id> macOS bundle identifier (e.g. com.example.demo)
|
|
37
37
|
--force Ignore the incremental cache
|
|
38
38
|
--verbose Print progress information
|
|
39
|
+
--time Print per-phase build timings
|
|
40
|
+
--debug Emit debug info (DWARF/CodeView) and keep frame pointers
|
|
39
41
|
```
|
|
40
42
|
|
|
41
43
|
Parsing details that occasionally surprise:
|
package/doc/ai/contributing.md
CHANGED
|
@@ -38,6 +38,7 @@ it. Release tags are created by `release.yml`, never by the hook.
|
|
|
38
38
|
| `npm run test:watch` | vitest in watch mode |
|
|
39
39
|
| `npm run coverage` | V8 coverage of the TypeScript compiler (`src/`) |
|
|
40
40
|
| `npm run coverage:runtime` | LLVM coverage of the C runtime (`runtime/`) |
|
|
41
|
+
| `npm run bench` | build and time the fixed benchmark suite (optionally vs Node) |
|
|
41
42
|
|
|
42
43
|
Unit tests live one directory per module under `tests/` (`lexer`, `parser`,
|
|
43
44
|
`binder`, `codegen`, `driver`, `extensions`, `cli`, `e2e`) and mirror the source
|
|
@@ -75,13 +76,15 @@ nondeterminism (a `Map`/`Set` iteration over insertion-ordered data you did not
|
|
|
75
76
|
control, a timestamp, a filesystem-order dependency) into codegen.
|
|
76
77
|
|
|
77
78
|
A second consequence is the string model: the compiler's own source text has to
|
|
78
|
-
mean the same thing in every generation. A compiled string
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
mean the same thing in every generation. A compiled string stores UTF-8 bytes
|
|
80
|
+
but indexes them in UTF-16 code units, so the self-hosted `readFileSync`
|
|
81
|
+
(`--ext node`) hands the scanner a byte string (one byte per code unit, all
|
|
82
|
+
`<= 0xFF`), while Node hands it the same file already decoded — read source
|
|
83
|
+
files through `decodeUtf8` ([src/diagnostics/utf8.ts](../../src/diagnostics/utf8.ts))
|
|
84
|
+
and never assume a code unit is a byte or a character. Getting this wrong shows
|
|
85
|
+
up as a non-ASCII literal (`—` in a hint string) coming out re-encoded in
|
|
86
|
+
`gen2.ll`, which is why the emitted IR is compared byte-for-byte rather than
|
|
87
|
+
line-by-line.
|
|
85
88
|
|
|
86
89
|
Verify locally:
|
|
87
90
|
|
|
@@ -103,7 +106,12 @@ diff scratch/ref.ll scratch/gen2.ll
|
|
|
103
106
|
in [../../src/codegen/values.ts](../../src/codegen/values.ts) and
|
|
104
107
|
[../../runtime/rt.h](../../runtime/rt.h); change both together or not at all.
|
|
105
108
|
- Awkward JS semantics (`+` coercion, relational comparison, property access,
|
|
106
|
-
inspection) are delegated to `@xt_*` runtime calls
|
|
109
|
+
inspection) are delegated to `@xt_*` runtime calls. Numeric arithmetic and
|
|
110
|
+
comparison are the exception: codegen inlines the two-double fast path
|
|
111
|
+
(`src/codegen/generator/numeric.ts`) and calls the runtime for everything else.
|
|
112
|
+
- String literals are interned: each distinct literal is materialised once in
|
|
113
|
+
`main`, stored in a GC-rooted global, and loaded at each use. Property names
|
|
114
|
+
therefore never allocate per access.
|
|
107
115
|
- The GC is a non-moving mark-sweep collector: new heap objects go through
|
|
108
116
|
`xt_alloc`, and a value must be reachable from an explicit root slot, a
|
|
109
117
|
registered root provider (the event loop, the microtask queue) or the
|
package/doc/ai/extensions.md
CHANGED
|
@@ -54,8 +54,9 @@ Coverage per module (exact functions and options) is in
|
|
|
54
54
|
[../node-unimplemented.md](../node-unimplemented.md).
|
|
55
55
|
|
|
56
56
|
Remember the runtime model before building on `net`/`http`: the event loop runs
|
|
57
|
-
**after** the program body,
|
|
58
|
-
|
|
57
|
+
**after** the program body, but `async`/`await` now suspends on pending promises,
|
|
58
|
+
so a promise settled from a socket callback can be awaited. See
|
|
59
|
+
[language-support.md](./language-support.md).
|
|
59
60
|
|
|
60
61
|
### `gui` — HTML/CSS window
|
|
61
62
|
|
|
@@ -31,7 +31,7 @@ Canonical detail (always current, much longer):
|
|
|
31
31
|
| `return`, `throw` as expressions' operands | ✅ | |
|
|
32
32
|
| `namespace` / `module` declaration | 🚫 | parse ✓, codegen ✗ |
|
|
33
33
|
| `with`, `debugger` | 🚫 | not supported |
|
|
34
|
-
| Top-level `await` |
|
|
34
|
+
| Top-level `await` | ⚠️ | works by blocking on the event loop until the promise settles (it does not yield the module body like an ES module); prefer wrapping it in an `async` function |
|
|
35
35
|
|
|
36
36
|
## Expressions and operators
|
|
37
37
|
|
|
@@ -45,8 +45,8 @@ Canonical detail (always current, much longer):
|
|
|
45
45
|
| Destructuring (bindings, parameters, nested) | ✅ | defaults + rest supported |
|
|
46
46
|
| `delete`, `in`, `instanceof`, `typeof` | ✅ | |
|
|
47
47
|
| Comma operator, `void` | ✅ | |
|
|
48
|
-
| `new.target` | 🚫 |
|
|
49
|
-
| `import.meta` |
|
|
48
|
+
| `new.target` | 🚫 | parsed, then rejected with a clear `UnsupportedFeature` |
|
|
49
|
+
| `import.meta` | ✅ | `url`, `dirname`, `filename` (resolved from the executable path) |
|
|
50
50
|
| `super` | ⚠️ | single-level inheritance correct; depth > 1 may be inaccurate |
|
|
51
51
|
|
|
52
52
|
## Functions, classes, objects
|
|
@@ -71,10 +71,11 @@ Canonical detail (always current, much longer):
|
|
|
71
71
|
|
|
72
72
|
| Feature | Status | Notes |
|
|
73
73
|
| --- | --- | --- |
|
|
74
|
-
| `async` / `await`, `Promise`, `Promise.all` |
|
|
75
|
-
| `setTimeout` and callbacks |
|
|
76
|
-
| Sockets / servers (`http`, `net`, `dgram`) |
|
|
77
|
-
|
|
|
74
|
+
| `async` / `await`, `Promise`, `Promise.all` | ✅ | real suspension: an `async` body runs on a stackful coroutine, and awaiting a **pending** promise pauses it until the promise settles. Awaiting an already-settled value still continues synchronously |
|
|
75
|
+
| `setTimeout` and callbacks | ✅ | timers run on the core event loop; `await new Promise(r => setTimeout(r, ms))` works |
|
|
76
|
+
| Sockets / servers (`http`, `net`, `dgram`) | ✅ | callbacks run on the event loop and can settle a promise you await (`net` / `http` examples included in the tests) |
|
|
77
|
+
| `fs/promises` | ⚠️ | awaitable, but each call performs its I/O synchronously before settling, so it does not yield while the I/O runs |
|
|
78
|
+
| `async` generators, worker threads | 🚫 | `async function*` is rejected; workers are child processes |
|
|
78
79
|
|
|
79
80
|
## Types: parsed, then erased
|
|
80
81
|
|
|
@@ -98,13 +99,14 @@ Implemented: `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `WeakMap`/`WeakSet`
|
|
|
98
99
|
`Symbol`, `Error` family, `BigInt`, `Array`/`String`/`Number`/`Object` methods,
|
|
99
100
|
typed arrays, `String.prototype.match`/`split`/`replace` with capture groups,
|
|
100
101
|
immutable array helpers (`toReversed`, `toSorted`, `toSpliced`, `with`), global
|
|
101
|
-
URI functions
|
|
102
|
+
URI functions, first-class built-in constructors (`const A = Array; new A(...)`,
|
|
103
|
+
`A.isArray`, `x instanceof A`) and `Object.prototype`
|
|
104
|
+
(`Object.getPrototypeOf({}) === Object.prototype`).
|
|
102
105
|
|
|
103
106
|
| Missing or different | Status |
|
|
104
107
|
| --- | --- |
|
|
105
108
|
| `String.prototype.normalize`, `structuredClone` | 🚫 |
|
|
106
|
-
| `Error.stack` capture |
|
|
107
|
-
| `Object.getPrototypeOf({})` | ⚠️ returns `undefined`, not `Object.prototype` |
|
|
109
|
+
| `Error.stack` capture | ⚠️ function-level frames (name/file/line), no columns; generator bodies are omitted |
|
|
108
110
|
| Global RegExp `lastIndex` | ⚠️ `test`/`exec` ignore it for `/g` and `/y` |
|
|
109
111
|
| Sparse array holes, array out-of-bounds | ⚠️ holes are not tracked distinctly; out-of-bounds reads give `undefined` |
|
|
110
112
|
|
|
@@ -122,13 +124,14 @@ See section 3 of [../unimplemented.md](../unimplemented.md) for the full list.
|
|
|
122
124
|
| `require()` / CommonJS | 🚫 | rejected with a hint to use `import` |
|
|
123
125
|
| Circular dependencies | 🚫 | |
|
|
124
126
|
| Live bindings | ⚠️ | imports and namespace members are snapshots |
|
|
125
|
-
| `
|
|
127
|
+
| `__dirname`, `__filename` | 🚫 | use `import.meta.dirname` / `import.meta.filename` |
|
|
126
128
|
|
|
127
129
|
## Strings, numbers, memory
|
|
128
130
|
|
|
129
131
|
| Item | Behaviour |
|
|
130
132
|
| --- | --- |
|
|
131
|
-
| `String.prototype.length` |
|
|
133
|
+
| `String.prototype.length` | ✅ UTF-16 code units (`"中文😀".length === 4`); indexing, `slice`, `indexOf`, `split`, `padStart` and `codePointAt` use the same model. Storage stays UTF-8 |
|
|
134
|
+
| RegExp Unicode matching | ⚠️ the engine is byte-oriented: a literal `中` still matches, but `.` and character classes consume one byte per repetition, and `\d`/`\w` stay ASCII. Match offsets (`match.index`, `search`, replacement callbacks) are reported in UTF-16 code units |
|
|
132
135
|
| Number formatting and coercion | ✅ matches Node (`toFixed`, `toPrecision`, hex/octal/binary parsing) |
|
|
133
136
|
| `BigInt` | ✅ implemented |
|
|
134
137
|
| Garbage collection | ✅ non-moving mark-sweep; explicit roots plus a conservative C-stack scan; single-threaded and stop-the-world; no weak references |
|