xbintsc 0.3.81 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/AGENTS.md +8 -4
  2. package/README.md +16 -5
  3. package/README.zh-CN.md +14 -6
  4. package/dist/src/ast/common.d.ts +23 -0
  5. package/dist/src/cli/main.js +68 -24
  6. package/dist/src/cli/main.js.map +1 -1
  7. package/dist/src/codegen/generator/calls/access.js +6 -2
  8. package/dist/src/codegen/generator/calls/access.js.map +1 -1
  9. package/dist/src/codegen/generator/calls/closures.js +4 -0
  10. package/dist/src/codegen/generator/calls/closures.js.map +1 -1
  11. package/dist/src/codegen/generator/calls/invocation.js +9 -4
  12. package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
  13. package/dist/src/codegen/generator/context.d.ts +50 -0
  14. package/dist/src/codegen/generator/context.js +124 -13
  15. package/dist/src/codegen/generator/context.js.map +1 -1
  16. package/dist/src/codegen/generator/debug.d.ts +33 -0
  17. package/dist/src/codegen/generator/debug.js +97 -0
  18. package/dist/src/codegen/generator/debug.js.map +1 -0
  19. package/dist/src/codegen/generator/expressions/assignment.js +9 -5
  20. package/dist/src/codegen/generator/expressions/assignment.js.map +1 -1
  21. package/dist/src/codegen/generator/expressions/operators.js +35 -9
  22. package/dist/src/codegen/generator/expressions/operators.js.map +1 -1
  23. package/dist/src/codegen/generator/expressions/primary.js +11 -3
  24. package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
  25. package/dist/src/codegen/generator/generator.d.ts +3 -1
  26. package/dist/src/codegen/generator/generator.js +3 -1
  27. package/dist/src/codegen/generator/generator.js.map +1 -1
  28. package/dist/src/codegen/generator/module.d.ts +1 -1
  29. package/dist/src/codegen/generator/module.js +82 -12
  30. package/dist/src/codegen/generator/module.js.map +1 -1
  31. package/dist/src/codegen/generator/numeric.d.ts +26 -0
  32. package/dist/src/codegen/generator/numeric.js +127 -0
  33. package/dist/src/codegen/generator/numeric.js.map +1 -0
  34. package/dist/src/codegen/generator/state.d.ts +17 -0
  35. package/dist/src/codegen/generator/state.js +9 -0
  36. package/dist/src/codegen/generator/state.js.map +1 -1
  37. package/dist/src/codegen/generator/statements/control-flow.js +2 -4
  38. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -1
  39. package/dist/src/codegen/generator/statements/dispatch.js +3 -0
  40. package/dist/src/codegen/generator/statements/dispatch.js.map +1 -1
  41. package/dist/src/codegen/generator/statements/variables.js +8 -2
  42. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  43. package/dist/src/codegen/generator/tables.d.ts +16 -0
  44. package/dist/src/codegen/generator/tables.js +99 -2
  45. package/dist/src/codegen/generator/tables.js.map +1 -1
  46. package/dist/src/driver/bundler/merge.js +41 -5
  47. package/dist/src/driver/bundler/merge.js.map +1 -1
  48. package/dist/src/driver/compiler.d.ts +23 -4
  49. package/dist/src/driver/compiler.js +46 -57
  50. package/dist/src/driver/compiler.js.map +1 -1
  51. package/dist/src/driver/fingerprint.d.ts +27 -0
  52. package/dist/src/driver/fingerprint.js +88 -0
  53. package/dist/src/driver/fingerprint.js.map +1 -0
  54. package/dist/src/driver/toolchain-provider.d.ts +9 -2
  55. package/dist/src/driver/toolchain-provider.js +15 -15
  56. package/dist/src/driver/toolchain-provider.js.map +1 -1
  57. package/dist/src/driver/toolchain.d.ts +58 -1
  58. package/dist/src/driver/toolchain.js +169 -22
  59. package/dist/src/driver/toolchain.js.map +1 -1
  60. package/dist/src/parser/expressions.js +20 -1
  61. package/dist/src/parser/expressions.js.map +1 -1
  62. package/dist/tests/cli/main.test.js +41 -1
  63. package/dist/tests/cli/main.test.js.map +1 -1
  64. package/dist/tests/codegen/closures.test.js +8 -0
  65. package/dist/tests/codegen/closures.test.js.map +1 -1
  66. package/dist/tests/codegen/expressions.test.js +14 -3
  67. package/dist/tests/codegen/expressions.test.js.map +1 -1
  68. package/dist/tests/codegen/llvm.test.js +23 -0
  69. package/dist/tests/codegen/llvm.test.js.map +1 -1
  70. package/dist/tests/driver/toolchain-provider.test.js +49 -2
  71. package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
  72. package/dist/tests/driver/toolchain.test.js +62 -3
  73. package/dist/tests/driver/toolchain.test.js.map +1 -1
  74. package/dist/tests/e2e/async-await.test.d.ts +10 -0
  75. package/dist/tests/e2e/async-await.test.js +247 -0
  76. package/dist/tests/e2e/async-await.test.js.map +1 -0
  77. package/dist/tests/e2e/child-process.test.d.ts +10 -0
  78. package/dist/tests/e2e/child-process.test.js +59 -0
  79. package/dist/tests/e2e/child-process.test.js.map +1 -0
  80. package/dist/tests/e2e/compile-objects-classes.test.js +47 -0
  81. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  82. package/dist/tests/e2e/error-stack.test.d.ts +9 -0
  83. package/dist/tests/e2e/error-stack.test.js +94 -0
  84. package/dist/tests/e2e/error-stack.test.js.map +1 -0
  85. package/dist/tests/e2e/runtime-coverage-globals.test.js +46 -0
  86. package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -1
  87. package/dist/tests/e2e/string-concat.test.d.ts +9 -0
  88. package/dist/tests/e2e/string-concat.test.js +102 -0
  89. package/dist/tests/e2e/string-concat.test.js.map +1 -0
  90. package/dist/tests/e2e/string-utf16.test.d.ts +6 -0
  91. package/dist/tests/e2e/string-utf16.test.js +133 -0
  92. package/dist/tests/e2e/string-utf16.test.js.map +1 -0
  93. package/dist/tests/helpers.d.ts +9 -0
  94. package/dist/tests/helpers.js +26 -3
  95. package/dist/tests/helpers.js.map +1 -1
  96. package/dist/tests/parser/expressions.test.js +7 -0
  97. package/dist/tests/parser/expressions.test.js.map +1 -1
  98. package/dist/tests/version.test.d.ts +1 -0
  99. package/dist/tests/version.test.js +24 -0
  100. package/dist/tests/version.test.js.map +1 -0
  101. package/doc/DESIGN.md +20 -12
  102. package/doc/ai/cli.md +2 -0
  103. package/doc/ai/contributing.md +16 -8
  104. package/doc/ai/extensions.md +3 -2
  105. package/doc/ai/language-support.md +15 -12
  106. package/doc/ai/troubleshooting.md +43 -5
  107. package/doc/ai/zh-CN/cli.md +2 -0
  108. package/doc/ai/zh-CN/contributing.md +11 -7
  109. package/doc/ai/zh-CN/extensions.md +2 -1
  110. package/doc/ai/zh-CN/language-support.md +15 -12
  111. package/doc/ai/zh-CN/troubleshooting.md +38 -4
  112. package/doc/implemented.md +16 -13
  113. package/doc/requirements.md +13 -4
  114. package/doc/unimplemented.md +20 -18
  115. package/doc/zh-CN/DESIGN.md +15 -9
  116. package/doc/zh-CN/implemented.md +15 -12
  117. package/doc/zh-CN/requirements.md +12 -3
  118. package/doc/zh-CN/unimplemented.md +19 -17
  119. package/package.json +3 -1
  120. package/runtime/ext_node/buffer/parts/construction.inc +2 -2
  121. package/runtime/ext_node/buffer/parts/methods.inc +1 -1
  122. package/runtime/ext_node/buffer/parts/search.inc +1 -1
  123. package/runtime/ext_node/child_process/child_process.c +25 -0
  124. package/runtime/ext_node/fs/fd_ops.c +1 -1
  125. package/runtime/rt.h +49 -1
  126. package/runtime/rt_internal.h +136 -4
  127. package/runtime/xt_alloc.c +20 -2
  128. package/runtime/xt_async.c +197 -0
  129. package/runtime/xt_bigint/conversions.inc +1 -1
  130. package/runtime/xt_builtins.c +169 -43
  131. package/runtime/xt_constructors.c +389 -0
  132. package/runtime/xt_containers/access.inc +61 -24
  133. package/runtime/xt_containers/arrays.inc +26 -2
  134. package/runtime/xt_containers/objects.inc +206 -8
  135. package/runtime/xt_coroutine.c +212 -0
  136. package/runtime/xt_generator.c +31 -162
  137. package/runtime/xt_io/exception.inc +171 -2
  138. package/runtime/xt_io/inspect.inc +48 -13
  139. package/runtime/xt_io.c +5 -0
  140. package/runtime/xt_promise.c +62 -17
  141. package/runtime/xt_stdlib/arrays.inc +2 -2
  142. package/runtime/xt_stdlib/dispatch.inc +20 -4
  143. package/runtime/xt_stdlib/strings.inc +98 -29
  144. package/runtime/xt_stdlib2/array-statics.inc +3 -2
  145. package/runtime/xt_stdlib2/arrays.inc +1 -1
  146. package/runtime/xt_stdlib2/error.inc +33 -6
  147. package/runtime/xt_stdlib2/json.inc +46 -16
  148. package/runtime/xt_stdlib2/number-string-statics.inc +24 -13
  149. package/runtime/xt_stdlib2/objects.inc +1 -1
  150. package/runtime/xt_stdlib2/regexp-match.inc +50 -35
  151. package/runtime/xt_stdlib2/set.inc +6 -0
  152. package/runtime/xt_stdlib2/strings.inc +81 -42
  153. package/runtime/xt_symbol.c +1 -1
  154. package/runtime/xt_typed_array/construction.inc +43 -2
  155. package/runtime/xt_typed_array.c +4 -0
  156. package/runtime/xt_values/comparison.inc +2 -2
  157. package/runtime/xt_values/constructors.inc +18 -5
  158. package/runtime/xt_values/conversions.inc +4 -3
  159. package/runtime/xt_values/strings.inc +94 -4
  160. package/runtime/xt_values/utf16.inc +340 -0
  161. package/runtime/xt_values.c +1 -0
  162. package/scripts/bench.ts +172 -0
  163. package/scripts/build-runtime.ts +2 -1
  164. package/scripts/check-version.ts +53 -0
  165. package/src/ast/common.ts +23 -0
  166. package/src/cli/main.ts +68 -26
  167. package/src/codegen/generator/calls/access.ts +7 -2
  168. package/src/codegen/generator/calls/closures.ts +3 -0
  169. package/src/codegen/generator/calls/invocation.ts +9 -3
  170. package/src/codegen/generator/context.ts +129 -18
  171. package/src/codegen/generator/debug.ts +132 -0
  172. package/src/codegen/generator/expressions/assignment.ts +9 -5
  173. package/src/codegen/generator/expressions/operators.ts +47 -8
  174. package/src/codegen/generator/expressions/primary.ts +11 -3
  175. package/src/codegen/generator/generator.ts +18 -2
  176. package/src/codegen/generator/module.ts +83 -13
  177. package/src/codegen/generator/numeric.ts +158 -0
  178. package/src/codegen/generator/state.ts +26 -0
  179. package/src/codegen/generator/statements/control-flow.ts +2 -3
  180. package/src/codegen/generator/statements/dispatch.ts +3 -0
  181. package/src/codegen/generator/statements/variables.ts +8 -2
  182. package/src/codegen/generator/tables.ts +110 -2
  183. package/src/driver/bundler/merge.ts +39 -5
  184. package/src/driver/compiler.ts +65 -55
  185. package/src/driver/fingerprint.ts +85 -0
  186. package/src/driver/toolchain-provider.ts +17 -16
  187. package/src/driver/toolchain.ts +210 -21
  188. package/src/parser/expressions.ts +20 -1
