xbintsc 0.1.6 → 0.1.9

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 (152) hide show
  1. package/README.md +7 -4
  2. package/dist/src/ast/common.d.ts +33 -0
  3. package/dist/src/ast/common.js +7 -0
  4. package/dist/src/ast/common.js.map +1 -0
  5. package/dist/src/ast/declarations.d.ts +110 -0
  6. package/dist/src/ast/declarations.js +5 -0
  7. package/dist/src/ast/declarations.js.map +1 -0
  8. package/dist/src/ast/expressions.d.ts +219 -0
  9. package/dist/src/ast/expressions.js +6 -0
  10. package/dist/src/ast/expressions.js.map +1 -0
  11. package/dist/src/ast/kinds.d.ts +160 -0
  12. package/dist/src/ast/kinds.js +171 -0
  13. package/dist/src/ast/kinds.js.map +1 -0
  14. package/dist/src/ast/modules.d.ts +61 -0
  15. package/dist/src/ast/modules.js +5 -0
  16. package/dist/src/ast/modules.js.map +1 -0
  17. package/dist/src/ast/nodes.d.ts +11 -839
  18. package/dist/src/ast/nodes.js +11 -237
  19. package/dist/src/ast/nodes.js.map +1 -1
  20. package/dist/src/ast/operators.d.ts +71 -0
  21. package/dist/src/ast/operators.js +77 -0
  22. package/dist/src/ast/operators.js.map +1 -0
  23. package/dist/src/ast/statements.d.ts +120 -0
  24. package/dist/src/ast/statements.js +5 -0
  25. package/dist/src/ast/statements.js.map +1 -0
  26. package/dist/src/ast/types.d.ts +123 -0
  27. package/dist/src/ast/types.js +6 -0
  28. package/dist/src/ast/types.js.map +1 -0
  29. package/dist/src/binder/binder.d.ts +35 -1
  30. package/dist/src/binder/binder.js +138 -0
  31. package/dist/src/binder/binder.js.map +1 -1
  32. package/dist/src/codegen/generator/calls.d.ts +26 -0
  33. package/dist/src/codegen/generator/calls.js +373 -0
  34. package/dist/src/codegen/generator/calls.js.map +1 -0
  35. package/dist/src/codegen/generator/context.d.ts +47 -0
  36. package/dist/src/codegen/generator/context.js +164 -0
  37. package/dist/src/codegen/generator/context.js.map +1 -0
  38. package/dist/src/codegen/generator/expressions.d.ts +25 -0
  39. package/dist/src/codegen/generator/expressions.js +454 -0
  40. package/dist/src/codegen/generator/expressions.js.map +1 -0
  41. package/dist/src/codegen/generator/generator.d.ts +22 -0
  42. package/dist/src/codegen/generator/generator.js +21 -0
  43. package/dist/src/codegen/generator/generator.js.map +1 -0
  44. package/dist/src/codegen/generator/module.d.ts +19 -0
  45. package/dist/src/codegen/generator/module.js +214 -0
  46. package/dist/src/codegen/generator/module.js.map +1 -0
  47. package/dist/src/codegen/generator/state.d.ts +42 -0
  48. package/dist/src/codegen/generator/state.js +125 -0
  49. package/dist/src/codegen/generator/state.js.map +1 -0
  50. package/dist/src/codegen/generator/statements.d.ts +22 -0
  51. package/dist/src/codegen/generator/statements.js +433 -0
  52. package/dist/src/codegen/generator/statements.js.map +1 -0
  53. package/dist/src/codegen/generator/tables.d.ts +23 -0
  54. package/dist/src/codegen/generator/tables.js +186 -0
  55. package/dist/src/codegen/generator/tables.js.map +1 -0
  56. package/dist/src/codegen/llvm.d.ts +4 -13
  57. package/dist/src/codegen/llvm.js +4 -1537
  58. package/dist/src/codegen/llvm.js.map +1 -1
  59. package/dist/src/driver/compiler.js +36 -11
  60. package/dist/src/driver/compiler.js.map +1 -1
  61. package/dist/src/driver/modules.d.ts +24 -0
  62. package/dist/src/driver/modules.js +347 -0
  63. package/dist/src/driver/modules.js.map +1 -0
  64. package/dist/src/lexer/char.d.ts +78 -0
  65. package/dist/src/lexer/char.js +106 -0
  66. package/dist/src/lexer/char.js.map +1 -0
  67. package/dist/src/lexer/scanner.js +1 -98
  68. package/dist/src/lexer/scanner.js.map +1 -1
  69. package/dist/src/parser/context.d.ts +58 -0
  70. package/dist/src/parser/context.js +174 -0
  71. package/dist/src/parser/context.js.map +1 -0
  72. package/dist/src/parser/declarations.d.ts +26 -0
  73. package/dist/src/parser/declarations.js +461 -0
  74. package/dist/src/parser/declarations.js.map +1 -0
  75. package/dist/src/parser/expressions.d.ts +27 -0
  76. package/dist/src/parser/expressions.js +440 -0
  77. package/dist/src/parser/expressions.js.map +1 -0
  78. package/dist/src/parser/helpers.d.ts +7 -0
  79. package/dist/src/parser/helpers.js +36 -0
  80. package/dist/src/parser/helpers.js.map +1 -0
  81. package/dist/src/parser/literals.d.ts +16 -0
  82. package/dist/src/parser/literals.js +193 -0
  83. package/dist/src/parser/literals.js.map +1 -0
  84. package/dist/src/parser/modules.d.ts +12 -0
  85. package/dist/src/parser/modules.js +175 -0
  86. package/dist/src/parser/modules.js.map +1 -0
  87. package/dist/src/parser/operators.d.ts +12 -0
  88. package/dist/src/parser/operators.js +172 -0
  89. package/dist/src/parser/operators.js.map +1 -0
  90. package/dist/src/parser/parser.d.ts +17 -122
  91. package/dist/src/parser/parser.js +18 -2311
  92. package/dist/src/parser/parser.js.map +1 -1
  93. package/dist/src/parser/speculation.d.ts +6 -0
  94. package/dist/src/parser/speculation.js +10 -0
  95. package/dist/src/parser/speculation.js.map +1 -0
  96. package/dist/src/parser/statements.d.ts +28 -0
  97. package/dist/src/parser/statements.js +402 -0
  98. package/dist/src/parser/statements.js.map +1 -0
  99. package/dist/src/parser/types.d.ts +21 -0
  100. package/dist/src/parser/types.js +338 -0
  101. package/dist/src/parser/types.js.map +1 -0
  102. package/dist/tests/codegen/llvm.test.js +1 -1
  103. package/dist/tests/codegen/llvm.test.js.map +1 -1
  104. package/dist/tests/e2e/compile.test.js +86 -0
  105. package/dist/tests/e2e/compile.test.js.map +1 -1
  106. package/package.json +1 -1
  107. package/runtime/rt.h +55 -4
  108. package/runtime/rt_internal.h +169 -0
  109. package/runtime/xt_alloc.c +38 -0
  110. package/runtime/xt_builtins.c +238 -0
  111. package/runtime/xt_containers.c +312 -0
  112. package/runtime/xt_io.c +246 -0
  113. package/runtime/xt_promise.c +292 -0
  114. package/runtime/xt_stdlib.c +556 -0
  115. package/runtime/xt_stdlib2.c +1043 -0
  116. package/runtime/xt_values.c +291 -0
  117. package/scripts/build-runtime.mjs +8 -1
  118. package/src/ast/common.ts +210 -0
  119. package/src/ast/declarations.ts +130 -0
  120. package/src/ast/expressions.ts +275 -0
  121. package/src/ast/kinds.ts +176 -0
  122. package/src/ast/modules.ts +73 -0
  123. package/src/ast/nodes.ts +11 -1101
  124. package/src/ast/operators.ts +76 -0
  125. package/src/ast/statements.ts +148 -0
  126. package/src/ast/types.ts +173 -0
  127. package/src/binder/binder.ts +196 -0
  128. package/src/codegen/generator/calls.ts +433 -0
  129. package/src/codegen/generator/context.ts +190 -0
  130. package/src/codegen/generator/expressions.ts +508 -0
  131. package/src/codegen/generator/generator.ts +35 -0
  132. package/src/codegen/generator/module.ts +244 -0
  133. package/src/codegen/generator/state.ts +169 -0
  134. package/src/codegen/generator/statements.ts +480 -0
  135. package/src/codegen/generator/tables.ts +206 -0
  136. package/src/codegen/llvm.ts +4 -1720
  137. package/src/driver/compiler.ts +45 -12
  138. package/src/driver/modules.ts +377 -0
  139. package/src/lexer/char.ts +116 -0
  140. package/src/lexer/scanner.ts +9 -109
  141. package/src/parser/context.ts +196 -0
  142. package/src/parser/declarations.ts +502 -0
  143. package/src/parser/expressions.ts +468 -0
  144. package/src/parser/helpers.ts +42 -0
  145. package/src/parser/literals.ts +207 -0
  146. package/src/parser/modules.ts +194 -0
  147. package/src/parser/operators.ts +181 -0
  148. package/src/parser/parser.ts +35 -2373
  149. package/src/parser/speculation.ts +9 -0
  150. package/src/parser/statements.ts +457 -0
  151. package/src/parser/types.ts +365 -0
  152. package/runtime/xt_runtime.c +0 -1372
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Operator taxonomies shared by the parser and code generator.
3
+ */
4
+
5
+ export const enum PrefixUnaryOperator {
6
+ Plus = "+",
7
+ Minus = "-",
8
+ Tilde = "~",
9
+ Exclamation = "!",
10
+ TypeOf = "typeof",
11
+ Void = "void",
12
+ Delete = "delete",
13
+ PlusPlus = "++",
14
+ MinusMinus = "--",
15
+ Await = "await",
16
+ }
17
+
18
+ export const enum PostfixUnaryOperator {
19
+ PlusPlus = "++",
20
+ MinusMinus = "--",
21
+ }
22
+
23
+ export const enum BinaryOperator {
24
+ Add = "+",
25
+ Subtract = "-",
26
+ Multiply = "*",
27
+ Divide = "/",
28
+ Remainder = "%",
29
+ Exponent = "**",
30
+ LessThan = "<",
31
+ LessThanEquals = "<=",
32
+ GreaterThan = ">",
33
+ GreaterThanEquals = ">=",
34
+ EqualsEquals = "==",
35
+ ExclamationEquals = "!=",
36
+ EqualsEqualsEquals = "===",
37
+ ExclamationEqualsEquals = "!==",
38
+ AmpersandAmpersand = "&&",
39
+ BarBar = "||",
40
+ QuestionQuestion = "??",
41
+ Ampersand = "&",
42
+ Bar = "|",
43
+ Caret = "^",
44
+ LessThanLessThan = "<<",
45
+ GreaterThanGreaterThan = ">>",
46
+ GreaterThanGreaterThanGreaterThan = ">>>",
47
+ Comma = ",",
48
+ In = "in",
49
+ InstanceOf = "instanceof",
50
+ }
51
+
52
+ /** Assignment operators, including the compound forms. */
53
+ export const enum AssignmentOperator {
54
+ Assign = "=",
55
+ AddAssign = "+=",
56
+ SubtractAssign = "-=",
57
+ MultiplyAssign = "*=",
58
+ DivideAssign = "/=",
59
+ RemainderAssign = "%=",
60
+ ExponentAssign = "**=",
61
+ LessThanLessThanAssign = "<<=",
62
+ GreaterThanGreaterThanAssign = ">>=",
63
+ GreaterThanGreaterThanGreaterThanAssign = ">>>=",
64
+ AmpersandAssign = "&=",
65
+ BarAssign = "|=",
66
+ CaretAssign = "^=",
67
+ AmpersandAmpersandAssign = "&&=",
68
+ BarBarAssign = "||=",
69
+ QuestionQuestionAssign = "??=",
70
+ }
71
+
72
+ export const enum TypeOperator {
73
+ KeyOf = "keyof",
74
+ Unique = "unique",
75
+ Readonly = "readonly",
76
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Statement nodes of the xbintsc AST.
3
+ */
4
+
5
+ import { SyntaxKind } from "./kinds.js";
6
+ import type { Expression, Modifier, Node, Statement, TypeNode } from "./common.js";
7
+ import type { Identifier } from "./expressions.js";
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Statements
11
+ // ---------------------------------------------------------------------------
12
+
13
+ export interface ExpressionStatement extends Node {
14
+ readonly kind: SyntaxKind.ExpressionStatement;
15
+ readonly expression: Expression;
16
+ }
17
+
18
+ export interface Block extends Node {
19
+ readonly kind: SyntaxKind.Block;
20
+ readonly statements: Statement[];
21
+ }
22
+
23
+ export interface EmptyStatement extends Node {
24
+ readonly kind: SyntaxKind.EmptyStatement;
25
+ }
26
+
27
+ export interface DebuggerStatement extends Node {
28
+ readonly kind: SyntaxKind.DebuggerStatement;
29
+ }
30
+
31
+ export interface VariableDeclaration extends Node {
32
+ readonly kind: SyntaxKind.VariableDeclaration;
33
+ readonly name: Identifier;
34
+ readonly exclamation: boolean;
35
+ readonly type?: TypeNode;
36
+ readonly initializer?: Expression;
37
+ }
38
+
39
+ export interface VariableDeclarationList extends Node {
40
+ readonly kind: SyntaxKind.VariableDeclarationList;
41
+ readonly declarations: VariableDeclaration[];
42
+ readonly declarationKind: "var" | "let" | "const" | "using";
43
+ }
44
+
45
+ export interface VariableStatement extends Node {
46
+ readonly kind: SyntaxKind.VariableStatement;
47
+ readonly declarationList: VariableDeclarationList;
48
+ readonly modifiers: Modifier[];
49
+ }
50
+
51
+ export interface IfStatement extends Node {
52
+ readonly kind: SyntaxKind.IfStatement;
53
+ readonly condition: Expression;
54
+ readonly thenStatement: Statement;
55
+ readonly elseStatement?: Statement;
56
+ }
57
+
58
+ export interface WhileStatement extends Node {
59
+ readonly kind: SyntaxKind.WhileStatement;
60
+ readonly condition: Expression;
61
+ readonly statement: Statement;
62
+ }
63
+
64
+ export interface DoStatement extends Node {
65
+ readonly kind: SyntaxKind.DoStatement;
66
+ readonly condition: Expression;
67
+ readonly statement: Statement;
68
+ }
69
+
70
+ export interface ForStatement extends Node {
71
+ readonly kind: SyntaxKind.ForStatement;
72
+ readonly initializer?: VariableDeclarationList | Expression;
73
+ readonly condition?: Expression;
74
+ readonly incrementor?: Expression;
75
+ readonly statement: Statement;
76
+ }
77
+
78
+ export interface ForOfStatement extends Node {
79
+ readonly kind: SyntaxKind.ForOfStatement;
80
+ readonly initializer: VariableDeclarationList | Expression;
81
+ readonly expression: Expression;
82
+ readonly statement: Statement;
83
+ readonly awaitModifier: boolean;
84
+ }
85
+
86
+ export interface ForInStatement extends Node {
87
+ readonly kind: SyntaxKind.ForInStatement;
88
+ readonly initializer: VariableDeclarationList | Expression;
89
+ readonly expression: Expression;
90
+ readonly statement: Statement;
91
+ }
92
+
93
+ export interface ReturnStatement extends Node {
94
+ readonly kind: SyntaxKind.ReturnStatement;
95
+ readonly expression?: Expression;
96
+ }
97
+
98
+ export interface BreakStatement extends Node {
99
+ readonly kind: SyntaxKind.BreakStatement;
100
+ readonly label?: Identifier;
101
+ }
102
+
103
+ export interface ContinueStatement extends Node {
104
+ readonly kind: SyntaxKind.ContinueStatement;
105
+ readonly label?: Identifier;
106
+ }
107
+
108
+ export interface ThrowStatement extends Node {
109
+ readonly kind: SyntaxKind.ThrowStatement;
110
+ readonly expression: Expression;
111
+ }
112
+
113
+ export interface CatchClause extends Node {
114
+ readonly kind: SyntaxKind.CatchClause;
115
+ readonly variable?: Identifier;
116
+ readonly type?: TypeNode;
117
+ readonly block: Block;
118
+ }
119
+
120
+ export interface TryStatement extends Node {
121
+ readonly kind: SyntaxKind.TryStatement;
122
+ readonly tryBlock: Block;
123
+ readonly catchClause?: CatchClause;
124
+ readonly finallyBlock?: Block;
125
+ }
126
+
127
+ export interface CaseClause extends Node {
128
+ readonly kind: SyntaxKind.CaseClause;
129
+ readonly expression: Expression;
130
+ readonly statements: Statement[];
131
+ }
132
+
133
+ export interface DefaultClause extends Node {
134
+ readonly kind: SyntaxKind.DefaultClause;
135
+ readonly statements: Statement[];
136
+ }
137
+
138
+ export interface SwitchStatement extends Node {
139
+ readonly kind: SyntaxKind.SwitchStatement;
140
+ readonly expression: Expression;
141
+ readonly clauses: (CaseClause | DefaultClause)[];
142
+ }
143
+
144
+ export interface LabeledStatement extends Node {
145
+ readonly kind: SyntaxKind.LabeledStatement;
146
+ readonly label: Identifier;
147
+ readonly statement: Statement;
148
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Type nodes of the xbintsc AST. The parser records type syntax so diagnostics
3
+ * and tooling can see it, but the code generator erases types before lowering.
4
+ */
5
+
6
+ import { SyntaxKind } from "./kinds.js";
7
+ import type { TypeOperator } from "./operators.js";
8
+ import type { Node, TypeNode } from "./common.js";
9
+ import type {
10
+ BooleanLiteral,
11
+ Identifier,
12
+ NullLiteral,
13
+ NumericLiteral,
14
+ StringLiteral,
15
+ ThisExpression,
16
+ PropertyName,
17
+ } from "./expressions.js";
18
+ import type { Parameter, TypeParameterDeclaration } from "./declarations.js";
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Type nodes
22
+ // ---------------------------------------------------------------------------
23
+
24
+ export interface TypeReference extends Node {
25
+ readonly kind: SyntaxKind.TypeReference;
26
+ readonly typeName: Identifier | QualifiedName;
27
+ readonly typeArguments: TypeNode[];
28
+ }
29
+
30
+ export interface QualifiedName extends Node {
31
+ readonly kind: SyntaxKind.QualifiedName;
32
+ readonly left: Identifier | QualifiedName;
33
+ readonly right: Identifier;
34
+ }
35
+
36
+ export interface TypePredicate extends Node {
37
+ readonly kind: SyntaxKind.TypePredicate;
38
+ readonly parameterName: Identifier | ThisExpression;
39
+ readonly type?: TypeNode;
40
+ }
41
+
42
+ export interface KeywordTypeNode extends Node {
43
+ readonly kind:
44
+ | SyntaxKind.AnyKeywordType
45
+ | SyntaxKind.UnknownKeywordType
46
+ | SyntaxKind.NumberKeywordType
47
+ | SyntaxKind.BigIntKeywordType
48
+ | SyntaxKind.StringKeywordType
49
+ | SyntaxKind.BooleanKeywordType
50
+ | SyntaxKind.SymbolKeywordType
51
+ | SyntaxKind.VoidKeywordType
52
+ | SyntaxKind.UndefinedKeywordType
53
+ | SyntaxKind.NullKeywordType
54
+ | SyntaxKind.NeverKeywordType
55
+ | SyntaxKind.ObjectKeywordType
56
+ | SyntaxKind.ThisKeywordType;
57
+ }
58
+
59
+ export interface LiteralTypeNode extends Node {
60
+ readonly kind: SyntaxKind.LiteralType;
61
+ readonly literal: StringLiteral | NumericLiteral | BooleanLiteral | NullLiteral;
62
+ }
63
+
64
+ export interface ArrayTypeNode extends Node {
65
+ readonly kind: SyntaxKind.ArrayType;
66
+ readonly elementType: TypeNode;
67
+ }
68
+
69
+ export interface TupleTypeNode extends Node {
70
+ readonly kind: SyntaxKind.TupleType;
71
+ readonly elements: TypeNode[];
72
+ }
73
+
74
+ export interface UnionTypeNode extends Node {
75
+ readonly kind: SyntaxKind.UnionType;
76
+ readonly types: TypeNode[];
77
+ }
78
+
79
+ export interface IntersectionTypeNode extends Node {
80
+ readonly kind: SyntaxKind.IntersectionType;
81
+ readonly types: TypeNode[];
82
+ }
83
+
84
+ export interface FunctionTypeNode extends Node {
85
+ readonly kind: SyntaxKind.FunctionType;
86
+ readonly typeParameters: TypeParameterDeclaration[];
87
+ readonly parameters: Parameter[];
88
+ readonly returnType: TypeNode;
89
+ }
90
+
91
+ export type TypeElement = PropertySignature | MethodSignature | IndexSignature;
92
+
93
+ export interface PropertySignature extends Node {
94
+ readonly kind: SyntaxKind.PropertySignature;
95
+ readonly name: PropertyName;
96
+ readonly questionToken: boolean;
97
+ readonly readonlyToken: boolean;
98
+ readonly type?: TypeNode;
99
+ }
100
+
101
+ export interface MethodSignature extends Node {
102
+ readonly kind: SyntaxKind.MethodSignature;
103
+ readonly name: PropertyName;
104
+ readonly questionToken: boolean;
105
+ readonly typeParameters: TypeParameterDeclaration[];
106
+ readonly parameters: Parameter[];
107
+ readonly returnType?: TypeNode;
108
+ }
109
+
110
+ export interface IndexSignature extends Node {
111
+ readonly kind: SyntaxKind.IndexSignature;
112
+ readonly parameters: Parameter[];
113
+ readonly type?: TypeNode;
114
+ }
115
+
116
+ export interface TypeLiteralNode extends Node {
117
+ readonly kind: SyntaxKind.TypeLiteral;
118
+ readonly members: TypeElement[];
119
+ }
120
+
121
+ export interface ParenthesizedTypeNode extends Node {
122
+ readonly kind: SyntaxKind.ParenthesizedType;
123
+ readonly type: TypeNode;
124
+ }
125
+
126
+ export interface TypeQueryNode extends Node {
127
+ readonly kind: SyntaxKind.TypeQuery;
128
+ readonly exprName: Identifier | QualifiedName;
129
+ readonly typeArguments: TypeNode[];
130
+ }
131
+
132
+ export interface IndexedAccessTypeNode extends Node {
133
+ readonly kind: SyntaxKind.IndexedAccessType;
134
+ readonly objectType: TypeNode;
135
+ readonly indexType: TypeNode;
136
+ }
137
+
138
+ export interface TypeOperatorNode extends Node {
139
+ readonly kind: SyntaxKind.TypeOperator;
140
+ readonly operator: TypeOperator;
141
+ readonly type: TypeNode;
142
+ }
143
+
144
+ export interface MappedTypeNode extends Node {
145
+ readonly kind: SyntaxKind.MappedType;
146
+ readonly readonlyToken: boolean | "+" | "-";
147
+ readonly typeParameter: TypeParameterDeclaration;
148
+ readonly questionToken: boolean | "+" | "-";
149
+ readonly type?: TypeNode;
150
+ }
151
+
152
+ export interface ConditionalTypeNode extends Node {
153
+ readonly kind: SyntaxKind.ConditionalType;
154
+ readonly checkType: TypeNode;
155
+ readonly extendsType: TypeNode;
156
+ readonly trueType: TypeNode;
157
+ readonly falseType: TypeNode;
158
+ }
159
+
160
+ export interface InferTypeNode extends Node {
161
+ readonly kind: SyntaxKind.InferType;
162
+ readonly typeParameter: TypeParameterDeclaration;
163
+ }
164
+
165
+ export interface OptionalTypeNode extends Node {
166
+ readonly kind: SyntaxKind.OptionalType;
167
+ readonly type: TypeNode;
168
+ }
169
+
170
+ export interface RestTypeNode extends Node {
171
+ readonly kind: SyntaxKind.RestType;
172
+ readonly type: TypeNode;
173
+ }
@@ -9,14 +9,21 @@
9
9
  * cached, serialized for the incremental build, and unit tested in isolation.
10
10
  */
11
11
 
12
+ import { NodeFlags, ModifierKind } from "../ast/kinds.js";
12
13
  import {
13
14
  SyntaxKind,
14
15
  type ArrowFunction,
15
16
  type Block,
17
+ type ClassDeclaration,
18
+ type ClassExpression,
19
+ type ConstructorDeclaration,
16
20
  type FunctionDeclaration,
17
21
  type FunctionExpression,
18
22
  type Identifier,
23
+ type MethodDeclaration,
19
24
  type Node,
25
+ type PropertyDeclaration,
26
+ type PropertyName,
20
27
  type SourceFileNode,
21
28
  type Statement,
22
29
  type Expression,
@@ -76,6 +83,40 @@ export interface FunctionInfo {
76
83
  readonly captureIndex: Map<number, number>;
77
84
  readonly isModule: boolean;
78
85
  readonly isArrow: boolean;
86
+ /** True when the function was declared `async`. */
87
+ readonly isAsync: boolean;
88
+ /** True when this function's body mentions `this` directly. */
89
+ usesThis: boolean;
90
+ /** True when an arrow function must receive `this` from its enclosing scope. */
91
+ capturesThis: boolean;
92
+ /** Set for class methods/constructors; carries the owning class. */
93
+ classInfo?: ClassInfo;
94
+ /** True for `static` class members. */
95
+ isStatic?: boolean;
96
+ /** True for an explicit `constructor`. */
97
+ isConstructor?: boolean;
98
+ }
99
+
100
+ export interface ClassInfo {
101
+ readonly id: number;
102
+ readonly name: string;
103
+ readonly node: Node;
104
+ readonly scope: Scope;
105
+ readonly parent?: ClassInfo;
106
+ readonly parentExpression?: Expression;
107
+ /** `this`-bearing fields declared on the class. */
108
+ readonly fields: ClassFieldInfo[];
109
+ readonly methods: FunctionInfo[];
110
+ readonly statics: FunctionInfo[];
111
+ ctor?: FunctionInfo;
112
+ /** The symbol the class name binds to, when there is one. */
113
+ }
114
+
115
+ export interface ClassFieldInfo {
116
+ readonly name: string;
117
+ readonly initializer: Expression | undefined;
118
+ readonly fn: FunctionInfo;
119
+ readonly isStatic: boolean;
79
120
  }
80
121
 
81
122
  export enum ScopeKind {
@@ -98,6 +139,9 @@ export interface Scope {
98
139
  export interface BindResult {
99
140
  readonly moduleFunction: FunctionInfo;
100
141
  readonly functions: FunctionInfo[];
142
+ readonly classes: ClassInfo[];
143
+ /** Maps a class-like AST node to the ClassInfo the binder built. */
144
+ readonly classOfNode: Map<Node, ClassInfo>;
101
145
  /** Maps a function-like AST node to the FunctionInfo the binder built for it. */
102
146
  readonly functionOfNode: Map<Node, FunctionInfo>;
103
147
  readonly symbolOfDeclaration: Map<Node, SymbolInfo>;
@@ -120,12 +164,15 @@ export function bind(sourceFile: SourceFileNode): BindResult {
120
164
 
121
165
  class Binder {
122
166
  private readonly functions: FunctionInfo[] = [];
167
+ private readonly classes: ClassInfo[] = [];
168
+ private readonly classOfNode = new Map<Node, ClassInfo>();
123
169
  private readonly symbolOfDeclaration = new Map<Node, SymbolInfo>();
124
170
  private readonly symbolOfIdentifier = new Map<Identifier, SymbolInfo>();
125
171
  private readonly scopes = new Map<Node, Scope>();
126
172
  private readonly unresolved: Identifier[] = [];
127
173
  private nextSymbolId = 1;
128
174
  private nextFunctionId = 1;
175
+ private nextClassId = 1;
129
176
  private current!: MutableFunction;
130
177
 
131
178
  constructor(private readonly sourceFile: SourceFileNode) {}
@@ -140,9 +187,22 @@ class Binder {
140
187
  this.collectFunctionScoped(this.sourceFile.statements, this.current);
141
188
  this.bindStatements(this.sourceFile.statements, scope);
142
189
 
190
+ // Arrows inherit `this` lexically: propagate the need to capture it up the
191
+ // chain of arrow functions until reaching a regular function.
192
+ for (let index = this.functions.length - 1; index >= 0; index--) {
193
+ const fn = this.functions[index]! as MutableFunction;
194
+ if (fn.usesThis && fn.isArrow) {
195
+ fn.capturesThis = true;
196
+ const parent = fn.parent as MutableFunction | undefined;
197
+ if (parent && parent.isArrow) parent.usesThis = true;
198
+ }
199
+ }
200
+
143
201
  return {
144
202
  moduleFunction: this.current,
145
203
  functions: this.functions,
204
+ classes: this.classes,
205
+ classOfNode: this.classOfNode,
146
206
  functionOfNode: new Map(this.functions.map((fn) => [fn.node as Node, fn])),
147
207
  symbolOfDeclaration: this.symbolOfDeclaration,
148
208
  symbolOfIdentifier: this.symbolOfIdentifier,
@@ -172,6 +232,9 @@ class Binder {
172
232
  captureIndex: new Map(),
173
233
  isModule,
174
234
  isArrow,
235
+ isAsync: (((node as { flags?: number }).flags ?? 0) & NodeFlags.Async) !== 0,
236
+ usesThis: false,
237
+ capturesThis: false,
175
238
  };
176
239
  this.functions.push(fn);
177
240
  return fn;
@@ -369,6 +432,13 @@ class Binder {
369
432
  case SyntaxKind.Identifier:
370
433
  this.reference(node as Identifier, scope);
371
434
  return;
435
+ case SyntaxKind.ThisKeyword:
436
+ this.current.usesThis = true;
437
+ return;
438
+ case SyntaxKind.ClassDeclaration:
439
+ case SyntaxKind.ClassExpression:
440
+ this.bindClass(node as ClassDeclaration | ClassExpression, scope);
441
+ return;
372
442
  case SyntaxKind.InterfaceDeclaration:
373
443
  case SyntaxKind.TypeAliasDeclaration:
374
444
  // Type-only: skip the body entirely.
@@ -490,7 +560,118 @@ class Binder {
490
560
  this.current = parentFn;
491
561
  }
492
562
 
563
+ private bindClass(node: ClassDeclaration | ClassExpression, scope: Scope): void {
564
+ const parentFn = this.current;
565
+ const name = node.name ? node.name.text : "(anonymous)";
566
+
567
+ let parentExpression: Expression | undefined;
568
+ let parentClass: ClassInfo | undefined;
569
+ const heritage = node.heritage.find((clause) => clause.token === "extends");
570
+ if (heritage && heritage.types.length > 0) {
571
+ parentExpression = heritage.types[0]!.expression;
572
+ this.bindNode(parentExpression, scope);
573
+ if (parentExpression.kind === SyntaxKind.Identifier) {
574
+ const symbol = this.symbolOfIdentifier.get(parentExpression as Identifier);
575
+ const declaration = symbol?.declarations[0];
576
+ if (declaration) parentClass = this.classOfNode.get(declaration);
577
+ }
578
+ }
579
+
580
+ const info: ClassInfo = {
581
+ id: this.nextClassId++,
582
+ name,
583
+ node,
584
+ scope,
585
+ parent: parentClass,
586
+ parentExpression,
587
+ fields: [],
588
+ methods: [],
589
+ statics: [],
590
+ };
591
+ this.classes.push(info);
592
+ this.classOfNode.set(node, info);
593
+
594
+ const classScope = this.createScope(ScopeKind.Block, node, scope);
595
+ this.scopes.set(node, classScope);
596
+
597
+ let constructor: FunctionInfo | undefined;
598
+ for (const member of node.members) {
599
+ if (member.kind === SyntaxKind.ConstructorDeclaration) {
600
+ const ctor = member as ConstructorDeclaration;
601
+ constructor = this.createClassFunction(ctor, "constructor", ctor.parameters, ctor.body, classScope, info, false, true);
602
+ } else if (member.kind === SyntaxKind.MethodDeclaration) {
603
+ const method = member as MethodDeclaration;
604
+ const isStatic = method.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
605
+ const fn = this.createClassFunction(method, classMemberName(method.name), method.parameters, method.body, classScope, info, isStatic, false);
606
+ if (isStatic) (info.statics as FunctionInfo[]).push(fn);
607
+ else (info.methods as FunctionInfo[]).push(fn);
608
+ }
609
+ }
610
+ if (!constructor) {
611
+ constructor = this.createClassFunction(node, "constructor", [], undefined, classScope, info, false, true);
612
+ }
613
+ info.ctor = constructor;
614
+
615
+ // Field initializers run in the constructor's context so they can capture
616
+ // enclosing variables.
617
+ for (const member of node.members) {
618
+ if (member.kind === SyntaxKind.PropertyDeclaration) {
619
+ const property = member as PropertyDeclaration;
620
+ const isStatic = property.modifiers.some((modifier) => modifier.modifierKind === ModifierKind.Static);
621
+ const owner = this.current;
622
+ this.current = constructor as MutableFunction;
623
+ if (property.initializer) this.bindNode(property.initializer, classScope);
624
+ this.current = owner;
625
+ info.fields.push({ name: classMemberName(property.name), initializer: property.initializer, fn: constructor, isStatic });
626
+ }
627
+ }
628
+
629
+ this.current = parentFn;
630
+ }
631
+
632
+ private createClassFunction(
633
+ member: Node,
634
+ name: string,
635
+ parameters: readonly import("../ast/declarations.js").Parameter[],
636
+ body: Block | undefined,
637
+ parentScope: Scope,
638
+ info: ClassInfo,
639
+ isStatic: boolean,
640
+ isConstructor: boolean,
641
+ ): FunctionInfo {
642
+ const parentFn = this.current;
643
+ const fn = this.createFunction(name, member as unknown as FunctionNode, parentFn, false, false);
644
+ (fn as MutableFunction & { classInfo: ClassInfo }).classInfo = info;
645
+ (fn as MutableFunction & { isStatic: boolean }).isStatic = isStatic;
646
+ (fn as MutableFunction & { isConstructor: boolean }).isConstructor = isConstructor;
647
+ this.current = fn as MutableFunction;
648
+ const scope = this.createScope(ScopeKind.Function, member, parentScope);
649
+ (fn as { scope: Scope }).scope = scope;
650
+ this.scopes.set(member, scope);
651
+
652
+ const params: SymbolInfo[] = [];
653
+ for (const parameter of parameters) {
654
+ const paramSymbol = this.declare(parameter.name.text, SymbolKind.Parameter, parameter, scope, true);
655
+ params.push(paramSymbol);
656
+ if (parameter.initializer) this.bindNode(parameter.initializer, scope);
657
+ }
658
+ (fn as { params: SymbolInfo[] }).params = params;
659
+
660
+ if (body) {
661
+ this.collectFunctionScoped([body], fn as MutableFunction);
662
+ this.predeclareStatements(body.statements, scope);
663
+ this.bindStatements(body.statements, scope);
664
+ }
665
+
666
+ this.current = parentFn;
667
+ return fn;
668
+ }
669
+
493
670
  private reference(identifier: Identifier, scope: Scope): void {
671
+ if (identifier.text === "super") {
672
+ this.current.usesThis = true;
673
+ return;
674
+ }
494
675
  let current: Scope | undefined = scope;
495
676
  while (current) {
496
677
  const symbol = current.symbols.get(identifier.text);
@@ -547,3 +728,18 @@ function isCapturable(kind: SymbolKind): boolean {
547
728
  kind === SymbolKind.Parameter
548
729
  );
549
730
  }
731
+
732
+ /** Extract the textual name of a class member (`method`, `"key"`, `0`). */
733
+ function classMemberName(name: PropertyName): string {
734
+ switch (name.kind) {
735
+ case SyntaxKind.Identifier:
736
+ case SyntaxKind.PrivateIdentifier:
737
+ return (name as unknown as { text: string }).text;
738
+ case SyntaxKind.StringLiteral:
739
+ return (name as unknown as { value: string }).value;
740
+ case SyntaxKind.NumericLiteral:
741
+ return String((name as unknown as { value: number }).value);
742
+ default:
743
+ return "";
744
+ }
745
+ }