xbintsc 0.2.9 → 0.3.3

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
@@ -7,176 +7,50 @@
7
7
  *
8
8
  * The result is deliberately plain data — maps and records — so it can be
9
9
  * cached, serialized for the incremental build, and unit tested in isolation.
10
+ *
11
+ * The walk is split by functional area into sibling modules:
12
+ * - `types` — the plain-data symbol/scope model
13
+ * - `declarations` — symbol/scope creation and hoisting
14
+ * - `references` — identifier resolution and capture analysis
15
+ * - `helpers` — small AST utilities
10
16
  */
11
17
 
12
- import { NodeFlags, ModifierKind } from "../ast/kinds.js";
18
+ import { NodeFlags } from "../ast/kinds.js";
19
+ import type { Identifier, Node, SourceFileNode } from "../ast/nodes.js";
13
20
  import {
14
- SyntaxKind,
15
- type ArrowFunction,
16
- type BindingName,
17
- type Block,
18
- type ClassDeclaration,
19
- type ClassExpression,
20
- type ConstructorDeclaration,
21
- type FunctionDeclaration,
22
- type FunctionExpression,
23
- type Identifier,
24
- type MethodDeclaration,
25
- type Node,
26
- type PropertyDeclaration,
27
- type PropertyName,
28
- type SourceFileNode,
29
- type Statement,
30
- type Expression,
31
- type VariableDeclarationList,
32
- type VariableStatement,
33
- type ImportDeclaration,
34
- type ExportDeclaration,
35
- type CatchClause,
36
- type ForStatement,
37
- type ForOfStatement,
38
- type ForInStatement,
39
- } from "../ast/nodes.js";
40
-
41
- export enum SymbolKind {
42
- Var = "var",
43
- Let = "let",
44
- Const = "const",
45
- Function = "function",
46
- Parameter = "parameter",
47
- Class = "class",
48
- Interface = "interface",
49
- TypeAlias = "type",
50
- Enum = "enum",
51
- Import = "import",
52
- Namespace = "namespace",
53
- }
54
-
55
- export interface SymbolInfo {
56
- readonly id: number;
57
- readonly name: string;
58
- readonly kind: SymbolKind;
59
- /** False for `const` bindings and imports. */
60
- readonly mutable: boolean;
61
- /** The function this symbol belongs to. */
62
- readonly fn: FunctionInfo;
63
- readonly declarations: Node[];
64
- readonly references: Identifier[];
65
- /** Set when referenced from a nested function. */
66
- captured: boolean;
67
- /** Assigned after construction once we know it is captured. */
68
- boxed: boolean;
69
- }
70
-
71
- export type FunctionNode = SourceFileNode | FunctionDeclaration | FunctionExpression | ArrowFunction;
72
-
73
- export interface FunctionInfo {
74
- readonly id: number;
75
- readonly name: string;
76
- readonly node: FunctionNode;
77
- readonly parent?: FunctionInfo;
78
- readonly scope: Scope;
79
- readonly params: SymbolInfo[];
80
- /** Every binding declared directly in this function (params + locals). */
81
- readonly locals: SymbolInfo[];
82
- /** Outer bindings referenced by this function or any descendant. */
83
- readonly captures: SymbolInfo[];
84
- readonly captureIndex: Map<number, number>;
85
- readonly isModule: boolean;
86
- readonly isArrow: boolean;
87
- /** True when the function was declared `async`. */
88
- readonly isAsync: boolean;
89
- /** True when this function's body mentions `this` directly. */
90
- usesThis: boolean;
91
- /** True when an arrow function must receive `this` from its enclosing scope. */
92
- capturesThis: boolean;
93
- /** Set for class methods/constructors; carries the owning class. */
94
- classInfo?: ClassInfo;
95
- /** True for `static` class members. */
96
- isStatic?: boolean;
97
- /** True for an explicit `constructor`. */
98
- isConstructor?: boolean;
99
- }
100
-
101
- export interface ClassInfo {
102
- readonly id: number;
103
- readonly name: string;
104
- readonly node: Node;
105
- readonly scope: Scope;
106
- readonly parent?: ClassInfo;
107
- readonly parentExpression?: Expression;
108
- /** `this`-bearing fields declared on the class. */
109
- readonly fields: ClassFieldInfo[];
110
- readonly methods: FunctionInfo[];
111
- readonly statics: FunctionInfo[];
112
- ctor?: FunctionInfo;
113
- /** The symbol the class name binds to, when there is one. */
114
- }
115
-
116
- export interface ClassFieldInfo {
117
- readonly name: string;
118
- readonly initializer: Expression | undefined;
119
- readonly fn: FunctionInfo;
120
- readonly isStatic: boolean;
121
- }
122
-
123
- export enum ScopeKind {
124
- Module = "module",
125
- Function = "function",
126
- Block = "block",
127
- For = "for",
128
- Catch = "catch",
129
- }
130
-
131
- export interface Scope {
132
- readonly kind: ScopeKind;
133
- readonly parent?: Scope;
134
- readonly fn: FunctionInfo;
135
- readonly symbols: Map<string, SymbolInfo>;
136
- /** The syntax node that introduced the scope, when there is one. */
137
- readonly node?: Node;
138
- }
139
-
140
- export interface BindResult {
141
- readonly moduleFunction: FunctionInfo;
142
- readonly functions: FunctionInfo[];
143
- readonly classes: ClassInfo[];
144
- /** Maps a class-like AST node to the ClassInfo the binder built. */
145
- readonly classOfNode: Map<Node, ClassInfo>;
146
- /** Maps a function-like AST node to the FunctionInfo the binder built for it. */
147
- readonly functionOfNode: Map<Node, FunctionInfo>;
148
- readonly symbolOfDeclaration: Map<Node, SymbolInfo>;
149
- readonly symbolOfIdentifier: Map<Identifier, SymbolInfo>;
150
- readonly scopes: Map<Node, Scope>;
151
- /** Identifier references that could not be resolved in user code. */
152
- readonly unresolved: Identifier[];
153
- }
154
-
155
- interface MutableFunction extends FunctionInfo {
156
- locals: SymbolInfo[];
157
- captures: SymbolInfo[];
158
- captureIndex: Map<number, number>;
159
- }
21
+ ScopeKind,
22
+ type ClassInfo,
23
+ type FunctionInfo,
24
+ type MutableFunction,
25
+ type Scope,
26
+ type SymbolInfo,
27
+ type BindResult,
28
+ type FunctionNode,
29
+ } from "./types.js";
30
+ import { declarationMethods, type DeclarationMethods } from "./declarations.js";
31
+ import { referenceMethods, type ReferenceMethods } from "./references.js";
32
+
33
+ export * from "./types.js";
160
34
 