@@ -22,8 +22,12 @@ D:\...\build\app.ll:382:37: error: '@.str.0' defined with type '[6 x i8]*' but e
22
22
 
23
23
  The compiler emits LLVM IR that relies on opaque pointers; typed pointers were
24
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:
25
+ `xbintsc build`/`run` check the version up front and stop with "reports clang
26
+ 15.0.2, but xbintsc requires clang 16 or newer", and `xbintsc doctor` prints
27
+ `status : ok` or `status : too old` (exiting non-zero in the latter case). The
28
+ search prefers a supported clang — including the LLVM bundled with Visual Studio
29
+ on Windows — so an old `/usr/bin/clang` is skipped when a newer one is installed.
30
+ To choose one explicitly:
27
31
 
28
32
  ```bash
29
33
  export xbintsc_CLANG=/usr/lib/llvm-18/bin/clang # PowerShell: $env:xbintsc_CLANG = "C:\Program Files\LLVM\bin\clang.exe"
@@ -118,6 +122,39 @@ described in [../gui.md](../gui.md).
118
122
  Windows, embedding a PE icon needs `llvm-rc` or `windres`; `doctor` reports which
119
123
  one was found, and a missing one is only fatal when an icon was requested.
120
124
 
125
+ ## Reading a stack trace
126
+
127
+ `Error.stack` is captured by codegen, not from the C runtime's native frames:
128
+ every non-generator function pushes `{name, file, line}` on entry and pops it
129
+ before returning. Frames look like
130
+
131
+ ```
132
+ Error: boom
133
+ at inner (app.ts:12)
134
+ at module (app.ts:3)
135
+ ```
136
+
137
+ Lines are function declaration lines, except that the innermost frame is moved
138
+ to the `new Error(...)` line; there are no column numbers. Generator bodies are
139
+ not tracked because they switch stacks. A fatal native signal prints
140
+ `xbintsc: fatal signal …` followed by the same frames, so a crash without a
141
+ debugger still shows which JavaScript functions were running.
142
+
143
+ ## Debugging with gdb / lldb / WinDbg
144
+
145
+ `xbintsc build app.ts --debug` emits LLVM debug metadata and passes `-g
146
+ -fno-omit-frame-pointer` to clang, so the object carries DWARF (Linux/macOS) or
147
+ CodeView (Windows) line tables. Function symbols keep their source names
148
+ (`xt_fn_3_add`) and every statement has a line location:
149
+
150
+ ```bash
151
+ xbintsc build app.ts --debug
152
+ gdb ./build/app # or: lldb ./build/app, or open the .exe in WinDbg
153
+ ```
154
+
155
+ The binary is larger and is cached separately from a normal build (the debug
156
+ flag is part of the cache key). `Error.stack` works without `--debug`.
157
+
121
158
  ## Build behaviour that looks wrong but is not
122
159
 
123
160
  ### The build printed `(cached)` and did nothing
@@ -144,9 +181,10 @@ directly (`./build/app`) to see the program's own output.
144
181
 
145
182
  ### Program output appears in an unexpected order
146
183
 
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).
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).
150
188
 
151
189
  ## Where to look in the code
152
190
 
@@ -33,6 +33,8 @@
33
33
  --app-id <id> macOS bundle 标识(如 com.example.demo)
34
34
  --force 忽略增量缓存
35
35
  --verbose 打印进度信息
36
+ --time 打印各构建阶段耗时
37
+ --debug 生成调试信息(DWARF/CodeView)并保留帧指针
36
38
  ```
