xbintsc 0.3.46 → 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.
Files changed (91) hide show
  1. package/AGENTS.md +95 -0
  2. package/README.md +25 -0
  3. package/README.zh-CN.md +23 -0
  4. package/dist/src/cli/hints.d.ts +54 -0
  5. package/dist/src/cli/hints.js +165 -0
  6. package/dist/src/cli/hints.js.map +1 -0
  7. package/dist/src/cli/main.js +73 -9
  8. package/dist/src/cli/main.js.map +1 -1
  9. package/dist/src/codegen/generator/tables.d.ts +26 -0
  10. package/dist/src/codegen/generator/tables.js +64 -12
  11. package/dist/src/codegen/generator/tables.js.map +1 -1
  12. package/dist/src/diagnostics/source-text.d.ts +22 -0
  13. package/dist/src/diagnostics/source-text.js +76 -0
  14. package/dist/src/diagnostics/source-text.js.map +1 -0
  15. package/dist/src/driver/bundler/graph.js +2 -1
  16. package/dist/src/driver/bundler/graph.js.map +1 -1
  17. package/dist/src/driver/compiler.js +3 -2
  18. package/dist/src/driver/compiler.js.map +1 -1
  19. package/dist/src/lexer/scanner/strings.js +16 -3
  20. package/dist/src/lexer/scanner/strings.js.map +1 -1
  21. package/dist/tests/cli/hints.test.d.ts +9 -0
  22. package/dist/tests/cli/hints.test.js +143 -0
  23. package/dist/tests/cli/hints.test.js.map +1 -0
  24. package/dist/tests/cli/main.test.js +6 -4
  25. package/dist/tests/cli/main.test.js.map +1 -1
  26. package/dist/tests/codegen/llvm.test.js +17 -2
  27. package/dist/tests/codegen/llvm.test.js.map +1 -1
  28. package/dist/tests/helpers.js +3 -2
  29. package/dist/tests/helpers.js.map +1 -1
  30. package/dist/tests/lexer/strings.test.js +14 -2
  31. package/dist/tests/lexer/strings.test.js.map +1 -1
  32. package/doc/DESIGN.md +117 -0
  33. package/doc/ai/README.md +63 -0
  34. package/doc/ai/build-recipe.md +137 -0
  35. package/doc/ai/cli.md +142 -0
  36. package/doc/ai/contributing.md +196 -0
  37. package/doc/ai/extensions.md +148 -0
  38. package/doc/ai/language-support.md +152 -0
  39. package/doc/ai/troubleshooting.md +163 -0
  40. package/doc/ai/zh-CN/README.md +56 -0
  41. package/doc/ai/zh-CN/build-recipe.md +132 -0
  42. package/doc/ai/zh-CN/cli.md +127 -0
  43. package/doc/ai/zh-CN/contributing.md +173 -0
  44. package/doc/ai/zh-CN/extensions.md +139 -0
  45. package/doc/ai/zh-CN/language-support.md +147 -0
  46. package/doc/ai/zh-CN/troubleshooting.md +150 -0
  47. package/doc/gui-scripts.md +350 -0
  48. package/doc/gui.md +646 -0
  49. package/doc/icon.md +265 -0
  50. package/doc/implemented.md +373 -0
  51. package/doc/node-implemented.md +588 -0
  52. package/doc/node-unimplemented.md +167 -0
  53. package/doc/post/announce.md +43 -0
  54. package/doc/requirements.md +145 -0
  55. package/doc/unimplemented.md +286 -0
  56. package/doc/xbintsc.config.schema.json +67 -0
  57. package/doc/zh-CN/DESIGN.md +104 -0
  58. package/doc/zh-CN/gui-scripts.md +329 -0
  59. package/doc/zh-CN/gui.md +588 -0
  60. package/doc/zh-CN/icon.md +241 -0
  61. package/doc/zh-CN/implemented.md +365 -0
  62. package/doc/zh-CN/node-implemented.md +533 -0
  63. package/doc/zh-CN/node-unimplemented.md +141 -0
  64. package/doc/zh-CN/plan-require-node-modules.md +284 -0
  65. package/doc/zh-CN/post/announce.md +47 -0
  66. package/doc/zh-CN/requirements.md +134 -0
  67. package/doc/zh-CN/unimplemented.md +247 -0
  68. package/llms.txt +45 -0
  69. package/package.json +4 -1
  70. package/runtime/ext_gui/gui.cpp +3 -1
  71. package/runtime/ext_gui/renderer.cpp +13 -11
  72. package/runtime/ext_gui/renderer_image.cpp +12 -8
  73. package/runtime/ext_gui/renderer_shaders.h +131 -4
  74. package/runtime/ext_gui/renderer_shaders_data.h +1809 -0
  75. package/runtime/ext_gui/renderer_text.cpp +12 -8
  76. package/runtime/ext_gui/shaders.hlsl +98 -0
  77. package/runtime/ext_gui/spirv/fill.frag +19 -0
  78. package/runtime/ext_gui/spirv/fill.vert +42 -0
  79. package/runtime/ext_gui/spirv/image.frag +16 -0
  80. package/runtime/ext_gui/spirv/quad.vert +30 -0
  81. package/runtime/ext_gui/spirv/text.frag +16 -0
  82. package/scripts/build-gui-shaders.mjs +204 -0
  83. package/scripts/build-gui.ts +35 -0
  84. package/scripts/check-file-length.ts +5 -1
  85. package/src/cli/hints.ts +194 -0
  86. package/src/cli/main.ts +82 -9
  87. package/src/codegen/generator/tables.ts +60 -14
  88. package/src/diagnostics/source-text.ts +78 -0
  89. package/src/driver/bundler/graph.ts +2 -1
  90. package/src/driver/compiler.ts +3 -2
  91. package/src/lexer/scanner/strings.ts +16 -3
