xbintsc 0.1.3 → 0.1.8
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 +14 -13
- package/dist/src/ast/common.d.ts +33 -0
- package/dist/src/ast/common.js +7 -0
- package/dist/src/ast/common.js.map +1 -0
- package/dist/src/ast/declarations.d.ts +110 -0
- package/dist/src/ast/declarations.js +5 -0
- package/dist/src/ast/declarations.js.map +1 -0
- package/dist/src/ast/expressions.d.ts +219 -0
- package/dist/src/ast/expressions.js +6 -0
- package/dist/src/ast/expressions.js.map +1 -0
- package/dist/src/ast/kinds.d.ts +160 -0
- package/dist/src/ast/kinds.js +171 -0
- package/dist/src/ast/kinds.js.map +1 -0
- package/dist/src/ast/modules.d.ts +61 -0
- package/dist/src/ast/modules.js +5 -0
- package/dist/src/ast/modules.js.map +1 -0
- package/dist/src/ast/nodes.d.ts +11 -839
- package/dist/src/ast/nodes.js +11 -237
- package/dist/src/ast/nodes.js.map +1 -1
- package/dist/src/ast/operators.d.ts +71 -0
- package/dist/src/ast/operators.js +77 -0
- package/dist/src/ast/operators.js.map +1 -0
- package/dist/src/ast/statements.d.ts +120 -0
- package/dist/src/ast/statements.js +5 -0
- package/dist/src/ast/statements.js.map +1 -0
- package/dist/src/ast/types.d.ts +123 -0
- package/dist/src/ast/types.js +6 -0
- package/dist/src/ast/types.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +22 -0
- package/dist/src/codegen/generator/calls.js +301 -0
- package/dist/src/codegen/generator/calls.js.map +1 -0
- package/dist/src/codegen/generator/context.d.ts +45 -0
- package/dist/src/codegen/generator/context.js +128 -0
- package/dist/src/codegen/generator/context.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +22 -0
- package/dist/src/codegen/generator/expressions.js +383 -0
- package/dist/src/codegen/generator/expressions.js.map +1 -0
- package/dist/src/codegen/generator/generator.d.ts +22 -0
- package/dist/src/codegen/generator/generator.js +21 -0
- package/dist/src/codegen/generator/generator.js.map +1 -0
- package/dist/src/codegen/generator/module.d.ts +15 -0
- package/dist/src/codegen/generator/module.js +114 -0
- package/dist/src/codegen/generator/module.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +40 -0
- package/dist/src/codegen/generator/state.js +84 -0
- package/dist/src/codegen/generator/state.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +22 -0
- package/dist/src/codegen/generator/statements.js +425 -0
- package/dist/src/codegen/generator/statements.js.map +1 -0
- package/dist/src/codegen/generator/tables.d.ts +19 -0
- package/dist/src/codegen/generator/tables.js +153 -0
- package/dist/src/codegen/generator/tables.js.map +1 -0
- package/dist/src/codegen/llvm.d.ts +4 -13
- package/dist/src/codegen/llvm.js +4 -1159
- package/dist/src/codegen/llvm.js.map +1 -1
- package/dist/src/driver/compiler.js +13 -4
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/lexer/char.d.ts +78 -0
- package/dist/src/lexer/char.js +106 -0
- package/dist/src/lexer/char.js.map +1 -0
- package/dist/src/lexer/scanner.js +1 -98
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/context.d.ts +58 -0
- package/dist/src/parser/context.js +174 -0
- package/dist/src/parser/context.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +26 -0
- package/dist/src/parser/declarations.js +461 -0
- package/dist/src/parser/declarations.js.map +1 -0
- package/dist/src/parser/expressions.d.ts +27 -0
- package/dist/src/parser/expressions.js +437 -0
- package/dist/src/parser/expressions.js.map +1 -0
- package/dist/src/parser/helpers.d.ts +7 -0
- package/dist/src/parser/helpers.js +36 -0
- package/dist/src/parser/helpers.js.map +1 -0
- package/dist/src/parser/literals.d.ts +16 -0
- package/dist/src/parser/literals.js +193 -0
- package/dist/src/parser/literals.js.map +1 -0
- package/dist/src/parser/modules.d.ts +12 -0
- package/dist/src/parser/modules.js +175 -0
- package/dist/src/parser/modules.js.map +1 -0
- package/dist/src/parser/operators.d.ts +12 -0
- package/dist/src/parser/operators.js +172 -0
- package/dist/src/parser/operators.js.map +1 -0
- package/dist/src/parser/parser.d.ts +17 -122
- package/dist/src/parser/parser.js +18 -2307
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/speculation.d.ts +6 -0
- package/dist/src/parser/speculation.js +10 -0
- package/dist/src/parser/speculation.js.map +1 -0
- package/dist/src/parser/statements.d.ts +28 -0
- package/dist/src/parser/statements.js +402 -0
- package/dist/src/parser/statements.js.map +1 -0
- package/dist/src/parser/types.d.ts +21 -0
- package/dist/src/parser/types.js +338 -0
- package/dist/src/parser/types.js.map +1 -0
- package/dist/tests/e2e/compile.test.js +122 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +9 -1
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/rt.h +32 -0
- package/runtime/rt_internal.h +106 -0
- package/runtime/xt_alloc.c +38 -0
- package/runtime/xt_builtins.c +192 -0
- package/runtime/xt_containers.c +225 -0
- package/runtime/xt_io.c +133 -0
- package/runtime/xt_stdlib.c +502 -0
- package/runtime/xt_values.c +291 -0
- package/scripts/build-runtime.mjs +8 -1
- package/src/ast/common.ts +210 -0
- package/src/ast/declarations.ts +130 -0
- package/src/ast/expressions.ts +275 -0
- package/src/ast/kinds.ts +176 -0
- package/src/ast/modules.ts +73 -0
- package/src/ast/nodes.ts +11 -1101
- package/src/ast/operators.ts +76 -0
- package/src/ast/statements.ts +148 -0
- package/src/ast/types.ts +173 -0
- package/src/codegen/generator/calls.ts +355 -0
- package/src/codegen/generator/context.ts +156 -0
- package/src/codegen/generator/expressions.ts +431 -0
- package/src/codegen/generator/generator.ts +35 -0
- package/src/codegen/generator/module.ts +139 -0
- package/src/codegen/generator/state.ts +126 -0
- package/src/codegen/generator/statements.ts +474 -0
- package/src/codegen/generator/tables.ts +171 -0
- package/src/codegen/llvm.ts +4 -1305
- package/src/driver/compiler.ts +17 -5
- package/src/lexer/char.ts +116 -0
- package/src/lexer/scanner.ts +9 -109
- package/src/parser/context.ts +196 -0
- package/src/parser/declarations.ts +502 -0
- package/src/parser/expressions.ts +465 -0
- package/src/parser/helpers.ts +42 -0
- package/src/parser/literals.ts +207 -0
- package/src/parser/modules.ts +194 -0
- package/src/parser/operators.ts +181 -0
- package/src/parser/parser.ts +35 -2369
- package/src/parser/speculation.ts +9 -0
- package/src/parser/statements.ts +457 -0
- package/src/parser/types.ts +365 -0
- package/runtime/xt_runtime.c +0 -682
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Statement parsing: blocks, control flow, loops, try/catch and the modifier
|
|
3
|
+
* handling shared by declarations.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
7
|
+
import { isOfKeyword, TokenKind } from "../lexer/token.js";
|
|
8
|
+
import {
|
|
9
|
+
ModifierKind,
|
|
10
|
+
SyntaxKind,
|
|
11
|
+
type Block,
|
|
12
|
+
type CatchClause,
|
|
13
|
+
type CaseClause,
|
|
14
|
+
type DefaultClause,
|
|
15
|
+
type Expression,
|
|
16
|
+
type ForInStatement,
|
|
17
|
+
type ForOfStatement,
|
|
18
|
+
type ForStatement,
|
|
19
|
+
type IfStatement,
|
|
20
|
+
type Identifier,
|
|
21
|
+
type Modifier,
|
|
22
|
+
type Statement,
|
|
23
|
+
type SwitchStatement,
|
|
24
|
+
type TryStatement,
|
|
25
|
+
type TypeNode,
|
|
26
|
+
type VariableDeclaration,
|
|
27
|
+
type VariableDeclarationList,
|
|
28
|
+
type VariableStatement,
|
|
29
|
+
} from "../ast/nodes.js";
|
|
30
|
+
import type { Parser } from "./parser.js";
|
|
31
|
+
|
|
32
|
+
export interface StatementMethods {
|
|
33
|
+
tryParseModifiers(this: Parser): Modifier[];
|
|
34
|
+
hasModifier(this: Parser, modifiers: readonly Modifier[], kind: ModifierKind): boolean;
|
|
35
|
+
parseStatement(this: Parser): Statement | undefined;
|
|
36
|
+
parseStatementWithModifiers(this: Parser, modifiers: Modifier[]): Statement;
|
|
37
|
+
parseBlock(this: Parser): Block;
|
|
38
|
+
parseVariableStatement(this: Parser, modifiers: Modifier[]): VariableStatement;
|
|
39
|
+
parseVariableDeclarationList(this: Parser): VariableDeclarationList;
|
|
40
|
+
parseVariableDeclaration(this: Parser): VariableDeclaration;
|
|
41
|
+
parseIfStatement(this: Parser): IfStatement;
|
|
42
|
+
parseWhileStatement(this: Parser): Statement;
|
|
43
|
+
parseDoStatement(this: Parser): Statement;
|
|
44
|
+
parseForStatement(this: Parser): ForStatement | ForOfStatement | ForInStatement;
|
|
45
|
+
parseReturnStatement(this: Parser): Statement;
|
|
46
|
+
parseBreakStatement(this: Parser): Statement;
|
|
47
|
+
parseContinueStatement(this: Parser): Statement;
|
|
48
|
+
parseThrowStatement(this: Parser): Statement;
|
|
49
|
+
parseTryStatement(this: Parser): TryStatement;
|
|
50
|
+
parseSwitchStatement(this: Parser): SwitchStatement;
|
|
51
|
+
parseExpressionStatement(this: Parser): Statement;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const statementMethods: StatementMethods = {
|
|
55
|
+
// -- modifiers ------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
tryParseModifiers(this: Parser): Modifier[] {
|
|
58
|
+
const modifiers: Modifier[] = [];
|
|
59
|
+
for (;;) {
|
|
60
|
+
const kind = this.token.kind;
|
|
61
|
+
let modifierKind: ModifierKind | undefined;
|
|
62
|
+
switch (kind) {
|
|
63
|
+
case TokenKind.ExportKeyword:
|
|
64
|
+
modifierKind = ModifierKind.Export;
|
|
65
|
+
break;
|
|
66
|
+
case TokenKind.DefaultKeyword:
|
|
67
|
+
if (this.atAhead(1, TokenKind.FunctionKeyword) || this.atAhead(1, TokenKind.ClassKeyword)) {
|
|
68
|
+
modifierKind = ModifierKind.Default;
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case TokenKind.DeclareKeyword:
|
|
72
|
+
modifierKind = ModifierKind.Declare;
|
|
73
|
+
break;
|
|
74
|
+
case TokenKind.AbstractKeyword:
|
|
75
|
+
modifierKind = ModifierKind.Abstract;
|
|
76
|
+
break;
|
|
77
|
+
case TokenKind.PublicKeyword:
|
|
78
|
+
modifierKind = ModifierKind.Public;
|
|
79
|
+
break;
|
|
80
|
+
case TokenKind.PrivateKeyword:
|
|
81
|
+
modifierKind = ModifierKind.Private;
|
|
82
|
+
break;
|
|
83
|
+
case TokenKind.ProtectedKeyword:
|
|
84
|
+
modifierKind = ModifierKind.Protected;
|
|
85
|
+
break;
|
|
86
|
+
case TokenKind.StaticKeyword:
|
|
87
|
+
modifierKind = ModifierKind.Static;
|
|
88
|
+
break;
|
|
89
|
+
case TokenKind.ReadonlyKeyword:
|
|
90
|
+
modifierKind = ModifierKind.Readonly;
|
|
91
|
+
break;
|
|
92
|
+
case TokenKind.AsyncKeyword:
|
|
93
|
+
if (!this.lookAhead(1).precededByLineBreak) modifierKind = ModifierKind.Async;
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
if (!modifierKind) break;
|
|
99
|
+
const token = this.nextToken();
|
|
100
|
+
modifiers.push({ kind: SyntaxKind.Unknown, modifierKind, start: token.start, end: token.end });
|
|
101
|
+
}
|
|
102
|
+
return modifiers;
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
hasModifier(this: Parser, modifiers: readonly Modifier[], kind: ModifierKind): boolean {
|
|
106
|
+
return modifiers.some((m) => m.modifierKind === kind);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// -- statements -----------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
parseStatement(this: Parser): Statement | undefined {
|
|
112
|
+
const token = this.token;
|
|
113
|
+
switch (token.kind) {
|
|
114
|
+
case TokenKind.OpenBrace:
|
|
115
|
+
return this.parseBlock();
|
|
116
|
+
case TokenKind.Semicolon: {
|
|
117
|
+
const t = this.nextToken();
|
|
118
|
+
return { kind: SyntaxKind.EmptyStatement, start: t.start, end: t.end } as Statement;
|
|
119
|
+
}
|
|
120
|
+
case TokenKind.VarKeyword:
|
|
121
|
+
case TokenKind.LetKeyword:
|
|
122
|
+
case TokenKind.ConstKeyword:
|
|
123
|
+
return this.parseVariableStatement([]);
|
|
124
|
+
case TokenKind.FunctionKeyword:
|
|
125
|
+
return this.parseFunctionDeclaration([]);
|
|
126
|
+
case TokenKind.AsyncKeyword:
|
|
127
|
+
if (this.atAhead(1, TokenKind.FunctionKeyword) && !this.lookAhead(1).precededByLineBreak) {
|
|
128
|
+
const asyncMod = this.tryParseModifiers();
|
|
129
|
+
return this.parseFunctionDeclaration(asyncMod);
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
case TokenKind.ClassKeyword:
|
|
133
|
+
return this.parseClassDeclaration([]);
|
|
134
|
+
case TokenKind.IfKeyword:
|
|
135
|
+
return this.parseIfStatement();
|
|
136
|
+
case TokenKind.WhileKeyword:
|
|
137
|
+
return this.parseWhileStatement();
|
|
138
|
+
case TokenKind.DoKeyword:
|
|
139
|
+
return this.parseDoStatement();
|
|
140
|
+
case TokenKind.ForKeyword:
|
|
141
|
+
return this.parseForStatement();
|
|
142
|
+
case TokenKind.ReturnKeyword:
|
|
143
|
+
return this.parseReturnStatement();
|
|
144
|
+
case TokenKind.BreakKeyword:
|
|
145
|
+
return this.parseBreakStatement();
|
|
146
|
+
case TokenKind.ContinueKeyword:
|
|
147
|
+
return this.parseContinueStatement();
|
|
148
|
+
case TokenKind.ThrowKeyword:
|
|
149
|
+
return this.parseThrowStatement();
|
|
150
|
+
case TokenKind.TryKeyword:
|
|
151
|
+
return this.parseTryStatement();
|
|
152
|
+
case TokenKind.SwitchKeyword:
|
|
153
|
+
return this.parseSwitchStatement();
|
|
154
|
+
case TokenKind.DebuggerKeyword: {
|
|
155
|
+
const t = this.nextToken();
|
|
156
|
+
this.parseSemicolon();
|
|
157
|
+
return { kind: SyntaxKind.DebuggerStatement, start: t.start, end: t.end } as Statement;
|
|
158
|
+
}
|
|
159
|
+
case TokenKind.ImportKeyword:
|
|
160
|
+
if (this.atAhead(1, TokenKind.OpenParen) || this.atAhead(1, TokenKind.Dot)) break;
|
|
161
|
+
return this.parseImportDeclaration();
|
|
162
|
+
case TokenKind.ExportKeyword:
|
|
163
|
+
return this.parseExportDeclaration();
|
|
164
|
+
case TokenKind.InterfaceKeyword:
|
|
165
|
+
return this.parseInterfaceDeclaration([]);
|
|
166
|
+
case TokenKind.TypeKeyword:
|
|
167
|
+
if (this.isIdentifierLike(this.lookAhead(1))) return this.parseTypeAliasDeclaration([]);
|
|
168
|
+
break;
|
|
169
|
+
case TokenKind.EnumKeyword:
|
|
170
|
+
return this.parseEnumDeclaration([]);
|
|
171
|
+
case TokenKind.NamespaceKeyword:
|
|
172
|
+
case TokenKind.ModuleKeyword:
|
|
173
|
+
return this.parseModuleDeclaration([]);
|
|
174
|
+
case TokenKind.DeclareKeyword: {
|
|
175
|
+
const modifiers = this.tryParseModifiers();
|
|
176
|
+
return this.parseStatementWithModifiers(modifiers);
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
return this.parseExpressionStatement();
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
parseStatementWithModifiers(this: Parser, modifiers: Modifier[]): Statement {
|
|
185
|
+
switch (this.token.kind) {
|
|
186
|
+
case TokenKind.VarKeyword:
|
|
187
|
+
case TokenKind.LetKeyword:
|
|
188
|
+
case TokenKind.ConstKeyword:
|
|
189
|
+
return this.parseVariableStatement(modifiers);
|
|
190
|
+
case TokenKind.FunctionKeyword:
|
|
191
|
+
return this.parseFunctionDeclaration(modifiers);
|
|
192
|
+
case TokenKind.ClassKeyword:
|
|
193
|
+
return this.parseClassDeclaration(modifiers);
|
|
194
|
+
case TokenKind.InterfaceKeyword:
|
|
195
|
+
return this.parseInterfaceDeclaration(modifiers);
|
|
196
|
+
case TokenKind.TypeKeyword:
|
|
197
|
+
return this.parseTypeAliasDeclaration(modifiers);
|
|
198
|
+
case TokenKind.EnumKeyword:
|
|
199
|
+
return this.parseEnumDeclaration(modifiers);
|
|
200
|
+
case TokenKind.NamespaceKeyword:
|
|
201
|
+
case TokenKind.ModuleKeyword:
|
|
202
|
+
return this.parseModuleDeclaration(modifiers);
|
|
203
|
+
default:
|
|
204
|
+
return this.parseExpressionStatement();
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
parseBlock(this: Parser): Block {
|
|
209
|
+
const open = this.parseExpected(TokenKind.OpenBrace);
|
|
210
|
+
const statements: Statement[] = [];
|
|
211
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
212
|
+
const before = this.consumed;
|
|
213
|
+
const s = this.parseStatement();
|
|
214
|
+
if (s) statements.push(s);
|
|
215
|
+
if (this.consumed === before) {
|
|
216
|
+
this.error(DiagnosticCode.UnexpectedToken, `Unexpected token '${this.token.text}'`, this.token);
|
|
217
|
+
this.nextToken();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
221
|
+
return { kind: SyntaxKind.Block, statements, start: open.start, end: close.end };
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
parseVariableStatement(this: Parser, modifiers: Modifier[]): VariableStatement {
|
|
225
|
+
const declList = this.parseVariableDeclarationList();
|
|
226
|
+
this.parseSemicolon();
|
|
227
|
+
return { kind: SyntaxKind.VariableStatement, declarationList: declList, modifiers, start: declList.start, end: declList.end };
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
parseVariableDeclarationList(this: Parser): VariableDeclarationList {
|
|
231
|
+
const keyword = this.nextToken();
|
|
232
|
+
const declarationKind = keyword.kind === TokenKind.ConstKeyword ? "const" : keyword.kind === TokenKind.LetKeyword ? "let" : "var";
|
|
233
|
+
const declarations: VariableDeclaration[] = [];
|
|
234
|
+
do {
|
|
235
|
+
declarations.push(this.parseVariableDeclaration());
|
|
236
|
+
} while (this.at(TokenKind.Comma) && this.nextToken());
|
|
237
|
+
return {
|
|
238
|
+
kind: SyntaxKind.VariableDeclarationList,
|
|
239
|
+
declarations,
|
|
240
|
+
declarationKind,
|
|
241
|
+
start: keyword.start,
|
|
242
|
+
end: declarations[declarations.length - 1]?.end ?? keyword.end,
|
|
243
|
+
};
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
parseVariableDeclaration(this: Parser): VariableDeclaration {
|
|
247
|
+
const name = this.parseIdentifier();
|
|
248
|
+
let exclamation = false;
|
|
249
|
+
if (this.at(TokenKind.Exclamation)) {
|
|
250
|
+
this.nextToken();
|
|
251
|
+
exclamation = true;
|
|
252
|
+
}
|
|
253
|
+
let type: TypeNode | undefined;
|
|
254
|
+
if (this.at(TokenKind.Colon)) {
|
|
255
|
+
this.nextToken();
|
|
256
|
+
type = this.parseType();
|
|
257
|
+
}
|
|
258
|
+
let initializer: Expression | undefined;
|
|
259
|
+
if (this.at(TokenKind.Equals)) {
|
|
260
|
+
this.nextToken();
|
|
261
|
+
initializer = this.parseAssignmentExpression();
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
kind: SyntaxKind.VariableDeclaration,
|
|
265
|
+
name,
|
|
266
|
+
exclamation,
|
|
267
|
+
type,
|
|
268
|
+
initializer,
|
|
269
|
+
start: name.start,
|
|
270
|
+
end: initializer?.end ?? type?.end ?? name.end,
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
parseIfStatement(this: Parser): IfStatement {
|
|
275
|
+
const start = this.parseExpected(TokenKind.IfKeyword).start;
|
|
276
|
+
this.parseExpected(TokenKind.OpenParen);
|
|
277
|
+
const condition = this.parseExpression();
|
|
278
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
279
|
+
const thenStatement = this.parseStatement()!;
|
|
280
|
+
let elseStatement: Statement | undefined;
|
|
281
|
+
if (this.at(TokenKind.ElseKeyword)) {
|
|
282
|
+
this.nextToken();
|
|
283
|
+
elseStatement = this.parseStatement();
|
|
284
|
+
}
|
|
285
|
+
return { kind: SyntaxKind.IfStatement, condition, thenStatement, elseStatement, start, end: elseStatement?.end ?? thenStatement.end };
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
parseWhileStatement(this: Parser): Statement {
|
|
289
|
+
const start = this.parseExpected(TokenKind.WhileKeyword).start;
|
|
290
|
+
this.parseExpected(TokenKind.OpenParen);
|
|
291
|
+
const condition = this.parseExpression();
|
|
292
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
293
|
+
const statement = this.parseStatement()!;
|
|
294
|
+
return { kind: SyntaxKind.WhileStatement, condition, statement, start, end: statement.end } as Statement;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
parseDoStatement(this: Parser): Statement {
|
|
298
|
+
const start = this.parseExpected(TokenKind.DoKeyword).start;
|
|
299
|
+
const statement = this.parseStatement()!;
|
|
300
|
+
this.parseExpected(TokenKind.WhileKeyword);
|
|
301
|
+
this.parseExpected(TokenKind.OpenParen);
|
|
302
|
+
const condition = this.parseExpression();
|
|
303
|
+
const close = this.parseExpected(TokenKind.CloseParen);
|
|
304
|
+
this.parseSemicolon();
|
|
305
|
+
return { kind: SyntaxKind.DoStatement, condition, statement, start, end: close.end } as Statement;
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
parseForStatement(this: Parser): ForStatement | ForOfStatement | ForInStatement {
|
|
309
|
+
const start = this.parseExpected(TokenKind.ForKeyword).start;
|
|
310
|
+
let awaitModifier = false;
|
|
311
|
+
if (this.at(TokenKind.AwaitKeyword)) {
|
|
312
|
+
this.nextToken();
|
|
313
|
+
awaitModifier = true;
|
|
314
|
+
}
|
|
315
|
+
this.parseExpected(TokenKind.OpenParen);
|
|
316
|
+
|
|
317
|
+
let initializer: VariableDeclarationList | Expression | undefined;
|
|
318
|
+
if (!this.at(TokenKind.Semicolon)) {
|
|
319
|
+
if (this.at(TokenKind.VarKeyword) || this.at(TokenKind.LetKeyword) || this.at(TokenKind.ConstKeyword)) {
|
|
320
|
+
initializer = this.parseVariableDeclarationList();
|
|
321
|
+
} else {
|
|
322
|
+
initializer = this.parseExpression(/* noIn */ true);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (isOfKeyword(this.token)) {
|
|
327
|
+
this.nextToken();
|
|
328
|
+
const expression = this.parseAssignmentExpression();
|
|
329
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
330
|
+
const statement = this.parseStatement()!;
|
|
331
|
+
return { kind: SyntaxKind.ForOfStatement, initializer: initializer!, expression, statement, awaitModifier, start, end: statement.end };
|
|
332
|
+
}
|
|
333
|
+
if (this.at(TokenKind.InKeyword)) {
|
|
334
|
+
this.nextToken();
|
|
335
|
+
const expression = this.parseExpression();
|
|
336
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
337
|
+
const statement = this.parseStatement()!;
|
|
338
|
+
return { kind: SyntaxKind.ForInStatement, initializer: initializer!, expression, statement, start, end: statement.end };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
this.parseExpected(TokenKind.Semicolon);
|
|
342
|
+
let condition: Expression | undefined;
|
|
343
|
+
if (!this.at(TokenKind.Semicolon)) condition = this.parseExpression();
|
|
344
|
+
this.parseExpected(TokenKind.Semicolon);
|
|
345
|
+
let incrementor: Expression | undefined;
|
|
346
|
+
if (!this.at(TokenKind.CloseParen)) incrementor = this.parseExpression();
|
|
347
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
348
|
+
const statement = this.parseStatement()!;
|
|
349
|
+
return { kind: SyntaxKind.ForStatement, initializer, condition, incrementor, statement, start, end: statement.end };
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
parseReturnStatement(this: Parser): Statement {
|
|
353
|
+
const start = this.parseExpected(TokenKind.ReturnKeyword).start;
|
|
354
|
+
let expression: Expression | undefined;
|
|
355
|
+
if (!this.at(TokenKind.Semicolon) && !this.canInsertSemicolon()) expression = this.parseExpression();
|
|
356
|
+
this.parseSemicolon();
|
|
357
|
+
return { kind: SyntaxKind.ReturnStatement, expression, start, end: expression?.end ?? start + 6 } as Statement;
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
parseBreakStatement(this: Parser): Statement {
|
|
361
|
+
const start = this.parseExpected(TokenKind.BreakKeyword).start;
|
|
362
|
+
let label: Identifier | undefined;
|
|
363
|
+
if (!this.canInsertSemicolon() && !this.at(TokenKind.Semicolon)) label = this.parseIdentifier();
|
|
364
|
+
this.parseSemicolon();
|
|
365
|
+
return { kind: SyntaxKind.BreakStatement, label, start, end: label?.end ?? start + 5 } as Statement;
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
parseContinueStatement(this: Parser): Statement {
|
|
369
|
+
const start = this.parseExpected(TokenKind.ContinueKeyword).start;
|
|
370
|
+
let label: Identifier | undefined;
|
|
371
|
+
if (!this.canInsertSemicolon() && !this.at(TokenKind.Semicolon)) label = this.parseIdentifier();
|
|
372
|
+
this.parseSemicolon();
|
|
373
|
+
return { kind: SyntaxKind.ContinueStatement, label, start, end: label?.end ?? start + 8 } as Statement;
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
parseThrowStatement(this: Parser): Statement {
|
|
377
|
+
const start = this.parseExpected(TokenKind.ThrowKeyword).start;
|
|
378
|
+
const expression = this.parseExpression();
|
|
379
|
+
this.parseSemicolon();
|
|
380
|
+
return { kind: SyntaxKind.ThrowStatement, expression, start, end: expression.end } as Statement;
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
parseTryStatement(this: Parser): TryStatement {
|
|
384
|
+
const start = this.parseExpected(TokenKind.TryKeyword).start;
|
|
385
|
+
const tryBlock = this.parseBlock();
|
|
386
|
+
let catchClause: CatchClause | undefined;
|
|
387
|
+
if (this.at(TokenKind.CatchKeyword)) {
|
|
388
|
+
const catchStart = this.nextToken().start;
|
|
389
|
+
let variable: Identifier | undefined;
|
|
390
|
+
let type: TypeNode | undefined;
|
|
391
|
+
if (this.at(TokenKind.OpenParen)) {
|
|
392
|
+
this.nextToken();
|
|
393
|
+
variable = this.parseIdentifier();
|
|
394
|
+
if (this.at(TokenKind.Colon)) {
|
|
395
|
+
this.nextToken();
|
|
396
|
+
type = this.parseType();
|
|
397
|
+
}
|
|
398
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
399
|
+
}
|
|
400
|
+
const block = this.parseBlock();
|
|
401
|
+
catchClause = { kind: SyntaxKind.CatchClause, variable, type, block, start: catchStart, end: block.end };
|
|
402
|
+
}
|
|
403
|
+
let finallyBlock: Block | undefined;
|
|
404
|
+
if (this.at(TokenKind.FinallyKeyword)) {
|
|
405
|
+
this.nextToken();
|
|
406
|
+
finallyBlock = this.parseBlock();
|
|
407
|
+
}
|
|
408
|
+
return { kind: SyntaxKind.TryStatement, tryBlock, catchClause, finallyBlock, start, end: finallyBlock?.end ?? catchClause?.end ?? tryBlock.end };
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
parseSwitchStatement(this: Parser): SwitchStatement {
|
|
412
|
+
const start = this.parseExpected(TokenKind.SwitchKeyword).start;
|
|
413
|
+
this.parseExpected(TokenKind.OpenParen);
|
|
414
|
+
const expression = this.parseExpression();
|
|
415
|
+
this.parseExpected(TokenKind.CloseParen);
|
|
416
|
+
this.parseExpected(TokenKind.OpenBrace);
|
|
417
|
+
const clauses: (CaseClause | DefaultClause)[] = [];
|
|
418
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
419
|
+
if (this.at(TokenKind.CaseKeyword)) {
|
|
420
|
+
const caseStart = this.nextToken().start;
|
|
421
|
+
const caseExpression = this.parseExpression();
|
|
422
|
+
this.parseExpected(TokenKind.Colon);
|
|
423
|
+
const statements: Statement[] = [];
|
|
424
|
+
while (
|
|
425
|
+
!this.at(TokenKind.CaseKeyword) &&
|
|
426
|
+
!this.at(TokenKind.DefaultKeyword) &&
|
|
427
|
+
!this.at(TokenKind.CloseBrace) &&
|
|
428
|
+
!this.at(TokenKind.EndOfFile)
|
|
429
|
+
) {
|
|
430
|
+
const s = this.parseStatement();
|
|
431
|
+
if (s) statements.push(s);
|
|
432
|
+
}
|
|
433
|
+
clauses.push({ kind: SyntaxKind.CaseClause, expression: caseExpression, statements, start: caseStart, end: statements[statements.length - 1]?.end ?? caseExpression.end });
|
|
434
|
+
} else if (this.at(TokenKind.DefaultKeyword)) {
|
|
435
|
+
const defaultStart = this.nextToken().start;
|
|
436
|
+
this.parseExpected(TokenKind.Colon);
|
|
437
|
+
const statements: Statement[] = [];
|
|
438
|
+
while (!this.at(TokenKind.CaseKeyword) && !this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
439
|
+
const s = this.parseStatement();
|
|
440
|
+
if (s) statements.push(s);
|
|
441
|
+
}
|
|
442
|
+
clauses.push({ kind: SyntaxKind.DefaultClause, statements, start: defaultStart, end: statements[statements.length - 1]?.end ?? defaultStart });
|
|
443
|
+
} else {
|
|
444
|
+
this.error(DiagnosticCode.UnexpectedToken, `Unexpected token '${this.token.text}' in switch body`);
|
|
445
|
+
this.nextToken();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
449
|
+
return { kind: SyntaxKind.SwitchStatement, expression, clauses, start, end: close.end };
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
parseExpressionStatement(this: Parser): Statement {
|
|
453
|
+
const expression = this.parseExpression();
|
|
454
|
+
this.parseSemicolon();
|
|
455
|
+
return { kind: SyntaxKind.ExpressionStatement, expression, start: expression.start, end: expression.end };
|
|
456
|
+
},
|
|
457
|
+
};
|