xbintsc 0.3.87 → 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 +4 -3
- package/README.zh-CN.md +2 -2
- 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 +4 -3
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +6 -1
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/module.d.ts +0 -1
- package/dist/src/codegen/generator/module.js +10 -10
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +4 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.js +1 -3
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +9 -0
- package/dist/src/codegen/generator/tables.js +74 -2
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +2 -2
- package/dist/src/driver/compiler.js +4 -1
- package/dist/src/driver/compiler.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/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/runtime-coverage-globals.test.js +46 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -1
- 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/doc/ai/contributing.md +9 -7
- package/doc/ai/extensions.md +3 -2
- package/doc/ai/language-support.md +11 -8
- package/doc/ai/troubleshooting.md +4 -3
- package/doc/ai/zh-CN/contributing.md +5 -5
- package/doc/ai/zh-CN/extensions.md +2 -1
- package/doc/ai/zh-CN/language-support.md +11 -8
- package/doc/ai/zh-CN/troubleshooting.md +3 -2
- package/doc/implemented.md +15 -12
- package/doc/unimplemented.md +11 -10
- package/doc/zh-CN/implemented.md +14 -11
- package/doc/zh-CN/unimplemented.md +11 -10
- package/package.json +1 -1
- package/runtime/rt.h +32 -0
- package/runtime/rt_internal.h +99 -10
- package/runtime/xt_alloc.c +6 -0
- package/runtime/xt_async.c +197 -0
- package/runtime/xt_builtins.c +40 -36
- package/runtime/xt_constructors.c +389 -0
- package/runtime/xt_containers/access.inc +47 -11
- package/runtime/xt_containers/arrays.inc +26 -2
- package/runtime/xt_containers/objects.inc +202 -5
- package/runtime/xt_coroutine.c +212 -0
- package/runtime/xt_generator.c +31 -162
- package/runtime/xt_io/inspect.inc +35 -2
- package/runtime/xt_promise.c +62 -17
- package/runtime/xt_stdlib/dispatch.inc +18 -2
- package/runtime/xt_stdlib/strings.inc +73 -16
- package/runtime/xt_stdlib2/array-statics.inc +3 -3
- package/runtime/xt_stdlib2/error.inc +11 -0
- package/runtime/xt_stdlib2/json.inc +44 -15
- package/runtime/xt_stdlib2/number-string-statics.inc +24 -15
- package/runtime/xt_stdlib2/objects.inc +1 -1
- package/runtime/xt_stdlib2/regexp-match.inc +2 -2
- package/runtime/xt_stdlib2/set.inc +6 -0
- package/runtime/xt_stdlib2/strings.inc +70 -40
- package/runtime/xt_typed_array/construction.inc +43 -2
- package/runtime/xt_typed_array.c +4 -0
- package/runtime/xt_values/constructors.inc +8 -0
- package/runtime/xt_values/strings.inc +19 -3
- package/runtime/xt_values/utf16.inc +340 -0
- package/runtime/xt_values.c +1 -0
- 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 +4 -3
- package/src/codegen/generator/expressions/primary.ts +6 -1
- package/src/codegen/generator/module.ts +10 -12
- package/src/codegen/generator/state.ts +4 -0
- package/src/codegen/generator/statements/control-flow.ts +1 -2
- package/src/codegen/generator/tables.ts +84 -2
- package/src/driver/compiler.ts +4 -1
|
@@ -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/doc/ai/contributing.md
CHANGED
|
@@ -76,13 +76,15 @@ nondeterminism (a `Map`/`Set` iteration over insertion-ordered data you did not
|
|
|
76
76
|
control, a timestamp, a filesystem-order dependency) into codegen.
|
|
77
77
|
|
|
78
78
|
A second consequence is the string model: the compiler's own source text has to
|
|
79
|
-
mean the same thing in every generation. A compiled string
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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.
|
|
86
88
|
|
|
87
89
|
Verify locally:
|
|
88
90
|
|
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
|
|
|
@@ -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
109
|
| `Error.stack` capture | ⚠️ function-level frames (name/file/line), no columns; generator bodies are omitted |
|
|
107
|
-
| `Object.getPrototypeOf({})` | ⚠️ returns `undefined`, not `Object.prototype` |
|
|
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
|
|
|
@@ -128,7 +130,8 @@ See section 3 of [../unimplemented.md](../unimplemented.md) for the full list.
|
|
|
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 |
|
|
@@ -181,9 +181,10 @@ directly (`./build/app`) to see the program's own output.
|
|
|
181
181
|
|
|
182
182
|
### Program output appears in an unexpected order
|
|
183
183
|
|
|
184
|
-
`async`/`await`
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
`async`/`await` suspends only on a **pending** promise; awaiting an already
|
|
185
|
+
settled value continues synchronously instead of queueing a microtask the way
|
|
186
|
+
Node does. The event loop starts after the program body, so timer and socket
|
|
187
|
+
callbacks still fire after it; see [language-support.md](./language-support.md).
|
|
187
188
|
|
|
188
189
|
## Where to look in the code
|
|
189
190
|
|
|
@@ -67,11 +67,11 @@ gen2 --emit--> gen3.ll # 必须等于 ref.ll
|
|
|
67
67
|
必须逐字节确定——包括迭代顺序、生成的符号名与编号。绝不要把不确定性(未受控的
|
|
68
68
|
`Map`/`Set` 迭代顺序、时间戳、依赖文件系统顺序的东西)引入代码生成。
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
UTF-
|
|
72
|
-
Node
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
第二个推论是字符串模型:编译器自身源码文本在各代中必须含义一致。编译后的字符串以 UTF-8
|
|
71
|
+
存储,但索引按 UTF-16 码元进行,所以自举后的 `readFileSync`(`--ext node`)交给扫描器的是
|
|
72
|
+
字节串(一个码元一个字节,全部 `<= 0xFF`),而 Node 交给它的是同一个文件已解码后的文本——
|
|
73
|
+
读取源码文件一律走 `decodeUtf8`([src/diagnostics/utf8.ts](../../../src/diagnostics/utf8.ts)),
|
|
74
|
+
不要假设一个码元就是一个字节或一个字符。弄错的表现是:`gen2.ll` 里非 ASCII 字面量(比如提示语里的 `—`)
|
|
75
75
|
被重新编码,这也正是这里逐字节比较 IR 而不是逐行比较的原因。
|
|
76
76
|
|
|
77
77
|
本地验证:
|
|
@@ -53,7 +53,8 @@ xbintsc run app.ts --ext node
|
|
|
53
53
|
[../../zh-CN/node-unimplemented.md](../../zh-CN/node-unimplemented.md)。
|
|
54
54
|
|
|
55
55
|
在 `net`/`http` 上搭东西之前,先记住运行时模型:事件循环在**程序主体之后**才运行,
|
|
56
|
-
|
|
56
|
+
但 `async`/`await` 现在会在 pending Promise 上挂起,因此由套接字回调 settle 的 Promise
|
|
57
|
+
可以被 await。见 [language-support.md](./language-support.md)。
|
|
57
58
|
|
|
58
59
|
### `gui` —— HTML/CSS 窗口
|
|
59
60
|
|
|
@@ -28,7 +28,7 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
|
|
|
28
28
|
| `function`、箭头函数、默认参数/剩余参数 | ✅ | |
|
|
29
29
|
| `namespace`/`module` 声明 | 🚫 | 解析 ✓,代码生成 ✗ |
|
|
30
30
|
| `with`、`debugger` | 🚫 | 不支持 |
|
|
31
|
-
| 顶层 `await` |
|
|
31
|
+
| 顶层 `await` | ⚠️ | 会在事件循环上阻塞直到 Promise settle(不会像 ES module 那样让出模块主体);建议包进 `async` 函数 |
|
|
32
32
|
|
|
33
33
|
## 表达式与运算符
|
|
34
34
|
|
|
@@ -68,10 +68,11 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
|
|
|
68
68
|
|
|
69
69
|
| 特性 | 状态 | 说明 |
|
|
70
70
|
| --- | --- | --- |
|
|
71
|
-
| `async`/`await`、`Promise`、`Promise.all` |
|
|
72
|
-
| `setTimeout` 与回调 |
|
|
73
|
-
| 套接字/服务端(`http`、`net`、`dgram`) |
|
|
74
|
-
|
|
|
71
|
+
| `async`/`await`、`Promise`、`Promise.all` | ✅ | 真实挂起:async 函数体运行在栈式协程上,等待**未 settle** 的 Promise 时暂停,settle 后恢复。等待已 settle 的值仍同步继续 |
|
|
72
|
+
| `setTimeout` 与回调 | ✅ | 定时器运行在核心事件循环上;`await new Promise(r => setTimeout(r, ms))` 可用 |
|
|
73
|
+
| 套接字/服务端(`http`、`net`、`dgram`) | ✅ | 回调在事件循环上执行,可以 settle 你正在 await 的 Promise(测试含 `net`/`http` 示例) |
|
|
74
|
+
| `fs/promises` | ⚠️ | 可以 await,但每次调用仍先同步完成 I/O 再 settle,I/O 期间不会让出 |
|
|
75
|
+
| `async` 生成器、worker 线程 | 🚫 | `async function*` 被拒绝;worker 是子进程 |
|
|
75
76
|
|
|
76
77
|
## 类型:解析后擦除
|
|
77
78
|
|
|
@@ -93,13 +94,14 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
|
|
|
93
94
|
已实现:`Math`、`JSON`、`Date`、`RegExp`、`Map`、`Set`、`WeakMap`/`WeakSet`、
|
|
94
95
|
`Symbol`、`Error` 家族、`BigInt`、`Array`/`String`/`Number`/`Object` 方法、TypedArray、
|
|
95
96
|
带捕获组的 `String.prototype.match`/`split`/`replace`、不可变数组方法
|
|
96
|
-
(`toReversed`、`toSorted`、`toSpliced`、`with`)、全局 URI
|
|
97
|
+
(`toReversed`、`toSorted`、`toSpliced`、`with`)、全局 URI 函数、
|
|
98
|
+
一等公民内建构造器(`const A = Array; new A(...)`、`A.isArray`、`x instanceof A`)
|
|
99
|
+
与 `Object.prototype`(`Object.getPrototypeOf({}) === Object.prototype`)。
|
|
97
100
|
|
|
98
101
|
| 缺失或行为不同 | 状态 |
|
|
99
102
|
| --- | --- |
|
|
100
103
|
| `String.prototype.normalize`、`structuredClone` | 🚫 |
|
|
101
104
|
| `Error.stack` 采集 | ⚠️ 函数级帧(名称/文件/行号),没有列号;生成器函数体不产生帧 |
|
|
102
|
-
| `Object.getPrototypeOf({})` | ⚠️ 返回 `undefined`,而非 `Object.prototype` |
|
|
103
105
|
| 全局 RegExp `lastIndex` | ⚠️ `/g`、`/y` 下 `test`/`exec` 忽略它 |
|
|
104
106
|
| 稀疏数组空洞、数组越界 | ⚠️ 不区分空洞;越界读得 `undefined` |
|
|
105
107
|
|
|
@@ -123,7 +125,8 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
|
|
|
123
125
|
|
|
124
126
|
| 项目 | 行为 |
|
|
125
127
|
| --- | --- |
|
|
126
|
-
| `String.prototype.length` |
|
|
128
|
+
| `String.prototype.length` | ✅ UTF-16 码元(`"中文😀".length === 4`);索引、`slice`、`indexOf`、`split`、`padStart`、`codePointAt` 使用同一模型。底层仍以 UTF-8 存储 |
|
|
129
|
+
| 正则 Unicode 匹配 | ⚠️ 引擎按字节工作:字面量 `中` 仍能匹配,但 `.` 与字符类每次只消费一个字节,`\d`/`\w` 仍是 ASCII。匹配偏移(`match.index`、`search`、替换回调)按 UTF-16 码元报告 |
|
|
127
130
|
| 数字格式化与强转 | ✅ 与 Node 一致(`toFixed`、`toPrecision`、十六/八/二进制解析) |
|
|
128
131
|
| `BigInt` | ✅ 已实现 |
|
|
129
132
|
| 垃圾回收 | ✅ 非移动标记清扫;显式根 + C 栈保守扫描;单线程、stop-the-world;无弱引用 |
|
|
@@ -166,8 +166,9 @@ gdb ./build/app # 或 lldb ./build/app,Windows 用 WinDbg 打开 .exe
|
|
|
166
166
|
|
|
167
167
|
### 程序输出顺序出乎意料
|
|
168
168
|
|
|
169
|
-
`async`/`await`
|
|
170
|
-
|
|
169
|
+
`async`/`await` 只在 **pending** Promise 上挂起;等待已 settle 的值会同步继续,而 Node
|
|
170
|
+
会排入微任务,因此顺序可能不同。事件循环仍在程序主体之后启动,定时器与套接字回调依然
|
|
171
|
+
在主体之后触发;见 [language-support.md](./language-support.md)。
|
|
171
172
|
|
|
172
173
|
## 该去源码哪里看
|
|
173
174
|
|
package/doc/implemented.md
CHANGED
|
@@ -198,7 +198,7 @@ xt_value fn(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv);
|
|
|
198
198
|
|
|
199
199
|
- `thisValue` is threaded as the first ABI parameter (exception-safe, supports nesting); arrow functions inherit `this` lexically from an extra environment slot.
|
|
200
200
|
- Closures thread captured variables through `env` (by reference, boxed); direct calls and closure calls share one code path.
|
|
201
|
-
- `xt_object` carries a prototype field, and property lookup walks the prototype chain; `xt_function` carries a `prototype` and a property bag (static members).
|
|
201
|
+
- `xt_object` carries a prototype field, and property lookup walks the prototype chain; `xt_function` carries a `prototype` and a property bag (static members). `xt_array` also carries a `[[Prototype]]` (Array.prototype). `Object.prototype` is the root of ordinary objects and provides `hasOwnProperty` / `toString` / `valueOf` / `isPrototypeOf` / `propertyIsEnumerable` / `__proto__`; `Object.getPrototypeOf({}) === Object.prototype`.
|
|
202
202
|
|
|
203
203
|
---
|
|
204
204
|
|
|
@@ -219,16 +219,17 @@ Location: `src/codegen/llvm.ts`
|
|
|
219
219
|
- Array literals (including spread `[...]`), object literals (including shorthand / methods / object spread `{...obj}`)
|
|
220
220
|
- Typed arrays (`Uint8Array`, `Int8Array`, `Uint8ClampedArray`, `Uint16Array`, `Int16Array`, `Uint32Array`, `Int32Array`, `Float32Array`, `Float64Array`): construction (`new X(n)` / `new X(iterable)` / `X.from` / `X.of`), `length` / `byteLength` / `byteOffset` / `BYTES_PER_ELEMENT`, element reads/writes with per-type coercion (`ToIntN` / `ToUintN`, `Uint8ClampedArray` rounding, `Float32` single-precision rounding) and the prototype methods `fill` / `set` / `slice` / `subarray` / `join` / `toString` / `indexOf` / `lastIndexOf` / `includes` / `forEach` / `map` / `filter` / `every` / `some` / `find` / `findIndex` / `reduce` / `reverse` / `sort` / `copyWithin` / `at` / `keys` / `values` / `entries`. See the unimplemented document for the deliberate divergences (`subarray` copies, iterator methods return arrays, no `ArrayBuffer`/`DataView`).
|
|
221
221
|
- Property access (with a `length` special case, `Math` constants), element access, calls
|
|
222
|
+
- First-class built-in constructors (`const A = Array`, `const M = Map`, `const E = TypeError`, typed arrays): a bare reference lowers to `xt_builtin_constructor`, giving a cached function with `name` / `length`, a `prototype`, and its statics (`A.isArray`, `A.from`, `M.prototype`, ...). Calling or `new`-ing an alias dispatches to the same runtime constructor, and `x instanceof A` walks the shared prototype chain.
|
|
222
223
|
- Optional chaining `?.` / `?.[]` / `?.()`: nullish check short-circuits to `undefined`
|
|
223
224
|
- `delete`, `in`, `instanceof`
|
|
224
225
|
- `this` (saved to the function's `%saved.this`; arrow functions read from an environment slot), `super` (`super.x` / `super(...)`), `new`, `await`
|
|
225
226
|
- Closures (arrow functions / function expressions) and capture environment construction
|
|
226
227
|
- Classes: constructor closure + prototype object, stored in an LLVM global (`@class.<id>`); instance fields are initialized before the constructor body; `static` members live in the constructor's property bag; `extends` sets up the prototype chain; `super(...)` is invoked through a hidden `__ctor` on the prototype.
|
|
227
|
-
- `async`:
|
|
228
|
+
- `async`: closures are marked with `xt_function_set_async`; calling one runs the body on a stackful coroutine (`xt_coroutine.c`, `xt_async.c`) and immediately returns a promise. The body runs synchronously until the first `await` of a pending promise, then suspends; settlement queues a microtask that resumes the coroutine. An exception that escapes the body rejects that promise instead of throwing synchronously. `await` on a non-promise or settled promise keeps the synchronous fast path and raises on rejection.
|
|
228
229
|
- Standard library calls: `console.*`, `Math.*`, `Object.*`, array / string methods all go through `xt_call_method` / `xt_math_call` / `xt_object_*`; `JSON`/`Date`/`Map`/`Set`/`RegExp`/`Promise` statics and constructors go through their `xt_*` functions; global functions (`parseInt`, `setTimeout`, etc.) go through `xt_parse_int`, `xt_set_timeout`, etc.
|
|
229
230
|
- Global string pool (`@.str.N` private constants, UTF-8 escaped).
|
|
230
231
|
- Builtin calls: `console.log` / `info` / `warn` / `error`, `Math.*`, `Object.*`, array / string methods, global functions, extension builtins (uniform `(argc, argv)` ABI).
|
|
231
|
-
- `main` entry point (returns 0, calls the module function, and runs
|
|
232
|
+
- `main` entry point (returns 0, calls the module function, then drains microtasks and runs the event loop until no timers or descriptors remain).
|
|
232
233
|
- Unsupported nodes uniformly report `UnsupportedFeature`; they never crash.
|
|
233
234
|
|
|
234
235
|
---
|
|
@@ -236,18 +237,19 @@ Location: `src/codegen/llvm.ts`
|
|
|
236
237
|
## 8. C runtime (Runtime, implemented)
|
|
237
238
|
|
|
238
239
|
Location: `runtime/xt_alloc.c`, `runtime/xt_values.c`, `runtime/xt_containers.c`,
|
|
239
|
-
`runtime/xt_stdlib.c`, `runtime/xt_stdlib2.c`, `runtime/xt_promise.c`, `runtime/
|
|
240
|
+
`runtime/xt_stdlib.c`, `runtime/xt_stdlib2.c`, `runtime/xt_promise.c`, `runtime/xt_async.c`,
|
|
241
|
+
`runtime/xt_coroutine.c`, `runtime/xt_builtins.c`,
|
|
240
242
|
`runtime/xt_io.c`, sharing the private header `runtime/rt_internal.h`; the public ABI is in `runtime/rt.h`.
|
|
241
243
|
|
|
242
244
|
- Allocator: non-moving mark-sweep collector behind `xt_alloc` (explicit roots, subsystem root providers and a conservative C-stack scan).
|
|
243
245
|
- Value construction: `xt_undefined/xt_null/xt_bool/xt_number/xt_string_new/xt_string_from_cstr`.
|
|
244
|
-
- Strings: UTF-8 storage, lazy cons-node concatenation (bytes are flattened on first observation, so append loops stay linear), equality comparison, formatted number-to-string.
|
|
246
|
+
- Strings: UTF-8 storage exposed through JavaScript's UTF-16 view (`length`, indexing, `slice`, `indexOf`, `split`, `padStart` and `codePointAt` count code units; `for...of` and `Array.from` count code points; lone surrogate halves are kept as WTF-8 and recombined on concatenation), lazy cons-node concatenation (bytes are flattened on first observation, so append loops stay linear), equality comparison, formatted number-to-string. `xt_string_length` reports bytes for I/O; `xt_string_utf16_length` reports the JavaScript length.
|
|
245
247
|
- Type conversion: `xt_truthy`, `xt_to_number`, `xt_to_string`, `xt_typeof`.
|
|
246
248
|
- Arithmetic: `add/sub/mul/div/mod/pow/neg/pos`.
|
|
247
249
|
- Bitwise: `and/or/xor/not/shl/shr/ushr` (including `ToInt32` semantics).
|
|
248
250
|
- Comparison: `lt/le/gt/ge`, loose / strict equality, `not`, `is_nullish`.
|
|
249
251
|
- Objects: linear property list, `object_new/get/set/has/keys/values/entries/assign/spread`.
|
|
250
|
-
- Arrays: `array_new/get/set/push/length/spread`; assigning `arr.length` truncates or extends (matching JS); `iter_length` / `iter_value` expose a uniform iteration view over arrays, strings, `Map` and `Set`.
|
|
252
|
+
- Arrays: `array_new/get/set/push/length/spread`; assigning `arr.length` truncates or extends (matching JS); `iter_length` / `iter_value` expose a uniform iteration view over arrays, strings (by code point), `Map` and `Set`.
|
|
251
253
|
- Typed arrays (`xt_typed_array.c`): typed arrays as property-bag objects with one prototype per element kind; element reads return the stored value and writes are coerced to the element type; `from` / `of` statics plus the full prototype method set; `subarray` copies.
|
|
252
254
|
- Symbols (`xt_symbol.c`): `Symbol(description)` primitives (`XT_OBJECT_KIND_SYMBOL`), the 13 well-known symbols (`Symbol.iterator`, `Symbol.asyncIterator`, `Symbol.match`, …), `Symbol.for` / `Symbol.keyFor` global registry, `symbol.description` / `toString()` / `valueOf()`; symbols are valid property keys (`Object.getOwnPropertySymbols`, symbol keyed `get`/`set`/`in`/`delete`), are skipped by `Object.keys` / `values` / `entries` / `for...in` / `JSON.stringify`, and print as `Symbol(desc)`.
|
|
253
255
|
- Generic member access: `xt_get` / `xt_set` (dispatch over arrays / objects / strings).
|
|
@@ -257,10 +259,11 @@ Location: `runtime/xt_alloc.c`, `runtime/xt_values.c`, `runtime/xt_containers.c`
|
|
|
257
259
|
- Functions and closures: `arg`, `closure_new/call/env/arity`.
|
|
258
260
|
- Exceptions: `xt_try_enter` / `xt_try_exception` / `xt_try_leave` maintain the `_setjmp` frame stack; `xt_throw` long-jumps to the nearest `try` when a frame exists, otherwise prints `Uncaught ...` and exits. Codegen also maintains a shadow call stack (function name, source file and line): `Error.stack` captures it, and a fatal-signal handler dumps the same frames on a native crash. `--debug` additionally emits `!DICompileUnit` / `!DISubprogram` / `!DILocation` metadata and compiles with `-g -fno-omit-frame-pointer`, so gdb/lldb/WinDbg map instructions back to source lines.
|
|
259
261
|
- Output: `xt_print/xt_println/xt_console_log/info/warn/error` (Node-style inspect: arrays `[ a, b ]`, objects `{ k: v }`; `info`/`log` to stdout, `warn`/`error` to stderr), plus `dir/trace/assert/count/countReset/group/groupEnd/table/time/timeEnd/timeLog`.
|
|
260
|
-
- Objects / functions: `xt_object` with a prototype chain, `xt_function` with a property bag (static members and `prototype`); `xt_new` (instantiation), `xt_instance_of` (prototype chain), `xt_object_freeze/is_frozen/from_entries
|
|
262
|
+
- Objects / functions: `xt_object` with a prototype chain, `xt_function` with a property bag (static members and `prototype`); `xt_new` (instantiation), `xt_instance_of` (prototype chain), `xt_object_freeze/is_frozen/from_entries`; `xt_constructors.c` holds the first-class constructor cache, constructor prototypes and static-value dispatch.
|
|
261
263
|
- Standard library extensions (`xt_stdlib2.c`): extended array / string / number / object methods; `Object` / `Array` / `Number` / `String` statics; `JSON.parse` / `JSON.stringify`; `Map` / `Set`; `Date` (`gmtime_r`); `RegExp` (POSIX ERE `regcomp`/`regexec` `test`/`exec`).
|
|
262
|
-
- Promise (`xt_promise.c`):
|
|
263
|
-
-
|
|
264
|
+
- Promise (`xt_promise.c`): microtask queue (`xt_microtasks`); `xt_promise_ctor/resolve/reject/static`, instance `then/catch/finally`; `xt_drain_microtasks` empties the queue at program exit and the event loop drains it between callbacks. `xt_await` (in `xt_async.c`) returns a settled value synchronously, or suspends the running async coroutine and registers a waiter when the promise is pending.
|
|
265
|
+
- Async coroutines (`xt_async.c`) on the shared stackful-coroutine runtime (`xt_coroutine.c`, POSIX `ucontext` / Windows fibers): each `async` call owns a private stack, swaps its `try` frame stack and GC stack region, and survives `await` across `try`/`finally`, loops and closures. A promise settled from a timer, a socket callback or another coroutine resumes the suspended body on the microtask queue.
|
|
266
|
+
- Fetch (`xt_fetch.c`): global `fetch(input, init)` is a blocking HTTP/1.1 client whose promise is already settled (the exchange happens synchronously; it is not scheduled on the reactor). It accepts `http://` URLs only — `https://` rejects with a `TypeError` because no TLS backend is linked — and supports `method`, `headers` (plain object or `Headers`), `body` and `redirect` (`follow` / `manual` / `error`), following up to 20 redirects and switching POST to GET on 301/302/303. The resolved `Response`-shaped object exposes `ok` / `status` / `statusText` / `url` / `headers` plus `text()` / `json()` / `arrayBuffer()` / `bytes()` / `clone()`, and `Headers` is case-insensitive with `get` / `has` / `set` / `append` / `delete` / `keys` / `values` / `entries` / `forEach` / `getSetCookie`. Invalid URLs and network failures reject with a `TypeError`.
|
|
264
267
|
|
|
265
268
|
---
|
|
266
269
|
|
|
@@ -346,7 +349,7 @@ const result = build("program.ts", { emit: "exe", outDir: "build" });
|
|
|
346
349
|
Location: `tests/` (`lexer` / `parser` / `binder` / `codegen` / `driver` / `extensions` / `cli` / `e2e`)
|
|
347
350
|
|
|
348
351
|
- Per-module unit tests; when `clang` is present, e2e really compiles and runs binaries, otherwise it is skipped automatically.
|
|
349
|
-
- e2e coverage: arithmetic and printing, recursive functions, loops / arrays / string concatenation, closures capturing by reference, JS-style printing of objects / arrays, the Node `fs` extension via `import`, `switch` fall-through, array / string methods, `Math` and global functions and all `console` levels, default / rest parameters and `arguments`, `Object` helpers and spread and `in`/`delete`, `for...in` object key enumeration, `try/catch/finally`, optional chaining, classes and `new`/`this`/`static`/`extends`/`super`/`instanceof`, `async`/`await` and `Promise`, `Map`/`Set`/`JSON` and extended standard library, `for...of` over `Map`/`Set`, array `length` assignment and iterable spread, multi-file `import`/`export` (including `.js` specifiers and plain JavaScript sources), destructuring bindings and assignments (including object rest), built-in `instanceof`, `enum`/`const enum`, regular-expression literals and `new Error(...)`, the `Error` family and `AggregateError`, generators and `Symbol` with custom `Symbol.iterator` iterables, typed arrays (element coercion, `from`/`of`, iteration and the prototype methods), and the global `fetch` (HTTP GET/POST, headers, redirects, JSON/text/binary bodies and `TypeError` rejection).
|
|
352
|
+
- e2e coverage: arithmetic and printing, recursive functions, loops / arrays / string concatenation, closures capturing by reference, JS-style printing of objects / arrays, the Node `fs` extension via `import`, `switch` fall-through, array / string methods, `Math` and global functions and all `console` levels, default / rest parameters and `arguments`, `Object` helpers and spread and `in`/`delete`, `for...in` object key enumeration, `try/catch/finally`, optional chaining, classes and `new`/`this`/`static`/`extends`/`super`/`instanceof`, `async`/`await` and `Promise`, real await suspension (timers, TCP sockets and `fs/promises` across event-loop turns, rejection and `finally` after resuming), `Map`/`Set`/`JSON` and extended standard library, `for...of` over `Map`/`Set`, array `length` assignment and iterable spread, multi-file `import`/`export` (including `.js` specifiers and plain JavaScript sources), destructuring bindings and assignments (including object rest), built-in `instanceof`, `enum`/`const enum`, regular-expression literals and `new Error(...)`, the `Error` family and `AggregateError`, generators and `Symbol` with custom `Symbol.iterator` iterables, typed arrays (element coercion, `from`/`of`, iteration and the prototype methods), first-class built-in constructors and `Object.prototype` (aliases, statics, `getPrototypeOf`, `hasOwnProperty.call`), and the global `fetch` (HTTP GET/POST, headers, redirects, JSON/text/binary bodies and `TypeError` rejection).
|
|
350
353
|
|
|
351
354
|
---
|
|
352
355
|
|
|
@@ -360,11 +363,11 @@ Location: `tests/` (`lexer` / `parser` / `binder` / `codegen` / `driver` / `exte
|
|
|
360
363
|
| Operators | Arithmetic, comparison, equality, logical, bitwise, shift, unary (including `typeof`/`void`), prefix/postfix increment-decrement, compound assignment, logical assignment, `in`, `delete`, `instanceof` |
|
|
361
364
|
| Functions | Default parameters, rest parameters, capturing closures, `this` binding, lexical `this` in arrow functions, `call`/`apply`/`bind`, `name`/`length` |
|
|
362
365
|
| Classes / OO | Constructors, instance fields, methods, `static`, inheritance `extends`/`super`, prototype chain, `instanceof` |
|
|
363
|
-
| Async | `async`/`await
|
|
366
|
+
| Async | `async`/`await` with real stackful-coroutine suspension (a pending promise pauses the body until a timer/socket/coroutine settles it), `Promise` (`then/catch/finally`, `resolve/reject/all/allSettled/race`) |
|
|
364
367
|
| Modules | `import`/`export` (named / default / re-export / `export *` / `export type`), multi-file bundling over relative paths (`.js`-family specifiers resolve to their `.ts` sources, and TypeScript suffixes are preferred over JavaScript siblings when the specifier omits the extension; plain `.js` / `.jsx` / `.mjs` / `.cjs` sources are bundled directly too) and `node_modules` packages (`exports` / `module` / `main`, scoped packages and subpaths), bare specifiers resolved to extension modules; CommonJS packages under `node_modules` are lowered (`require` / `module.exports` / `exports`), while `require()` in user code is rejected with an `import` hint |
|
|
365
368
|
| Standard library | Array / string / number / object extension methods, typed arrays, `Math`, `JSON`, `Date`, `RegExp`, `Map`, `Set`, `Symbol`, `Error` family, `Object/Array/Number/String/Symbol` statics, `console.*` |
|
|
366
369
|
| Value model | 64-bit NaN-boxing, uniform function ABI (including `this`), closure environments, object prototype chains |
|
|
367
|
-
| Runtime | Strings / objects / arrays / typed arrays / closures / arithmetic / comparison / catchable exceptions / Promise / collections / symbols / generators / `fetch` / `console` |
|
|
370
|
+
| Runtime | Strings / objects / arrays / typed arrays / closures / arithmetic / comparison / catchable exceptions / Promise / async coroutines / collections / symbols / generators / `fetch` / `console` |
|
|
368
371
|
| Extensions | Extension registry, `core` (print), `node` (fs / path / os / process / buffer / stream / net / dgram / http imported by specifier) |
|
|
369
372
|
| GUI (`gui` extension) | Self-hosted HTML/CSS renderer window (SDL3 + SDL_GPU): DOM/CSS/layout, CSS `transform`/`transform-origin`, `<img>`/SVG, `<video>`/`<audio>`, `<canvas>` 2D, events, transitions (including `transform`) |
|
|
370
373
|
| Toolchain | clang compiles IR/C, linking, incremental cache |
|
package/doc/unimplemented.md
CHANGED
|
@@ -101,6 +101,7 @@ None known at the expression level.
|
|
|
101
101
|
- `JSON.parse` / `JSON.stringify`
|
|
102
102
|
- `Date`, `RegExp` (POSIX ERE subset with capture groups), `Map`, `Set`, `Promise`, `BigInt`
|
|
103
103
|
- `Array` statics (`isArray/of/from`), `Object` statics, `Number` statics, `String` statics (`fromCharCode` / `fromCodePoint` / `raw`)
|
|
104
|
+
- Built-in constructors as first-class values (`const A = Array`, `new A(...)`, `A.isArray`, `x instanceof A`) and `Object.prototype` (`hasOwnProperty`, `toString`, `valueOf`, `isPrototypeOf`, `propertyIsEnumerable`, `__proto__`), with `Object.getPrototypeOf({}) === Object.prototype`
|
|
104
105
|
- `Error` family (`Error`, `TypeError`, `RangeError`, `SyntaxError`, `ReferenceError`, `EvalError`, `URIError`, `AggregateError`): `new`, `instanceof`, `extends`, `String(err)` / `err.toString()` and `.stack`
|
|
105
106
|
|
|
106
107
|
### 3.3 Still unimplemented
|
|
@@ -114,7 +115,7 @@ None known at the expression level.
|
|
|
114
115
|
| `AggregateError` constructor | ✓ `new AggregateError(errors, message)`; `Promise.any` now rejects with one |
|
|
115
116
|
| Iterator protocol / `Symbol.iterator` / custom `for...of` iterables | ✓ arrays, strings, `Map`, `Set`, generators and any object exposing `[Symbol.iterator]()` are iterable in `for...of` / spread |
|
|
116
117
|
| Generators (`function*`, `yield`, `yield*`, `next`/`throw`/`return`) | ✓ implemented with stackful coroutines; `for...of`, spread and delegation supported. `return()` completes without running `finally` |
|
|
117
|
-
| Timers | ✓ `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` on the core event loop (numeric ids, no `Timeout` object; no `setImmediate` / `queueMicrotask`) |
|
|
118
|
+
| Timers | ✓ `setTimeout` / `clearTimeout` / `setInterval` / `clearInterval` on the core event loop (numeric ids, no `Timeout` object; no `setImmediate` / `queueMicrotask`). A promise settled from a timer can be awaited: the async body suspends on the pending promise and resumes when the timer fires |
|
|
118
119
|
| I/O / process and other host APIs | only via extensions (e.g. Node `fs`) |
|
|
119
120
|
|
|
120
121
|
### 3.4 Typed arrays
|
|
@@ -133,7 +134,7 @@ element writes, and `fill` / `set` / `slice` / `subarray` / `join` / `toString`
|
|
|
133
134
|
| `keys` / `values` / `entries` | ~ return arrays, not iterator objects |
|
|
134
135
|
| `ArrayBuffer` / `DataView` / `.buffer` / `.byteOffset` semantics | ✗ no backing buffer type; `.byteOffset` is always 0 |
|
|
135
136
|
| `BigInt64Array` / `BigUint64Array` | ✗ not implemented |
|
|
136
|
-
| `instanceof` built-in constructors | ✓ `instanceof Array` / `Object` / `Map` / `Set` / `Date` / `RegExp` / `Promise` / `Error` family / typed arrays are recognised by name
|
|
137
|
+
| `instanceof` built-in constructors | ✓ `instanceof Array` / `Object` / `Map` / `Set` / `Date` / `RegExp` / `Promise` / `Error` family / typed arrays are recognised by name **and through a first-class constructor value** (`const A = Array; x instanceof A`); constructors can be stored, passed, aliased, called and used with `new` |
|
|
137
138
|
| Typed-array views over a `Buffer` / `ArrayBuffer` | ✗ constructors copy from a length / array-like / typed array only |
|
|
138
139
|
|
|
139
140
|
---
|
|
@@ -169,12 +170,13 @@ element writes, and `fill` / `set` / `slice` / `subarray` / `join` / `toString`
|
|
|
169
170
|
| Destructuring parameters / bindings | ✓ | ✓ implemented |
|
|
170
171
|
| `arguments` object | ✓ (implicit) | ✓ implemented (arrow functions get their own parameters, not the outer function's `arguments`, unlike JS) |
|
|
171
172
|
| `this` binding / method call semantics | ✓ | ✓ implemented (`this` is threaded as the first ABI parameter; arrow functions inherit lexically) |
|
|
172
|
-
| `async` / `await` / Promise | ✓ | ✓ implemented (
|
|
173
|
+
| `async` / `await` / Promise | ✓ | ✓ implemented with stackful-coroutine suspension: awaiting a pending promise pauses the body and the event loop resumes it (see the deviations table for the remaining differences) |
|
|
173
174
|
| `new.target` | ✗ | parsed, then rejected with `UnsupportedFeature` (no `new.target` semantics) |
|
|
174
175
|
| Generators / iterators / `yield` | ✓ implemented | `function*`, `yield`, `yield*`, `.next/.throw/.return`; `async` generators are rejected with `UnsupportedFeature` |
|
|
175
176
|
| Closure `arity` | — | `xt_closure_arity` is always -1, never filled in |
|
|
176
177
|
| `fn.call` / `fn.apply` / `fn.bind` | ✓ | ✓ implemented (the bound closure does not track partial-argument `length`) |
|
|
177
178
|
| `fn.name` / `fn.length` | ✓ | ✓ implemented (inferred from the declaration / assignment / property key; bound functions use `"bound ..."` and adjusted arity) |
|
|
179
|
+
| First-class built-in constructors (`const A = Array`, `new A(...)`, `typeof Map`) | ✓ | ✓ constructors are ordinary function values with `name`/`length`, a `prototype`, their statics (`A.isArray`) and the full `instanceof` protocol |
|
|
178
180
|
| First-class built-in methods (`typeof arr.map`, `const f = arr.push`, `obj.method?.()`) | ✓ | ✓ implemented as *unbound* method values: reading `arr.map` yields a function, `arr.map?.(cb)` and `obj.method?.()` bind the receiver as `this`, and a detached call (`const f = arr.map; f(cb)`) throws exactly like JavaScript. Method `name`/`length` are exposed |
|
|
179
181
|
| `fn.toString()` | ~ | returns a native-style placeholder (`function name() { [native code] }`) instead of the original source text |
|
|
180
182
|
|
|
@@ -222,8 +224,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
|
|
|
222
224
|
|
|
223
225
|
| Item | Deviation |
|
|
224
226
|
| --- | --- |
|
|
225
|
-
|
|
|
226
|
-
| `Object.getPrototypeOf({})` | Returns `undefined` instead of the `Object.prototype` object |
|
|
227
|
+
| RegExp byte-oriented matching | The engine matches UTF-8 bytes: literal multi-byte text works, but `.` and character classes consume one byte per repetition (`\d` / `\w` stay ASCII). Offsets returned by `exec` / `search` / replacement callbacks are converted to UTF-16 code units |
|
|
227
228
|
| Global RegExp `lastIndex` | `test` / `exec` do not advance or honour a caller-set `lastIndex` for `/g` / `/y` regexes |
|
|
228
229
|
| String `normalize` / `structuredClone` | Not implemented |
|
|
229
230
|
| First-class built-in methods | Implemented as unbound method values (see section 5); `fn.toString()` returns a placeholder rather than source text |
|
|
@@ -231,9 +232,9 @@ These features **compile and run**, but the result does not fully match ECMAScri
|
|
|
231
232
|
| Array out-of-bounds / sparse | Out-of-bounds access returns `undefined`; assigning `arr.length` truncates / extends, but sparse holes are not tracked distinctly |
|
|
232
233
|
| Memory management | Non-moving mark-sweep collector behind `xt_alloc`: explicit roots, subsystem root providers and a conservative C-stack scan. Single-threaded and stop-the-world; no moving/compaction or generational mode |
|
|
233
234
|
| Function `arity` / argument count | No argument count validation; `fn.length` reports the declared arity but calls are never checked against it |
|
|
234
|
-
| `async` / `await` |
|
|
235
|
+
| `async` / `await` | Real suspension on a stackful coroutine, but `await` on a value that is **already settled** continues synchronously instead of queueing a microtask as the specification requires, so interleaving with pending `.then` callbacks can differ. Top-level `await` blocks on the event loop rather than yielding the module body. `fs/promises` still performs the I/O synchronously before settling; `fetch` is blocking; `async` generators are unsupported |
|
|
235
236
|
| `super` | `super.x` / `super(...)` takes the prototype of `this`'s prototype; single-level inheritance is correct, but depth > 1 may be inaccurate |
|
|
236
|
-
| `Error.stack` | Function-level frames only: each frame is `at name (file:line)` with the function's declaration line (updated to the construction line for the innermost frame); no column numbers and no frames for generator bodies (they switch stacks) |
|
|
237
|
+
| `Error.stack` | Function-level frames only: each frame is `at name (file:line)` with the function's declaration line (updated to the construction line for the innermost frame); no column numbers and no frames for generator / `async` bodies (they switch stacks) |
|
|
237
238
|
| Module live bindings | Namespace imports and imported bindings are snapshots (see section 4) |
|
|
238
239
|
| `import.meta` | ✓ `import.meta.url` / `.dirname` / `.filename`, resolved from the executable path |
|
|
239
240
|
|
|
@@ -253,7 +254,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
|
|
|
253
254
|
| Type checker | ✗ only diagnostic codes are defined; no checker |
|
|
254
255
|
| Full standard library | partial: Math / JSON / Date / Map / Set / RegExp / `Error` / `BigInt` / `Symbol` implemented; String.normalize / structuredClone missing |
|
|
255
256
|
| Multi-file module bundling | partial: relative-path `.ts` bundling, ESM `node_modules` packages, namespace imports and bare-specifier extension module imports implemented; circular dependencies / CommonJS / live bindings not implemented |
|
|
256
|
-
|
|
|
257
|
+
| Real async runtime | ✓ `async`/`await` suspends on pending promises on the `select(2)` reactor: timers, TCP sockets and promise callbacks resume the coroutine. Still missing: truly asynchronous I/O scheduling (`fs/promises` blocks before settling), a non-blocking `fetch` and worker threads (workers are child processes) |
|
|
257
258
|
| Windows binary artifact verification | adapted at the build layer (`.exe` suffix, link flag branch), verified in CI |
|
|
258
259
|
| Precise ECMAScript number / string / comparison semantics | partial, see section 8 |
|
|
259
260
|
|
|
@@ -280,8 +281,8 @@ Unimplemented (modules): circular dependencies, live bindings, dynamic
|
|
|
280
281
|
Unimplemented (type system): type checking, generic instantiation, assertion
|
|
281
282
|
semantics, optional-chaining narrowing
|
|
282
283
|
|
|
283
|
-
Unimplemented (runtime):
|
|
284
|
-
|
|
284
|
+
Unimplemented (runtime): asynchronous I/O scheduling,
|
|
285
|
+
global-regex lastIndex
|
|
285
286
|
|
|
286
287
|
Unimplemented (engineering): type checker
|
|
287
288
|
```
|