xbintsc 0.2.9 → 0.3.1

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 (311) hide show
  1. package/README.md +17 -2
  2. package/README.zh-CN.md +16 -2
  3. package/bin/xbintsc.js +49 -10
  4. package/dist/src/ast/expressions.d.ts +2 -0
  5. package/dist/src/binder/binder.d.ts +24 -98
  6. package/dist/src/binder/binder.js +13 -559
  7. package/dist/src/binder/binder.js.map +1 -1
  8. package/dist/src/binder/declarations.d.ts +16 -0
  9. package/dist/src/binder/declarations.js +168 -0
  10. package/dist/src/binder/declarations.js.map +1 -0
  11. package/dist/src/binder/helpers.d.ts +11 -0
  12. package/dist/src/binder/helpers.js +46 -0
  13. package/dist/src/binder/helpers.js.map +1 -0
  14. package/dist/src/binder/references.d.ts +21 -0
  15. package/dist/src/binder/references.js +349 -0
  16. package/dist/src/binder/references.js.map +1 -0
  17. package/dist/src/binder/types.d.ts +114 -0
  18. package/dist/src/binder/types.js +27 -0
  19. package/dist/src/binder/types.js.map +1 -0
  20. package/dist/src/cli/main.d.ts +1 -0
  21. package/dist/src/cli/main.js +40 -0
  22. package/dist/src/cli/main.js.map +1 -1
  23. package/dist/src/codegen/generator/calls/access.d.ts +13 -0
  24. package/dist/src/codegen/generator/calls/access.js +115 -0
  25. package/dist/src/codegen/generator/calls/access.js.map +1 -0
  26. package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
  27. package/dist/src/codegen/generator/calls/closures.js +50 -0
  28. package/dist/src/codegen/generator/calls/closures.js.map +1 -0
  29. package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
  30. package/dist/src/codegen/generator/calls/invocation.js +242 -0
  31. package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
  32. package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
  33. package/dist/src/codegen/generator/calls/literals.js +69 -0
  34. package/dist/src/codegen/generator/calls/literals.js.map +1 -0
  35. package/dist/src/codegen/generator/calls/super.d.ts +10 -0
  36. package/dist/src/codegen/generator/calls/super.js +47 -0
  37. package/dist/src/codegen/generator/calls/super.js.map +1 -0
  38. package/dist/src/codegen/generator/calls.d.ts +15 -24
  39. package/dist/src/codegen/generator/calls.js +15 -482
  40. package/dist/src/codegen/generator/calls.js.map +1 -1
  41. package/dist/src/codegen/generator/context.d.ts +1 -1
  42. package/dist/src/codegen/generator/context.js +2 -2
  43. package/dist/src/codegen/generator/context.js.map +1 -1
  44. package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
  45. package/dist/src/codegen/generator/expressions/assignment.js +203 -0
  46. package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
  47. package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
  48. package/dist/src/codegen/generator/expressions/operators.js +163 -0
  49. package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
  50. package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
  51. package/dist/src/codegen/generator/expressions/primary.js +260 -0
  52. package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
  53. package/dist/src/codegen/generator/expressions.d.ts +11 -21
  54. package/dist/src/codegen/generator/expressions.js +11 -494
  55. package/dist/src/codegen/generator/expressions.js.map +1 -1
  56. package/dist/src/codegen/generator/module.js +16 -4
  57. package/dist/src/codegen/generator/module.js.map +1 -1
  58. package/dist/src/codegen/generator/state.js +8 -0
  59. package/dist/src/codegen/generator/state.js.map +1 -1
  60. package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
  61. package/dist/src/codegen/generator/statements/control-flow.js +199 -0
  62. package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
  63. package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
  64. package/dist/src/codegen/generator/statements/dispatch.js +100 -0
  65. package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
  66. package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
  67. package/dist/src/codegen/generator/statements/loops.js +152 -0
  68. package/dist/src/codegen/generator/statements/loops.js.map +1 -0
  69. package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
  70. package/dist/src/codegen/generator/statements/variables.js +146 -0
  71. package/dist/src/codegen/generator/statements/variables.js.map +1 -0
  72. package/dist/src/codegen/generator/statements.d.ts +13 -21
  73. package/dist/src/codegen/generator/statements.js +13 -568
  74. package/dist/src/codegen/generator/statements.js.map +1 -1
  75. package/dist/src/codegen/generator/tables.js +7 -0
  76. package/dist/src/codegen/generator/tables.js.map +1 -1
  77. package/dist/src/codegen/values.d.ts +17 -17
  78. package/dist/src/codegen/values.js +21 -57
  79. package/dist/src/codegen/values.js.map +1 -1
  80. package/dist/src/diagnostics/diagnostic.d.ts +1 -0
  81. package/dist/src/diagnostics/diagnostic.js +1 -0
  82. package/dist/src/diagnostics/diagnostic.js.map +1 -1
  83. package/dist/src/diagnostics/source.d.ts +1 -1
  84. package/dist/src/diagnostics/source.js +7 -12
  85. package/dist/src/diagnostics/source.js.map +1 -1
  86. package/dist/src/driver/compiler.d.ts +4 -0
  87. package/dist/src/driver/compiler.js +51 -16
  88. package/dist/src/driver/compiler.js.map +1 -1
  89. package/dist/src/driver/index.d.ts +5 -2
  90. package/dist/src/driver/index.js +5 -2
  91. package/dist/src/driver/index.js.map +1 -1
  92. package/dist/src/driver/paths.d.ts +20 -0
  93. package/dist/src/driver/paths.js +49 -0
  94. package/dist/src/driver/paths.js.map +1 -1
  95. package/dist/src/driver/runtime-lib.d.ts +18 -0
  96. package/dist/src/driver/runtime-lib.js +31 -0
  97. package/dist/src/driver/runtime-lib.js.map +1 -0
  98. package/dist/src/driver/toolchain-download.d.ts +50 -0
  99. package/dist/src/driver/toolchain-download.js +76 -0
  100. package/dist/src/driver/toolchain-download.js.map +1 -0
  101. package/dist/src/driver/toolchain-provider.d.ts +33 -0
  102. package/dist/src/driver/toolchain-provider.js +71 -0
  103. package/dist/src/driver/toolchain-provider.js.map +1 -0
  104. package/dist/src/driver/toolchain.d.ts +9 -4
  105. package/dist/src/driver/toolchain.js +6 -10
  106. package/dist/src/driver/toolchain.js.map +1 -1
  107. package/dist/src/extensions/node/child_process/index.d.ts +4 -2
  108. package/dist/src/extensions/node/child_process/index.js +4 -2
  109. package/dist/src/extensions/node/child_process/index.js.map +1 -1
  110. package/dist/src/extensions/node/events/index.d.ts +10 -0
  111. package/dist/src/extensions/node/events/index.js +22 -0
  112. package/dist/src/extensions/node/events/index.js.map +1 -0
  113. package/dist/src/extensions/node/index.js +6 -0
  114. package/dist/src/extensions/node/index.js.map +1 -1
  115. package/dist/src/extensions/node/querystring/index.d.ts +10 -0
  116. package/dist/src/extensions/node/querystring/index.js +25 -0
  117. package/dist/src/extensions/node/querystring/index.js.map +1 -0
  118. package/dist/src/extensions/node/util/index.d.ts +11 -0
  119. package/dist/src/extensions/node/util/index.js +41 -0
  120. package/dist/src/extensions/node/util/index.js.map +1 -0
  121. package/dist/src/extensions/registry.d.ts +6 -0
  122. package/dist/src/extensions/registry.js.map +1 -1
  123. package/dist/src/index.d.ts +1 -1
  124. package/dist/src/index.js +1 -1
  125. package/dist/src/index.js.map +1 -1
  126. package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
  127. package/dist/src/lexer/scanner/identifiers.js +33 -0
  128. package/dist/src/lexer/scanner/identifiers.js.map +1 -0
  129. package/dist/src/lexer/scanner/numbers.d.ts +10 -0
  130. package/dist/src/lexer/scanner/numbers.js +89 -0
  131. package/dist/src/lexer/scanner/numbers.js.map +1 -0
  132. package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
  133. package/dist/src/lexer/scanner/punctuation.js +151 -0
  134. package/dist/src/lexer/scanner/punctuation.js.map +1 -0
  135. package/dist/src/lexer/scanner/regex.d.ts +11 -0
  136. package/dist/src/lexer/scanner/regex.js +69 -0
  137. package/dist/src/lexer/scanner/regex.js.map +1 -0
  138. package/dist/src/lexer/scanner/strings.d.ts +13 -0
  139. package/dist/src/lexer/scanner/strings.js +118 -0
  140. package/dist/src/lexer/scanner/strings.js.map +1 -0
  141. package/dist/src/lexer/scanner.d.ts +20 -27
  142. package/dist/src/lexer/scanner.js +11 -415
  143. package/dist/src/lexer/scanner.js.map +1 -1
  144. package/dist/src/parser/declarations/classes.d.ts +14 -0
  145. package/dist/src/parser/declarations/classes.js +191 -0
  146. package/dist/src/parser/declarations/classes.js.map +1 -0
  147. package/dist/src/parser/declarations/functions.d.ts +17 -0
  148. package/dist/src/parser/declarations/functions.js +241 -0
  149. package/dist/src/parser/declarations/functions.js.map +1 -0
  150. package/dist/src/parser/declarations/type-members.d.ts +16 -0
  151. package/dist/src/parser/declarations/type-members.js +156 -0
  152. package/dist/src/parser/declarations/type-members.js.map +1 -0
  153. package/dist/src/parser/declarations.d.ts +13 -24
  154. package/dist/src/parser/declarations.js +13 -571
  155. package/dist/src/parser/declarations.js.map +1 -1
  156. package/dist/src/parser/helpers.js +13 -4
  157. package/dist/src/parser/helpers.js.map +1 -1
  158. package/dist/src/parser/literals.js +10 -1
  159. package/dist/src/parser/literals.js.map +1 -1
  160. package/dist/tests/codegen/llvm.test.js +24 -0
  161. package/dist/tests/codegen/llvm.test.js.map +1 -1
  162. package/dist/tests/driver/compiler.test.js +3 -0
  163. package/dist/tests/driver/compiler.test.js.map +1 -1
  164. package/dist/tests/driver/paths.test.d.ts +1 -0
  165. package/dist/tests/driver/paths.test.js +26 -0
  166. package/dist/tests/driver/paths.test.js.map +1 -0
  167. package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
  168. package/dist/tests/driver/toolchain-download.test.js +38 -0
  169. package/dist/tests/driver/toolchain-download.test.js.map +1 -0
  170. package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
  171. package/dist/tests/driver/toolchain-provider.test.js +37 -0
  172. package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
  173. package/dist/tests/e2e/compile-node.test.d.ts +7 -0
  174. package/dist/tests/e2e/compile-node.test.js +123 -0
  175. package/dist/tests/e2e/compile-node.test.js.map +1 -0
  176. package/dist/tests/e2e/compile.test.d.ts +4 -1
  177. package/dist/tests/e2e/compile.test.js +78 -130
  178. package/dist/tests/e2e/compile.test.js.map +1 -1
  179. package/dist/tests/e2e/harness.d.ts +36 -0
  180. package/dist/tests/e2e/harness.js +64 -0
  181. package/dist/tests/e2e/harness.js.map +1 -0
  182. package/dist/tests/e2e/node-modules.test.js +60 -0
  183. package/dist/tests/e2e/node-modules.test.js.map +1 -1
  184. package/dist/tests/extensions/registry.test.js +4 -0
  185. package/dist/tests/extensions/registry.test.js.map +1 -1
  186. package/package.json +5 -3
  187. package/runtime/ext_node/buffer/buffer.c +12 -552
  188. package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
  189. package/runtime/ext_node/buffer/parts/construction.inc +60 -0
  190. package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
  191. package/runtime/ext_node/buffer/parts/methods.inc +135 -0
  192. package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
  193. package/runtime/ext_node/buffer/parts/search.inc +86 -0
  194. package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
  195. package/runtime/ext_node/child_process/child_process.c +37 -3
  196. package/runtime/ext_node/events/events.c +285 -0
  197. package/runtime/ext_node/http/http.c +11 -736
  198. package/runtime/ext_node/http/parts/client.inc +290 -0
  199. package/runtime/ext_node/http/parts/helpers.inc +45 -0
  200. package/runtime/ext_node/http/parts/prototypes.inc +57 -0
  201. package/runtime/ext_node/http/parts/response.inc +149 -0
  202. package/runtime/ext_node/http/parts/server.inc +133 -0
  203. package/runtime/ext_node/http/parts/string-builder.inc +58 -0
  204. package/runtime/ext_node/net/net.c +12 -504
  205. package/runtime/ext_node/net/parts/construction.inc +22 -0
  206. package/runtime/ext_node/net/parts/platform.inc +60 -0
  207. package/runtime/ext_node/net/parts/prototypes.inc +35 -0
  208. package/runtime/ext_node/net/parts/read-loop.inc +58 -0
  209. package/runtime/ext_node/net/parts/server.inc +131 -0
  210. package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
  211. package/runtime/ext_node/net/parts/static-api.inc +93 -0
  212. package/runtime/ext_node/querystring/querystring.c +251 -0
  213. package/runtime/ext_node/util/util.c +456 -0
  214. package/runtime/rt.h +8 -2
  215. package/runtime/rt_internal.h +34 -0
  216. package/runtime/xt_bigint/arithmetic.inc +135 -0
  217. package/runtime/xt_bigint/bits.inc +98 -0
  218. package/runtime/xt_bigint/bitwise.inc +103 -0
  219. package/runtime/xt_bigint/compare.inc +30 -0
  220. package/runtime/xt_bigint/conversions.inc +51 -0
  221. package/runtime/xt_bigint/division.inc +85 -0
  222. package/runtime/xt_bigint/format.inc +145 -0
  223. package/runtime/xt_bigint/helpers.inc +92 -0
  224. package/runtime/xt_bigint/magnitude.inc +88 -0
  225. package/runtime/xt_bigint/public.inc +59 -0
  226. package/runtime/xt_bigint/small-arithmetic.inc +58 -0
  227. package/runtime/xt_bigint.c +42 -0
  228. package/runtime/xt_builtins.c +1 -0
  229. package/runtime/xt_io.c +7 -0
  230. package/runtime/xt_stdlib/arrays.inc +161 -0
  231. package/runtime/xt_stdlib/dispatch.inc +116 -0
  232. package/runtime/xt_stdlib/helpers.inc +23 -0
  233. package/runtime/xt_stdlib/math.inc +72 -0
  234. package/runtime/xt_stdlib/strings.inc +178 -0
  235. package/runtime/xt_stdlib.c +10 -549
  236. package/runtime/xt_stdlib2/array-statics.inc +37 -0
  237. package/runtime/xt_stdlib2/arrays.inc +189 -0
  238. package/runtime/xt_stdlib2/container.inc +23 -0
  239. package/runtime/xt_stdlib2/date.inc +72 -0
  240. package/runtime/xt_stdlib2/error.inc +22 -0
  241. package/runtime/xt_stdlib2/helpers.inc +43 -0
  242. package/runtime/xt_stdlib2/json.inc +213 -0
  243. package/runtime/xt_stdlib2/map.inc +95 -0
  244. package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
  245. package/runtime/xt_stdlib2/numbers.inc +38 -0
  246. package/runtime/xt_stdlib2/objects.inc +41 -0
  247. package/runtime/xt_stdlib2/regexp-match.inc +204 -0
  248. package/runtime/xt_stdlib2/regexp.inc +20 -0
  249. package/runtime/xt_stdlib2/set.inc +105 -0
  250. package/runtime/xt_stdlib2/strings.inc +94 -0
  251. package/runtime/xt_stdlib2.c +19 -1278
  252. package/runtime/xt_values.c +155 -12
  253. package/scripts/build-runtime.ts +109 -0
  254. package/scripts/fetch-toolchain.ts +101 -0
  255. package/scripts/package-release.ts +192 -0
  256. package/src/ast/expressions.ts +2 -0
  257. package/src/binder/binder.ts +40 -725
  258. package/src/binder/declarations.ts +203 -0
  259. package/src/binder/helpers.ts +47 -0
  260. package/src/binder/references.ts +410 -0
  261. package/src/binder/types.ts +134 -0
  262. package/src/cli/main.ts +43 -0
  263. package/src/codegen/generator/calls/access.ts +139 -0
  264. package/src/codegen/generator/calls/closures.ts +60 -0
  265. package/src/codegen/generator/calls/invocation.ts +282 -0
  266. package/src/codegen/generator/calls/literals.ts +77 -0
  267. package/src/codegen/generator/calls/super.ts +61 -0
  268. package/src/codegen/generator/calls.ts +30 -552
  269. package/src/codegen/generator/context.ts +2 -2
  270. package/src/codegen/generator/expressions/assignment.ts +226 -0
  271. package/src/codegen/generator/expressions/operators.ts +182 -0
  272. package/src/codegen/generator/expressions/primary.ts +304 -0
  273. package/src/codegen/generator/expressions.ts +22 -553
  274. package/src/codegen/generator/module.ts +14 -4
  275. package/src/codegen/generator/state.ts +8 -0
  276. package/src/codegen/generator/statements/control-flow.ts +225 -0
  277. package/src/codegen/generator/statements/dispatch.ts +122 -0
  278. package/src/codegen/generator/statements/loops.ts +173 -0
  279. package/src/codegen/generator/statements/variables.ts +152 -0
  280. package/src/codegen/generator/statements.ts +26 -612
  281. package/src/codegen/generator/tables.ts +7 -0
  282. package/src/codegen/values.ts +22 -57
  283. package/src/diagnostics/diagnostic.ts +1 -0
  284. package/src/diagnostics/source.ts +7 -12
  285. package/src/driver/compiler.ts +61 -18
  286. package/src/driver/index.ts +17 -2
  287. package/src/driver/paths.ts +54 -0
  288. package/src/driver/runtime-lib.ts +32 -0
  289. package/src/driver/toolchain-download.ts +108 -0
  290. package/src/driver/toolchain-provider.ts +91 -0
  291. package/src/driver/toolchain.ts +29 -11
  292. package/src/extensions/node/child_process/index.ts +4 -2
  293. package/src/extensions/node/events/index.ts +27 -0
  294. package/src/extensions/node/index.ts +6 -0
  295. package/src/extensions/node/querystring/index.ts +29 -0
  296. package/src/extensions/node/util/index.ts +48 -0
  297. package/src/extensions/registry.ts +6 -0
  298. package/src/index.ts +1 -0
  299. package/src/lexer/scanner/identifiers.ts +37 -0
  300. package/src/lexer/scanner/numbers.ts +84 -0
  301. package/src/lexer/scanner/punctuation.ts +132 -0
  302. package/src/lexer/scanner/regex.ts +79 -0
  303. package/src/lexer/scanner/strings.ts +128 -0
  304. package/src/lexer/scanner.ts +35 -401
  305. package/src/parser/declarations/classes.ts +215 -0
  306. package/src/parser/declarations/functions.ts +254 -0
  307. package/src/parser/declarations/type-members.ts +181 -0
  308. package/src/parser/declarations.ts +32 -609
  309. package/src/parser/helpers.ts +13 -6
  310. package/src/parser/literals.ts +10 -1
  311. package/scripts/build-runtime.mjs +0 -55