37
39
 
38
40
  少数容易踩的解析细节:
@@ -35,6 +35,7 @@ git config core.hooksPath .githooks
35
35
  | `npm run test:watch` | vitest 监听模式 |
36
36
  | `npm run coverage` | TypeScript 编译器(`src/`)的 V8 覆盖率 |
37
37
  | `npm run coverage:runtime` | C 运行时(`runtime/`)的 LLVM 覆盖率 |
38
+ | `npm run bench` | 构建并计时固定基准套件(可与 Node 对比) |
38
39
 
39
40
  单元测试在 `tests/` 下按模块一个目录(`lexer`、`parser`、`binder`、`codegen`、
40
41
  `driver`、`extensions`、`cli`、`e2e`),与源码树镜像对应。边界用例放在它覆盖的模块
@@ -66,11 +67,11 @@ gen2 --emit--> gen3.ll # 必须等于 ref.ll
66
67
  必须逐字节确定——包括迭代顺序、生成的符号名与编号。绝不要把不确定性(未受控的
67
68
  `Map`/`Set` 迭代顺序、时间戳、依赖文件系统顺序的东西)引入代码生成。
68
69
 
69
- 第二个推论是字符串模型:编译器自身源码文本在各代中必须含义一致。编译后的字符串是
70
- UTF-8 字节,所以自举后的 `readFileSync`(`--ext node`)交给扫描器的是文件字节,而
71
- Node 交给它的是同一个文件已解码后的文本——读取源码文件一律走 `decodeUtf8`
72
- ([src/diagnostics/utf8.ts](../../../src/diagnostics/utf8.ts)),不要假设一个码元就是
73
- 一个字节或一个字符。弄错的表现是:`gen2.ll` 里非 ASCII 字面量(比如提示语里的 `—`)
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 字面量(比如提示语里的 `—`)
74
75
  被重新编码,这也正是这里逐字节比较 IR 而不是逐行比较的原因。
