xbintsc 0.2.8 → 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 +90 -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 +40 -5
  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
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Declaration pass: creates symbols/scopes and pre-declares the bindings that
3
+ * are visible before their textual position (`var`, functions, hoisted blocks).
4
+ */
5
+
6
+ import {
7
+ SyntaxKind,
8
+ type BindingName,
9
+ type ExportDeclaration,
10
+ type FunctionDeclaration,
11
+ type Identifier,
12
+ type ImportDeclaration,
13
+ type Node,
14
+ type Statement,
15
+ type VariableDeclarationList,
16
+ type VariableStatement,
17
+ } from "../ast/nodes.js";
18
+ import type { ArrayBindingPattern, ObjectBindingPattern } from "../ast/declarations.js";
19
+ import { SymbolKind, type MutableFunction, type Scope, type SymbolInfo } from "./types.js";
20
+ import { childNodes } from "./helpers.js";
21
+ import type { Binder } from "./binder.js";
22
+
23
+ export interface DeclarationMethods {
24
+ declareBinding(this: Binder, name: BindingName, kind: SymbolKind, declaration: Node, scope: Scope, mutable: boolean): SymbolInfo | undefined;
25
+ declare(this: Binder, name: string, kind: SymbolKind, node: Node, scope: Scope, mutable: boolean): SymbolInfo;
26
+ predeclareStatements(this: Binder, statements: readonly Statement[], scope: Scope): void;
27
+ predeclareVariableList(this: Binder, list: VariableDeclarationList, scope: Scope): void;
28
+ predeclareImport(this: Binder, node: ImportDeclaration, scope: Scope): void;
29
+ collectFunctionScoped(this: Binder, statements: readonly Statement[], fn: MutableFunction): void;
30
+ }
31
+
32
+ export const declarationMethods: DeclarationMethods = {
33
+ /** Declare every identifier introduced by a (possibly destructured) binding. */
34
+ declareBinding(
35
+ name: BindingName,
36
+ kind: SymbolKind,
37
+ declaration: Node,
38
+ scope: Scope,
39
+ mutable: boolean,
40
+ ): SymbolInfo | undefined {
41
+ if (name.kind === SyntaxKind.Identifier) {
42
+ return this.declare(name.text, kind, declaration, scope, mutable);
43
+ }
44
+ let first: SymbolInfo | undefined;
45
+ const pattern = name as ArrayBindingPattern | ObjectBindingPattern;
46
+ for (const element of pattern.elements) {
47
+ if (!element) continue;
48
+ const symbol = this.declareBinding(element.name, kind, element.name, scope, mutable);
49
+ if (!first) first = symbol;
50
+ }
51
+ return first;
52
+ },
53
+
54
+ declare(
55
+ name: string,
56
+ kind: SymbolKind,
57
+ node: Node,
58
+ scope: Scope,
59
+ mutable: boolean,
60
+ ): SymbolInfo {
61
+ const existing = scope.symbols.get(name);
62
+ if (existing) {
63
+ // `var` redeclarations and duplicate functions merge into one symbol.
64
+ if (
65
+ (kind === SymbolKind.Var && existing.kind === SymbolKind.Var) ||
66
+ (kind === SymbolKind.Function && existing.kind === SymbolKind.Function)
67
+ ) {
68
+ (existing.declarations as Node[]).push(node);
69
+ }
70
+ this.symbolOfDeclaration.set(node, existing);
71
+ return existing;
72
+ }
73
+ const symbol: SymbolInfo = {
74
+ id: this.nextSymbolId++,
75
+ name,
76
+ kind,
77
+ mutable,
78
+ fn: this.current,
79
+ declarations: [node],
80
+ references: [],
81
+ captured: false,
82
+ boxed: false,
83
+ };
84
+ scope.symbols.set(name, symbol);
85
+ this.symbolOfDeclaration.set(node, symbol);
86
+ if (scope.fn === this.current) this.current.locals.push(symbol);
87
+ return symbol;
88
+ },
89
+
90
+ /** Pre-declare block-scoped bindings that appear directly in `statements`. */
91
+ predeclareStatements(statements: readonly Statement[], scope: Scope): void {
92
+ for (const statement of statements) {
93
+ switch (statement.kind) {
94
+ case SyntaxKind.VariableStatement: {
95
+ this.predeclareVariableList((statement as VariableStatement).declarationList, scope);
96
+ break;
97
+ }
98
+ case SyntaxKind.FunctionDeclaration:
99
+ this.declare((statement as FunctionDeclaration).name?.text ?? "(anonymous)", SymbolKind.Function, statement, scope, true);
100
+ break;
101
+ case SyntaxKind.ClassDeclaration:
102
+ this.declare((statement as { name: Identifier }).name.text, SymbolKind.Class, statement, scope, false);
103
+ break;
104
+ case SyntaxKind.InterfaceDeclaration:
105
+ this.declare((statement as { name: Identifier }).name.text, SymbolKind.Interface, statement, scope, false);
106
+ break;
107
+ case SyntaxKind.TypeAliasDeclaration:
108
+ this.declare((statement as { name: Identifier }).name.text, SymbolKind.TypeAlias, statement, scope, false);
109
+ break;
110
+ case SyntaxKind.EnumDeclaration:
111
+ this.declare((statement as { name: Identifier }).name.text, SymbolKind.Enum, statement, scope, true);
112
+ break;
113
+ case SyntaxKind.ImportDeclaration:
114
+ this.predeclareImport(statement as ImportDeclaration, scope);
115
+ break;
116
+ case SyntaxKind.ExportDeclaration: {
117
+ const exported = statement as ExportDeclaration;
118
+ if (exported.exportClause && exported.exportClause.kind === SyntaxKind.NamedExports) {
119
+ for (const specifier of exported.exportClause.elements) {
120
+ if (specifier.propertyName) this.reference(specifier.propertyName, scope);
121
+ }
122
+ }
123
+ break;
124
+ }
125
+ case SyntaxKind.ModuleDeclaration:
126
+ this.declare((statement as { name: Identifier }).name.text, SymbolKind.Namespace, statement, scope, false);
127
+ break;
128
+ default:
129
+ break;
130
+ }
131
+ }
132
+ },
133
+
134
+ predeclareVariableList(list: VariableDeclarationList, scope: Scope): void {
135
+ const kind =
136
+ list.declarationKind === "const"
137
+ ? SymbolKind.Const
138
+ : list.declarationKind === "var"
139
+ ? SymbolKind.Var
140
+ : SymbolKind.Let;
141
+ for (const declaration of list.declarations) {
142
+ this.declareBinding(declaration.name, kind, declaration, scope, kind !== SymbolKind.Const);
143
+ }
144
+ },
145
+
146
+ predeclareImport(node: ImportDeclaration, scope: Scope): void {
147
+ const clause = node.importClause;
148
+ if (!clause) return;
149
+ if (clause.name) this.declare(clause.name.text, SymbolKind.Import, clause.name, scope, false);
150
+ const bindings = clause.namedBindings;
151
+ if (bindings && bindings.kind === SyntaxKind.NamedImports) {
152
+ for (const specifier of bindings.elements) {
153
+ this.declare(specifier.name.text, SymbolKind.Import, specifier.name, scope, false);
154
+ }
155
+ } else if (bindings && bindings.kind === SyntaxKind.NamespaceImport) {
156
+ this.declare(bindings.name.text, SymbolKind.Import, bindings.name, scope, false);
157
+ }
158
+ },
159
+
160
+ /**
161
+ * Collect `var` and function declarations from nested blocks into the
162
+ * enclosing function scope, without crossing function boundaries.
163
+ */
164
+ collectFunctionScoped(statements: readonly Statement[], fn: MutableFunction): void {
165
+ const visit = (node: Node): void => {
166
+ switch (node.kind) {
167
+ case SyntaxKind.FunctionDeclaration:
168
+ case SyntaxKind.FunctionExpression:
169
+ case SyntaxKind.ArrowFunction:
170
+ case SyntaxKind.ClassDeclaration:
171
+ case SyntaxKind.ClassExpression:
172
+ return; // opaque, except we still want the declaration name handled at its site
173
+ case SyntaxKind.VariableStatement: {
174
+ const decl = node as VariableStatement;
175
+ if (decl.declarationList.declarationKind === "var") {
176
+ for (const d of decl.declarationList.declarations) {
177
+ const existing = d.name.kind === SyntaxKind.Identifier ? fn.scope.symbols.get(d.name.text) : undefined;
178
+ if (!existing) this.declareBinding(d.name, SymbolKind.Var, d, fn.scope, true);
179
+ else if (d.name.kind === SyntaxKind.Identifier) this.symbolOfDeclaration.set(d, existing);
180
+ }
181
+ }
182
+ return;
183
+ }
184
+ default:
185
+ break;
186
+ }
187
+ for (const child of childNodes(node)) visit(child);
188
+ };
189
+ for (const statement of statements) {
190
+ if (
191
+ statement.kind === SyntaxKind.FunctionDeclaration ||
192
+ statement.kind === SyntaxKind.ClassDeclaration
193
+ ) {
194
+ const name = (statement as { name: Identifier }).name.text;
195
+ if (!fn.scope.symbols.has(name)) {
196
+ this.declare(name, statement.kind === SyntaxKind.FunctionDeclaration ? SymbolKind.Function : SymbolKind.Class, statement, fn.scope, statement.kind === SyntaxKind.FunctionDeclaration);
197
+ }
198
+ continue;
199
+ }
200
+ visit(statement);
201
+ }
202
+ },
203
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Small AST helpers shared by the binder's declaration and reference passes.
3
+ */
4
+
5
+ import { SyntaxKind, type Node, type PropertyName } from "../ast/nodes.js";
6
+ import { SymbolKind } from "./types.js";
7
+
8
+ /** Direct AST children, tolerant of both arrays and single nodes. */
9
+ export function childNodes(node: Node): Node[] {
10
+ const result: Node[] = [];
11
+ const n = node as unknown as Record<string, unknown>;
12
+ for (const key of Object.keys(n)) {
13
+ if (key === "kind" || key === "start" || key === "end") continue;
14
+ const value = n[key];
15
+ if (Array.isArray(value)) {
16
+ for (const item of value) if (item && typeof item === "object" && "kind" in (item as object)) result.push(item as Node);
17
+ } else if (value && typeof value === "object" && "kind" in (value as object)) {
18
+ result.push(value as Node);
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+
24
+ /** Only value bindings participate in closure capture. */
25
+ export function isCapturable(kind: SymbolKind): boolean {
26
+ return (
27
+ kind === SymbolKind.Var ||
28
+ kind === SymbolKind.Let ||
29
+ kind === SymbolKind.Const ||
30
+ kind === SymbolKind.Parameter
31
+ );
32
+ }
33
+
34
+ /** Extract the textual name of a class member (`method`, `"key"`, `0`). */
35
+ export function classMemberName(name: PropertyName): string {
36
+ switch (name.kind) {
37
+ case SyntaxKind.Identifier:
38
+ case SyntaxKind.PrivateIdentifier:
39
+ return (name as unknown as { text: string }).text;
40
+ case SyntaxKind.StringLiteral:
41
+ return (name as unknown as { value: string }).value;
42
+ case SyntaxKind.NumericLiteral:
43
+ return String((name as unknown as { value: number }).value);
44
+ default:
45
+ return "";
46
+ }
47
+ }
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Reference pass: walks statements/expressions, resolves identifier references
3
+ * to symbols, and records closure captures.
4
+ */
5
+
6
+ import { ModifierKind } from "../ast/kinds.js";
7
+ import {
8
+ SyntaxKind,
9
+ type ArrowFunction,
10
+ type BindingName,
11
+ type Block,
12
+ type CatchClause,
13
+ type ClassDeclaration,
14
+ type ClassExpression,
15
+ type ConstructorDeclaration,
16
+ type ExportDeclaration,
17
+ type Expression,
18
+ type ForInStatement,
19
+ type ForOfStatement,
20
+ type ForStatement,
21
+ type FunctionDeclaration,
22
+ type FunctionExpression,
23
+ type Identifier,
24
+ type MethodDeclaration,
25
+ type Node,
26
+ type PropertyDeclaration,
27
+ type PropertyName,
28
+ type Statement,
29
+ type VariableDeclarationList,
30
+ type VariableStatement,
31
+ } from "../ast/nodes.js";
32
+ import type { ArrayBindingPattern, ObjectBindingPattern, Parameter } from "../ast/declarations.js";
33
+ import {
34
+ ScopeKind,
35
+ SymbolKind,
36
+ type ClassInfo,
37
+ type FunctionInfo,
38
+ type FunctionNode,
39
+ type MutableFunction,
40
+ type Scope,
41
+ type SymbolInfo,
42
+ } from "./types.js";
43
+ import { childNodes, classMemberName, isCapturable } from "./helpers.js";
44
+ import type { Binder } from "./binder.js";
45
+
46
+ export interface ReferenceMethods {
47
+ bindStatements(this: Binder, statements: readonly Statement[], scope: Scope): void;
48
+ bindBlock(this: Binder, block: Block, scope: Scope): void;
49
+ bindNode(this: Binder, node: Node | undefined, scope: Scope): void;
50
+ bindVariableList(this: Binder, list: VariableDeclarationList, scope: Scope): void;
51
+ bindBindingPattern(this: Binder, name: BindingName, scope: Scope): void;
52
+ bindFunction(this: Binder, node: FunctionDeclaration | FunctionExpression | ArrowFunction, parentScope: Scope, symbol: SymbolInfo | undefined): void;
53
+ bindClass(this: Binder, node: ClassDeclaration | ClassExpression, scope: Scope): void;
54
+ createClassFunction(this: Binder, member: Node, name: string, parameters: readonly Parameter[], body: Block | undefined, parentScope: Scope, info: ClassInfo, isStatic: boolean, isConstructor: boolean): FunctionInfo;
55
+ reference(this: Binder, identifier: Identifier, scope: Scope): void;
56
+ markCaptured(this: Binder, symbol: SymbolInfo): void;
57
+ }
58
+
59
+ export const referenceMethods: ReferenceMethods = {
60
+ bindStatements(statements: readonly Statement[], scope: Scope): void {
61
+ for (const statement of statements) this.bindNode(statement, scope);
62
+ },
63
+
64
+ bindBlock(block: Block, scope: Scope): void {
65
+ const blockScope = this.createScope(ScopeKind.Block, block, scope);
66
+ this.scopes.set(block, blockScope);
67
+ this.predeclareStatements(block.statements, blockScope);
68
+ this.bindStatements(block.statements, blockScope);
69
+ },
70
+
71
+ bindNode(node: Node | undefined, scope: Scope): void {
72
+ if (!node) return;
73
+ switch (node.kind) {
74
+ case SyntaxKind.Block:
75
+ this.bindBlock(node as Block, scope);
76
+ return;
77
+ case SyntaxKind.VariableStatement:
78
+ this.bindVariableList((node as VariableStatement).declarationList, scope);
79
+ return;
80
+ case SyntaxKind.FunctionDeclaration: {
81
+ const fn = node as FunctionDeclaration;
82
+ const symbol = this.symbolOfDeclaration.get(fn);
83
+ if (symbol) (symbol.declarations as Node[]).length; // keep declaration mapping warm
84
+ this.bindFunction(fn, scope, symbol);
85
+ return;
86
+ }
87
+ case SyntaxKind.FunctionExpression:
88
+ case SyntaxKind.ArrowFunction:
89
+ this.bindFunction(node as FunctionExpression | ArrowFunction, scope, undefined);
90
+ return;
91
+ case SyntaxKind.Identifier:
92
+ this.reference(node as Identifier, scope);
93
+ return;
94
+ case SyntaxKind.PropertyAccessExpression:
95
+ // `obj.name` reads a property, not a variable named `name`.
96
+ this.bindNode((node as unknown as { expression: Expression }).expression, scope);
97
+ return;
98
+ case SyntaxKind.ElementAccessExpression: {
99
+ const access = node as unknown as { expression: Expression; argumentExpression: Expression };
100
+ this.bindNode(access.expression, scope);
101
+ this.bindNode(access.argumentExpression, scope);
102
+ return;
103
+ }
104
+ case SyntaxKind.PropertyAssignment: {
105
+ // `{ key: value }` / `{ key() {} }`: only the value is an expression,
106
+ // except a computed key (`{ [expr]: value }`) whose expression is real.
107
+ const property = node as unknown as { name: PropertyName; initializer: Expression };
108
+ if (property.name.kind === SyntaxKind.ComputedPropertyName) {
109
+ this.bindNode((property.name as unknown as { expression: Expression }).expression, scope);
110
+ }
111
+ this.bindNode(property.initializer, scope);
112
+ return;
113
+ }
114
+ case SyntaxKind.ShorthandPropertyAssignment: {
115
+ const shorthand = node as unknown as { name: Identifier; initializer?: Expression };
116
+ this.reference(shorthand.name, scope);
117
+ if (shorthand.initializer) this.bindNode(shorthand.initializer, scope);
118
+ return;
119
+ }
120
+ case SyntaxKind.LabeledStatement:
121
+ this.bindNode((node as unknown as { statement: Node }).statement, scope);
122
+ return;
123
+ case SyntaxKind.BreakStatement:
124
+ case SyntaxKind.ContinueStatement:
125
+ return;
126
+ case SyntaxKind.ThisKeyword:
127
+ this.current.usesThis = true;
128
+ return;
129
+ case SyntaxKind.ClassDeclaration:
130
+ case SyntaxKind.ClassExpression:
131
+ this.bindClass(node as ClassDeclaration | ClassExpression, scope);
132
+ return;
133
+ case SyntaxKind.InterfaceDeclaration:
134
+ case SyntaxKind.TypeAliasDeclaration:
135
+ // Type-only: skip the body entirely.
136
+ return;
137
+ case SyntaxKind.ImportDeclaration:
138
+ return;
139
+ case SyntaxKind.ExportDeclaration: {
140
+ const exported = node as ExportDeclaration;
141
+ if (exported.exportClause && exported.exportClause.kind === SyntaxKind.NamedExports) {
142
+ for (const specifier of exported.exportClause.elements) {
143
+ if (specifier.propertyName) this.reference(specifier.propertyName, scope);
144
+ }
145
+ }
146
+ return;
147
+ }
148
+ case SyntaxKind.ExportAssignment:
149
+ this.bindNode((node as unknown as { expression: Expression }).expression, scope);
150
+ return;
151
+ case SyntaxKind.ForStatement: {
152
+ const forNode = node as ForStatement;
153
+ const forScope = this.createScope(ScopeKind.For, forNode, scope);
154
+ this.scopes.set(forNode, forScope);
155
+ if (forNode.initializer) {
156
+ if (forNode.initializer.kind === SyntaxKind.VariableDeclarationList) {
157
+ this.predeclareVariableList(forNode.initializer as VariableDeclarationList, forScope);
158
+ this.bindVariableList(forNode.initializer as VariableDeclarationList, forScope);
159
+ } else {
160
+ this.bindNode(forNode.initializer, forScope);
161
+ }
162
+ }
163
+ this.bindNode(forNode.condition, forScope);
164
+ this.bindNode(forNode.incrementor, forScope);
165
+ this.bindNode(forNode.statement, forScope);
166
+ return;
167
+ }
168
+ case SyntaxKind.ForOfStatement:
169
+ case SyntaxKind.ForInStatement: {
170
+ const loop = node as ForOfStatement | ForInStatement;
171
+ const loopScope = this.createScope(ScopeKind.For, loop, scope);
172
+ this.scopes.set(loop, loopScope);
173
+ if (loop.initializer.kind === SyntaxKind.VariableDeclarationList) {
174
+ this.predeclareVariableList(loop.initializer, loopScope);
175
+ this.bindVariableList(loop.initializer, loopScope);
176
+ } else {
177
+ this.bindNode(loop.initializer, loopScope);
178
+ }
179
+ this.bindNode(loop.expression, loopScope);
180
+ this.bindNode(loop.statement, loopScope);
181
+ return;
182
+ }
183
+ case SyntaxKind.CatchClause: {
184
+ const clause = node as CatchClause;
185
+ const catchScope = this.createScope(ScopeKind.Catch, clause, scope);
186
+ this.scopes.set(clause, catchScope);
187
+ if (clause.variable) this.declare(clause.variable.text, SymbolKind.Let, clause.variable, catchScope, true);
188
+ this.bindBlock(clause.block, catchScope);
189
+ return;
190
+ }
191
+ default:
192
+ break;
193
+ }
194
+ for (const child of childNodes(node)) this.bindNode(child, scope);
195
+ },
196
+
197
+ bindVariableList(list: VariableDeclarationList, scope: Scope): void {
198
+ for (const declaration of list.declarations) {
199
+ const symbol = this.symbolOfDeclaration.get(declaration);
200
+ if (declaration.name.kind === SyntaxKind.Identifier) {
201
+ this.symbolOfDeclaration.set(declaration.name, symbol ?? this.symbolOfDeclaration.get(declaration) as SymbolInfo);
202
+ } else {
203
+ this.bindBindingPattern(declaration.name, scope);
204
+ }
205
+ this.bindNode(declaration.initializer, scope);
206
+ }
207
+ },
208
+
209
+ /** Bind default-value expressions inside a binding pattern. */
210
+ bindBindingPattern(name: BindingName, scope: Scope): void {
211
+ if (name.kind === SyntaxKind.Identifier) return;
212
+ const pattern = name as ArrayBindingPattern | ObjectBindingPattern;
213
+ for (const element of pattern.elements) {
214
+ if (!element) continue;
215
+ if (element.initializer) this.bindNode(element.initializer, scope);
216
+ this.bindBindingPattern(element.name, scope);
217
+ }
218
+ },
219
+
220
+ bindFunction(
221
+ node: FunctionDeclaration | FunctionExpression | ArrowFunction,
222
+ parentScope: Scope,
223
+ symbol: SymbolInfo | undefined,
224
+ ): void {
225
+ const name =
226
+ node.kind === SyntaxKind.FunctionDeclaration
227
+ ? (node as FunctionDeclaration).name?.text ?? "(anonymous)"
228
+ : node.kind === SyntaxKind.FunctionExpression
229
+ ? (node as FunctionExpression).name?.text ?? "(anonymous)"
230
+ : "(arrow)";
231
+ const parentFn = this.current;
232
+ const fn = this.createFunction(name, node, parentFn, false, node.kind === SyntaxKind.ArrowFunction);
233
+ this.current = fn;
234
+
235
+ const scope = this.createScope(ScopeKind.Function, node, parentScope);
236
+ (fn as { scope: Scope }).scope = scope;
237
+ this.scopes.set(node, scope);
238
+
239
+ // Parameters live in the function scope.
240
+ const params: SymbolInfo[] = [];
241
+ for (const parameter of node.parameters) {
242
+ const paramSymbol = this.declareBinding(parameter.name, SymbolKind.Parameter, parameter, scope, true);
243
+ if (paramSymbol) params.push(paramSymbol);
244
+ if (parameter.initializer) this.bindNode(parameter.initializer, scope);
245
+ }
246
+ (fn as { params: SymbolInfo[] }).params = params;
247
+
248
+ // Initialize a named function expression's own name inside its scope.
249
+ if (node.kind === SyntaxKind.FunctionExpression && (node as FunctionExpression).name) {
250
+ const selfName = (node as FunctionExpression).name!;
251
+ this.declare(selfName.text, SymbolKind.Const, selfName, scope, false);
252
+ }
253
+ if (symbol) this.symbolOfDeclaration.set(node, symbol);
254
+
255
+ const body = node.body as unknown as Block | Expression | undefined;
256
+ if (body) {
257
+ this.collectFunctionScoped([body.kind === SyntaxKind.Block ? body : ({ kind: SyntaxKind.Block, statements: [], start: body.start, end: body.end } as Block)], fn);
258
+ if (body.kind === SyntaxKind.Block) {
259
+ this.predeclareStatements(body.statements, scope);
260
+ this.bindStatements(body.statements, scope);
261
+ } else {
262
+ this.bindNode(body, scope);
263
+ }
264
+ }
265
+
266
+ this.current = parentFn;
267
+ },
268
+
269
+ bindClass(node: ClassDeclaration | ClassExpression, scope: Scope): void {
270
+ const parentFn = this.current;
271
+ const name = node.name ? node.name.text : "(anonymous)";
272
+
273
+ let parentExpression: Expression | undefined;
274
+ let parentClass: ClassInfo | undefined;
275
+ const heritage = node.heritage.find((clause) => clause.token === "extends");
276
+ if (heritage && heritage.types.length > 0) {
277
+ parentExpression = heritage.types[0]!.expression;
278
+ this.bindNode(parentExpression, scope);
279
+ if (parentExpression.kind === SyntaxKind.Identifier) {
280
+ const symbol = this.symbolOfIdentifier.get(parentExpression as Identifier);
281
+ const declaration = symbol?.declarations[0];
282
+ if (declaration) parentClass = this.classOfNode.get(declaration);
283
+ }
284
+ }
285
+
286
+ const info: ClassInfo = {
287
+ id: this.nextClassId++,
288
+ name,
289
+ node,
290
+ scope,
291
+ parent: parentClass,
292
+ parentExpression,
293
+ fields: [],
294
+ methods: [],
295
+ statics: [],
296
+ };
297
+ this.classes.push(info);
298
+ this.classOfNode.set(node, info);
299
+
300
+ const classScope = this.createScope(ScopeKind.Block, node, scope);
301
+ this.scopes.set(node, classScope);
302
+
303
+ let constructor: FunctionInfo | undefined;
304
+ for (const member of node.members) {
305
+ if (member.kind === SyntaxKind.ConstructorDeclaration) {
306
+ const ctor = member as ConstructorDeclaration;
307
+ constructor = this.createClassFunction(ctor, "constructor", ctor.parameters, ctor.body, classScope, info, false, true);
308
+ } else if (member.kind === SyntaxKind.MethodDeclaration) {
309
+ const method = member as MethodDeclaration;
310
+ const isStatic = method.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
311
+ const fn = this.createClassFunction(method, classMemberName(method.name), method.parameters, method.body, classScope, info, isStatic, false);
312
+ if (isStatic) (info.statics as FunctionInfo[]).push(fn);
313
+ else (info.methods as FunctionInfo[]).push(fn);
314
+ }
315
+ }
316
+ if (!constructor) {
317
+ constructor = this.createClassFunction(node, "constructor", [], undefined, classScope, info, false, true);
318
+ }
319
+ info.ctor = constructor;
320
+
321
+ // Field initializers run in the constructor's context so they can capture
322
+ // enclosing variables.
323
+ for (const member of node.members) {
324
+ if (member.kind === SyntaxKind.PropertyDeclaration) {
325
+ const property = member as PropertyDeclaration;
326
+ const isStatic = property.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
327
+ const owner = this.current;
328
+ this.current = constructor as MutableFunction;
329
+ if (property.initializer) this.bindNode(property.initializer, classScope);
330
+ this.current = owner;
331
+ info.fields.push({ name: classMemberName(property.name), initializer: property.initializer, fn: constructor, isStatic });
332
+ }
333
+ }
334
+
335
+ this.current = parentFn;
336
+ },
337
+
338
+ createClassFunction(
339
+ member: Node,
340
+ name: string,
341
+ parameters: readonly Parameter[],
342
+ body: Block | undefined,
343
+ parentScope: Scope,
344
+ info: ClassInfo,
345
+ isStatic: boolean,
346
+ isConstructor: boolean,
347
+ ): FunctionInfo {
348
+ const parentFn = this.current;
349
+ const fn = this.createFunction(name, member as unknown as FunctionNode, parentFn, false, false);
350
+ (fn as MutableFunction & { classInfo: ClassInfo }).classInfo = info;
351
+ (fn as MutableFunction & { isStatic: boolean }).isStatic = isStatic;
352
+ (fn as MutableFunction & { isConstructor: boolean }).isConstructor = isConstructor;
353
+ this.current = fn as MutableFunction;
354
+ const scope = this.createScope(ScopeKind.Function, member, parentScope);
355
+ (fn as { scope: Scope }).scope = scope;
356
+ this.scopes.set(member, scope);
357
+
358
+ const params: SymbolInfo[] = [];
359
+ for (const parameter of parameters) {
360
+ const paramSymbol = this.declareBinding(parameter.name, SymbolKind.Parameter, parameter, scope, true);
361
+ if (paramSymbol) params.push(paramSymbol);
362
+ if (parameter.initializer) this.bindNode(parameter.initializer, scope);
363
+ }
364
+ (fn as { params: SymbolInfo[] }).params = params;
365
+
366
+ if (body) {
367
+ this.collectFunctionScoped([body], fn as MutableFunction);
368
+ this.predeclareStatements(body.statements, scope);
369
+ this.bindStatements(body.statements, scope);
370
+ }
371
+
372
+ this.current = parentFn;
373
+ return fn;
374
+ },
375
+
376
+ reference(identifier: Identifier, scope: Scope): void {
377
+ if (identifier.text === "super") {
378
+ this.current.usesThis = true;
379
+ return;
380
+ }
381
+ let current: Scope | undefined = scope;
382
+ while (current) {
383
+ const symbol = current.symbols.get(identifier.text);
384
+ if (symbol) {
385
+ (symbol.references as Identifier[]).push(identifier);
386
+ this.symbolOfIdentifier.set(identifier, symbol);
387
+ // Functions, classes and type-only names are resolved to their
388
+ // declaration sites by codegen; they are never captured as values.
389
+ if (symbol.fn !== this.current && isCapturable(symbol.kind)) this.markCaptured(symbol);
390
+ return;
391
+ }
392
+ current = current.parent;
393
+ }
394
+ this.unresolved.push(identifier);
395
+ },
396
+
397
+ /** Record that `symbol` escapes into `this.current`, threading it through every intermediate closure. */
398
+ markCaptured(symbol: SymbolInfo): void {
399
+ symbol.captured = true;
400
+ symbol.boxed = true;
401
+ let fn: MutableFunction | undefined = this.current;
402
+ while (fn && fn !== symbol.fn) {
403
+ if (!fn.captureIndex.has(symbol.id)) {
404
+ fn.captureIndex.set(symbol.id, fn.captures.length);
405
+ fn.captures.push(symbol);
406
+ }
407
+ fn = fn.parent as MutableFunction | undefined;
408
+ }
409
+ },
410
+ };