xbintsc 0.3.35 → 0.3.49
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 +95 -0
- package/README.md +31 -3
- package/README.zh-CN.md +23 -0
- package/dist/src/cli/hints.d.ts +54 -0
- package/dist/src/cli/hints.js +165 -0
- package/dist/src/cli/hints.js.map +1 -0
- package/dist/src/cli/main.js +73 -9
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/module.js +10 -0
- 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/tables.d.ts +26 -0
- package/dist/src/codegen/generator/tables.js +64 -12
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/diagnostics/source-text.d.ts +22 -0
- package/dist/src/diagnostics/source-text.js +76 -0
- package/dist/src/diagnostics/source-text.js.map +1 -0
- package/dist/src/driver/bundler/graph.js +2 -1
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/compiler.js +3 -2
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/lexer/scanner/strings.js +16 -3
- package/dist/src/lexer/scanner/strings.js.map +1 -1
- package/dist/tests/cli/hints.test.d.ts +9 -0
- package/dist/tests/cli/hints.test.js +143 -0
- package/dist/tests/cli/hints.test.js.map +1 -0
- package/dist/tests/cli/main.test.js +6 -4
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +17 -2
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/e2e/gc.test.d.ts +1 -0
- package/dist/tests/e2e/gc.test.js +168 -0
- package/dist/tests/e2e/gc.test.js.map +1 -0
- package/dist/tests/e2e/harness.d.ts +2 -0
- package/dist/tests/e2e/harness.js +1 -0
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/helpers.js +3 -2
- package/dist/tests/helpers.js.map +1 -1
- package/dist/tests/lexer/strings.test.js +14 -2
- package/dist/tests/lexer/strings.test.js.map +1 -1
- package/doc/DESIGN.md +117 -0
- package/doc/ai/README.md +63 -0
- package/doc/ai/build-recipe.md +137 -0
- package/doc/ai/cli.md +142 -0
- package/doc/ai/contributing.md +196 -0
- package/doc/ai/extensions.md +148 -0
- package/doc/ai/language-support.md +152 -0
- package/doc/ai/troubleshooting.md +163 -0
- package/doc/ai/zh-CN/README.md +56 -0
- package/doc/ai/zh-CN/build-recipe.md +132 -0
- package/doc/ai/zh-CN/cli.md +127 -0
- package/doc/ai/zh-CN/contributing.md +173 -0
- package/doc/ai/zh-CN/extensions.md +139 -0
- package/doc/ai/zh-CN/language-support.md +147 -0
- package/doc/ai/zh-CN/troubleshooting.md +150 -0
- package/doc/gui-scripts.md +350 -0
- package/doc/gui.md +646 -0
- package/doc/icon.md +265 -0
- package/doc/implemented.md +373 -0
- package/doc/node-implemented.md +588 -0
- package/doc/node-unimplemented.md +167 -0
- package/doc/post/announce.md +43 -0
- package/doc/requirements.md +145 -0
- package/doc/unimplemented.md +286 -0
- package/doc/xbintsc.config.schema.json +67 -0
- package/doc/zh-CN/DESIGN.md +104 -0
- package/doc/zh-CN/gui-scripts.md +329 -0
- package/doc/zh-CN/gui.md +588 -0
- package/doc/zh-CN/icon.md +241 -0
- package/doc/zh-CN/implemented.md +365 -0
- package/doc/zh-CN/node-implemented.md +533 -0
- package/doc/zh-CN/node-unimplemented.md +141 -0
- package/doc/zh-CN/plan-require-node-modules.md +284 -0
- package/doc/zh-CN/post/announce.md +47 -0
- package/doc/zh-CN/requirements.md +134 -0
- package/doc/zh-CN/unimplemented.md +247 -0
- package/llms.txt +45 -0
- package/package.json +6 -2
- package/runtime/ext_gui/dom_api_proto.cpp +5 -0
- package/runtime/ext_gui/gui.cpp +3 -1
- package/runtime/ext_gui/renderer.cpp +13 -11
- package/runtime/ext_gui/renderer_image.cpp +12 -8
- package/runtime/ext_gui/renderer_shaders.h +131 -4
- package/runtime/ext_gui/renderer_shaders_data.h +1809 -0
- package/runtime/ext_gui/renderer_text.cpp +12 -8
- package/runtime/ext_gui/shaders.hlsl +98 -0
- package/runtime/ext_gui/spirv/fill.frag +19 -0
- package/runtime/ext_gui/spirv/fill.vert +42 -0
- package/runtime/ext_gui/spirv/image.frag +16 -0
- package/runtime/ext_gui/spirv/quad.vert +30 -0
- package/runtime/ext_gui/spirv/text.frag +16 -0
- package/runtime/ext_gui/window.cpp +1 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +1 -0
- package/runtime/ext_node/dgram/dgram.c +1 -0
- package/runtime/ext_node/events/events.c +1 -0
- package/runtime/ext_node/fs/fs_ops.c +10 -25
- package/runtime/ext_node/fs/glob.c +13 -30
- package/runtime/ext_node/fs/promises.c +1 -0
- package/runtime/ext_node/http/parts/prototypes.inc +5 -0
- package/runtime/ext_node/net/parts/prototypes.inc +2 -0
- package/runtime/ext_node/process/process.c +9 -7
- package/runtime/ext_node/stream/stream.c +1 -0
- package/runtime/ext_node/util/util.c +6 -6
- package/runtime/rt.h +10 -0
- package/runtime/rt_internal.h +63 -2
- package/runtime/xt_alloc.c +442 -5
- package/runtime/xt_generator.c +95 -1
- package/runtime/xt_loop.c +35 -1
- package/runtime/xt_promise.c +46 -0
- package/runtime/xt_stdlib2/error.inc +1 -0
- package/runtime/xt_stdlib2/regexp-match.inc +8 -7
- package/runtime/xt_symbol.c +2 -0
- package/runtime/xt_typed_array/construction.inc +142 -0
- package/runtime/xt_typed_array/elements.inc +92 -0
- package/runtime/xt_typed_array/methods.inc +329 -0
- package/runtime/xt_typed_array.c +6 -548
- package/runtime/xt_values/number-format.inc +26 -0
- package/scripts/build-gui-shaders.mjs +204 -0
- package/scripts/build-gui.ts +35 -0
- package/scripts/check-file-length.ts +89 -0
- package/src/cli/hints.ts +194 -0
- package/src/cli/main.ts +82 -9
- package/src/codegen/generator/module.ts +10 -0
- package/src/codegen/generator/state.ts +4 -0
- package/src/codegen/generator/tables.ts +60 -14
- package/src/diagnostics/source-text.ts +78 -0
- package/src/driver/bundler/graph.ts +2 -1
- package/src/driver/compiler.ts +3 -2
- package/src/lexer/scanner/strings.ts +16 -3
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# CLI 与配置参考
|
|
2
|
+
|
|
3
|
+
权威的 `--help` 文本就是 [../../src/cli/main.ts](../../../src/cli/main.ts) 里的 `HELP`
|
|
4
|
+
常量。本页补充帮助文本没有明说的语义。
|
|
5
|
+
|
|
6
|
+
## 子命令
|
|
7
|
+
|
|
8
|
+
| 命令 | 作用 | 需要 clang? |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| `xbintsc build <file.ts>` | 编译为 `exe`(默认)、`obj` 或 `ir` | 需要,`--emit ir` 除外 |
|
|
11
|
+
| `xbintsc run <file.ts> [-- args]` | 编译成可执行文件并运行 | 需要(且只支持 `--emit exe`) |
|
|
12
|
+
| `xbintsc emit <file.ts>` | 把 LLVM IR 打到 stdout,不写文件 | 不需要 |
|
|
13
|
+
| `xbintsc doctor` | 报告解析到的工具链、运行时与图标工具 | 仅在探测时需要 |
|
|
14
|
+
| `xbintsc version` | 打印版本 | 不需要 |
|
|
15
|
+
| `xbintsc help` | 打印帮助文本 | 不需要 |
|
|
16
|
+
|
|
17
|
+
任何命令加 `--help` 都会打印帮助并返回 0。未知命令会打印错误与帮助文本,返回 1。
|
|
18
|
+
|
|
19
|
+
## 参数
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
-o, --output <path> 显式输出路径(覆盖 --out 与配置)
|
|
23
|
+
--out <dir> 输出目录(默认 build/)
|
|
24
|
+
--emit <kind> exe | obj | ir(默认 exe)
|
|
25
|
+
-O0 .. -O3 传给 clang 的优化级别(默认 -O2)
|
|
26
|
+
--ext <names> 开启内置扩展,逗号分隔(如 node,gui)
|
|
27
|
+
--ext-native <m> 通过 JSON 清单注册 C++/Rust 扩展(多个用逗号分隔)
|
|
28
|
+
--config <path> 使用指定项目配置,不做自动发现
|
|
29
|
+
--no-config 完全不读取项目配置
|
|
30
|
+
--icon <path> 嵌入应用图标(PNG/ICO/ICNS)
|
|
31
|
+
--bundle macOS:额外产出 <name>.app
|
|
32
|
+
--app-name <name> Bundle / 显示名
|
|
33
|
+
--app-id <id> macOS bundle 标识(如 com.example.demo)
|
|
34
|
+
--force 忽略增量缓存
|
|
35
|
+
--verbose 打印进度信息
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
少数容易踩的解析细节:
|
|
39
|
+
|
|
40
|
+
- `--flag=value` 与 `--flag value` 都支持。
|
|
41
|
+
- `-O`、`-O1`、`-O2`、`-O3` 都可以;裸 `-O` 等价于 `-O2`。
|
|
42
|
+
- `--` 结束参数解析:其后的内容在 `run` 下属于被运行程序,在其他命令下是位置参数。
|
|
43
|
+
- `-o` 会无条件吃掉下一个参数;其他带值参数在后一个参数以 `-` 开头时视为未给值。
|
|
44
|
+
|
|
45
|
+
## 项目配置
|
|
46
|
+
|
|
47
|
+
`xbintsc.config.json` 从**入口文件所在目录向上**查找(没有给入口文件时从当前目录
|
|
48
|
+
开始)。文件里的每个路径相对该配置文件解析,命令行参数覆盖对应字段。`--no-config`
|
|
49
|
+
完全跳过发现流程。
|
|
50
|
+
|
|
51
|
+
| 字段 | 类型 | 含义 |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `entry` | string | 入口 TypeScript 文件,使 `xbintsc build` 无需位置参数 |
|
|
54
|
+
| `outDir` | string | 输出目录(默认 `build/`) |
|
|
55
|
+
| `output` | string | 显式输出路径,覆盖 `outDir` |
|
|
56
|
+
| `optimize` | `"0"|"1"|"2"|"3"` | 优化级别 |
|
|
57
|
+
| `extensions` | string[] | 开启的内置扩展,如 `["node"]` |
|
|
58
|
+
| `extNative` | string[] | 原生扩展清单路径 |
|
|
59
|
+
| `force` | boolean | 忽略增量缓存 |
|
|
60
|
+
| `app.name` / `app.icon` / `app.bundle` / `app.bundleId` | | 应用元信息([icon.md](../../zh-CN/icon.md)) |
|
|
61
|
+
|
|
62
|
+
JSON schema:[xbintsc.config.schema.json](../../xbintsc.config.schema.json)。配置读不了
|
|
63
|
+
或格式错误时,构建会以 `invalid JSON` 或 `Unable to read` 失败,而不会静默退回默认值。
|
|
64
|
+
|
|
65
|
+
## 环境变量
|
|
66
|
+
|
|
67
|
+
| 变量 | 作用 |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `xbintsc_CLANG` | 指定 clang,替代从 `PATH` 解析 |
|
|
70
|
+
| `xbintsc_LINKER_ARGS` | 额外链接参数(如 `-fuse-ld=lld`) |
|
|
71
|
+
| `xbintsc_CACHE_DIR` | 对象缓存目录(默认 `.xbintsc`) |
|
|
72
|
+
| `xbintsc_PREFER_PREBUILT` | `0` 强制从源码编译运行时 |
|
|
73
|
+
| `xbintsc_BINARY` | `bin/` 启动器应运行的原生编译器二进制 |
|
|
74
|
+
|
|
75
|
+
## 增量编译
|
|
76
|
+
|
|
77
|
+
每次构建的键由入口源码哈希、编译器版本、构建选项、平台和已启用扩展集合共同决定
|
|
78
|
+
([../../src/driver/cache.ts](../../../src/driver/cache.ts))。如果记录中的产物都还在,
|
|
79
|
+
构建立即返回并打印 `(cached)`。C 运行时与扩展源码按同样机制缓存,对象文件放在
|
|
80
|
+
`.xbintsc/`(或 `xbintsc_CACHE_DIR`)。
|
|
81
|
+
|
|
82
|
+
`--force`(或配置 `force: true`)跳过新鲜度检查。如果构建结果疑似过期,这个键是
|
|
83
|
+
第一个该看的东西——注意对象缓存的键刻意不含编译参数,这正是运行时覆盖率脚本使用
|
|
84
|
+
独立缓存目录的原因。
|
|
85
|
+
|
|
86
|
+
## 退出码
|
|
87
|
+
|
|
88
|
+
- `0` —— 成功(对 `run` 而言是被运行程序退出 0)。
|
|
89
|
+
- `1` —— 有诊断、用法错误,或编译器自身失败。
|
|
90
|
+
- `run` 其他情况直接透传被运行程序的退出码。
|
|
91
|
+
|
|
92
|
+
## 诊断信息
|
|
93
|
+
|
|
94
|
+
错误渲染为 `file:line:col - error TS<code>: <message>`,并附带源码片段与插入符下划线。
|
|
95
|
+
代码按阶段分段([../../src/diagnostics/diagnostic.ts](../../../src/diagnostics/diagnostic.ts)):
|
|
96
|
+
|
|
97
|
+
| 区间 | 阶段 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| TS1xxx | 词法分析 |
|
|
100
|
+
| TS2xxx | 语法分析 |
|
|
101
|
+
| TS3xxx | 名称绑定 |
|
|
102
|
+
| TS4xxx | 检查器(`TS4005` 即 `UnsupportedFeature`) |
|
|
103
|
+
| TS5xxx | 代码生成 |
|
|
104
|
+
| TS6xxx | 驱动:`TS6001` 模块未找到、`TS6002` IO、`TS6003` 工具链、`TS6004` 缓存 |
|
|
105
|
+
|
|
106
|
+
CLI 会在错误之后追加一行 `hint:`,指向对应文档(例如 `TS4005` 指向
|
|
107
|
+
[language-support.md](./language-support.md),`TS6001`/`TS6003` 指向
|
|
108
|
+
[troubleshooting.md](./troubleshooting.md))。工具链与 IO 失败是抛异常而非产生诊断,
|
|
109
|
+
CLI 会以 `xbintsc: <message>` 加上同款提示来报告。
|
|
110
|
+
|
|
111
|
+
## 编程 API
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { build, compileString } from "xbintsc";
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- `compileString(source, fileName?, extensions?)` → `{ ir, diagnostics }`。纯 IR 生成:
|
|
118
|
+
不碰文件系统,不调用 clang。
|
|
119
|
+
- `build(entryPath, options?)` → `BuildResult`。`options` 支持 `output`、`outDir`、
|
|
120
|
+
`emit`、`optimize`、`force`、`verbose`、`extensions`(注册表)、`app`、`clang`、
|
|
121
|
+
`preferPrebuilt`。
|
|
122
|
+
- 返回值形状:`{ outputPath, irPath?, cached, diagnostics, ir?, bundlePath? }`。
|
|
123
|
+
|
|
124
|
+
`build` 把源码级问题通过 `diagnostics` 报告——使用产物之前务必检查
|
|
125
|
+
`diagnostics.some((d) => d.category === "error")`——但 clang 自身失败时会**抛出**
|
|
126
|
+
`ToolchainError`([../../src/driver/toolchain.ts](../../../src/driver/toolchain.ts))。
|
|
127
|
+
子路径 `xbintsc/driver` 另外导出缓存、工具链解析、配置加载、图标与 macOS bundle 助手。
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# 参与编译器开发
|
|
2
|
+
|
|
3
|
+
本页接在 [../../AGENTS.md](../../../AGENTS.md) 之后读:那里讲了目录结构、构建门禁与规则,
|
|
4
|
+
这里讲容易搞错的工作流细节。
|
|
5
|
+
|
|
6
|
+
## 准备环境
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install
|
|
10
|
+
npm run typecheck # tsc --noEmit
|
|
11
|
+
npm run lint # eslint + 600 行文件预算
|
|
12
|
+
npm test # 单元测试 + 端到端测试
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
从源码运行编译器需要 Node.js ≥ 22;任何会链接二进制的操作都需要 **clang 16+** 工具链
|
|
16
|
+
(见 [troubleshooting.md](./troubleshooting.md))。`xbintsc emit` 既不需要 clang 也不需要
|
|
17
|
+
运行时库,因此它是最快的内循环。
|
|
18
|
+
|
|
19
|
+
可选但推荐——安装仓库钩子:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git config core.hooksPath .githooks
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`.githooks/pre-commit` **会在每次提交时把补丁版本号 +1**,并把 `package.json` 与
|
|
26
|
+
`package-lock.json` 一起折进该提交(`npm version patch --no-git-tag-version`)。请预期
|
|
27
|
+
你的提交里会带版本号变更,不要对抗它。发布标签由 `release.yml` 创建,钩子从不打标签。
|
|
28
|
+
|
|
29
|
+
## 测试套件
|
|
30
|
+
|
|
31
|
+
| 命令 | 范围 |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `npm test` | 全部:按模块的单元测试 + `tests/e2e` |
|
|
34
|
+
| `npm run test:e2e` | 只跑"编译并运行"的测试 |
|
|
35
|
+
| `npm run test:watch` | vitest 监听模式 |
|
|
36
|
+
| `npm run coverage` | TypeScript 编译器(`src/`)的 V8 覆盖率 |
|
|
37
|
+
| `npm run coverage:runtime` | C 运行时(`runtime/`)的 LLVM 覆盖率 |
|
|
38
|
+
|
|
39
|
+
单元测试在 `tests/` 下按模块一个目录(`lexer`、`parser`、`binder`、`codegen`、
|
|
40
|
+
`driver`、`extensions`、`cli`、`e2e`),与源码树镜像对应。边界用例放在它覆盖的模块
|
|
41
|
+
旁边。
|
|
42
|
+
|
|
43
|
+
`tests/e2e/` 会编译真实程序并运行产出的二进制,其中包含一个**差分测试框架**
|
|
44
|
+
(`tests/e2e/differential-*.test.ts`):把同一份源码分别交给 xbintsc 和 Node 执行,
|
|
45
|
+
逐字节比较输出。这是仓库里最强的工具:只要动到语义,就往那里加用例,而不是断言一个
|
|
46
|
+
手写的期望字符串。需要 clang 的测试在 clang 缺失时会自动跳过
|
|
47
|
+
([tests/helpers.ts](../../../tests/helpers.ts) 里的 `hasClang()`)——不要把这种跳过
|
|
48
|
+
变成静默通过。
|
|
49
|
+
|
|
50
|
+
## 两条不能破坏的不变量
|
|
51
|
+
|
|
52
|
+
### 1. 自举不动点
|
|
53
|
+
|
|
54
|
+
CI([.github/workflows/ci.yml](../../../.github/workflows/ci.yml) 的 `self-host` 任务)
|
|
55
|
+
用编译器编译自身,并要求各代生成的 IR 完全一致:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
源码 --emit--> ref.ll
|
|
59
|
+
源码 --build--> gen1 二进制
|
|
60
|
+
gen1 --emit--> gen2.ll # 必须等于 ref.ll
|
|
61
|
+
gen1 --build--> gen2 二进制
|
|
62
|
+
gen2 --emit--> gen3.ll # 必须等于 ref.ll
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
由此推论:**任何改变生成 IR 的修改,都必须能被正在被修改的编译器自己复现**,并且 IR
|
|
66
|
+
必须逐字节确定——包括迭代顺序、生成的符号名与编号。绝不要把不确定性(未受控的
|
|
67
|
+
`Map`/`Set` 迭代顺序、时间戳、依赖文件系统顺序的东西)引入代码生成。
|
|
68
|
+
|
|
69
|
+
第二个推论是字符串模型:编译器自身源码文本在各代中必须含义一致。编译后的字符串是
|
|
70
|
+
UTF-8 字节,所以自举后的 `readFileSync`(`--ext node`)交给扫描器的是文件字节,而
|
|
71
|
+
Node 交给它的是同一个文件已解码后的文本——读取源码文件一律走 `decodeUtf8`
|
|
72
|
+
([src/diagnostics/utf8.ts](../../../src/diagnostics/utf8.ts)),不要假设一个码元就是
|
|
73
|
+
一个字节或一个字符。弄错的表现是:`gen2.ll` 里非 ASCII 字面量(比如提示语里的 `—`)
|
|
74
|
+
被重新编码,这也正是这里逐字节比较 IR 而不是逐行比较的原因。
|
|
75
|
+
|
|
76
|
+
本地验证:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx tsx src/cli/main.ts emit src/cli/main.ts --ext node > scratch/ref.ll
|
|
80
|
+
npx tsx src/cli/main.ts build src/cli/main.ts --ext node --out scratch/self --force
|
|
81
|
+
./scratch/self/main emit src/cli/main.ts --ext node > scratch/gen2.ll # Windows 上是 .exe
|
|
82
|
+
diff scratch/ref.ll scratch/gen2.ll
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. 运行时 ABI 与值模型
|
|
86
|
+
|
|
87
|
+
- 每个编译后的函数都用同一条 ABI:
|
|
88
|
+
`xt_value fn(xt_value env, int32_t argc, xt_value *argv)` —— 直接调用与闭包调用共用
|
|
89
|
+
这一条路径,`env` 通过 box 传递被捕获的变量。
|
|
90
|
+
- 每个值都是一个 64 位字:double 不装箱,其余都是带标签指针(16 位标签 + 48 位载荷)。
|
|
91
|
+
该表示只定义一次:[../../../src/codegen/values.ts](../../../src/codegen/values.ts) 与
|
|
92
|
+
[../../../runtime/rt.h](../../../runtime/rt.h);要改就一起改,否则别动。
|
|
93
|
+
- 别扭的 JS 语义(`+` 强转、关系比较、属性访问、打印)委托给 `@xt_*` 运行时调用,而
|
|
94
|
+
不是内联。
|
|
95
|
+
- GC 是非移动标记清扫:新堆对象走 `xt_alloc`;值存活期间必须能从显式根槽、已注册的
|
|
96
|
+
根提供者(事件循环、微任务队列)或 C 栈保守扫描到达。只存在于未被扫描的 C 局部
|
|
97
|
+
变量里的值就是 bug。
|
|
98
|
+
|
|
99
|
+
## 修改运行时
|
|
100
|
+
|
|
101
|
+
`runtime/` 是 C,按函数拆到多个编译单元(`xt_alloc.c`、`xt_values.c`、
|
|
102
|
+
`xt_containers.c`、`xt_stdlib.c`、`xt_stdlib2.c` 等),共享 `runtime/rt_internal.h`。
|
|
103
|
+
C 改动必须重建运行时才会生效:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm run runtime # tsx scripts/build-runtime.ts -> runtime/lib/<os>-<arch>/
|
|
107
|
+
npm run runtime:clean # 删除 build/runtime-obj 与 runtime/lib
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
新增 C 文件时必须同时更新列出运行时源文件的地方([../../../src/driver/compiler.ts](../../../src/driver/compiler.ts)
|
|
111
|
+
里的 `RUNTIME_SOURCES`),因为那份列表决定什么会被编译和链接。扩展的 C 源由扩展自己声明。
|
|
112
|
+
|
|
113
|
+
## 新增或扩展一个扩展
|
|
114
|
+
|
|
115
|
+
扩展就是一个普通对象([../../../src/extensions/registry.ts](../../../src/extensions/registry.ts)),
|
|
116
|
+
贡献 `runtimeSources()`、`modules()` / `builtins()`,可选贡献 `nativeObjects()` 或
|
|
117
|
+
`assetLoaders()`。Node 扩展是"每个模块一个目录",把 TypeScript 导出与实现它的 C 源
|
|
118
|
+
配成对:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
src/extensions/node/fs/index.ts runtime/ext_node/fs/read_file.c
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
因此新增一个 Node 模块就是在两处各放一个目录,并在模块列表里注册;核心编译器不改。
|
|
125
|
+
如果你的特性是可选的或与平台相关,它属于某个扩展,而不是 `src/codegen`。内置扩展
|
|
126
|
+
列在 [../../../src/extensions/catalog.ts](../../../src/extensions/catalog.ts) —— 列在那里
|
|
127
|
+
但未开启的扩展会产生可操作的 `pass --ext <name>` 提示,所以即使默认关闭也要把模块
|
|
128
|
+
加进列表。
|
|
129
|
+
|
|
130
|
+
不改编译器、纯用 C++/Rust 编写扩展的做法见
|
|
131
|
+
[../../../examples/extensions/README.md](../../../examples/extensions/README.md)。
|
|
132
|
+
|
|
133
|
+
## 新增一条诊断
|
|
134
|
+
|
|
135
|
+
1. 在 [../../../src/diagnostics/diagnostic.ts](../../../src/diagnostics/diagnostic.ts)
|
|
136
|
+
的枚举里按阶段加入稳定代码(1xxx 词法、2xxx 语法、3xxx 绑定、4xxx 检查、5xxx 代码
|
|
137
|
+
生成、6xxx 驱动)。诊断码是公开接口——绝不要重新编号。
|
|
138
|
+
2. 用你手上最精确的范围发出它;`formatDiagnostic` 会据此渲染文件、行、列、片段与
|
|
139
|
+
插入符。
|
|
140
|
+
3. 让消息可操作,风格与现有消息一致:既说清哪里错了,也说清该做什么(`pass --ext
|
|
141
|
+
node`、`use an ESM import` 等)。如果读者还需要更多信息,CLI 的提示层会把诊断码
|
|
142
|
+
映射到文档——新增诊断码时同步扩展
|
|
143
|
+
[../../../src/cli/main.ts](../../../src/cli/main.ts) 里的映射。
|
|
144
|
+
4. 在 `tests/diagnostics` 或该模块自己的测试里覆盖它。
|
|
145
|
+
|
|
146
|
+
## 文档是改动的一部分
|
|
147
|
+
|
|
148
|
+
文档没同步,功能就不算完成:
|
|
149
|
+
|
|
150
|
+
| 文档 | 何时更新 |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| [../../zh-CN/implemented.md](../../zh-CN/implemented.md) | 某特性开始可用 |
|
|
153
|
+
| [../../zh-CN/unimplemented.md](../../zh-CN/unimplemented.md) | 出现或解除了某个限制 |
|
|
154
|
+
| [../../zh-CN/node-implemented.md](../../zh-CN/node-implemented.md) / [../../zh-CN/node-unimplemented.md](../../zh-CN/node-unimplemented.md) | Node 模块覆盖变化 |
|
|
155
|
+
| [language-support.md](./language-support.md) | 上述内容的 AI 摘要变化 |
|
|
156
|
+
| [../../zh-CN/requirements.md](../../zh-CN/requirements.md) | 工具链或平台要求变化 |
|
|
157
|
+
| [cli.md](./cli.md) | 参数、配置字段或环境变量变化 |
|
|
158
|
+
|
|
159
|
+
中文翻译(`doc/zh-CN/`、`doc/ai/zh-CN/`)要与英文源同步;半翻译的页面比没有更糟,因为
|
|
160
|
+
它会静默过期。
|
|
161
|
+
|
|
162
|
+
## 仓库卫生
|
|
163
|
+
|
|
164
|
+
- **每个代码文件 600 行**:TS/JS 由 ESLint(`max-lines`)强制,C、C++、Rust、`.inc`
|
|
165
|
+
与 shell 由 [scripts/check-file-length.ts](../../../scripts/check-file-length.ts) 强制。
|
|
166
|
+
请按职责拆分而不是把文件撑大;vendored 源码豁免。
|
|
167
|
+
- **禁止 `any`**;`prefer-const` 与 `eqeqeq` 是错误。解析器/生成器里的声明合并模式是
|
|
168
|
+
有意放行的。
|
|
169
|
+
- **公开 API 变更**走 [../../../src/index.ts](../../../src/index.ts),并且必须保持
|
|
170
|
+
[../../../package.json](../../../package.json) 里 `xbintsc` / `xbintsc/driver` 的导出
|
|
171
|
+
映射有效。
|
|
172
|
+
- `npm run package-release` 会把各平台压缩包组装到 `dist/release/`;发布工作流负责打
|
|
173
|
+
标签,所以永远不要手工推标签。
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# 扩展:Node 模块、GUI、C++/Rust 库
|
|
2
|
+
|
|
3
|
+
编译器核心与平台无关。任何与平台相关的东西——Node 的 `fs`、一个 HTML/CSS 渲染器、
|
|
4
|
+
你自己的 C++ 库——都以**扩展**的形式接入:它既贡献模块绑定,也贡献要一起编译/链接的
|
|
5
|
+
C/C++ 源码或目标文件。
|
|
6
|
+
|
|
7
|
+
## 最容易踩的规则
|
|
8
|
+
|
|
9
|
+
**只要扩展没开启,import 它提供的模块就会失败。** xbintsc 知道该模块存在,并明确
|
|
10
|
+
告诉你要传什么:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
$ xbintsc run app.ts # app.ts: import { readFileSync } from "fs";
|
|
14
|
+
error TS6001: module 'fs' is provided by the 'node' extension; pass --ext node
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
xbintsc run app.ts --ext node
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
多个扩展用逗号分隔一次开启:`--ext node,gui`。在项目里写进
|
|
22
|
+
`xbintsc.config.json` 就不需要每次带参数:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{ "entry": "src/app.ts", "outDir": "build", "extensions": ["node"] }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 内置扩展
|
|
29
|
+
|
|
30
|
+
### `node` —— Node 内置模块
|
|
31
|
+
|
|
32
|
+
用 `--ext node` 开启。可以用裸名或 `node:` 前缀导入(`import { readFileSync } from
|
|
33
|
+
"node:fs"`),两种写法解析到同一实现。
|
|
34
|
+
|
|
35
|
+
| 模块 | 说明 |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `fs` | **仅同步 API**(`readFileSync`、`writeFileSync` 等);`fs/promises` 是独立模块 |
|
|
38
|
+
| `fs/promises` | 基于 Promise 的文件 API |
|
|
39
|
+
| `path` | 同时接入命名空间分发,`path.join(...)` 可用 |
|
|
40
|
+
| `os` | |
|
|
41
|
+
| `process` | `process.cwd()`、`argv`、`env` 等;也接入命名空间分发 |
|
|
42
|
+
| `buffer` | |
|
|
43
|
+
| `crypto` | |
|
|
44
|
+
| `stream`、`stream/promises` | |
|
|
45
|
+
| `events` | |
|
|
46
|
+
| `net`、`dgram`、`http` | 跑在 xbintsc 事件循环上的套接字与服务端(注意下面的异步限制) |
|
|
47
|
+
| `child_process` | |
|
|
48
|
+
| `worker_threads` | |
|
|
49
|
+
| `util`、`querystring`、`url`、`assert`、`test`、`zlib` | |
|
|
50
|
+
|
|
51
|
+
各模块的具体覆盖(确切函数与选项)见
|
|
52
|
+
[../../zh-CN/node-implemented.md](../../zh-CN/node-implemented.md),缺失项见
|
|
53
|
+
[../../zh-CN/node-unimplemented.md](../../zh-CN/node-unimplemented.md)。
|
|
54
|
+
|
|
55
|
+
在 `net`/`http` 上搭东西之前,先记住运行时模型:事件循环在**程序主体之后**才运行,
|
|
56
|
+
而 `async`/`await` 是同步微任务模型。见 [language-support.md](./language-support.md)。
|
|
57
|
+
|
|
58
|
+
### `gui` —— HTML/CSS 窗口
|
|
59
|
+
|
|
60
|
+
用 `--ext gui` 开启并导入 `gui` 模块:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { createWindow, run } from "gui";
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
它是自带渲染引擎的 GPU 加速实现(自己的 HTML 解析器、CSS 级联、布局与合成器),不是
|
|
67
|
+
系统 WebView。因为主体是 C++,它以各平台预编译的 `gui.a`/`gui.lib` 形式分发。如果该
|
|
68
|
+
平台的归档不存在,构建会以明确的提示失败;设计与路线图见 [../../zh-CN/gui.md](../../zh-CN/gui.md),
|
|
69
|
+
脚本接口见 [../../zh-CN/gui-scripts.md](../../zh-CN/gui-scripts.md)。
|
|
70
|
+
|
|
71
|
+
## 第三方 npm 包
|
|
72
|
+
|
|
73
|
+
没有被已启用扩展认领的裸说明符,会在 `node_modules` 里查找并**作为源码**打包。不是
|
|
74
|
+
纯 ESM TypeScript/JavaScript 的包——或依赖 CommonJS、`require`、`__dirname`、循环
|
|
75
|
+
依赖的包——都不会工作。`require()` 会被拒绝并提示改用 `import`。
|
|
76
|
+
|
|
77
|
+
实践结论:写 Node 程序时,正确做法通常就是开 `--ext node`;只有确实必要时才去依赖
|
|
78
|
+
npm 包。
|
|
79
|
+
|
|
80
|
+
## 原生扩展(C++ / Rust,无需改编译器)
|
|
81
|
+
|
|
82
|
+
任何暴露了运行时 ABI 的 `extern "C"` 入口的代码都能被链接进来:
|
|
83
|
+
|
|
84
|
+
```c
|
|
85
|
+
xt_value my_fn(int32_t argc, xt_value *argv);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
用**外部**工具链(clang++ 或 cargo)构建它,把产物写进一个 JSON 清单,然后传清单:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
xbintsc build demo.ts --ext-native ./xbintsc.manifest.json
|
|
92
|
+
xbintsc build demo.ts --ext-native a.json,b.json # 多个
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```jsonc
|
|
96
|
+
{
|
|
97
|
+
"name": "mathx-cpp", // 必填,唯一
|
|
98
|
+
"objects": ["build/mathx.o"], // .o / .a / .lib,相对本文件
|
|
99
|
+
"linkerFlagsByPlatform": { // C++/Rust 运行时
|
|
100
|
+
"linux": ["-lstdc++", "-lm"],
|
|
101
|
+
"darwin": ["-lc++"],
|
|
102
|
+
"win32": ["-lmsvcprt"]
|
|
103
|
+
},
|
|
104
|
+
"builtins": { "cppClamp": { "symbol": "mathx_clamp" } }, // 无需 import
|
|
105
|
+
"modules": {
|
|
106
|
+
"mathx": { "exports": { "add": { "symbol": "mathx_add" } } }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
之后 `import { add } from "mathx"` 会像 C 运行时绑定一样降级到原生符号;`builtins`
|
|
112
|
+
无需导入即可全局调用。
|
|
113
|
+
|
|
114
|
+
编写辅助头:`runtime/xt_ext.h`(C/C++)与 `runtime/xt_ext.rs`(Rust),它们封装了参数
|
|
115
|
+
与值的辅助函数。关键 ABI 事实:值是 64 位 NaN-boxed 字;字符串**不**以 NUL 结尾,
|
|
116
|
+
所以要把 `xt_string_data` 与 `xt_string_length_value` 配对使用;运行时交给你的内存
|
|
117
|
+
不会被移动或释放。请使用与 xbintsc 解析到的同一个 clang/ABI 构建(`xbintsc doctor`
|
|
118
|
+
会打印它);在 Windows 上要在 **x64/ARM64 Native Tools 命令提示符**里构建。
|
|
119
|
+
|
|
120
|
+
可直接照抄的工程:[`examples/extensions/cpp`](../../../examples/extensions/cpp) 与
|
|
121
|
+
[`examples/extensions/rust`](../../../examples/extensions/rust);完整指南见
|
|
122
|
+
[../../../examples/extensions/README.md](../../../examples/extensions/README.md)。
|
|
123
|
+
|
|
124
|
+
## 编程式注册
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { build, createDefaultRegistry, nativeExtensionFromManifest, nodeExtension } from "xbintsc";
|
|
128
|
+
|
|
129
|
+
const extensions = createDefaultRegistry()
|
|
130
|
+
.register(nodeExtension)
|
|
131
|
+
.register(nativeExtensionFromManifest("./xbintsc.manifest.json"));
|
|
132
|
+
|
|
133
|
+
build("demo.ts", { extensions });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
注册表也是宿主工具提示"某扩展未开启"的机制,正是它把错误变成了可操作的
|
|
137
|
+
"pass `--ext node`",而不是下游令人困惑的报错
|
|
138
|
+
([../../../src/extensions/catalog.ts](../../../src/extensions/catalog.ts))。内置扩展
|
|
139
|
+
列表由 `bundledExtensions()` 提供。
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 语言支持范围:什么能编译,什么行为不同
|
|
2
|
+
|
|
3
|
+
xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能写什么;要精确措辞请
|
|
4
|
+
点开链接。
|
|
5
|
+
|
|
6
|
+
权威细节(始终最新、篇幅长得多):
|
|
7
|
+
|
|
8
|
+
- [../../zh-CN/implemented.md](../../zh-CN/implemented.md) —— 所有已实现能力,按编译器阶段组织
|
|
9
|
+
- [../../zh-CN/unimplemented.md](../../zh-CN/unimplemented.md) —— 不支持的语法、行为偏差、速查表
|
|
10
|
+
- [../../zh-CN/node-implemented.md](../../zh-CN/node-implemented.md) / [../../zh-CN/node-unimplemented.md](../../zh-CN/node-unimplemented.md) —— Node 扩展
|
|
11
|
+
|
|
12
|
+
## 图例
|
|
13
|
+
|
|
14
|
+
| 标记 | 含义 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| ✅ | 与 Node/TypeScript 一致 |
|
|
17
|
+
| ⚠️ | 可用,但与标准行为有偏差 |
|
|
18
|
+
| 🚫 | 被拒绝——语法错误或 `UnsupportedFeature` |
|
|
19
|
+
| — | 被解析后擦除,运行时无任何作用 |
|
|
20
|
+
|
|
21
|
+
## 语句与声明
|
|
22
|
+
|
|
23
|
+
| 特性 | 状态 | 说明 |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `var`/`let`/`const`、块、`if`、`for`、`for...of`、`for...in`、`while`、`do...while` | ✅ | `for...in` 只枚举自有键(不含原型链) |
|
|
26
|
+
| `switch`、`break`、`continue`、标签 | ✅ | 含带标签的 `break`/`continue` |
|
|
27
|
+
| `try`/`catch`/`finally`、`throw` | ✅ | 提前 `return`/`break`/`continue` 时 `finally` 仍会执行 |
|
|
28
|
+
| `function`、箭头函数、默认参数/剩余参数 | ✅ | |
|
|
29
|
+
| `namespace`/`module` 声明 | 🚫 | 解析 ✓,代码生成 ✗ |
|
|
30
|
+
| `with`、`debugger` | 🚫 | 不支持 |
|
|
31
|
+
| 顶层 `await` | 🚫 | 请包进 `async` 函数 |
|
|
32
|
+
|
|
33
|
+
## 表达式与运算符
|
|
34
|
+
|
|
35
|
+
| 特性 | 状态 | 说明 |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| 算术、位运算、逻辑、比较、赋值运算符 | ✅ | `+` 与 `ToPrimitive` 强转与 Node 一致 |
|
|
38
|
+
| `===`/`!==`/`==`/`!=` | ✅ | 宽松相等与 Node 一致 |
|
|
39
|
+
| 可选链 `?.`、空值合并 `??`、逻辑赋值 `??=` | ✅ | 整条链的短路都已实现 |
|
|
40
|
+
| 模板字符串、标签模板 | ✅ | 标签模板提供 `raw` 与 `String.raw` |
|
|
41
|
+
| 调用/数组/对象字面量中的展开与剩余 | ✅ | |
|
|
42
|
+
| 解构(绑定、参数、嵌套) | ✅ | 支持默认值与剩余 |
|
|
43
|
+
| `delete`、`in`、`instanceof`、`typeof` | ✅ | |
|
|
44
|
+
| 逗号运算符、`void` | ✅ | |
|
|
45
|
+
| `new.target` | 🚫 | 未实现 |
|
|
46
|
+
| `import.meta` | 🚫 | 能解析,但没有值 |
|
|
47
|
+
| `super` | ⚠️ | 单层继承正确;继承深度 > 1 可能不准 |
|
|
48
|
+
|
|
49
|
+
## 函数、类与对象
|
|
50
|
+
|
|
51
|
+
| 特性 | 状态 | 说明 |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| 闭包(通过 box 按引用捕获) | ✅ | 直接调用与闭包调用共用一条 ABI |
|
|
54
|
+
| `this`、方法调用、箭头函数词法 `this` | ✅ | 与 JS 不同:箭头函数有自己的 `arguments` |
|
|
55
|
+
| `call`/`apply`/`bind`、`fn.name`/`fn.length` | ✅ | bind 出的闭包不跟踪部分应用后的 `length` |
|
|
56
|
+
| 一等内置方法(把 `arr.map` 当值用) | ✅ | 暴露为*未绑定*方法值;脱离接收者调用时与 JS 一样抛错 |
|
|
57
|
+
| `fn.toString()` | ⚠️ | 返回 `function name() { [native code] }`,不是源码 |
|
|
58
|
+
| 类:字段、方法、静态成员、getter/setter、`extends`/`super`、`instanceof` | ✅ | |
|
|
59
|
+
| 构造器参数属性 `constructor(public x: T)` | ✅ | |
|
|
60
|
+
| `#private` 字段/方法/静态成员 | ⚠️ | 以字面量 `#x` 键存储;不做访问控制;父子类同名可能互相覆盖 |
|
|
61
|
+
| `enum`/`const enum` | ✅ | 正向 + 反向映射 |
|
|
62
|
+
| `private`/`protected`/`public`/`readonly`/`abstract`/`implements` | — | 被擦除,无访问控制 |
|
|
63
|
+
| 生成器 `function*`、`yield`、`yield*` | ✅ | 不支持 `async` 生成器 |
|
|
64
|
+
| `arguments` 对象 | ✅ | 隐式提供;箭头函数看到的是自己的参数 |
|
|
65
|
+
| 参数个数校验 | 🚫 | 从不校验,虽然 `fn.length` 会报声明元数 |
|
|
66
|
+
|
|
67
|
+
## 异步、Promise 与事件循环
|
|
68
|
+
|
|
69
|
+
| 特性 | 状态 | 说明 |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `async`/`await`、`Promise`、`Promise.all` | ⚠️ | **同步微任务模型**——`await` 一个已敲定的 Promise 会同步继续 |
|
|
72
|
+
| `setTimeout` 与回调 | ⚠️ | 事件循环在**程序主体之后**才运行,因此定时器里敲定的 Promise 无法被 await |
|
|
73
|
+
| 套接字/服务端(`http`、`net`、`dgram`) | ⚠️ | 同一模型:回调在程序主体之后的循环里执行 |
|
|
74
|
+
| 真正的异步事件循环、worker 线程 | 🚫 | 未实现 |
|
|
75
|
+
|
|
76
|
+
## 类型:解析后擦除
|
|
77
|
+
|
|
78
|
+
**不做任何类型检查。** 类型语法被解析进 AST,随后在绑定/代码生成阶段擦除:
|
|
79
|
+
|
|
80
|
+
| 构造 | 状态 |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| 类型注解、返回类型、类型别名、接口 | — 解析后擦除,从不检查 |
|
|
83
|
+
| 泛型参数与约束 | — 运行时无实例化 |
|
|
84
|
+
| `as`、`satisfies`、非空断言 `!` | — 擦除,无断言语义 |
|
|
85
|
+
| 可选链的类型收窄 | 🚫 |
|
|
86
|
+
| 诊断码 `TS4001`–`TS4004`(`TypeMismatch`、`NotCallable`、`PropertyNotFound`、`ArgumentCountMismatch`) | 🚫 有定义但从不发出 |
|
|
87
|
+
|
|
88
|
+
因此源码里的类型错误**不是**编译错误——只有运行时行为会被检查。你想跑出什么行为,
|
|
89
|
+
就写什么代码。
|
|
90
|
+
|
|
91
|
+
## 标准库
|
|
92
|
+
|
|
93
|
+
已实现:`Math`、`JSON`、`Date`、`RegExp`、`Map`、`Set`、`WeakMap`/`WeakSet`、
|
|
94
|
+
`Symbol`、`Error` 家族、`BigInt`、`Array`/`String`/`Number`/`Object` 方法、TypedArray、
|
|
95
|
+
带捕获组的 `String.prototype.match`/`split`/`replace`、不可变数组方法
|
|
96
|
+
(`toReversed`、`toSorted`、`toSpliced`、`with`)、全局 URI 函数。
|
|
97
|
+
|
|
98
|
+
| 缺失或行为不同 | 状态 |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `String.prototype.normalize`、`structuredClone` | 🚫 |
|
|
101
|
+
| `Error.stack` 采集 | 🚫(不采集) |
|
|
102
|
+
| `Object.getPrototypeOf({})` | ⚠️ 返回 `undefined`,而非 `Object.prototype` |
|
|
103
|
+
| 全局 RegExp `lastIndex` | ⚠️ `/g`、`/y` 下 `test`/`exec` 忽略它 |
|
|
104
|
+
| 稀疏数组空洞、数组越界 | ⚠️ 不区分空洞;越界读得 `undefined` |
|
|
105
|
+
|
|
106
|
+
完整列表见 [../../zh-CN/unimplemented.md](../../zh-CN/unimplemented.md) 第 3 节。
|
|
107
|
+
|
|
108
|
+
## 模块
|
|
109
|
+
|
|
110
|
+
| 特性 | 状态 | 说明 |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| ESM `import`/`export` | ✅ | |
|
|
113
|
+
| 相对路径多文件打包 | ✅ | `./helper.js` 会解析到 `helper.ts` |
|
|
114
|
+
| `import * as ns`、默认导入与具名导入 | ✅ | |
|
|
115
|
+
| Node 内置模块 | ✅ | 仅在 `--ext node` 下——见 [extensions.md](./extensions.md) |
|
|
116
|
+
| 裸第三方 npm 包 | 🚫 | 只有当没有扩展认领该说明符时,`node_modules` 的 ESM 包才会作为源码打包 |
|
|
117
|
+
| `require()` / CommonJS | 🚫 | 被拒绝,并提示改用 `import` |
|
|
118
|
+
| 循环依赖 | 🚫 | |
|
|
119
|
+
| 实时绑定 | ⚠️ | 导入与命名空间成员都是快照 |
|
|
120
|
+
| `import.meta`、`__dirname`、`__filename` | 🚫 | |
|
|
121
|
+
|
|
122
|
+
## 字符串、数字与内存
|
|
123
|
+
|
|
124
|
+
| 项目 | 行为 |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `String.prototype.length` | ⚠️ 按 **UTF-8 字节**计,不是 UTF-16 码元:`"é".length === 1`,`"😀".length === 4`;`codePointAt` 相应不同 |
|
|
127
|
+
| 数字格式化与强转 | ✅ 与 Node 一致(`toFixed`、`toPrecision`、十六/八/二进制解析) |
|
|
128
|
+
| `BigInt` | ✅ 已实现 |
|
|
129
|
+
| 垃圾回收 | ✅ 非移动标记清扫;显式根 + C 栈保守扫描;单线程、stop-the-world;无弱引用 |
|
|
130
|
+
| 线程 | 🚫 单线程;`worker_threads` 只存在于 Node 扩展中 |
|
|
131
|
+
|
|
132
|
+
## 平台
|
|
133
|
+
|
|
134
|
+
构建目标覆盖 macOS、Linux、Windows 的 x64 与 arm64。Windows 上是 **MSVC ABI**,
|
|
135
|
+
clang 需要 MSVC/SDK 环境——见 [../../zh-CN/requirements.md](../../zh-CN/requirements.md)。
|
|
136
|
+
需要 clang **16 或更新**。
|
|
137
|
+
|
|
138
|
+
## 写大程序之前
|
|
139
|
+
|
|
140
|
+
1. 扫一眼你要用的特性所在的行;凡标 ⚠️ 或 🚫 的,打开
|
|
141
|
+
[../../zh-CN/unimplemented.md](../../zh-CN/unimplemented.md) 确认。
|
|
142
|
+
2. 用 `xbintsc emit app.ts` 做原型验证——这是确认某构造是否被支持最便宜的方式,
|
|
143
|
+
不需要 clang。
|
|
144
|
+
3. 用 `xbintsc run app.ts` 跑真实程序;构建失败就去
|
|
145
|
+
[troubleshooting.md](./troubleshooting.md)。
|
|
146
|
+
4. 需要精确对齐 Node 行为时,把同一程序在 Node 下跑一遍对比输出;项目自带测试套件
|
|
147
|
+
就是这么做的差分验证。
|