75
76
 
76
77
  本地验证:
@@ -90,8 +91,11 @@ diff scratch/ref.ll scratch/gen2.ll
90
91
  - 每个值都是一个 64 位字:double 不装箱,其余都是带标签指针(16 位标签 + 48 位载荷)。
91
92
  该表示只定义一次:[../../../src/codegen/values.ts](../../../src/codegen/values.ts) 与
92
93
  [../../../runtime/rt.h](../../../runtime/rt.h);要改就一起改,否则别动。
93
- - 别扭的 JS 语义(`+` 强转、关系比较、属性访问、打印)委托给 `@xt_*` 运行时调用,而
94
- 不是内联。
94
+ - 别扭的 JS 语义(`+` 强转、关系比较、属性访问、打印)委托给 `@xt_*` 运行时调用。
95
+ 数值算术与比较是例外:codegen 内联双 double 快路径
96
+ (`src/codegen/generator/numeric.ts`),其余情况调用运行时。
97
+ - 字符串字面量会被驻留:每个不同字面量只在 `main` 中创建一次,存入 GC 根全局,
98
+ 每次使用只做一次 load;属性名因此不再逐次分配。
95
99
  - GC 是非移动标记清扫:新堆对象走 `xt_alloc`;值存活期间必须能从显式根槽、已注册的
96
100
  根提供者(事件循环、微任务队列)或 C 栈保守扫描到达。只存在于未被扫描的 C 局部
97
101
  变量里的值就是 bug。