161
35
  export function bind(sourceFile: SourceFileNode): BindResult {
162
36
  const binder = new Binder(sourceFile);
163
37
  return binder.bind();
164
38
  }
165
39
 
166
- class Binder {
167
- private readonly functions: FunctionInfo[] = [];
168
- private readonly classes: ClassInfo[] = [];
169
- private readonly classOfNode = new Map<Node, ClassInfo>();
170
- private readonly symbolOfDeclaration = new Map<Node, SymbolInfo>();
171
- private readonly symbolOfIdentifier = new Map<Identifier, SymbolInfo>();
172
- private readonly scopes = new Map<Node, Scope>();
173
- private readonly unresolved: Identifier[] = [];
174
- private nextSymbolId = 1;
175
- private nextFunctionId = 1;
176
- private nextClassId = 1;
177
- private current!: MutableFunction;
178
-
179
- constructor(private readonly sourceFile: SourceFileNode) {}
40
+ export class Binder {
41
+ readonly functions: FunctionInfo[] = [];
42
+ readonly classes: ClassInfo[] = [];
43
+ readonly classOfNode = new Map<Node, ClassInfo>();
44
+ readonly symbolOfDeclaration = new Map<Node, SymbolInfo>();
45
+ readonly symbolOfIdentifier = new Map<Identifier, SymbolInfo>();
46
+ readonly scopes = new Map<Node, Scope>();
47
+ readonly unresolved: Identifier[] = [];
48
+ nextSymbolId = 1;
49
+ nextFunctionId = 1;
50
+ nextClassId = 1;
51
+ current!: MutableFunction;
52
+
53
+ constructor(readonly sourceFile: SourceFileNode) {}
180
54
 
181
55
  bind(): BindResult {
182
56
  this.current = this.createFunction("(module)", this.sourceFile, undefined, true, false);
@@ -214,7 +88,7 @@ class Binder {
214
88
 
215
89
  // -- construction helpers ------------------------------------------------
216
90
 
217
- private createFunction(
91
+ createFunction(
218
92
  name: string,
219
93
  node: FunctionNode,
220
94
  parent: MutableFunction | undefined,
@@ -241,571 +115,12 @@ class Binder {
241
115
  return fn;
242
116
  }
243
117
 
244
- private createScope(kind: ScopeKind, node: Node | undefined, parent: Scope | undefined): Scope {
118
+ createScope(kind: ScopeKind, node: Node | undefined, parent: Scope | undefined): Scope {
245
119
  return { kind, node, parent, fn: this.current, symbols: new Map() };
246
120
  }
247
-
248
- /** Declare every identifier introduced by a (possibly destructured) binding. */
249
- private declareBinding(
250
- name: BindingName,
251
- kind: SymbolKind,
252
- declaration: Node,
253
- scope: Scope,
254
- mutable: boolean,
255
- ): SymbolInfo | undefined {
256
- if (name.kind === SyntaxKind.Identifier) {
257
- return this.declare(name.text, kind, declaration, scope, mutable);
258
- }
259
- let first: SymbolInfo | undefined;
260
- const pattern = name as import("../ast/declarations.js").ArrayBindingPattern | import("../ast/declarations.js").ObjectBindingPattern;
261
- for (const element of pattern.elements) {
262
- if (!element) continue;
263
- const symbol = this.declareBinding(element.name, kind, element.name, scope, mutable);
264
- if (!first) first = symbol;
265
- }
266
- return first;
267
- }
268
-
269
- private declare(
270
- name: string,
271
- kind: SymbolKind,
272
- node: Node,
273
- scope: Scope,
274
- mutable: boolean,
275
- ): SymbolInfo {
276
- const existing = scope.symbols.get(name);
277
- if (existing) {
278
- // `var` redeclarations and duplicate functions merge into one symbol.
279
- if (
280
- (kind === SymbolKind.Var && existing.kind === SymbolKind.Var) ||
281
- (kind === SymbolKind.Function && existing.kind === SymbolKind.Function)
282
- ) {
283
- (existing.declarations as Node[]).push(node);
284
- }
285
- this.symbolOfDeclaration.set(node, existing);
286
- return existing;
287
- }
288
- const symbol: SymbolInfo = {
289
- id: this.nextSymbolId++,
290
- name,
291
- kind,
292
- mutable,
293
- fn: this.current,
294
- declarations: [node],
295
- references: [],
296
- captured: false,
297
- boxed: false,
298
- };
299
- scope.symbols.set(name, symbol);
300
- this.symbolOfDeclaration.set(node, symbol);
301
- if (scope.fn === this.current) this.current.locals.push(symbol);
302
- return symbol;
303
- }
304
-
305
- // -- declaration passes --------------------------------------------------
306
-
307
- /** Pre-declare block-scoped bindings that appear directly in `statements`. */
308
- private predeclareStatements(statements: readonly Statement[], scope: Scope): void {
309
- for (const statement of statements) {
310
- switch (statement.kind) {
311
- case SyntaxKind.VariableStatement: {
312
- this.predeclareVariableList((statement as VariableStatement).declarationList, scope);
313
- break;
314
- }
315
- case SyntaxKind.FunctionDeclaration:
316
- this.declare((statement as FunctionDeclaration).name?.text ?? "(anonymous)", SymbolKind.Function, statement, scope, true);
317
- break;
318
- case SyntaxKind.ClassDeclaration:
319
- this.declare((statement as { name: Identifier }).name.text, SymbolKind.Class, statement, scope, false);
320
- break;
321
- case SyntaxKind.InterfaceDeclaration:
322
- this.declare((statement as { name: Identifier }).name.text, SymbolKind.Interface, statement, scope, false);
323
- break;
324
- case SyntaxKind.TypeAliasDeclaration:
325
- this.declare((statement as { name: Identifier }).name.text, SymbolKind.TypeAlias, statement, scope, false);
326
- break;
327
- case SyntaxKind.EnumDeclaration:
328
- this.declare((statement as { name: Identifier }).name.text, SymbolKind.Enum, statement, scope, true);
329
- break;
330
- case SyntaxKind.ImportDeclaration:
331
- this.predeclareImport(statement as ImportDeclaration, scope);
332
- break;
333
- case SyntaxKind.ExportDeclaration: {
334
- const exported = statement as ExportDeclaration;
335
- if (exported.exportClause && exported.exportClause.kind === SyntaxKind.NamedExports) {
336
- for (const specifier of exported.exportClause.elements) {
337
- if (specifier.propertyName) this.reference(specifier.propertyName, scope);
338
- }
339
- }
340
- break;
341
- }
342
- case SyntaxKind.ModuleDeclaration:
343
- this.declare((statement as { name: Identifier }).name.text, SymbolKind.Namespace, statement, scope, false);
344
- break;
345
- default:
346
- break;
347
- }
348
- }
349
- }
350
-
351
- private predeclareVariableList(list: VariableDeclarationList, scope: Scope): void {
352
- const kind =
353
- list.declarationKind === "const"
354
- ? SymbolKind.Const
355
- : list.declarationKind === "var"
356
- ? SymbolKind.Var
357
- : SymbolKind.Let;
358
- for (const declaration of list.declarations) {
359
- this.declareBinding(declaration.name, kind, declaration, scope, kind !== SymbolKind.Const);
360
- }
361
- }
362
-
363
- private predeclareImport(node: ImportDeclaration, scope: Scope): void {
364
- const clause = node.importClause;
365
- if (!clause) return;
366
- if (clause.name) this.declare(clause.name.text, SymbolKind.Import, clause.name, scope, false);
367
- const bindings = clause.namedBindings;
368
- if (bindings && bindings.kind === SyntaxKind.NamedImports) {
369
- for (const specifier of bindings.elements) {
370
- this.declare(specifier.name.text, SymbolKind.Import, specifier.name, scope, false);
371
- }
372
- } else if (bindings && bindings.kind === SyntaxKind.NamespaceImport) {
373
- this.declare(bindings.name.text, SymbolKind.Import, bindings.name, scope, false);
374
- }
375
- }
376
-
377
- /**
378
- * Collect `var` and function declarations from nested blocks into the
379
- * enclosing function scope, without crossing function boundaries.
380
- */
381
- private collectFunctionScoped(statements: readonly Statement[], fn: MutableFunction): void {
382
- const visit = (node: Node): void => {
383
- switch (node.kind) {
384
- case SyntaxKind.FunctionDeclaration:
385
- case SyntaxKind.FunctionExpression:
386
- case SyntaxKind.ArrowFunction:
387
- case SyntaxKind.ClassDeclaration:
388
- case SyntaxKind.ClassExpression:
389
- return; // opaque, except we still want the declaration name handled at its site
390
- case SyntaxKind.VariableStatement: {
391
- const decl = node as VariableStatement;
392
- if (decl.declarationList.declarationKind === "var") {
393
- for (const d of decl.declarationList.declarations) {
394
- const existing = d.name.kind === SyntaxKind.Identifier ? fn.scope.symbols.get(d.name.text) : undefined;
395
- if (!existing) this.declareBinding(d.name, SymbolKind.Var, d, fn.scope, true);
396
- else if (d.name.kind === SyntaxKind.Identifier) this.symbolOfDeclaration.set(d, existing);
397
- }
398
- }
399
- return;
400
- }
401
- default:
402
- break;
403
- }
404
- for (const child of childNodes(node)) visit(child);
405
- };
406
- for (const statement of statements) {
407
- if (
408
- statement.kind === SyntaxKind.FunctionDeclaration ||
409
- statement.kind === SyntaxKind.ClassDeclaration
410
- ) {
411
- const name = (statement as { name: Identifier }).name.text;
412
- if (!fn.scope.symbols.has(name)) {
413
- this.declare(name, statement.kind === SyntaxKind.FunctionDeclaration ? SymbolKind.Function : SymbolKind.Class, statement, fn.scope, statement.kind === SyntaxKind.FunctionDeclaration);
414
- }
415
- continue;
416
- }
417
- visit(statement);
418
- }
419
- }
420
-
421
- // -- reference pass ------------------------------------------------------
422
-
423
- private bindStatements(statements: readonly Statement[], scope: Scope): void {
424
- for (const statement of statements) this.bindNode(statement, scope);
425
- }
426
-
427
- private bindBlock(block: Block, scope: Scope): void {
428
- const blockScope = this.createScope(ScopeKind.Block, block, scope);
429
- this.scopes.set(block, blockScope);
430
- this.predeclareStatements(block.statements, blockScope);
431
- this.bindStatements(block.statements, blockScope);
432
- }
433
-
434
- private bindNode(node: Node | undefined, scope: Scope): void {
435
- if (!node) return;
436
- switch (node.kind) {
437
- case SyntaxKind.Block:
438
- this.bindBlock(node as Block, scope);
439
- return;
440
- case SyntaxKind.VariableStatement:
441
- this.bindVariableList((node as VariableStatement).declarationList, scope);
442
- return;
443
- case SyntaxKind.FunctionDeclaration: {
444
- const fn = node as FunctionDeclaration;
445
- const symbol = this.symbolOfDeclaration.get(fn);
446
- if (symbol) (symbol.declarations as Node[]).length; // keep declaration mapping warm
447
- this.bindFunction(fn, scope, symbol);
448
- return;
449
- }
450
- case SyntaxKind.FunctionExpression:
451
- case SyntaxKind.ArrowFunction:
452
- this.bindFunction(node as FunctionExpression | ArrowFunction, scope, undefined);
453
- return;
454
- case SyntaxKind.Identifier:
455
- this.reference(node as Identifier, scope);
456
- return;
457
- case SyntaxKind.PropertyAccessExpression:
458
- // `obj.name` reads a property, not a variable named `name`.
459
- this.bindNode((node as unknown as { expression: Expression }).expression, scope);
460
- return;
461
- case SyntaxKind.ElementAccessExpression: {
462
- const access = node as unknown as { expression: Expression; argumentExpression: Expression };
463
- this.bindNode(access.expression, scope);
464
- this.bindNode(access.argumentExpression, scope);
465
- return;
466
- }
467
- case SyntaxKind.PropertyAssignment: {
468
- // `{ key: value }` / `{ key() {} }`: only the value is an expression,
469
- // except a computed key (`{ [expr]: value }`) whose expression is real.
470
- const property = node as unknown as { name: PropertyName; initializer: Expression };
471
- if (property.name.kind === SyntaxKind.ComputedPropertyName) {
472
- this.bindNode((property.name as unknown as { expression: Expression }).expression, scope);
473
- }
474
- this.bindNode(property.initializer, scope);
475
- return;
476
- }
477
- case SyntaxKind.ShorthandPropertyAssignment:
478
- this.reference((node as unknown as { name: Identifier }).name, scope);
479
- return;
480
- case SyntaxKind.LabeledStatement:
481
- this.bindNode((node as unknown as { statement: Node }).statement, scope);
482
- return;
483
- case SyntaxKind.BreakStatement:
484
- case SyntaxKind.ContinueStatement:
485
- return;
486
- case SyntaxKind.ThisKeyword:
487
- this.current.usesThis = true;
488
- return;
489
- case SyntaxKind.ClassDeclaration:
490
- case SyntaxKind.ClassExpression:
491
- this.bindClass(node as ClassDeclaration | ClassExpression, scope);
492
- return;
493
- case SyntaxKind.InterfaceDeclaration:
494
- case SyntaxKind.TypeAliasDeclaration:
495
- // Type-only: skip the body entirely.
496
- return;
497
- case SyntaxKind.ImportDeclaration:
498
- return;
499
- case SyntaxKind.ExportDeclaration: {
500
- const exported = node as ExportDeclaration;
501
- if (exported.exportClause && exported.exportClause.kind === SyntaxKind.NamedExports) {
502
- for (const specifier of exported.exportClause.elements) {
503
- if (specifier.propertyName) this.reference(specifier.propertyName, scope);
504
- }
505
- }
506
- return;
507
- }
508
- case SyntaxKind.ExportAssignment:
509
- this.bindNode((node as unknown as { expression: Expression }).expression, scope);
510
- return;
511
- case SyntaxKind.ForStatement: {
512
- const forNode = node as ForStatement;
513
- const forScope = this.createScope(ScopeKind.For, forNode, scope);
514
- this.scopes.set(forNode, forScope);
515
- if (forNode.initializer) {
516
- if (forNode.initializer.kind === SyntaxKind.VariableDeclarationList) {
517
- this.predeclareVariableList(forNode.initializer as VariableDeclarationList, forScope);
518
- this.bindVariableList(forNode.initializer as VariableDeclarationList, forScope);
519
- } else {
520
- this.bindNode(forNode.initializer, forScope);
521
- }
522
- }
523
- this.bindNode(forNode.condition, forScope);
524
- this.bindNode(forNode.incrementor, forScope);
525
- this.bindNode(forNode.statement, forScope);
526
- return;
527
- }
528
- case SyntaxKind.ForOfStatement:
529
- case SyntaxKind.ForInStatement: {
530
- const loop = node as ForOfStatement | ForInStatement;
531
- const loopScope = this.createScope(ScopeKind.For, loop, scope);
532
- this.scopes.set(loop, loopScope);
533
- if (loop.initializer.kind === SyntaxKind.VariableDeclarationList) {
534
- this.predeclareVariableList(loop.initializer, loopScope);
535
- this.bindVariableList(loop.initializer, loopScope);
536
- } else {
537
- this.bindNode(loop.initializer, loopScope);
538
- }
539
- this.bindNode(loop.expression, loopScope);
540
- this.bindNode(loop.statement, loopScope);
541
- return;
542
- }
543
- case SyntaxKind.CatchClause: {
544
- const clause = node as CatchClause;
545
- const catchScope = this.createScope(ScopeKind.Catch, clause, scope);
546
- this.scopes.set(clause, catchScope);
547
- if (clause.variable) this.declare(clause.variable.text, SymbolKind.Let, clause.variable, catchScope, true);
548
- this.bindBlock(clause.block, catchScope);
549
- return;
550
- }
551
- default:
552
- break;
553
- }
554
- for (const child of childNodes(node)) this.bindNode(child, scope);
555
- }
556
-
557
- private bindVariableList(list: VariableDeclarationList, scope: Scope): void {
558
- for (const declaration of list.declarations) {
559
- const symbol = this.symbolOfDeclaration.get(declaration);
560
- if (declaration.name.kind === SyntaxKind.Identifier) {
561
- this.symbolOfDeclaration.set(declaration.name, symbol ?? this.symbolOfDeclaration.get(declaration) as SymbolInfo);
562
- } else {
563
- this.bindBindingPattern(declaration.name, scope);
564
- }
565
- this.bindNode(declaration.initializer, scope);
566
- }
567
- }
568
-
569
- /** Bind default-value expressions inside a binding pattern. */
570
- private bindBindingPattern(name: BindingName, scope: Scope): void {
571
- if (name.kind === SyntaxKind.Identifier) return;
572
- const pattern = name as import("../ast/declarations.js").ArrayBindingPattern | import("../ast/declarations.js").ObjectBindingPattern;
573
- for (const element of pattern.elements) {
574
- if (!element) continue;
575
- if (element.initializer) this.bindNode(element.initializer, scope);
576
- this.bindBindingPattern(element.name, scope);
577
- }
578
- }
579
-
580
- private bindFunction(
581
- node: FunctionDeclaration | FunctionExpression | ArrowFunction,
582
- parentScope: Scope,
583
- symbol: SymbolInfo | undefined,
584
- ): void {
585
- const name =
586
- node.kind === SyntaxKind.FunctionDeclaration
587
- ? (node as FunctionDeclaration).name?.text ?? "(anonymous)"
588
- : node.kind === SyntaxKind.FunctionExpression
589
- ? (node as FunctionExpression).name?.text ?? "(anonymous)"
590
- : "(arrow)";
591
- const parentFn = this.current;
592
- const fn = this.createFunction(name, node, parentFn, false, node.kind === SyntaxKind.ArrowFunction);
593
- this.current = fn;
594
-
595
- const scope = this.createScope(ScopeKind.Function, node, parentScope);
596
- (fn as { scope: Scope }).scope = scope;
597
- this.scopes.set(node, scope);
598
-
599
- // Parameters live in the function scope.
600
- const params: SymbolInfo[] = [];
601
- for (const parameter of node.parameters) {
602
- const paramSymbol = this.declareBinding(parameter.name, SymbolKind.Parameter, parameter, scope, true);
603
- if (paramSymbol) params.push(paramSymbol);
604
- if (parameter.initializer) this.bindNode(parameter.initializer, scope);
605
- }
606
- (fn as { params: SymbolInfo[] }).params = params;
607
-
608
- // Initialize a named function expression's own name inside its scope.
609
- if (node.kind === SyntaxKind.FunctionExpression && (node as FunctionExpression).name) {
610
- const selfName = (node as FunctionExpression).name!;
611
- this.declare(selfName.text, SymbolKind.Const, selfName, scope, false);
612
- }
613
- if (symbol) this.symbolOfDeclaration.set(node, symbol);
614
-
615
- const body = node.body as unknown as Block | Expression | undefined;
616
- if (body) {
617
- this.collectFunctionScoped([body.kind === SyntaxKind.Block ? body : ({ kind: SyntaxKind.Block, statements: [], start: body.start, end: body.end } as Block)], fn);
618
- if (body.kind === SyntaxKind.Block) {
619
- this.predeclareStatements(body.statements, scope);
620
- this.bindStatements(body.statements, scope);
621
- } else {
622
- this.bindNode(body, scope);
623
- }
624
- }
625
-
626
- this.current = parentFn;
627
- }
628
-
629
- private bindClass(node: ClassDeclaration | ClassExpression, scope: Scope): void {
630
- const parentFn = this.current;
631
- const name = node.name ? node.name.text : "(anonymous)";
632
-
633
- let parentExpression: Expression | undefined;
634
- let parentClass: ClassInfo | undefined;
635
- const heritage = node.heritage.find((clause) => clause.token === "extends");
636
- if (heritage && heritage.types.length > 0) {
637
- parentExpression = heritage.types[0]!.expression;
638
- this.bindNode(parentExpression, scope);
639
- if (parentExpression.kind === SyntaxKind.Identifier) {
640
- const symbol = this.symbolOfIdentifier.get(parentExpression as Identifier);
641
- const declaration = symbol?.declarations[0];
642
- if (declaration) parentClass = this.classOfNode.get(declaration);
643
- }
644
- }
645
-
646
- const info: ClassInfo = {
647
- id: this.nextClassId++,
648
- name,
649
- node,
650
- scope,
651
- parent: parentClass,
652
- parentExpression,
653
- fields: [],
654
- methods: [],
655
- statics: [],
656
- };
657
- this.classes.push(info);
658
- this.classOfNode.set(node, info);
659
-
660
- const classScope = this.createScope(ScopeKind.Block, node, scope);
661
- this.scopes.set(node, classScope);
662
-
663
- let constructor: FunctionInfo | undefined;
664
- for (const member of node.members) {
665
- if (member.kind === SyntaxKind.ConstructorDeclaration) {
666
- const ctor = member as ConstructorDeclaration;
667
- constructor = this.createClassFunction(ctor, "constructor", ctor.parameters, ctor.body, classScope, info, false, true);
668
- } else if (member.kind === SyntaxKind.MethodDeclaration) {
669
- const method = member as MethodDeclaration;
670
- const isStatic = method.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
671
- const fn = this.createClassFunction(method, classMemberName(method.name), method.parameters, method.body, classScope, info, isStatic, false);
672
- if (isStatic) (info.statics as FunctionInfo[]).push(fn);
673
- else (info.methods as FunctionInfo[]).push(fn);
674
- }
675
- }
676
- if (!constructor) {
677
- constructor = this.createClassFunction(node, "constructor", [], undefined, classScope, info, false, true);
678
- }
679
- info.ctor = constructor;
680
-
681
- // Field initializers run in the constructor's context so they can capture
682
- // enclosing variables.
683
- for (const member of node.members) {
684
- if (member.kind === SyntaxKind.PropertyDeclaration) {
685
- const property = member as PropertyDeclaration;
686
- const isStatic = property.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
687
- const owner = this.current;
688
- this.current = constructor as MutableFunction;
689
- if (property.initializer) this.bindNode(property.initializer, classScope);
690
- this.current = owner;
691
- info.fields.push({ name: classMemberName(property.name), initializer: property.initializer, fn: constructor, isStatic });
692
- }
693
- }
694
-
695
- this.current = parentFn;
696
- }
697
-
698
- private createClassFunction(
699
- member: Node,
700
- name: string,
701
- parameters: readonly import("../ast/declarations.js").Parameter[],
702
- body: Block | undefined,
703
- parentScope: Scope,
704
- info: ClassInfo,
705
- isStatic: boolean,
706
- isConstructor: boolean,
707
- ): FunctionInfo {
708
- const parentFn = this.current;
709
- const fn = this.createFunction(name, member as unknown as FunctionNode, parentFn, false, false);
710
- (fn as MutableFunction & { classInfo: ClassInfo }).classInfo = info;
711
- (fn as MutableFunction & { isStatic: boolean }).isStatic = isStatic;
712
- (fn as MutableFunction & { isConstructor: boolean }).isConstructor = isConstructor;
713
- this.current = fn as MutableFunction;
714
- const scope = this.createScope(ScopeKind.Function, member, parentScope);
715
- (fn as { scope: Scope }).scope = scope;
716
- this.scopes.set(member, scope);
717
-
718
- const params: SymbolInfo[] = [];
719
- for (const parameter of parameters) {
720
- const paramSymbol = this.declareBinding(parameter.name, SymbolKind.Parameter, parameter, scope, true);
721
- if (paramSymbol) params.push(paramSymbol);
722
- if (parameter.initializer) this.bindNode(parameter.initializer, scope);
723
- }
724
- (fn as { params: SymbolInfo[] }).params = params;
725
-
726
- if (body) {
727
- this.collectFunctionScoped([body], fn as MutableFunction);
728
- this.predeclareStatements(body.statements, scope);
729
- this.bindStatements(body.statements, scope);
730
- }
731
-
732
- this.current = parentFn;
733
- return fn;
734
- }
735
-
736
- private reference(identifier: Identifier, scope: Scope): void {
737
- if (identifier.text === "super") {
738
- this.current.usesThis = true;
739
- return;
740
- }
741
- let current: Scope | undefined = scope;
742
- while (current) {
743
- const symbol = current.symbols.get(identifier.text);
744
- if (symbol) {
745
- (symbol.references as Identifier[]).push(identifier);
746
- this.symbolOfIdentifier.set(identifier, symbol);
747
- // Functions, classes and type-only names are resolved to their
748
- // declaration sites by codegen; they are never captured as values.
749
- if (symbol.fn !== this.current && isCapturable(symbol.kind)) this.markCaptured(symbol);
750
- return;
751
- }
752
- current = current.parent;
753
- }
754
- this.unresolved.push(identifier);
755
- }
756
-
757
- /** Record that `symbol` escapes into `this.current`, threading it through every intermediate closure. */
758
- private markCaptured(symbol: SymbolInfo): void {
759
- symbol.captured = true;
760
- symbol.boxed = true;
761
- let fn: MutableFunction | undefined = this.current;
762
- while (fn && fn !== symbol.fn) {
763
- if (!fn.captureIndex.has(symbol.id)) {
764
- fn.captureIndex.set(symbol.id, fn.captures.length);
765
- fn.captures.push(symbol);
766
- }
767
- fn = fn.parent as MutableFunction | undefined;
768
- }
769
- }
770
121
  }
771
122
 
772
- /** Direct AST children, tolerant of both arrays and single nodes. */
773
- function childNodes(node: Node): Node[] {
774
- const result: Node[] = [];
775
- const n = node as unknown as Record<string, unknown>;
776
- for (const key of Object.keys(n)) {
777
- if (key === "kind" || key === "start" || key === "end") continue;
778
- const value = n[key];
779
- if (Array.isArray(value)) {
780
- for (const item of value) if (item && typeof item === "object" && "kind" in (item as object)) result.push(item as Node);
781
- } else if (value && typeof value === "object" && "kind" in (value as object)) {
782
- result.push(value as Node);
783
- }
784
- }
785
- return result;
786
- }
123
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
124
+ export interface Binder extends DeclarationMethods, ReferenceMethods {}
787
125
 
788
- /** Only value bindings participate in closure capture. */
789
- function isCapturable(kind: SymbolKind): boolean {
790
- return (
791
- kind === SymbolKind.Var ||
792
- kind === SymbolKind.Let ||
793
- kind === SymbolKind.Const ||
794
- kind === SymbolKind.Parameter
795
- );
796
- }
797
-
798
- /** Extract the textual name of a class member (`method`, `"key"`, `0`). */
799
- function classMemberName(name: PropertyName): string {
800
- switch (name.kind) {
801
- case SyntaxKind.Identifier:
802
- case SyntaxKind.PrivateIdentifier:
803
- return (name as unknown as { text: string }).text;
804
- case SyntaxKind.StringLiteral:
805
- return (name as unknown as { value: string }).value;
806
- case SyntaxKind.NumericLiteral:
807
- return String((name as unknown as { value: number }).value);
808
- default:
809
- return "";
810
- }
811
- }
126
+ Object.assign(Binder.prototype, declarationMethods, referenceMethods);