@@ -6,34 +6,34 @@
6
6
  * emits these constants directly into LLVM IR, so this module (together with
7
7
  * runtime/rt.h) is the single source of truth for the representation.
8
8
  *
9
- * The constants are written as pre-computed signed 64-bit decimal literals
10
- * rather than BigInt expressions, and `numberLiteral` derives the raw bits of a
11
- * double with plain arithmetic. That keeps this module free of BigInt and
12
- * typed-array APIs so the compiler can be compiled by itself on every platform.
9
+ * BigInts are available both to the host (Node) running the compiler and to
10
+ * the compiler once self-hosted, so the constants below are written as BigInt
11
+ * literals and `numberLiteral` derives a double's raw bits with BigInt
12
+ * arithmetic. `i64` normalises any 64-bit pattern to the signed decimal form
13
+ * LLVM expects.
13
14
  */
14
15
 
15
- /** `0xffff000000000000` as a signed i64. */
16
- export const XT_TAG_MASK = "-281474976710656";
17
- /** `0xfff8000000000000` as a signed i64. */
18
- export const XT_NUMBER_MASK = "-2251799813685248";
16
+ export const XT_TAG_MASK = 0xffff000000000000n;
17
+ export const XT_NUMBER_MASK = 0xfff8000000000000n;
19
18
 