@@ -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
- 而 `async`/`await` 是同步微任务模型。见 [language-support.md](./language-support.md)。
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` | 🚫 | 请包进 `async` 函数 |
31
+ | 顶层 `await` | ⚠️ | 会在事件循环上阻塞直到 Promise settle(不会像 ES module 那样让出模块主体);建议包进 `async` 函数 |
32
32
 
33
33
  ## 表达式与运算符
34
34
 
@@ -42,8 +42,8 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
42
42
  | 解构(绑定、参数、嵌套) | ✅ | 支持默认值与剩余 |
43
43
  | `delete`、`in`、`instanceof`、`typeof` | ✅ | |
44
44
  | 逗号运算符、`void` | ✅ | |
45
- | `new.target` | 🚫 | 未实现 |
46
- | `import.meta` | 🚫 | 能解析,但没有值 |
45
+ | `new.target` | 🚫 | 能解析,但会给出明确的 `UnsupportedFeature` |
46
+ | `import.meta` | ✅ | `url`、`dirname`、`filename`(由可执行文件路径解析) |
47
47
  | `super` | ⚠️ | 单层继承正确;继承深度 > 1 可能不准 |
48
48
 
49
49
  ## 函数、类与对象
@@ -68,10 +68,11 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
68
68
 
69
69
  | 特性 | 状态 | 说明 |
70
70
  | --- | --- | --- |
71
- | `async`/`await`、`Promise`、`Promise.all` | ⚠️ | **同步微任务模型**——`await` 一个已敲定的 Promise 会同步继续 |
72
- | `setTimeout` 与回调 | ⚠️ | 事件循环在**程序主体之后**才运行,因此定时器里敲定的 Promise 无法被 await |
73
- | 套接字/服务端(`http`、`net`、`dgram`) | ⚠️ | 同一模型:回调在程序主体之后的循环里执行 |
74
- | 真正的异步事件循环、worker 线程 | 🚫 | 未实现 |
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
- | `Error.stack` 采集 | 🚫(不采集) |
102
- | `Object.getPrototypeOf({})` | ⚠️ 返回 `undefined`,而非 `Object.prototype` |
104
+ | `Error.stack` 采集 | ⚠️ 函数级帧(名称/文件/行号),没有列号;生成器函数体不产生帧 |
103
105
  | 全局 RegExp `lastIndex` | ⚠️ `/g`、`/y` 下 `test`/`exec` 忽略它 |
104
106
  | 稀疏数组空洞、数组越界 | ⚠️ 不区分空洞;越界读得 `undefined` |
105
107
 
@@ -117,13 +119,14 @@ xbintsc 编译 TypeScript 的一个**实用子集**。本页用来判断你能
117
119
  | `require()` / CommonJS | 🚫 | 被拒绝,并提示改用 `import` |
118
120
  | 循环依赖 | 🚫 | |
119
121
  | 实时绑定 | ⚠️ | 导入与命名空间成员都是快照 |
120
- | `import.meta`、`__dirname`、`__filename` | 🚫 | |
122
+ | `__dirname`、`__filename` | 🚫 | 请使用 `import.meta.dirname` / `import.meta.filename` |
121
123
 
122
124
  ## 字符串、数字与内存
123
125
 
124
126
  | 项目 | 行为 |
125
127
  | --- | --- |
126
- | `String.prototype.length` | ⚠️ 按 **UTF-8 字节**计,不是 UTF-16 码元:`"é".length === 1`,`"😀".length === 4`;`codePointAt` 相应不同 |
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;无弱引用 |
@@ -21,8 +21,11 @@ D:\...\build\app.ll:382:37: error: '@.str.0' defined with type '[6 x i8]*' but e
21
21
 
22
22
  编译器生成的 LLVM IR 依赖不透明指针(opaque pointers),而有类型指针在 LLVM 16
23
23
  中被移除([LLVM 发布说明](https://github.com/llvm/llvm-project/blob/release/15.x/llvm/docs/ReleaseNotes.rst#changes-to-the-llvm-ir))。
24
- 用 `clang --version` 确认;如果机器上的系统 clang 太旧,装一个新版 LLVM 并让 xbintsc
25
- 用它:
24
+ `xbintsc build`/`run` 现在会先检查版本,直接停止并提示 "reports clang 15.0.2,
25
+ but xbintsc requires clang 16 or newer";`xbintsc doctor` 会打印
26
+ `status : ok` 或 `status : too old`(后者以非零码退出)。搜索工具链时会优先选择受支持
27
+ 的 clang——包括 Windows 上 Visual Studio 自带的 LLVM——所以装了新版时旧的
28
+ `/usr/bin/clang` 会被跳过。也可以显式指定:
26
29
 
27
30
  ```powershell
28
31
  $env:xbintsc_CLANG = "C:\Program Files\LLVM\bin\clang.exe"
@@ -110,6 +113,36 @@ clang 自身失败。抛出的消息包含完整的 clang 命令与 stderr——
110
113
  `llvm-rc` 或 `windres`;`doctor` 会报告找到了哪个,只有在确实请求了图标时缺失才是
111
114
  致命错误。
112
115
 
116
+ ## 怎么看堆栈
117
+
118
+ `Error.stack` 由 codegen 采集,而不是依赖 C 运行时的原生帧:每个非生成器函数
119
+ 在入口压入 `{名称, 文件, 行号}`,返回前弹出。帧形如
120
+
121
+ ```
122
+ Error: boom
123
+ at inner (app.ts:12)
124
+ at module (app.ts:3)
125
+ ```
126
+
127
+ 行号取函数声明行;最内层帧会更新为 `new Error(...)` 所在行。没有列号;生成器
128
+ 函数体因为会切换栈而不记录。原生致命信号会先打印 `xbintsc: fatal signal …`,
129
+ 再打印同一组帧,所以即使没有调试器也能看出崩溃时正在运行哪些 JS 函数。
130
+
131
+ ## 用 gdb / lldb / WinDbg 调试
132
+
133
+ `xbintsc build app.ts --debug` 会生成 LLVM 调试元数据,并把 `-g
134
+ -fno-omit-frame-pointer` 传给 clang,因此目标文件带有 DWARF(Linux/macOS)或
135
+ CodeView(Windows)行号表。函数符号保留源码名(如 `xt_fn_3_add`),每条语句都有
136
+ 对应的行位置:
137
+
138
+ ```bash
139
+ xbintsc build app.ts --debug
140
+ gdb ./build/app # 或 lldb ./build/app,Windows 用 WinDbg 打开 .exe
141
+ ```
142
+
143
+ 调试版二进制更大,并且与普通构建分开缓存(debug 标志参与缓存键)。`Error.stack`
144
+ 不需要 `--debug` 也能工作。
145
+
113
146
  ## 看起来不对、其实正常的构建行为
114
147
 
115
148
  ### 构建打印了 `(cached)` 并什么都没做
@@ -133,8 +166,9 @@ clang 自身失败。抛出的消息包含完整的 clang 命令与 stderr——
133
166
 
134
167
  ### 程序输出顺序出乎意料
135
168
 