@@ -0,0 +1,163 @@
1
+ # Troubleshooting
2
+
3
+ Start with the command that shows what xbintsc actually resolved:
4
+
5
+ ```bash
6
+ xbintsc doctor
7
+ ```
8
+
9
+ It prints the platform, the toolchain it will use (and where it came from), the
10
+ compiler version, the runtime directory, the runtime library directory and the
11
+ icon resource compiler. Most "it doesn't work" reports are answered here.
12
+
13
+ ## Before anything else: is clang new enough?
14
+
15
+ **clang/LLVM 16 or newer is required.** Older clang rejects the emitted IR with a
16
+ typed-pointer error:
17
+
18
+ ```
19
+ D:\...\build\app.ll:382:37: error: '@.str.0' defined with type '[6 x i8]*' but expected 'i8*'
20
+ %r0 = call i64 @xt_string_new(i8* @.str.0, i64 5)
21
+ ```
22
+
23
+ The compiler emits LLVM IR that relies on opaque pointers; typed pointers were
24
+ removed in LLVM 16 ([LLVM release notes](https://github.com/llvm/llvm-project/blob/release/15.x/llvm/docs/ReleaseNotes.rst#changes-to-the-llvm-ir)).
25
+ Confirm with `clang --version`; if the machine has an old system clang, install a
26
+ newer LLVM and point xbintsc at it:
27
+
28
+ ```bash
29
+ export xbintsc_CLANG=/usr/lib/llvm-18/bin/clang # PowerShell: $env:xbintsc_CLANG = "C:\Program Files\LLVM\bin\clang.exe"
30
+ ```
31
+
32
+ Note that front-end-only work (`xbintsc emit`) never needs clang, so it keeps
33
+ working on an old toolchain.
34
+
35
+ ## Error messages and what they mean
36
+
37
+ ### `module '…' is provided by the 'node' extension; pass --ext node`
38
+
39
+ The program imports a Node module but the extension is off. Add the flag, or put
40
+ it in `xbintsc.config.json` so it is always on:
41
+
42
+ ```bash
43
+ xbintsc run app.ts --ext node
44
+ ```
45
+
46
+ ### `module '<pkg>' is not supported: xbintsc can import built-in platform modules, relative '.ts' files and ESM packages under node_modules; CommonJS packages are not supported`
47
+
48
+ A bare third-party import that nothing can link. Either the package is CommonJS
49
+ (unsupported), or it is an ESM package that failed to bundle. Prefer a Node
50
+ built-in from the `node` extension; see [extensions.md](./extensions.md) for
51
+ what can actually be bundled.
52
+
53
+ ### ``CommonJS `require()` is not supported``
54
+
55
+ Convert to ESM: `const fs = require("fs")` becomes `import fs from "fs"` (plus
56
+ `--ext node`). `require` inside `node_modules` packages *is* handled by the
57
+ bundler; it is only rejected in your own source. `require(<non-literal>)` is
58
+ never supported.
59
+
60
+ ### `error TS4005: xbintsc does not yet support this <construct>`
61
+
62
+ The syntax is parsed but codegen does not implement it. Check
63
+ [language-support.md](./language-support.md) and
64
+ [../unimplemented.md](../unimplemented.md), then rewrite the construct (or
65
+ contribute support). `namespace` declarations and `new.target` are the common
66
+ ones.
67
+
68
+ ### `error TS2xxx` (parser) or `error TS1xxx` (lexer)
69
+
70
+ A syntax error in the source. The diagnostic prints the file, line, column, the
71
+ offending line and a caret. Note that xbintsc's parser accepts most TypeScript,
72
+ so a parse error usually means genuinely broken syntax rather than an
73
+ unsupported feature.
74
+
75
+ ### `error TS6001: Cannot resolve module './x' from '<file>'` / `Cannot find module`
76
+
77
+ A relative import that does not resolve. A `./helper.js` specifier maps to
78
+ `helper.ts`, so import the runtime path you actually wrote in TypeScript.
79
+
80
+ ### `Cannot resolve module '…' required from '<file>'`
81
+
82
+ A `require(...)` inside a bundled `node_modules` package that could not be
83
+ resolved. The package is not usable as-is; prefer the built-in or a different
84
+ dependency.
85
+
86
+ ### `xbintsc: <config path>: invalid JSON (…)` / `Unable to read …`
87
+
88
+ The project config or a native extension manifest is malformed or missing. Fix
89
+ the JSON, or bypass discovery with `--no-config` / `--config <path>`.
90
+
91
+ ### `error TS6003` / `Command failed (N): clang …`
92
+
93
+ clang itself failed. The thrown message includes the full clang command and its
94
+ stderr — read the stderr, not just the first line. Frequent causes:
95
+
96
+ - the toolchain is too old (see above);
97
+ - on Windows, clang cannot find the MSVC/SDK headers or libraries because the
98
+ environment was not imported. Run from an **x64 Native Tools Command Prompt
99
+ for VS 2022** (or **ARM64 Native Tools** on Windows on ARM), or import it
100
+ first:
101
+ ```powershell
102
+ & "$env:ProgramFiles\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
103
+ ```
104
+ - the linker is wrong on Linux — set `xbintsc_CLANG` and/or pass
105
+ `xbintsc_LINKER_ARGS=-fuse-ld=lld`;
106
+ - `No C compiler found. Set xbintsc_CLANG to a clang binary.` — no clang on
107
+ `PATH` at all.
108
+
109
+ ### `GUI native library not found at …`
110
+
111
+ The `gui` extension needs its per-platform prebuilt `gui.a`/`gui.lib`, which is
112
+ not built in a plain source checkout. Drop `--ext gui`, or build the archive as
113
+ described in [../gui.md](../gui.md).
114
+
115
+ ### `Icon file not found` / icon tools missing
116
+
117
+ `--icon`/`app.icon` paths resolve against the config file's directory. On
118
+ Windows, embedding a PE icon needs `llvm-rc` or `windres`; `doctor` reports which
119
+ one was found, and a missing one is only fatal when an icon was requested.
120
+
121
+ ## Build behaviour that looks wrong but is not
122
+
123
+ ### The build printed `(cached)` and did nothing
124
+
125
+ The incremental cache matched: same source hash, compiler version, options,
126
+ platform and extension set, with every output still present. That is the feature
127
+ working. Force a rebuild with `--force`.
128
+
129
+ ### Stale output after changing a flag
130
+
131
+ The object cache key deliberately excludes compiler flags, which is why scripts
132
+ that change flags (such as runtime coverage) use a separate
133
+ `xbintsc_CACHE_DIR`. If you suspect a stale artefact, pass `--force` or delete
134
+ `.xbintsc/`.
135
+
136
+ ### `run` exits with a non-zero status but there is no error message
137
+
138
+ `run` propagates the **program's** exit status; the compiler succeeded. Run it
139
+ directly (`./build/app`) to see the program's own output.
140
+
141
+ ### `xbintsc: run requires --emit exe`
142
+
143
+ `run` only executes executables. Use `build --emit ir` or `emit` to inspect IR.
144
+
145
+ ### Program output appears in an unexpected order
146
+
147
+ `async`/`await` is a synchronous microtask model and the event loop only runs
148
+ after the program body. Timer and socket callbacks therefore fire late; see
149
+ [language-support.md](./language-support.md).
150
+
151
+ ## Where to look in the code
152
+
153
+ | Symptom | Source |
154
+ | --- | --- |
155
+ | A diagnostic message or code | [../../src/diagnostics/diagnostic.ts](../../src/diagnostics/diagnostic.ts), emit sites under `src/` |
156
+ | A missing feature | [../../src/codegen/](../../src/codegen/) — `UnsupportedFeature` is raised there |
157
+ | An import that will not resolve | [../../src/driver/bundler/](../../src/driver/bundler/) |
158
+ | clang invocation, linker flags | [../../src/driver/toolchain.ts](../../src/driver/toolchain.ts), [../../src/driver/toolchain-provider.ts](../../src/driver/toolchain-provider.ts) |
159
+ | Cache behaviour | [../../src/driver/cache.ts](../../src/driver/cache.ts) |
160
+ | Runtime crashes, GC, values | `runtime/*.c`, `runtime/rt.h` |
161
+
162
+ If you are changing the compiler rather than using it, read
163
+ [contributing.md](./contributing.md) next.
@@ -0,0 +1,56 @@
1
+ # 面向 AI 的 xbintsc 使用指南
2
+
3
+ **xbintsc 把 TypeScript 的一个子集直接编译成原生二进制。** 它自己解析
4
+ TypeScript,把程序降级为 LLVM IR 文本,再调用 `clang` 链接一个小型 C 运行时
5
+ (`runtime/`)产出独立可执行文件。产物里没有 Node.js,也没有 TypeScript 编译器。
6
+
7
+ ```
8
+ source.ts --词法分析--> tokens --语法分析--> AST --绑定--> 绑定后的 AST
9
+ --代码生成--> module.ll --clang--> module.o --链接--> 可执行文件
10
+ ```
11
+
12
+ 本目录是**面向 AI、按任务组织**的文档层:刻意写得短,并指向更权威的文档。
13
+ 请只读你当前任务需要的那一篇,不要通读整个目录。
14
+
15
+ | 页面 | 什么时候读 |
16
+ | --- | --- |
17
+ | [build-recipe.md](./build-recipe.md) | 要编译或运行一个程序,需要确切的命令形状 |
18
+ | [cli.md](./cli.md) | 需要完整参数表、项目配置或编程 API |
19
+ | [language-support.md](./language-support.md) | 必须确认某个语法/API 是否存在,或是否与 Node 一致 |
20
+ | [extensions.md](./extensions.md) | 需要 `fs`/`http`/…、GUI,或 C++/Rust 库 |
21
+ | [troubleshooting.md](./troubleshooting.md) | 报错了,要定位原因并修好 |
22
+
23
+ 如果你要改的是**这个仓库本身**(而不是用它编译程序),先读
24
+ [../../AGENTS.md](../../../AGENTS.md):那里讲了目录结构、构建门禁与改动规则。
25
+
26
+ ## 三个决定一切的事实
27
+
28
+ 1. **只有 TypeScript 的一个子集能编译。** 不支持的语法会被直接拒绝,而不是
29
+ 近似实现。动手写大段代码之前先确认。
30
+ 2. **类型全部被擦除,从不做类型检查。** 类型注解、接口、泛型、`as`/`satisfies`、
31
+ 非空断言 `!` 在运行时没有任何作用,也没有类型检查器会跑。只有真实的运行时
32
+ 行为才算数。
33
+ 3. **Node 兼容是可选且不完整的。** Node 模块由 `node` 扩展提供(`--ext node`);
34
+ 不支持直接 import 第三方 npm 包。
35
+
36
+ ## 选一条命令
37
+
38
+ ```bash
39
+ # 直接运行程序(先编译成临时二进制,再执行)
40
+ xbintsc run app.ts
41
+
42
+ # 产出独立二进制
43
+ xbintsc build app.ts --out build # -> build/app[.exe]
44
+
45
+ # 查看会被编译的 LLVM IR
46
+ xbintsc emit app.ts
47
+
48
+ # 查看 xbintsc 解析到的工具链
49
+ xbintsc doctor
50
+ ```
51
+
52
+ 在源码检出里,把 `xbintsc` 换成 `npx tsx src/cli/main.ts`(或
53
+ `npm run xbintsc --`)。发布压缩包里的二进制不需要 Node.js。
54
+
55
+ 下一步:要命令就[build-recipe.md](./build-recipe.md),要写正经程序就先看
56
+ [language-support.md](./language-support.md)。
@@ -0,0 +1,132 @@
1
+ # 构建配方
2
+
3
+ 常见任务的可直接复制命令,以及让构建成功的关键前提。完整参数见
4
+ [cli.md](./cli.md);命令报错见 [troubleshooting.md](./troubleshooting.md)。
5
+
6
+ ## 调用编译器
7
+
8
+ | 场景 | 调用方式 |
9
+ | --- | --- |
10
+ | 已发布的独立压缩包 | `xbintsc …`(`bin/xbintsc[.exe]` 在 `PATH` 上) |
11
+ | 源码检出,已编译 | `node dist/src/cli/main.js …` |
12
+ | 源码检出,直接跑 TypeScript | `npx tsx src/cli/main.ts …` |
13
+ | 源码检出,npm 脚本 | `npm run xbintsc -- …` |
14
+ | 源码检出,bin 启动器 | `node bin/xbintsc.js …`(会自动回退到 `tsx`) |
15
+
16
+ 下文为简洁统一写作 `xbintsc`。
17
+
18
+ ## 运行程序
19
+
20
+ ```bash
21
+ xbintsc run app.ts
22
+ xbintsc run app.ts -- --flag value # -- 之后的所有参数传给被运行的程序
23
+ ```
24
+
25
+ `run` 先把程序编译成可执行文件,再以继承 stdio 的方式启动它。它要求
26
+ `--emit exe`;`xbintsc run app.ts --emit ir` 是错误用法。`run` 的退出码就是被运行
27
+ 程序的退出码。
28
+
29
+ ## 构建独立二进制
30
+
31
+ ```bash
32
+ xbintsc build app.ts # -> build/app(Windows 上是 build/app.exe)
33
+ xbintsc build app.ts --out build/app # 指定输出目录
34
+ xbintsc build app.ts -o app.bin # 或指定确切输出路径
35
+ xbintsc build app.ts -O0 # 优化级别:-O0 .. -O3(默认 -O2)
36
+ xbintsc build app.ts --force # 忽略增量缓存
37
+ xbintsc build app.ts --verbose # 输出进度
38
+ ```
39
+
40
+ `build` 会打印产出的文件;如果增量缓存让本次构建无需干活,会额外打印
41
+ `(cached)`:
42
+
43
+ ```
44
+ xbintsc: wrote /abs/path/build/app
45
+ ```
46
+
47
+ 其他产出类型用于检查:
48
+
49
+ ```bash
50
+ xbintsc build app.ts --emit ir # 写出 app.ll
51
+ xbintsc build app.ts --emit obj # 写出 app.o
52
+ ```
53
+
54
+ ## 查看 LLVM IR
55
+
56
+ ```bash
57
+ xbintsc emit app.ts > app.ll # IR 输出到 stdout,不写任何文件
58
+ ```
59
+
60
+ `emit` 不需要 clang,也不需要运行时库——它是确认"编译器到底理解了什么"最便宜
61
+ 的手段,也是不确定某个语法是否被支持时最快的反馈回路。
62
+
63
+ ## 能编译的程序形态
64
+
65
+ ```ts
66
+ // app.ts —— ESM,不用 require()
67
+ import { readFileSync } from "fs"; // 需要 `--ext node`
68
+
69
+ function main(): void {
70
+ const text = readFileSync("package.json", "utf8");
71
+ console.log(text.length);
72
+ }
73
+
74
+ main(); // 顶层代码按顺序执行
75
+ ```
76
+
77
+ - 使用 `import`/`export`;`require()` 会被拒绝。
78
+ - 相对导入会被打包(`import { helper } from "./helper.js"` 会解析到
79
+ `helper.ts`)。
80
+ - Node 内置模块用裸名(`fs`、`path`、`node:fs`),并且需要开启 `node` 扩展。
81
+
82
+ ## 项目配置:不带参数即可构建
83
+
84
+ `xbintsc.config.json`(从入口文件所在目录向上查找,或用 `--config <path>` 指定,
85
+ 用 `--no-config` 关闭)承载构建选项,因此只敲 `xbintsc build` 就能工作。配置里的
86
+ 路径相对该配置文件解析,任何命令行参数都会覆盖对应字段。
87
+
88
+ ```json
89
+ {
90
+ "entry": "src/app.ts",
91
+ "outDir": "build",
92
+ "optimize": "2",
93
+ "extensions": ["node"],
94
+ "app": { "name": "Demo", "icon": "assets/app.png" }
95
+ }
96
+ ```
97
+
98
+ 机器可读的 schema 见 [../xbintsc.config.schema.json](../../xbintsc.config.schema.json);
99
+ 完整字段表见 [cli.md](./cli.md)。
100
+
101
+ ## 带扩展编译
102
+
103
+ 只要 import 了 Node 模块,就必须开启对应扩展,否则编译失败。可一次开多个,用逗号
104
+ 分隔:
105
+
106
+ ```bash
107
+ xbintsc run app.ts --ext node
108
+ xbintsc run app.ts --ext node,gui
109
+ ```
110
+
111
+ C++/Rust 库改用清单注册:
112
+
113
+ ```bash
114
+ xbintsc run app.ts --ext-native ./mathx.manifest.json
115
+ ```
116
+
117
+ 两种扩展的编写方式都在 [extensions.md](./extensions.md)。
118
+
119
+ ## 编程 API
120
+
121
+ 写工具而不是写程序时:
122
+
123
+ ```ts
124
+ import { build, compileString } from "xbintsc";
125
+
126
+ const { ir } = compileString("console.log(1 + 1);"); // IR 文本,不需要 clang
127
+ const result = build("program.ts", { emit: "exe", outDir: "build" });
128
+ ```
129
+
130
+ `build` 返回 `{ outputPath, irPath?, cached, diagnostics, bundlePath? }`,可恢复的
131
+ 问题通过 `diagnostics` 报告;但工具链失败会**抛异常**。子路径导出
132
+ `xbintsc/driver` 暴露驱动内部能力。
@@ -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
+ 标签,所以永远不要手工推标签。