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.
- package/README.md +17 -2
- package/README.zh-CN.md +16 -2
- package/bin/xbintsc.js +49 -10
- package/dist/src/ast/expressions.d.ts +2 -0
- package/dist/src/binder/binder.d.ts +24 -98
- package/dist/src/binder/binder.js +13 -559
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +16 -0
- package/dist/src/binder/declarations.js +168 -0
- package/dist/src/binder/declarations.js.map +1 -0
- package/dist/src/binder/helpers.d.ts +11 -0
- package/dist/src/binder/helpers.js +46 -0
- package/dist/src/binder/helpers.js.map +1 -0
- package/dist/src/binder/references.d.ts +21 -0
- package/dist/src/binder/references.js +349 -0
- package/dist/src/binder/references.js.map +1 -0
- package/dist/src/binder/types.d.ts +114 -0
- package/dist/src/binder/types.js +27 -0
- package/dist/src/binder/types.js.map +1 -0
- package/dist/src/cli/main.d.ts +1 -0
- package/dist/src/cli/main.js +40 -0
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +13 -0
- package/dist/src/codegen/generator/calls/access.js +115 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -0
- package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
- package/dist/src/codegen/generator/calls/closures.js +50 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -0
- package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
- package/dist/src/codegen/generator/calls/invocation.js +242 -0
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
- package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
- package/dist/src/codegen/generator/calls/literals.js +69 -0
- package/dist/src/codegen/generator/calls/literals.js.map +1 -0
- package/dist/src/codegen/generator/calls/super.d.ts +10 -0
- package/dist/src/codegen/generator/calls/super.js +47 -0
- package/dist/src/codegen/generator/calls/super.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +15 -24
- package/dist/src/codegen/generator/calls.js +15 -482
- package/dist/src/codegen/generator/calls.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +1 -1
- package/dist/src/codegen/generator/context.js +2 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
- package/dist/src/codegen/generator/expressions/assignment.js +203 -0
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
- package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
- package/dist/src/codegen/generator/expressions/operators.js +163 -0
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
- package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
- package/dist/src/codegen/generator/expressions/primary.js +260 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +11 -21
- package/dist/src/codegen/generator/expressions.js +11 -494
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +16 -4
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
- package/dist/src/codegen/generator/statements/control-flow.js +199 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
- package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
- package/dist/src/codegen/generator/statements/dispatch.js +100 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
- package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
- package/dist/src/codegen/generator/statements/loops.js +152 -0
- package/dist/src/codegen/generator/statements/loops.js.map +1 -0
- package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
- package/dist/src/codegen/generator/statements/variables.js +146 -0
- package/dist/src/codegen/generator/statements/variables.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +13 -21
- package/dist/src/codegen/generator/statements.js +13 -568
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +7 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/codegen/values.d.ts +17 -17
- package/dist/src/codegen/values.js +21 -57
- package/dist/src/codegen/values.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +1 -0
- package/dist/src/diagnostics/diagnostic.js +1 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/diagnostics/source.d.ts +1 -1
- package/dist/src/diagnostics/source.js +7 -12
- package/dist/src/diagnostics/source.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +4 -0
- package/dist/src/driver/compiler.js +51 -16
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +5 -2
- package/dist/src/driver/index.js +5 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/paths.d.ts +20 -0
- package/dist/src/driver/paths.js +49 -0
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +18 -0
- package/dist/src/driver/runtime-lib.js +31 -0
- package/dist/src/driver/runtime-lib.js.map +1 -0
- package/dist/src/driver/toolchain-download.d.ts +50 -0
- package/dist/src/driver/toolchain-download.js +76 -0
- package/dist/src/driver/toolchain-download.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +33 -0
- package/dist/src/driver/toolchain-provider.js +71 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -0
- package/dist/src/driver/toolchain.d.ts +9 -4
- package/dist/src/driver/toolchain.js +6 -10
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +4 -2
- package/dist/src/extensions/node/child_process/index.js +4 -2
- package/dist/src/extensions/node/child_process/index.js.map +1 -1
- package/dist/src/extensions/node/events/index.d.ts +10 -0
- package/dist/src/extensions/node/events/index.js +22 -0
- package/dist/src/extensions/node/events/index.js.map +1 -0
- package/dist/src/extensions/node/index.js +6 -0
- package/dist/src/extensions/node/index.js.map +1 -1
- package/dist/src/extensions/node/querystring/index.d.ts +10 -0
- package/dist/src/extensions/node/querystring/index.js +25 -0
- package/dist/src/extensions/node/querystring/index.js.map +1 -0
- package/dist/src/extensions/node/util/index.d.ts +11 -0
- package/dist/src/extensions/node/util/index.js +41 -0
- package/dist/src/extensions/node/util/index.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +6 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
- package/dist/src/lexer/scanner/identifiers.js +33 -0
- package/dist/src/lexer/scanner/identifiers.js.map +1 -0
- package/dist/src/lexer/scanner/numbers.d.ts +10 -0
- package/dist/src/lexer/scanner/numbers.js +89 -0
- package/dist/src/lexer/scanner/numbers.js.map +1 -0
- package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
- package/dist/src/lexer/scanner/punctuation.js +151 -0
- package/dist/src/lexer/scanner/punctuation.js.map +1 -0
- package/dist/src/lexer/scanner/regex.d.ts +11 -0
- package/dist/src/lexer/scanner/regex.js +69 -0
- package/dist/src/lexer/scanner/regex.js.map +1 -0
- package/dist/src/lexer/scanner/strings.d.ts +13 -0
- package/dist/src/lexer/scanner/strings.js +118 -0
- package/dist/src/lexer/scanner/strings.js.map +1 -0
- package/dist/src/lexer/scanner.d.ts +20 -27
- package/dist/src/lexer/scanner.js +11 -415
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.d.ts +14 -0
- package/dist/src/parser/declarations/classes.js +191 -0
- package/dist/src/parser/declarations/classes.js.map +1 -0
- package/dist/src/parser/declarations/functions.d.ts +17 -0
- package/dist/src/parser/declarations/functions.js +241 -0
- package/dist/src/parser/declarations/functions.js.map +1 -0
- package/dist/src/parser/declarations/type-members.d.ts +16 -0
- package/dist/src/parser/declarations/type-members.js +156 -0
- package/dist/src/parser/declarations/type-members.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +13 -24
- package/dist/src/parser/declarations.js +13 -571
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/helpers.js +13 -4
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +10 -1
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +24 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +3 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/paths.test.d.ts +1 -0
- package/dist/tests/driver/paths.test.js +26 -0
- package/dist/tests/driver/paths.test.js.map +1 -0
- package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-download.test.js +38 -0
- package/dist/tests/driver/toolchain-download.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +37 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
- package/dist/tests/e2e/compile-node.test.d.ts +7 -0
- package/dist/tests/e2e/compile-node.test.js +123 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -0
- package/dist/tests/e2e/compile.test.d.ts +4 -1
- package/dist/tests/e2e/compile.test.js +90 -130
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.d.ts +36 -0
- package/dist/tests/e2e/harness.js +64 -0
- package/dist/tests/e2e/harness.js.map +1 -0
- package/dist/tests/e2e/node-modules.test.js +60 -0
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/extensions/registry.test.js +4 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/package.json +5 -3
- package/runtime/ext_node/buffer/buffer.c +12 -552
- package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
- package/runtime/ext_node/buffer/parts/construction.inc +60 -0
- package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
- package/runtime/ext_node/buffer/parts/methods.inc +135 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
- package/runtime/ext_node/buffer/parts/search.inc +86 -0
- package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
- package/runtime/ext_node/child_process/child_process.c +37 -3
- package/runtime/ext_node/events/events.c +285 -0
- package/runtime/ext_node/http/http.c +11 -736
- package/runtime/ext_node/http/parts/client.inc +290 -0
- package/runtime/ext_node/http/parts/helpers.inc +45 -0
- package/runtime/ext_node/http/parts/prototypes.inc +57 -0
- package/runtime/ext_node/http/parts/response.inc +149 -0
- package/runtime/ext_node/http/parts/server.inc +133 -0
- package/runtime/ext_node/http/parts/string-builder.inc +58 -0
- package/runtime/ext_node/net/net.c +12 -504
- package/runtime/ext_node/net/parts/construction.inc +22 -0
- package/runtime/ext_node/net/parts/platform.inc +60 -0
- package/runtime/ext_node/net/parts/prototypes.inc +35 -0
- package/runtime/ext_node/net/parts/read-loop.inc +58 -0
- package/runtime/ext_node/net/parts/server.inc +131 -0
- package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
- package/runtime/ext_node/net/parts/static-api.inc +93 -0
- package/runtime/ext_node/querystring/querystring.c +251 -0
- package/runtime/ext_node/util/util.c +456 -0
- package/runtime/rt.h +8 -2
- package/runtime/rt_internal.h +34 -0
- package/runtime/xt_bigint/arithmetic.inc +135 -0
- package/runtime/xt_bigint/bits.inc +98 -0
- package/runtime/xt_bigint/bitwise.inc +103 -0
- package/runtime/xt_bigint/compare.inc +30 -0
- package/runtime/xt_bigint/conversions.inc +51 -0
- package/runtime/xt_bigint/division.inc +85 -0
- package/runtime/xt_bigint/format.inc +145 -0
- package/runtime/xt_bigint/helpers.inc +92 -0
- package/runtime/xt_bigint/magnitude.inc +88 -0
- package/runtime/xt_bigint/public.inc +59 -0
- package/runtime/xt_bigint/small-arithmetic.inc +58 -0
- package/runtime/xt_bigint.c +42 -0
- package/runtime/xt_builtins.c +40 -5
- package/runtime/xt_io.c +7 -0
- package/runtime/xt_stdlib/arrays.inc +161 -0
- package/runtime/xt_stdlib/dispatch.inc +116 -0
- package/runtime/xt_stdlib/helpers.inc +23 -0
- package/runtime/xt_stdlib/math.inc +72 -0
- package/runtime/xt_stdlib/strings.inc +178 -0
- package/runtime/xt_stdlib.c +10 -549
- package/runtime/xt_stdlib2/array-statics.inc +37 -0
- package/runtime/xt_stdlib2/arrays.inc +189 -0
- package/runtime/xt_stdlib2/container.inc +23 -0
- package/runtime/xt_stdlib2/date.inc +72 -0
- package/runtime/xt_stdlib2/error.inc +22 -0
- package/runtime/xt_stdlib2/helpers.inc +43 -0
- package/runtime/xt_stdlib2/json.inc +213 -0
- package/runtime/xt_stdlib2/map.inc +95 -0
- package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
- package/runtime/xt_stdlib2/numbers.inc +38 -0
- package/runtime/xt_stdlib2/objects.inc +41 -0
- package/runtime/xt_stdlib2/regexp-match.inc +204 -0
- package/runtime/xt_stdlib2/regexp.inc +20 -0
- package/runtime/xt_stdlib2/set.inc +105 -0
- package/runtime/xt_stdlib2/strings.inc +94 -0
- package/runtime/xt_stdlib2.c +19 -1278
- package/runtime/xt_values.c +155 -12
- package/scripts/build-runtime.ts +109 -0
- package/scripts/fetch-toolchain.ts +101 -0
- package/scripts/package-release.ts +192 -0
- package/src/ast/expressions.ts +2 -0
- package/src/binder/binder.ts +40 -725
- package/src/binder/declarations.ts +203 -0
- package/src/binder/helpers.ts +47 -0
- package/src/binder/references.ts +410 -0
- package/src/binder/types.ts +134 -0
- package/src/cli/main.ts +43 -0
- package/src/codegen/generator/calls/access.ts +139 -0
- package/src/codegen/generator/calls/closures.ts +60 -0
- package/src/codegen/generator/calls/invocation.ts +282 -0
- package/src/codegen/generator/calls/literals.ts +77 -0
- package/src/codegen/generator/calls/super.ts +61 -0
- package/src/codegen/generator/calls.ts +30 -552
- package/src/codegen/generator/context.ts +2 -2
- package/src/codegen/generator/expressions/assignment.ts +226 -0
- package/src/codegen/generator/expressions/operators.ts +182 -0
- package/src/codegen/generator/expressions/primary.ts +304 -0
- package/src/codegen/generator/expressions.ts +22 -553
- package/src/codegen/generator/module.ts +14 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/statements/control-flow.ts +225 -0
- package/src/codegen/generator/statements/dispatch.ts +122 -0
- package/src/codegen/generator/statements/loops.ts +173 -0
- package/src/codegen/generator/statements/variables.ts +152 -0
- package/src/codegen/generator/statements.ts +26 -612
- package/src/codegen/generator/tables.ts +7 -0
- package/src/codegen/values.ts +22 -57
- package/src/diagnostics/diagnostic.ts +1 -0
- package/src/diagnostics/source.ts +7 -12
- package/src/driver/compiler.ts +61 -18
- package/src/driver/index.ts +17 -2
- package/src/driver/paths.ts +54 -0
- package/src/driver/runtime-lib.ts +32 -0
- package/src/driver/toolchain-download.ts +108 -0
- package/src/driver/toolchain-provider.ts +91 -0
- package/src/driver/toolchain.ts +29 -11
- package/src/extensions/node/child_process/index.ts +4 -2
- package/src/extensions/node/events/index.ts +27 -0
- package/src/extensions/node/index.ts +6 -0
- package/src/extensions/node/querystring/index.ts +29 -0
- package/src/extensions/node/util/index.ts +48 -0
- package/src/extensions/registry.ts +6 -0
- package/src/index.ts +1 -0
- package/src/lexer/scanner/identifiers.ts +37 -0
- package/src/lexer/scanner/numbers.ts +84 -0
- package/src/lexer/scanner/punctuation.ts +132 -0
- package/src/lexer/scanner/regex.ts +79 -0
- package/src/lexer/scanner/strings.ts +128 -0
- package/src/lexer/scanner.ts +35 -401
- package/src/parser/declarations/classes.ts +215 -0
- package/src/parser/declarations/functions.ts +254 -0
- package/src/parser/declarations/type-members.ts +181 -0
- package/src/parser/declarations.ts +32 -609
- package/src/parser/helpers.ts +13 -6
- package/src/parser/literals.ts +10 -1
- package/scripts/build-runtime.mjs +0 -55
package/src/binder/binder.ts
CHANGED
|
@@ -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
|
|
18
|
+
import { NodeFlags } from "../ast/kinds.js";
|
|
19
|
+
import type { Identifier, Node, SourceFileNode } from "../ast/nodes.js";
|
|
13
20
|
import {
|
|
14
|
-
|
|
15
|
-
type
|
|
16
|
-
type
|
|
17
|
-
type
|
|
18
|
-
type
|
|
19
|
-
type
|
|
20
|
-
type
|
|
21
|
-
type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
constructor(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
773
|
-
|
|
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
|
-
|
|
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);
|