136
- `async`/`await` 是同步微任务模型,且事件循环只在程序主体之后运行,所以定时器和套接字
137
- 回调会晚触发;见 [language-support.md](./language-support.md)。
169
+ `async`/`await` 只在 **pending** Promise 上挂起;等待已 settle 的值会同步继续,而 Node
170
+ 会排入微任务,因此顺序可能不同。事件循环仍在程序主体之后启动,定时器与套接字回调依然
171
+ 在主体之后触发;见 [language-support.md](./language-support.md)。
138
172
 
139
173
  ## 该去源码哪里看
140
174
 
@@ -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`: wrapped with `xt_promise_resolve` before returning; `await` calls `xt_await` (drives the microtask queue and raises an exception on rejection).
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 `xt_drain_microtasks` before returning).
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/xt_builtins.c`,
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, concatenation, 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).
@@ -255,12 +257,13 @@ Location: `runtime/xt_alloc.c`, `runtime/xt_values.c`, `runtime/xt_containers.c`
255
257
  - Operator helpers: `xt_in` (`in`), `xt_delete` (`delete`), `xt_rest_args` (rest parameters / `arguments`).
256
258
  - Box: `box_new/get/set` (for closure-captured variables).
257
259
  - Functions and closures: `arg`, `closure_new/call/env/arity`.
258
- - 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.
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`): synchronous microtask queue (`xt_microtasks`); `xt_promise_ctor/resolve/reject/static`, instance `then/catch/finally`; `xt_await` drives the queue until settle, and rejection raises via `xt_throw`; `xt_drain_microtasks` empties the queue at program exit.
263
- - Fetch (`xt_fetch.c`): global `fetch(input, init)` is a blocking HTTP/1.1 client whose promise is already settled (the runtime has no event loop). 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
+ - 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, `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`, `Promise` (`then/catch/finally`, `resolve/reject/all/allSettled/race`), synchronous microtask queue |
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 |
@@ -20,10 +20,19 @@ build/app.ll:382:37: error: '@.str.0' defined with type '[6 x i8]*' but expected
20
20
  ```
21
21
 