20
- export const XT_UNDEFINED = "-2251799813685248"; // 0xfff8000000000000
21
- export const XT_NULL = "-1970324836974592"; // 0xfff9000000000000
22
- export const XT_FALSE = "-1688849860263936"; // 0xfffa000000000000
23
- export const XT_TRUE = "-1407374883553280"; // 0xfffb000000000000
24
- export const XT_STRING = "-1125899906842624"; // 0xfffc000000000000
25
- export const XT_OBJECT = "-844424930131968"; // 0xfffd000000000000
26
- export const XT_ARRAY = "-562949953421312"; // 0xfffe000000000000
27
- export const XT_FUNCTION = "-281474976710656"; // 0xffff000000000000
19
+ export const XT_UNDEFINED = 0xfff8000000000000n;
20
+ export const XT_NULL = 0xfff9000000000000n;
21
+ export const XT_FALSE = 0xfffa000000000000n;
22
+ export const XT_TRUE = 0xfffa000000000001n;
23
+ export const XT_BIGINT = 0xfffb000000000000n;
24
+ export const XT_STRING = 0xfffc000000000000n;
25
+ export const XT_OBJECT = 0xfffd000000000000n;
26
+ export const XT_ARRAY = 0xfffe000000000000n;
27
+ export const XT_FUNCTION = 0xffff000000000000n;
28
28
 