22
22
  Typed pointers were removed in LLVM 16 ([release notes](https://github.com/llvm/llvm-project/blob/release/15.x/llvm/docs/ReleaseNotes.rst#changes-to-the-llvm-ir)),
23
- so check `clang --version` before anything else, and point xbintsc at a newer
24
- build with `xbintsc_CLANG` when the system clang is older. `xbintsc doctor`
25
- reports the resolved toolchain and its version. Working around the limitation by
26
- compiling the IR elsewhere is not supported.
23
+ so xbintsc now **checks the version before it compiles anything**:
24
+
25
+ - `xbintsc build` / `run` stop immediately with an actionable error when the
26
+ resolved driver is older than 16, instead of emitting IR that cannot compile.
27
+ - `xbintsc doctor` prints `status : ok` or `status : too old` and exits non-zero
28
+ when the toolchain cannot build binaries, so scripts and CI can preflight it.
29
+ - The search prefers a clang >= 16: on Windows the LLVM bundled with Visual
30
+ Studio (`<VS install>\VC\Tools\Llvm\x64\bin\clang.exe`) is found even when an
31
+ older `clang` comes first on `PATH`. Set `xbintsc_CLANG` to override the
32
+ choice; an explicit older binary is rejected with a "too old" error rather
33
+ than silently ignored.
34
+
35
+ Working around the limitation by compiling the IR elsewhere is not supported.
27
36
 
28
37
  ## Summary
29
38
 
@@ -68,8 +68,9 @@ None — generators are implemented.
68
68
  > Tagged templates are implemented, including raw strings and `String.raw`.
69
69
  > Generators (`function*`, `yield`, `yield*`) are implemented with stackful
70
70
  > coroutines, including `next`/`throw`/`return`, `for...of`, spread and
71
- > delegation. `import.meta` is parsed but has no runtime value; `async`
72
- > generators are not yet supported.
71
+ > delegation. `import.meta` exposes `url`, `dirname` and `filename`, resolved
72
+ > from the running executable's path. `async function*` is **rejected with
73
+ > `UnsupportedFeature`** instead of silently producing a synchronous generator.
73
74
 
74
75
  ### 2.2 Not supported by the parser
75
76
 
@@ -79,7 +80,7 @@ None known at the expression level.
79
80
 
80
81
  | Operator | Status | Notes |
81
82
  | --- | --- | --- |
82
- | `new.target` | ✗ | not implemented |
83
+ | `new.target` | ✗ | parsed, then rejected with `UnsupportedFeature` (no `new.target` semantics) |
83
84
  | `typeof` / `void` / `in` / `delete` / `instanceof` | ✓ | mapped to runtime helpers (`xt_typeof`, `xt_in`, `xt_delete`, `xt_instance_of`) |
84
85
 
85
86
  ---
@@ -100,6 +101,7 @@ None known at the expression level.
100
101
  - `JSON.parse` / `JSON.stringify`
101
102
  - `Date`, `RegExp` (POSIX ERE subset with capture groups), `Map`, `Set`, `Promise`, `BigInt`
102
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`
103
105
  - `Error` family (`Error`, `TypeError`, `RangeError`, `SyntaxError`, `ReferenceError`, `EvalError`, `URIError`, `AggregateError`): `new`, `instanceof`, `extends`, `String(err)` / `err.toString()` and `.stack`
104
106
 
105
107
  ### 3.3 Still unimplemented
@@ -113,7 +115,7 @@ None known at the expression level.
113
115
  | `AggregateError` constructor | ✓ `new AggregateError(errors, message)`; `Promise.any` now rejects with one |
114
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 |
115
117
  | Generators (`function*`, `yield`, `yield*`, `next`/`throw`/`return`) | ✓ implemented with stackful coroutines; `for...of`, spread and delegation supported. `return()` completes without running `finally` |
116
- | 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 |
117
119
  | I/O / process and other host APIs | only via extensions (e.g. Node `fs`) |
118
120
 
119
121
  ### 3.4 Typed arrays
@@ -132,7 +134,7 @@ element writes, and `fill` / `set` / `slice` / `subarray` / `join` / `toString`
132
134
  | `keys` / `values` / `entries` | ~ return arrays, not iterator objects |
133
135
  | `ArrayBuffer` / `DataView` / `.buffer` / `.byteOffset` semantics | ✗ no backing buffer type; `.byteOffset` is always 0 |
134
136
  | `BigInt64Array` / `BigUint64Array` | ✗ not implemented |
135
- | `instanceof Uint8Array` | ✗ global constructors are not first-class values, so `x instanceof Uint8Array` fails with `Cannot find name 'Uint8Array'` |
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` |
136
138
  | Typed-array views over a `Buffer` / `ArrayBuffer` | ✗ constructors copy from a length / array-like / typed array only |
137
139
 
138
140
  ---
@@ -168,12 +170,13 @@ element writes, and `fill` / `set` / `slice` / `subarray` / `join` / `toString`
168
170
  | Destructuring parameters / bindings | ✓ | ✓ implemented |
169
171
  | `arguments` object | ✓ (implicit) | ✓ implemented (arrow functions get their own parameters, not the outer function's `arguments`, unlike JS) |
170
172
  | `this` binding / method call semantics | ✓ | ✓ implemented (`this` is threaded as the first ABI parameter; arrow functions inherit lexically) |
171
- | `async` / `await` / Promise | ✓ | ✓ implemented (synchronous microtask model) |
172
- | `new.target` | ✗ | not implemented |
173
- | Generators / iterators / `yield` | ✓ implemented | `function*`, `yield`, `yield*`, `.next/.throw/.return`; `async` generators not supported |
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) |
174
+ | `new.target` | ✗ | parsed, then rejected with `UnsupportedFeature` (no `new.target` semantics) |
175
+ | Generators / iterators / `yield` | ✓ implemented | `function*`, `yield`, `yield*`, `.next/.throw/.return`; `async` generators are rejected with `UnsupportedFeature` |
174
176
  | Closure `arity` | — | `xt_closure_arity` is always -1, never filled in |
175
177
  | `fn.call` / `fn.apply` / `fn.bind` | ✓ | ✓ implemented (the bound closure does not track partial-argument `length`) |
176
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 |
177
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 |
178
181
  | `fn.toString()` | ~ | returns a native-style placeholder (`function name() { [native code] }`) instead of the original source text |
179
182
 
@@ -221,8 +224,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
221
224
 
222
225
  | Item | Deviation |
223
226
  | --- | --- |
224
- | String `length` | Counted in UTF-8 bytes, not UTF-16 code units (`"\u00e9".length` reports 1 instead of 2; `"\u{1F600}".length` reports 4 instead of 2; `codePointAt` likewise differs) |
225
- | `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 |
226
228
  | Global RegExp `lastIndex` | `test` / `exec` do not advance or honour a caller-set `lastIndex` for `/g` / `/y` regexes |
227
229
  | String `normalize` / `structuredClone` | Not implemented |
228
230
  | First-class built-in methods | Implemented as unbound method values (see section 5); `fn.toString()` returns a placeholder rather than source text |
@@ -230,11 +232,11 @@ These features **compile and run**, but the result does not fully match ECMAScri
230
232
  | Array out-of-bounds / sparse | Out-of-bounds access returns `undefined`; assigning `arr.length` truncates / extends, but sparse holes are not tracked distinctly |
231
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 |
232
234
  | Function `arity` / argument count | No argument count validation; `fn.length` reports the declared arity but calls are never checked against it |
233
- | `async` / `await` | **Synchronous microtask model**: `await` on an already-settled promise continues synchronously. Timers and sockets run on the event loop only after the program body, so a promise settled from a timer callback cannot be awaited |
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 |
234
236
  | `super` | `super.x` / `super(...)` takes the prototype of `this`'s prototype; single-level inheritance is correct, but depth > 1 may be inaccurate |
235
- | `Error.stack` | Not captured |
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) |
236
238
  | Module live bindings | Namespace imports and imported bindings are snapshots (see section 4) |
237
- | `import.meta` | Parsed but has no value |
239
+ | `import.meta` | ✓ `import.meta.url` / `.dirname` / `.filename`, resolved from the executable path |
238
240
 
239
241
  > Number formatting, loose equality, `+` / relational `ToPrimitive`, whole-chain
240
242
  > optional chaining, `finally` on early exit and object-key ordering have all
@@ -252,7 +254,7 @@ These features **compile and run**, but the result does not fully match ECMAScri
252
254
  | Type checker | ✗ only diagnostic codes are defined; no checker |
253
255
  | Full standard library | partial: Math / JSON / Date / Map / Set / RegExp / `Error` / `BigInt` / `Symbol` implemented; String.normalize / structuredClone missing |
254
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 |
255
- | A real async runtime / event loop | ✗ (Promise is a synchronous microtask model) |
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) |
256
258
  | Windows binary artifact verification | adapted at the build layer (`.exe` suffix, link flag branch), verified in CI |
257
259
  | Precise ECMAScript number / string / comparison semantics | partial, see section 8 |
258
260
 
@@ -263,9 +265,9 @@ These features **compile and run**, but the result does not fully match ECMAScri
263
265
  ```
264
266
  Unimplemented (statements): namespace/module declarations
265
267
 
266
- Unimplemented (expressions): new.target, import.meta value
268
+ Unimplemented (expressions): new.target (clear UnsupportedFeature)
267
269
 
268
- Unimplemented (functions): `fn.toString()` source text, async generators
270
+ Unimplemented (functions): `fn.toString()` source text, async generators (rejected)
269
271
 
270
272
  Unimplemented (classes/OO): abstract/implements, access control,
271
273
  parent/child #x collision
@@ -279,8 +281,8 @@ Unimplemented (modules): circular dependencies, live bindings, dynamic
279
281
  Unimplemented (type system): type checking, generic instantiation, assertion
280
282
  semantics, optional-chaining narrowing
281
283
 
282
- Unimplemented (runtime): a real async event loop, UTF-16 string length,
283
- Object.prototype identity, global-regex lastIndex
284
+ Unimplemented (runtime): asynchronous I/O scheduling,
285
+ global-regex lastIndex
284
286
 
285
287
  Unimplemented (engineering): type checker
286
288
  ```
@@ -39,13 +39,18 @@ xt_value fn(xt_value env, int32_t argc, xt_value *argv);
39
39
  ```
40
40
 
41
41
  `env` 通过 box 以引用方式传递捕获变量,直接调用与闭包调用共用一条代码路径。
42
- 不易内联的 JS 语义(`+` 隐式转换、关系比较、属性访问、打印)委托给 `@xt_*` 运行时调用。
42
+ 不易内联的 JS 语义(`+` 隐式转换、属性访问、打印)委托给 `@xt_*` 运行时调用。
43
+ 数值算术与比较是例外:codegen 内联 double 快路径(`numeric.ts`),需要隐式转换时
44
+ 才调用运行时。
43
45
 
44
46
  ### 运行时
45
47
 
46
- `runtime/xt_runtime.c` 实现字符串、对象、数组、闭包、算术、比较、异常与
47
- 类 Node 的 `console.log` 打印。现在 `xt_alloc` 背后使用非移动标记-清扫回收器
48
- (显式根、子系统根提供者与保守 C 栈扫描),其内部实现对编译器保持隔离。
48
+ `runtime/` 实现字符串、对象、数组、闭包、算术、比较、异常与类 Node 的
49
+ `console.log` 打印。它按职责拆分为多个编译单元(`xt_values.c`、
50
+ `xt_containers.c`、`xt_stdlib.c`、`xt_builtins.c`、`xt_io.c`、`xt_alloc.c` 等),
51
+ 每个单元 `#include` 自己的实现片段(`.inc`),这样文件保持小巧而不改变链接范围。
52
+ `xt_alloc` 背后使用非移动标记-清扫回收器(显式根、子系统根提供者与保守 C 栈扫描),
53
+ 其内部实现对编译器保持隔离。
49
54
 
50
55
  ### llc 的替代
51
56
 
@@ -92,13 +97,14 @@ xt_value fn(xt_value env, int32_t argc, xt_value *argv);
92
97
  同样覆盖:Windows 下 xbintsc 使用系统 clang 按 MSVC ABI 链接,示例即针对该 ABI 构建。
93
98
  参见 `examples/extensions/` 与 `runtime/xt_ext.h` / `runtime/xt_ext.rs`。
94
99
 
95
- ## 自举路线
100
+ ## 自举
96
101
 
97
- 编译器本身使用 TypeScript 编写并输出 IR 文本,`runtime` 已与编译器解耦。后续可
98
- 用 TS 重写运行时,并由 xbintsc 编译自身,逐步达成自举。
102
+ 编译器已经能编译自身:`xbintsc build src/cli/main.ts --ext node` 会产出一个可用的
103
+ `xbintsc` 二进制,且从第一代起生成的 IR 就是不动点。CI 会为每个支持的平台构建这些
104
+ 二进制并检查不动点。运行时仍使用 C;以后是否用 TS 重写只是可选项,并不是自举的前提。
99
105
 
100
106
  ## 测试
101
107
 
102
108
  按模块划分:`tests/lexer`、`tests/parser`、`tests/binder`、`tests/codegen`、
103
- `tests/driver`、`tests/extensions`、`tests/cli`、`tests/e2e`。e2e 会在存在
104
- `clang` 时真正编译并运行二进制,否则自动跳过。
109
+ `tests/driver`、`tests/extensions`、`tests/cli`、`tests/e2e`。存在受支持的 clang
110
+ (16+,与 `build` 使用的版本门槛一致)时,e2e 会真正编译并运行二进制,否则自动跳过。