29
29
  /** Render a 64-bit constant the way LLVM expects signed i64 literals. */
30
- export function i64(value: string): string {
31
- return value;
30
+ export function i64(value: bigint): string {
31
+ return BigInt.asIntN(64, value).toString();
32
32
  }
33
33
 
34
34
  /** The raw 64 bits of an IEEE-754 double, as a signed i64 literal. */
35
35
  export function numberLiteral(value: number): string {
36
- if (value !== value) return "9221120237041090560"; // 0x7ff8000000000000 (NaN)
36
+ if (value !== value) return i64(0x7ff8000000000000n);
37
37
  const negative = value < 0 || (value === 0 && 1 / value < 0);
38
38
  const abs = negative ? -value : value;
39
39
  let high: number;
@@ -61,45 +61,10 @@ export function numberLiteral(value: number): string {
61
61
  low = mantissa % 0x100000000;
62
62
  }
63
63
  if (negative) high += 0x80000000;
64
- return signedDecimal(high >>> 0, low >>> 0);
64
+ const bits = (BigInt(high >>> 0) << 32n) | BigInt(low >>> 0);
65
+ return i64(bits);
65
66
  }
66
67
 
67
68
  export function booleanLiteral(value: boolean): string {
68
- return value ? XT_TRUE : XT_FALSE;
69
- }
70
-
71
- /** Two's-complement (high, low) 32-bit halves as a signed decimal string. */
72
- function signedDecimal(high: number, low: number): string {
73
- if (high >= 0x80000000) {
74
- let h = (~high) >>> 0;
75
- let l = (~low) >>> 0;
76
- l = (l + 1) >>> 0;
77
- if (l === 0) h = (h + 1) >>> 0;
78
- return "-" + unsignedDecimal(h, l);
79
- }
80
- return unsignedDecimal(high, low);
81
- }
82
-
83
- /** Unsigned 64-bit `high * 2^32 + low` as a decimal string. */
84
- function unsignedDecimal(high: number, low: number): string {
85
- const digits: number[] = [];
86
- let h = high;
87
- if (h === 0) digits.push(0);
88
- while (h > 0) {
89
- digits.push(h % 10);
90
- h = Math.floor(h / 10);
91
- }
92
- let carry = low;
93
- for (let i = 0; i < digits.length; i++) {
94
- const current = digits[i]! * 4294967296 + carry;
95
- digits[i] = current % 10;
96
- carry = Math.floor(current / 10);
97
- }
98
- while (carry > 0) {
99
- digits.push(carry % 10);
100
- carry = Math.floor(carry / 10);
101
- }
102
- let out = "";
103
- for (let i = digits.length - 1; i >= 0; i--) out += digits[i]!;
104
- return out;
69
+ return i64(value ? XT_TRUE : XT_FALSE);
105
70
  }
@@ -25,6 +25,7 @@ export enum DiagnosticCode {
25
25
  DuplicateIdentifier = 3001,
26
26
  CannotFindName = 3002,
27
27
  IllegalRedeclaration = 3003,
28
+ CannotAssignToConst = 3004,
28
29
 
29
30
  // Checker 4xxx
30
31
  TypeMismatch = 4001,
@@ -80,20 +80,15 @@ export class SourceFile {
80
80
  * and stable across platforms which is exactly what the incremental cache
81
81
  * needs. Collision resistance is not a security property here.
82
82
  */
83
- export function hashText(text: string, seed = 0): string {
84
- // Two independent 32-bit FNV-1a lanes give a wide, stable fingerprint
85
- // without relying on BigInt, which the compiler cannot assume at runtime.
86
- let a = (0xcbf29ce4 ^ seed) >>> 0;
87
- let b = (0x84222325 ^ seed) >>> 0;
88
- const prime = 0x01000193;
83
+ export function hashText(text: string, seed = 0xcbf29ce484222325n): string {
84
+ let hash = seed;
85
+ const prime = 0x100000001b3n;
86
+ const mask = 0xffffffffffffffffn;
89
87
  for (let i = 0; i < text.length; i++) {
90
- const code = text.charCodeAt(i);
91
- a = Math.imul(a ^ (code & 0xff), prime) >>> 0;
92
- a = Math.imul(a ^ (code >>> 8), prime) >>> 0;
93
- b = Math.imul(b ^ (code >>> 8), prime) >>> 0;
94
- b = Math.imul(b ^ (code & 0xff), prime) >>> 0;
88
+ hash ^= BigInt(text.charCodeAt(i));
89
+ hash = (hash * prime) & mask;
95
90
  }
96
- return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
91
+ return hash.toString(16).padStart(16, "0");
97
92
  }
98
93
 
99
94
  /** Combine several hashes/strings into one stable fingerprint. */
@@ -18,10 +18,11 @@ import { bundleModules } from "./modules.js";
18
18
  import { createDefaultRegistry, type ExtensionRegistry } from "../extensions/registry.js";
19
19
  import { BuildCache, hashParts } from "./cache.js";
20
20
  import { findRuntimeDir } from "./paths.js";
21
+ import { findRuntimeLibrary } from "./runtime-lib.js";
22
+ import { resolveToolchain } from "./toolchain-provider.js";
21
23
  import {
22
24
  compileC,
23
25
  compileIr,
24
- findClang,
25
26
  link,
26
27
  realRunner,
27
28
  type Runner,
@@ -43,6 +44,8 @@ export interface BuildOptions {
43
44
  readonly extensions?: ExtensionRegistry;
44
45
  readonly runner?: Runner;
45
46
  readonly clang?: string;
47
+ /** Prefer a prebuilt `runtime/lib/<os>-<arch>/*.a` archive when present (default true). */
48
+ readonly preferPrebuilt?: boolean;
46
49
  readonly write?: boolean;
47
50
  }
48
51
 
@@ -189,14 +192,14 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
189
192
  }
190
193
 
191
194
  // -- toolchain -----------------------------------------------------------
192
- const clang = options.clang ?? findClang(runner);
193
- const runtimeDir = findRuntimeDir();
195
+ const toolchain = options.clang
196
+ ? { clang: options.clang, linkerArgs: [] as string[], env: {} as Record<string, string> }
197
+ : resolveToolchain(runner);
198
+ const clang = toolchain.clang;
194
199
  mkdirSync(cacheDir, { recursive: true });
195
200
 
196
- const { runtimeObjects, extensionObjects } = ensureRuntimeObjects(runner, clang, runtimeDir, cacheDir, registry);
197
-
198
201
  const objectPath = emit === "obj" ? outputPath : resolve(outDir, baseName + ".o");
199
- compileIr(runner, { clang, irPath, objectPath, optimize });
202
+ compileIr(runner, { clang, irPath, objectPath, optimize, env: toolchain.env });
200
203
 
201
204
  if (emit === "obj") {
202
205
  cache.record(cacheKey, outputs);
@@ -204,12 +207,28 @@ export function build(entryPath: string, options: BuildOptions = {}): BuildResul
204
207
  return { outputPath, irPath, cached: false, diagnostics: [], ir };
205
208
  }
206
209
 
210
+ const runtimeDir = findRuntimeDir();
211
+ const { runtimeObjects, extensionObjects } = ensureRuntimeObjects(
212
+ runner,
213
+ clang,
214
+ runtimeDir,
215
+ cacheDir,
216
+ registry,
217
+ options.preferPrebuilt ?? true,
218
+ toolchain.env,
219
+ );
220
+
207
221
  link(runner, {
208
222
  clang,
209
223
  objectPaths: [objectPath, ...runtimeObjects, ...extensionObjects],
210
224
  outputPath,
211
- linkerFlags: [...(process.platform === "win32" ? ["-lws2_32"] : ["-lm"]), ...registry.linkerFlags()],
225
+ linkerFlags: [
226
+ ...toolchain.linkerArgs,
227
+ ...(process.platform === "win32" ? ["-lws2_32"] : ["-lm"]),
228
+ ...registry.linkerFlags(),
229
+ ],
212
230
  optimize,
231
+ env: toolchain.env,
213
232
  });
214
233
 
215
234
  cache.record(cacheKey, outputs);
@@ -223,9 +242,10 @@ interface RuntimeObjects {
223
242
  }
224
243
 
225
244
  /** Core runtime translation units (each compiled and cached independently). */
226
- const RUNTIME_SOURCES = [
245
+ export const RUNTIME_SOURCES = [
227
246
  "xt_alloc.c",
228
247
  "xt_values.c",
248
+ "xt_bigint.c",
229
249
  "xt_containers.c",
230
250
  "xt_stdlib.c",
231
251
  "xt_stdlib2.c",
@@ -238,6 +258,10 @@ const RUNTIME_SOURCES = [
238
258
  /**
239
259
  * Compile the core runtime and every extension source, reusing cached object
240
260
  * files keyed on the C source hash. Returns the object paths to link.
261
+ *
262
+ * When `preferPrebuilt` is set, a shipped static archive
263
+ * (`runtime/lib/<os>-<arch>/{core,ext_<name>}.a`) is used instead of compiling
264
+ * that group's C sources. Missing archives fall back to compiling the sources.
241
265
  */
242
266
  function ensureRuntimeObjects(
243
267
  runner: Runner,
@@ -245,15 +269,18 @@ function ensureRuntimeObjects(
245
269
  runtimeDir: string,
246
270
  cacheDir: string,
247
271
  registry: ExtensionRegistry,
272
+ preferPrebuilt: boolean,
273
+ env: Record<string, string>,
248
274
  ): RuntimeObjects {
249
- /* Runtime objects depend on the shared headers (rt.h/rt_internal.h/...),
250
- so a header change must invalidate every cached object. Hash them all. */
275
+ /* Runtime objects depend on the shared headers (rt.h/rt_internal.h/...) and
276
+ the `#include`d implementation fragments (`.inc`), so any change to them
277
+ must invalidate every cached object. Hash them all. */
251
278
  const headerParts: string[] = [];
252
279
  const collectHeaders = (dir: string): void => {
253
280
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
254
281
  const full = join(dir, entry.name);
255
282
  if (entry.isDirectory()) collectHeaders(full);
256
- else if (entry.name.endsWith(".h")) headerParts.push(readFileSync(full, "utf8"));
283
+ else if (entry.name.endsWith(".h") || entry.name.endsWith(".inc")) headerParts.push(readFileSync(full, "utf8"));
257
284
  }
258
285
  };
259
286
  collectHeaders(runtimeDir);
@@ -264,16 +291,32 @@ function ensureRuntimeObjects(
264
291
  const key = hashParts(["runtime", COMPILER_VERSION, tag, headerStamp, body, clang, process.platform]);
265
292
  const objectPath = join(cacheDir, `${tag}-${key}.o`);
266
293
  if (!existsSync(objectPath)) {
267
- compileC(runner, clang, sourcePath, objectPath, runtimeDir);
294
+ compileC(runner, clang, sourcePath, objectPath, runtimeDir, env);
268
295
  }
269
296
  return objectPath;
270
297
  };
271
298
 
272
- const runtimeObjects = RUNTIME_SOURCES.map((source) =>
273
- compileOne(join(runtimeDir, source), basename(source, ".c")),
274
- );
275
- const extensionObjects = registry
276
- .runtimeSources()
277
- .map((sourcePath, index) => compileOne(sourcePath, `ext_${index}_${basename(sourcePath, ".c")}`));
299
+ const coreArchive = preferPrebuilt ? findRuntimeLibrary("core") : undefined;
300
+ const runtimeObjects = coreArchive
301
+ ? [coreArchive]
302
+ : RUNTIME_SOURCES.map((source) => compileOne(join(runtimeDir, source), basename(source, ".c")));
303
+
304
+ const extensionObjects: string[] = [];
305
+ const seen = new Set<string>();
306
+ for (const extension of registry.all()) {
307
+ const sources = extension.runtimeSources ? extension.runtimeSources() : [];
308
+ if (sources.length === 0) continue;
309
+ const archive = preferPrebuilt ? findRuntimeLibrary(`ext_${extension.name}`) : undefined;
310
+ if (archive) {
311
+ extensionObjects.push(archive);
312
+ continue;
313
+ }
314
+ for (const sourcePath of sources) {
315
+ const dedupeKey = resolve(sourcePath);
316
+ if (seen.has(dedupeKey)) continue;
317
+ seen.add(dedupeKey);
318
+ extensionObjects.push(compileOne(sourcePath, `ext_${extensionObjects.length}_${basename(sourcePath, ".c")}`));
319
+ }
320
+ }
278
321
  return { runtimeObjects, extensionObjects };
279
322
  }
@@ -1,4 +1,19 @@
1
1
  export { build, compileString, COMPILER_VERSION, type BuildOptions, type BuildResult, type EmitKind } from "./compiler.js";
2
2
  export { BuildCache, hashParts, hashString } from "./cache.js";
3
- export { findRuntimeDir, findPackageRoot } from "./paths.js";
4
- export { findClang, realRunner, ToolchainError, type Runner } from "./toolchain.js";
3
+ export { findRuntimeDir, findPackageRoot, findVendorDir, vendorRootDir, platformSlug, releaseArchiveBase, releaseArchiveExtension } from "./paths.js";
4
+ export {
5
+ toolchainDownload,
6
+ toolchainSupportLibraries,
7
+ LLVM_VERSION,
8
+ LLVM_MINGW_VERSION,
9
+ type ToolchainDownload,
10
+ type SupportLibrary,
11
+ } from "./toolchain-download.js";
12
+ export { findRuntimeLibrary, runtimeLibDir } from "./runtime-lib.js";
13
+ export {
14
+ findClang,
15
+ realRunner,
16
+ ToolchainError,
17
+ type Runner,
18
+ } from "./toolchain.js";
19
+ export { resolveToolchain, type ResolvedToolchain, type ToolchainSource } from "./toolchain-provider.js";
@@ -11,6 +11,9 @@ export function findRuntimeDir(): string {
11
11
  const candidates = [
12
12
  resolve(here, "../../runtime"),
13
13
  resolve(here, "../../../runtime"),
14
+ // Packaged release layout: `<root>/bin/xbintsc` next to `<root>/runtime`.
15
+ resolve(here, "../runtime"),
16
+ resolve(here, "runtime"),
14
17
  resolve(process.cwd(), "runtime"),
15
18
  ];
16
19
  for (const candidate of candidates) {
@@ -22,3 +25,54 @@ export function findRuntimeDir(): string {
22
25
  export function findPackageRoot(): string {
23
26
  return resolve(findRuntimeDir(), "..");
24
27
  }
28
+
29
+ /** `<package>/vendor` — where a bundled toolchain is assembled (may not exist). */
30
+ export function vendorRootDir(): string {
31
+ return resolve(findPackageRoot(), "vendor");
32
+ }
33
+
34
+ /** Platform-architecture slug, e.g. `darwin-arm64`, `linux-x64`, `win32-x64`. */
35
+ export function platformSlug(): string {
36
+ return `${process.platform}-${process.arch}`;
37
+ }
38
+
39
+ /**
40
+ * Base name (no extension) of a packaged release archive, e.g.
41
+ * `xbintsc-linux-x64`. Matches the top-level directory inside the archive.
42
+ */
43
+ export function releaseArchiveBase(
44
+ platform: string = process.platform,
45
+ arch: string = process.arch,
46
+ ): string {
47
+ return `xbintsc-${platform}-${arch}`;
48
+ }
49
+
50
+ /**
51
+ * Extension for a release archive. `.tar.zst` when a `zstd` binary is available
52
+ * (smaller, faster), otherwise the universally supported `.tar.gz`.
53
+ */
54
+ export function releaseArchiveExtension(useZstd: boolean): string {
55
+ return useZstd ? ".tar.zst" : ".tar.gz";
56
+ }
57
+
58
+ /**
59
+ * Directory that may hold a toolchain shipped next to the package:
60
+ * `<package>/vendor/<os>-<arch>` (or a generic `vendor/`). Undefined when none
61
+ * is present, in which case the driver falls back to the system PATH.
62
+ */
63
+ export function findVendorDir(): string | undefined {
64
+ const roots: string[] = [];
65
+ try {
66
+ roots.push(findPackageRoot());
67
+ } catch {
68
+ // `runtime/` may be absent (e.g. a bare `emit` install); vendor is optional.
69
+ }
70
+ roots.push(resolve(here, "../../.."), resolve(here, "../.."), process.cwd());
71
+ for (const root of roots) {
72
+ const specific = join(root, "vendor", platformSlug());
73
+ if (existsSync(specific)) return specific;
74
+ const generic = join(root, "vendor");
75
+ if (existsSync(generic)) return generic;
76
+ }
77
+ return undefined;
78
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Prebuilt runtime archives.
3
+ *
4
+ * The C runtime is normally compiled once into a static archive by
5
+ * `npm run runtime`:
6
+ *
7
+ * runtime/lib/<os>-<arch>/core.a (the core `xt_*.c` runtime)
8
+ * runtime/lib/<os>-<arch>/ext_<name>.a (per-extension sources, e.g. ext_node.a)
9
+ *
10
+ * Shipping these lets `build` link without compiling C, and shortens the first
11
+ * build. When an archive is missing the driver transparently falls back to
12
+ * compiling the `.c` sources, so the archives are an optimization, not a hard
13
+ * dependency.
14
+ */
15
+
16
+ import { existsSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { findRuntimeDir, platformSlug } from "./paths.js";
19
+
20
+ /** Directory holding the prebuilt archives for the current host. */
21
+ export function runtimeLibDir(): string {
22
+ return join(findRuntimeDir(), "lib", platformSlug());
23
+ }
24
+
25
+ /** Absolute path to a prebuilt archive (`core`, `ext_node`, …), if present. */
26
+ export function findRuntimeLibrary(name: string): string | undefined {
27
+ const base = join(runtimeLibDir(), name);
28
+ for (const candidate of [`${base}.a`, `${base}.lib`]) {
29
+ if (existsSync(candidate)) return candidate;
30
+ }
31
+ return undefined;
32
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Which toolchain xbintsc bundles for each host.
3
+ *
4
+ * The end goal is that `build` needs no user-installed compiler. Per the
5
+ * recorded decisions (see `doc/requirements.md`):
6
+ *
7
+ * Linux -> the official LLVM release (clang + lld + llvm-ar)
8
+ * Windows -> llvm-mingw (clang + lld + the MinGW-w64 sysroot/CRT/import libs)
9
+ * macOS -> nothing; the Xcode Command Line Tools are the prerequisite
10
+ *
11
+ * This module only maps a host to a pinned download; the actual fetch lives in
12
+ * `scripts/fetch-toolchain.ts`.
13
+ */
14
+
15
+ /** Pinned LLVM release used for the Linux bundle. */
16
+ export const LLVM_VERSION = "18.1.8";
17
+ /** Pinned llvm-mingw release used for the Windows bundle. */
18
+ export const LLVM_MINGW_VERSION = "20260908";
19
+
20
+ export interface ToolchainDownload {
21
+ /** Download URL. */
22
+ readonly url: string;
23
+ /** Suggested local file name for the archive. */
24
+ readonly archive: string;
25
+ /** Archive type. Both are unpacked with `tar` (bsdtar reads zip). */
26
+ readonly kind: "tar.xz" | "zip";
27
+ /** Leading path segments to strip while extracting. */
28
+ readonly stripComponents: number;
29
+ }
30
+
31
+ /**
32
+ * The toolchain to bundle for a host, or undefined when the host's own SDK is
33
+ * used instead (macOS: the Xcode Command Line Tools).
34
+ */
35
+ export function toolchainDownload(
36
+ platform: string = process.platform,
37
+ arch: string = process.arch,
38
+ ): ToolchainDownload | undefined {
39
+ if (platform === "linux") {
40
+ if (arch === "x64") {
41
+ return {
42
+ url: `https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-18.04.tar.xz`,
43
+ archive: `clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu.tar.xz`,
44
+ kind: "tar.xz",
45
+ stripComponents: 1,
46
+ };
47
+ }
48
+ if (arch === "arm64") {
49
+ return {
50
+ url: `https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-aarch64-linux-gnu.tar.xz`,
51
+ archive: `clang+llvm-${LLVM_VERSION}-aarch64-linux-gnu.tar.xz`,
52
+ kind: "tar.xz",
53
+ stripComponents: 1,
54
+ };
55
+ }
56
+ return undefined;
57
+ }
58
+
59
+ if (platform === "win32" && arch === "x64") {
60
+ return {
61
+ url: `https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-x86_64.zip`,
62
+ archive: `llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-x86_64.zip`,
63
+ kind: "zip",
64
+ stripComponents: 1,
65
+ };
66
+ }
67
+
68
+ // macOS (and any other host) uses the system SDK; nothing to bundle.
69
+ return undefined;
70
+ }
71
+
72
+ export interface SupportLibrary {
73
+ /** Candidate download URLs, tried in order. */
74
+ readonly urls: readonly string[];
75
+ /** Local file name for the downloaded `.deb`. */
76
+ readonly archive: string;
77
+ /** Path inside the extracted `.deb` data tree. */
78
+ readonly member: string;
79
+ /** File name placed in `vendor/<os>-<arch>/lib/`. */
80
+ readonly dest: string;
81
+ }
82
+
83
+ /**
84
+ * Extra shared libraries the bundled toolchain needs but that are not part of
85
+ * the OS C library. The official Linux LLVM build links the legacy
86
+ * `libtinfo.so.5` soname, which current distributions no longer ship, so we
87
+ * bundle it (from the Ubuntu `libtinfo5` package) into `vendor/<os>-<arch>/lib`
88
+ * and point `LD_LIBRARY_PATH` at that directory.
89
+ */
90
+ export function toolchainSupportLibraries(
91
+ platform: string = process.platform,
92
+ arch: string = process.arch,
93
+ ): readonly SupportLibrary[] {
94
+ if (platform === "linux" && arch === "x64") {
95
+ return [
96
+ {
97
+ urls: [
98
+ "https://security.ubuntu.com/ubuntu/pool/main/n/ncurses/libtinfo5_6.1-1ubuntu1.18.04.1_amd64.deb",
99
+ "https://archive.ubuntu.com/ubuntu/pool/main/n/ncurses/libtinfo5_6.1-1ubuntu1.18.04.1_amd64.deb",
100
+ ],
101
+ archive: "libtinfo5.deb",
102
+ member: "lib/x86_64-linux-gnu/libtinfo.so.5.9",
103
+ dest: "libtinfo.so.5",
104
+ },
105
+ ];
106
+ }
107
+ return [];
108
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Toolchain selection.
3
+ *
4
+ * xbintsc shells out to a clang-compatible driver for three jobs: lowering LLVM
5
+ * IR to an object, compiling the C runtime, and linking. This module decides
6
+ * *which* driver to use, in a fixed priority order, so a bundled toolchain can
7
+ * shadow the system one without touching the driver code:
8
+ *
9
+ * 1. an explicit `xbintsc_CLANG` / `xbintsc_TOOLCHAIN`
10
+ * 2. a toolchain shipped next to the package (`vendor/<os>-<arch>/bin`)
11
+ * 3. the system `PATH` (`findClang`)
12
+ *
13
+ * Extra linker arguments (for example `-fuse-ld=lld`) can be supplied through
14
+ * `xbintsc_LINKER_ARGS`.
15
+ */
16
+
17
+ import { existsSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { findVendorDir } from "./paths.js";
20
+ import { findClang, realRunner, type Runner } from "./toolchain.js";
21
+
22
+ export type ToolchainSource = "env" | "vendor" | "system";
23
+
24
+ export interface ResolvedToolchain {
25
+ /** Path or name of the clang-compatible driver to invoke. */
26
+ readonly clang: string;
27
+ /** Where the driver came from. */
28
+ readonly source: ToolchainSource;
29
+ /** Extra arguments to pass to the link step. */
30
+ readonly linkerArgs: readonly string[];
31
+ /**
32
+ * Extra environment for the toolchain subprocesses, merged over the current
33
+ * environment. Used to point `LD_LIBRARY_PATH` at bundled shared libraries
34
+ * (for example the legacy `libtinfo.so.5` the official Linux build needs).
35
+ */
36
+ readonly env: Record<string, string>;
37
+ }
38
+
39
+ function works(runner: Runner, command: string, env?: Record<string, string>): boolean {
40
+ try {
41
+ return runner.run(command, ["--version"], env ? { env } : undefined).status === 0;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ function linkerArgs(fallback: readonly string[]): string[] {
48
+ const raw = process.env.xbintsc_LINKER_ARGS;
49
+ if (raw) return raw.split(" ").filter((part) => part.length > 0);
50
+ return [...fallback];
51
+ }
52
+
53
+ /**
54
+ * Environment overrides for a bundled toolchain. The official Linux build links
55
+ * the removed `libtinfo.so.5` soname, so when we ship it under `vendor/lib/` we
56
+ * prepend that directory to the dynamic linker search path.
57
+ */
58
+ function vendorEnv(vendor: string): Record<string, string> {
59
+ const libDir = join(vendor, "lib");
60
+ if (process.platform !== "linux" || !existsSync(libDir)) return {};
61
+ const existing = process.env.LD_LIBRARY_PATH;
62
+ return { LD_LIBRARY_PATH: existing ? libDir + ":" + existing : libDir };
63
+ }
64
+
65
+ /** Resolve the toolchain that `build` should use. See the module docblock. */
66
+ export function resolveToolchain(runner: Runner = realRunner): ResolvedToolchain {
67
+ const explicit = process.env.xbintsc_CLANG ?? process.env.xbintsc_TOOLCHAIN;
68
+ if (explicit && works(runner, explicit)) {
69
+ return { clang: explicit, source: "env", linkerArgs: linkerArgs([]), env: {} };
70
+ }
71
+
72
+ const vendor = findVendorDir();
73
+ if (vendor) {
74
+ const env = vendorEnv(vendor);
75
+ const names = process.platform === "win32" ? ["clang.exe", "clang"] : ["clang"];
76
+ for (const name of names) {
77
+ const candidate = join(vendor, "bin", name);
78
+ if (existsSync(candidate) && works(runner, candidate, env)) {
79
+ // A bundled toolchain ships `ld.lld`, so prefer lld over any system linker.
80
+ return {
81
+ clang: candidate,
82
+ source: "vendor",
83
+ linkerArgs: linkerArgs(["-fuse-ld=lld"]),
84
+ env,
85
+ };
86
+ }
87
+ }
88
+ }
89
+
90
+ return { clang: findClang(runner), source: "system", linkerArgs: linkerArgs([]), env: {} };
91
+ }