xbintsc 0.2.4 → 0.2.5
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/dist/src/ast/declarations.d.ts +20 -1
- package/dist/src/ast/kinds.d.ts +5 -1
- package/dist/src/ast/kinds.js +4 -0
- package/dist/src/ast/kinds.js.map +1 -1
- package/dist/src/ast/statements.d.ts +2 -1
- package/dist/src/binder/binder.js +44 -9
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/cli/main.js +2 -4
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/expressions.js +25 -0
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +16 -5
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements.d.ts +4 -1
- package/dist/src/codegen/generator/statements.js +121 -7
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +5 -0
- package/dist/src/driver/compiler.js +26 -0
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/modules.js +29 -4
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/lexer/token.d.ts +10 -0
- package/dist/src/lexer/token.js +69 -0
- package/dist/src/lexer/token.js.map +1 -1
- package/dist/src/parser/context.js +4 -16
- package/dist/src/parser/context.js.map +1 -1
- package/dist/src/parser/declarations.d.ts +2 -0
- package/dist/src/parser/declarations.js +136 -24
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/expressions.js +19 -2
- package/dist/src/parser/expressions.js.map +1 -1
- package/dist/src/parser/helpers.js +2 -0
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/modules.js +7 -2
- package/dist/src/parser/modules.js.map +1 -1
- package/dist/src/parser/statements.js +28 -3
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/src/parser/types.js +5 -0
- package/dist/src/parser/types.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +16 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +13 -1
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +21 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +53 -0
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/xt_stdlib2.c +11 -0
- package/src/ast/declarations.ts +26 -1
- package/src/ast/kinds.ts +4 -0
- package/src/ast/statements.ts +2 -1
- package/src/binder/binder.ts +46 -9
- package/src/cli/main.ts +2 -3
- package/src/codegen/generator/expressions.ts +25 -0
- package/src/codegen/generator/module.ts +19 -6
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/statements.ts +118 -5
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/compiler.ts +29 -0
- package/src/driver/modules.ts +28 -3
- package/src/lexer/token.ts +73 -0
- package/src/parser/context.ts +4 -15
- package/src/parser/declarations.ts +130 -22
- package/src/parser/expressions.ts +19 -3
- package/src/parser/helpers.ts +2 -0
- package/src/parser/modules.ts +7 -2
- package/src/parser/statements.ts +27 -3
- package/src/parser/types.ts +5 -0
package/src/parser/context.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { DiagnosticBag, DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
11
11
|
import type { SourceFile } from "../diagnostics/source.js";
|
|
12
12
|
import { Scanner } from "../lexer/scanner.js";
|
|
13
|
-
import { Token, TokenKind } from "../lexer/token.js";
|
|
13
|
+
import { isIdentifierNameToken, isKeywordKind, Token, TokenKind } from "../lexer/token.js";
|
|
14
14
|
import { SyntaxKind } from "../ast/kinds.js";
|
|
15
15
|
import type { Identifier, StringLiteral } from "../ast/nodes.js";
|
|
16
16
|
import { SpeculationError } from "./speculation.js";
|
|
@@ -121,24 +121,13 @@ export class ParserContext {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
isIdentifierLike(token: Token): boolean {
|
|
124
|
-
|
|
125
|
-
switch (token.kind) {
|
|
126
|
-
case TokenKind.AsKeyword:
|
|
127
|
-
case TokenKind.SatisfiesKeyword:
|
|
128
|
-
case TokenKind.FromKeyword:
|
|
129
|
-
case TokenKind.TypeKeyword:
|
|
130
|
-
case TokenKind.GetKeyword:
|
|
131
|
-
case TokenKind.SetKeyword:
|
|
132
|
-
case TokenKind.AsyncKeyword:
|
|
133
|
-
return true;
|
|
134
|
-
default:
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
124
|
+
return isIdentifierNameToken(token.kind);
|
|
137
125
|
}
|
|
138
126
|
|
|
139
127
|
parseIdentifier(allowKeywords = false): Identifier {
|
|
140
128
|
const token = this.token;
|
|
141
|
-
|
|
129
|
+
const ok = allowKeywords ? isKeywordKind(token.kind) : isIdentifierNameToken(token.kind);
|
|
130
|
+
if (token.kind === TokenKind.Identifier || ok) {
|
|
142
131
|
this.nextToken();
|
|
143
132
|
return { kind: SyntaxKind.Identifier, text: token.text, start: token.start, end: token.end };
|
|
144
133
|
}
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type TypeParameterDeclaration,
|
|
38
38
|
} from "../ast/nodes.js";
|
|
39
39
|
import { expressionToPropertyName } from "./helpers.js";
|
|
40
|
+
import { SpeculationError } from "./speculation.js";
|
|
40
41
|
import type { Parser } from "./parser.js";
|
|
41
42
|
|
|
42
43
|
export interface DeclarationMethods {
|
|
@@ -44,6 +45,8 @@ export interface DeclarationMethods {
|
|
|
44
45
|
parseTypeParameters(this: Parser): TypeParameterDeclaration[];
|
|
45
46
|
parseGreaterThan(this: Parser): void;
|
|
46
47
|
parseParameters(this: Parser): Parameter[];
|
|
48
|
+
parseBindingName(this: Parser): import("../ast/declarations.js").BindingName;
|
|
49
|
+
parseBindingElement(this: Parser, allowPropertyName: boolean): import("../ast/declarations.js").BindingElement;
|
|
47
50
|
parseReturnType(this: Parser): TypeNode;
|
|
48
51
|
parseClassDeclaration(this: Parser, modifiers: Modifier[]): ClassDeclaration;
|
|
49
52
|
parseHeritageClauses(this: Parser): HeritageClause[];
|
|
@@ -153,7 +156,13 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
153
156
|
this.nextToken();
|
|
154
157
|
dotDotDotToken = true;
|
|
155
158
|
}
|
|
156
|
-
|
|
159
|
+
let name: import("../ast/declarations.js").BindingName;
|
|
160
|
+
if (this.at(TokenKind.ThisKeyword)) {
|
|
161
|
+
const thisToken = this.nextToken();
|
|
162
|
+
name = { kind: SyntaxKind.Identifier, text: "this", start: thisToken.start, end: thisToken.end };
|
|
163
|
+
} else {
|
|
164
|
+
name = this.parseBindingName();
|
|
165
|
+
}
|
|
157
166
|
let questionToken = false;
|
|
158
167
|
if (this.at(TokenKind.Question)) {
|
|
159
168
|
this.nextToken();
|
|
@@ -177,6 +186,76 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
177
186
|
return params;
|
|
178
187
|
},
|
|
179
188
|
|
|
189
|
+
parseBindingName(this: Parser): import("../ast/declarations.js").BindingName {
|
|
190
|
+
if (this.at(TokenKind.OpenBracket)) {
|
|
191
|
+
const open = this.nextToken();
|
|
192
|
+
const elements: (import("../ast/declarations.js").BindingElement | undefined)[] = [];
|
|
193
|
+
while (!this.at(TokenKind.CloseBracket) && !this.at(TokenKind.EndOfFile)) {
|
|
194
|
+
if (this.at(TokenKind.Comma)) {
|
|
195
|
+
elements.push(undefined);
|
|
196
|
+
this.nextToken();
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
elements.push(this.parseBindingElement(false));
|
|
200
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
201
|
+
else break;
|
|
202
|
+
}
|
|
203
|
+
const close = this.parseExpected(TokenKind.CloseBracket);
|
|
204
|
+
return { kind: SyntaxKind.ArrayBindingPattern, elements, start: open.start, end: close.end };
|
|
205
|
+
}
|
|
206
|
+
if (this.at(TokenKind.OpenBrace)) {
|
|
207
|
+
const open = this.nextToken();
|
|
208
|
+
const elements: import("../ast/declarations.js").BindingElement[] = [];
|
|
209
|
+
while (!this.at(TokenKind.CloseBrace) && !this.at(TokenKind.EndOfFile)) {
|
|
210
|
+
elements.push(this.parseBindingElement(true));
|
|
211
|
+
if (this.at(TokenKind.Comma)) this.nextToken();
|
|
212
|
+
else break;
|
|
213
|
+
}
|
|
214
|
+
const close = this.parseExpected(TokenKind.CloseBrace);
|
|
215
|
+
return { kind: SyntaxKind.ObjectBindingPattern, elements, start: open.start, end: close.end };
|
|
216
|
+
}
|
|
217
|
+
return this.parseIdentifier();
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
parseBindingElement(this: Parser, allowPropertyName: boolean): import("../ast/declarations.js").BindingElement {
|
|
221
|
+
const start = this.token.start;
|
|
222
|
+
let dotDotDotToken = false;
|
|
223
|
+
if (this.at(TokenKind.DotDotDot)) {
|
|
224
|
+
this.nextToken();
|
|
225
|
+
dotDotDotToken = true;
|
|
226
|
+
}
|
|
227
|
+
let propertyName: PropertyName | undefined;
|
|
228
|
+
let name: import("../ast/declarations.js").BindingName;
|
|
229
|
+
if (allowPropertyName && this.at(TokenKind.OpenBracket)) {
|
|
230
|
+
// Computed property key: `{ [expr]: target }`.
|
|
231
|
+
this.nextToken();
|
|
232
|
+
const expr = this.parseAssignmentExpression();
|
|
233
|
+
this.parseExpected(TokenKind.CloseBracket);
|
|
234
|
+
propertyName = expressionToPropertyName(expr) ?? { kind: SyntaxKind.Identifier, text: "<computed>", start: expr.start, end: expr.end };
|
|
235
|
+
this.parseExpected(TokenKind.Colon);
|
|
236
|
+
name = this.parseBindingName();
|
|
237
|
+
} else if (allowPropertyName && !this.at(TokenKind.OpenBrace) && !this.at(TokenKind.OpenBracket)) {
|
|
238
|
+
const first = this.parseIdentifierName();
|
|
239
|
+
if (this.at(TokenKind.Colon)) {
|
|
240
|
+
this.nextToken();
|
|
241
|
+
propertyName = first;
|
|
242
|
+
name = this.parseBindingName();
|
|
243
|
+
} else {
|
|
244
|
+
name = first;
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
// Array element, or a nested pattern used as an object value.
|
|
248
|
+
name = this.parseBindingName();
|
|
249
|
+
}
|
|
250
|
+
let initializer: Expression | undefined;
|
|
251
|
+
if (this.at(TokenKind.Equals)) {
|
|
252
|
+
this.nextToken();
|
|
253
|
+
initializer = this.parseAssignmentExpression();
|
|
254
|
+
}
|
|
255
|
+
const end = initializer?.end ?? (name.kind === SyntaxKind.Identifier ? name.end : name.end);
|
|
256
|
+
return { kind: SyntaxKind.BindingElement, name, propertyName, dotDotDotToken, initializer, start, end };
|
|
257
|
+
},
|
|
258
|
+
|
|
180
259
|
parseReturnType(this: Parser): TypeNode {
|
|
181
260
|
if (this.at(TokenKind.AssertsKeyword)) {
|
|
182
261
|
const start = this.nextToken().start;
|
|
@@ -249,6 +328,42 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
249
328
|
this.nextToken();
|
|
250
329
|
return undefined;
|
|
251
330
|
}
|
|
331
|
+
if (
|
|
332
|
+
(this.at(TokenKind.GetKeyword) || this.at(TokenKind.SetKeyword)) &&
|
|
333
|
+
!this.atAhead(1, TokenKind.OpenParen) &&
|
|
334
|
+
!this.atAhead(1, TokenKind.Colon) &&
|
|
335
|
+
!this.atAhead(1, TokenKind.Equals) &&
|
|
336
|
+
!this.atAhead(1, TokenKind.Question) &&
|
|
337
|
+
!this.atAhead(1, TokenKind.LessThan) &&
|
|
338
|
+
!this.atAhead(1, TokenKind.Semicolon)
|
|
339
|
+
) {
|
|
340
|
+
const accessorToken = this.nextToken();
|
|
341
|
+
const name = this.parsePropertyName();
|
|
342
|
+
const parameters = this.parseParameters();
|
|
343
|
+
let returnType: TypeNode | undefined;
|
|
344
|
+
if (this.at(TokenKind.Colon)) {
|
|
345
|
+
this.nextToken();
|
|
346
|
+
returnType = this.parseReturnType();
|
|
347
|
+
}
|
|
348
|
+
let body: Block | undefined;
|
|
349
|
+
if (this.at(TokenKind.OpenBrace)) body = this.parseBlock();
|
|
350
|
+
else this.parseSemicolon();
|
|
351
|
+
const accessor: MethodDeclaration = {
|
|
352
|
+
kind: SyntaxKind.MethodDeclaration,
|
|
353
|
+
name,
|
|
354
|
+
modifiers,
|
|
355
|
+
typeParameters: [],
|
|
356
|
+
parameters,
|
|
357
|
+
returnType,
|
|
358
|
+
body,
|
|
359
|
+
flags: NodeFlags.None,
|
|
360
|
+
optional: false,
|
|
361
|
+
accessor: accessorToken.kind === TokenKind.GetKeyword ? "get" : "set",
|
|
362
|
+
start,
|
|
363
|
+
end: body?.end ?? returnType?.end ?? name.end,
|
|
364
|
+
};
|
|
365
|
+
return accessor;
|
|
366
|
+
}
|
|
252
367
|
if (this.at(TokenKind.ConstructorKeyword)) {
|
|
253
368
|
const name = this.nextToken();
|
|
254
369
|
const parameters = this.parseParameters();
|
|
@@ -439,34 +554,27 @@ export const declarationMethods: DeclarationMethods = {
|
|
|
439
554
|
const name: Identifier = { kind: SyntaxKind.Identifier, text: "__call", start, end: start };
|
|
440
555
|
return { kind: SyntaxKind.MethodSignature, name, questionToken: false, typeParameters, parameters, returnType, start, end: returnType?.end ?? start };
|
|
441
556
|
}
|
|
442
|
-
if (this.at(TokenKind.OpenBracket)
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
this.nextToken();
|
|
447
|
-
const parameters: Parameter[] = [];
|
|
448
|
-
let ok = true;
|
|
449
|
-
try {
|
|
557
|
+
if (this.at(TokenKind.OpenBracket)) {
|
|
558
|
+
const indexSignature = this.tryParse<TypeElement>(() => {
|
|
559
|
+
const open = this.nextToken();
|
|
560
|
+
const parameters: Parameter[] = [];
|
|
450
561
|
const paramName = this.parseIdentifier();
|
|
451
|
-
let
|
|
562
|
+
let paramType: TypeNode | undefined;
|
|
452
563
|
if (this.at(TokenKind.Colon)) {
|
|
453
564
|
this.nextToken();
|
|
454
|
-
|
|
455
|
-
} else
|
|
565
|
+
paramType = this.parseType();
|
|
566
|
+
} else {
|
|
567
|
+
throw new SpeculationError();
|
|
568
|
+
}
|
|
456
569
|
this.parseExpected(TokenKind.CloseBracket);
|
|
457
|
-
|
|
458
|
-
} catch {
|
|
459
|
-
ok = false;
|
|
460
|
-
}
|
|
461
|
-
if (ok && this.at(TokenKind.Colon)) {
|
|
570
|
+
if (!this.at(TokenKind.Colon)) throw new SpeculationError();
|
|
462
571
|
this.nextToken();
|
|
463
572
|
const type = this.parseType();
|
|
464
573
|
this.parseSemicolonOrComma();
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
this.scanner.seek(savePos);
|
|
574
|
+
parameters.push({ kind: SyntaxKind.Parameter, name: paramName, modifiers: [], dotDotDotToken: false, questionToken: false, type: paramType, start: paramName.start, end: paramType?.end ?? paramName.end });
|
|
575
|
+
return { kind: SyntaxKind.IndexSignature, parameters, type, start: open.start, end: type.end };
|
|
576
|
+
});
|
|
577
|
+
if (indexSignature) return indexSignature;
|
|
470
578
|
}
|
|
471
579
|
const name = this.parsePropertyName();
|
|
472
580
|
let questionToken = false;
|
|
@@ -180,9 +180,11 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
180
180
|
const t = this.lookAhead(i);
|
|
181
181
|
if (t.kind === TokenKind.EndOfFile) return -1;
|
|
182
182
|
if (t.kind === TokenKind.OpenParen || t.kind === TokenKind.OpenBracket || t.kind === TokenKind.OpenBrace) depth++;
|
|
183
|
-
else if (t.kind === TokenKind.CloseParen || t.kind === TokenKind.CloseBracket || t.kind === TokenKind.CloseBrace)
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
else if (t.kind === TokenKind.CloseParen || t.kind === TokenKind.CloseBracket || t.kind === TokenKind.CloseBrace) {
|
|
184
|
+
if (depth === 0) return -1;
|
|
185
|
+
depth--;
|
|
186
|
+
} else if (t.kind === TokenKind.EqualsGreaterThan && depth === 0) return i;
|
|
187
|
+
else if (depth === 0 && (t.kind === TokenKind.Semicolon || t.kind === TokenKind.Comma)) return -1;
|
|
186
188
|
}
|
|
187
189
|
},
|
|
188
190
|
|
|
@@ -374,7 +376,16 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
374
376
|
case TokenKind.NoSubstitutionTemplateLiteral:
|
|
375
377
|
return this.parseTemplateLiteral();
|
|
376
378
|
case TokenKind.Slash:
|
|
379
|
+
case TokenKind.RegularExpressionLiteral:
|
|
377
380
|
return this.parseRegularExpression();
|
|
381
|
+
case TokenKind.ImportKeyword:
|
|
382
|
+
if (this.atAhead(1, TokenKind.Dot)) {
|
|
383
|
+
const importToken = this.nextToken();
|
|
384
|
+
this.nextToken();
|
|
385
|
+
const metaName = this.parseIdentifierName();
|
|
386
|
+
return { kind: SyntaxKind.Identifier, text: "import.meta", start: importToken.start, end: metaName.end };
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
378
389
|
default:
|
|
379
390
|
break;
|
|
380
391
|
}
|
|
@@ -422,6 +433,11 @@ export const expressionMethods: ExpressionMethods = {
|
|
|
422
433
|
expression = { kind: SyntaxKind.TaggedTemplateExpression, tag: expression, template, start: expression.start, end: template.end };
|
|
423
434
|
continue;
|
|
424
435
|
}
|
|
436
|
+
if (token.kind === TokenKind.Exclamation && !token.precededByLineBreak) {
|
|
437
|
+
this.nextToken();
|
|
438
|
+
expression = { kind: SyntaxKind.NonNullExpression, expression, start: expression.start, end: token.end };
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
425
441
|
return expression;
|
|
426
442
|
}
|
|
427
443
|
},
|
package/src/parser/helpers.ts
CHANGED
package/src/parser/modules.ts
CHANGED
|
@@ -126,6 +126,11 @@ export const moduleMethods: ModuleMethods = {
|
|
|
126
126
|
const assignment: ExportAssignment = { kind: SyntaxKind.ExportAssignment, isExportEquals: false, expression, start, end: expression.end };
|
|
127
127
|
return assignment;
|
|
128
128
|
}
|
|
129
|
+
let isTypeOnly = false;
|
|
130
|
+
if (this.at(TokenKind.TypeKeyword) && (this.atAhead(1, TokenKind.OpenBrace) || this.atAhead(1, TokenKind.Asterisk))) {
|
|
131
|
+
isTypeOnly = true;
|
|
132
|
+
this.nextToken();
|
|
133
|
+
}
|
|
129
134
|
if (this.at(TokenKind.Asterisk)) {
|
|
130
135
|
this.nextToken();
|
|
131
136
|
let nsName: Identifier | undefined;
|
|
@@ -144,7 +149,7 @@ export const moduleMethods: ModuleMethods = {
|
|
|
144
149
|
modifiers: [],
|
|
145
150
|
exportClause: nsName ? { kind: SyntaxKind.NamespaceImport, name: nsName, start: nsName.start, end: nsName.end } : undefined,
|
|
146
151
|
moduleSpecifier,
|
|
147
|
-
isTypeOnly
|
|
152
|
+
isTypeOnly,
|
|
148
153
|
start,
|
|
149
154
|
end: moduleSpecifier?.end ?? nsName?.end ?? start,
|
|
150
155
|
};
|
|
@@ -158,7 +163,7 @@ export const moduleMethods: ModuleMethods = {
|
|
|
158
163
|
if (this.at(TokenKind.StringLiteral)) moduleSpecifier = this.stringLiteralFromToken(this.nextToken());
|
|
159
164
|
}
|
|
160
165
|
this.parseSemicolon();
|
|
161
|
-
const decl: ExportDeclaration = { kind: SyntaxKind.ExportDeclaration, modifiers: [], exportClause: namedExports, moduleSpecifier, isTypeOnly
|
|
166
|
+
const decl: ExportDeclaration = { kind: SyntaxKind.ExportDeclaration, modifiers: [], exportClause: namedExports, moduleSpecifier, isTypeOnly, start, end: moduleSpecifier?.end ?? namedExports.end };
|
|
162
167
|
return decl;
|
|
163
168
|
}
|
|
164
169
|
const modifiers = this.tryParseModifiers();
|
package/src/parser/statements.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { DiagnosticCode } from "../diagnostics/diagnostic.js";
|
|
7
|
-
import { isOfKeyword, TokenKind } from "../lexer/token.js";
|
|
7
|
+
import { isIdentifierNameToken, isKeywordKind, isOfKeyword, TokenKind } from "../lexer/token.js";
|
|
8
8
|
import {
|
|
9
9
|
ModifierKind,
|
|
10
10
|
SyntaxKind,
|
|
@@ -58,6 +58,15 @@ export const statementMethods: StatementMethods = {
|
|
|
58
58
|
const modifiers: Modifier[] = [];
|
|
59
59
|
for (;;) {
|
|
60
60
|
const kind = this.token.kind;
|
|
61
|
+
const nextKind = this.lookAhead(1).kind;
|
|
62
|
+
const nextStartsName =
|
|
63
|
+
isIdentifierNameToken(nextKind) ||
|
|
64
|
+
isKeywordKind(nextKind) ||
|
|
65
|
+
nextKind === TokenKind.OpenBracket ||
|
|
66
|
+
nextKind === TokenKind.StringLiteral ||
|
|
67
|
+
nextKind === TokenKind.NumericLiteral ||
|
|
68
|
+
nextKind === TokenKind.Asterisk ||
|
|
69
|
+
nextKind === TokenKind.OpenBrace;
|
|
61
70
|
let modifierKind: ModifierKind | undefined;
|
|
62
71
|
switch (kind) {
|
|
63
72
|
case TokenKind.ExportKeyword:
|
|
@@ -89,6 +98,9 @@ export const statementMethods: StatementMethods = {
|
|
|
89
98
|
case TokenKind.ReadonlyKeyword:
|
|
90
99
|
modifierKind = ModifierKind.Readonly;
|
|
91
100
|
break;
|
|
101
|
+
case TokenKind.ConstKeyword:
|
|
102
|
+
if (this.atAhead(1, TokenKind.EnumKeyword)) modifierKind = ModifierKind.Const;
|
|
103
|
+
break;
|
|
92
104
|
case TokenKind.AsyncKeyword:
|
|
93
105
|
if (!this.lookAhead(1).precededByLineBreak) modifierKind = ModifierKind.Async;
|
|
94
106
|
break;
|
|
@@ -96,6 +108,10 @@ export const statementMethods: StatementMethods = {
|
|
|
96
108
|
break;
|
|
97
109
|
}
|
|
98
110
|
if (!modifierKind) break;
|
|
111
|
+
// Contextual modifiers (`declare`, `readonly`, `static`, …) are only
|
|
112
|
+
// modifiers when a member/declaration name follows; otherwise they are
|
|
113
|
+
// names themselves (`private declare(...)`, `readonly()`).
|
|
114
|
+
if (modifierKind !== ModifierKind.Export && modifierKind !== ModifierKind.Default && !nextStartsName) break;
|
|
99
115
|
const token = this.nextToken();
|
|
100
116
|
modifiers.push({ kind: SyntaxKind.Unknown, modifierKind, start: token.start, end: token.end });
|
|
101
117
|
}
|
|
@@ -120,6 +136,10 @@ export const statementMethods: StatementMethods = {
|
|
|
120
136
|
case TokenKind.VarKeyword:
|
|
121
137
|
case TokenKind.LetKeyword:
|
|
122
138
|
case TokenKind.ConstKeyword:
|
|
139
|
+
if (this.at(TokenKind.ConstKeyword) && this.atAhead(1, TokenKind.EnumKeyword)) {
|
|
140
|
+
const constToken = this.nextToken();
|
|
141
|
+
return this.parseEnumDeclaration([{ kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Const, start: constToken.start, end: constToken.end }]);
|
|
142
|
+
}
|
|
123
143
|
return this.parseVariableStatement([]);
|
|
124
144
|
case TokenKind.FunctionKeyword:
|
|
125
145
|
return this.parseFunctionDeclaration([]);
|
|
@@ -186,6 +206,10 @@ export const statementMethods: StatementMethods = {
|
|
|
186
206
|
case TokenKind.VarKeyword:
|
|
187
207
|
case TokenKind.LetKeyword:
|
|
188
208
|
case TokenKind.ConstKeyword:
|
|
209
|
+
if (this.at(TokenKind.ConstKeyword) && this.atAhead(1, TokenKind.EnumKeyword)) {
|
|
210
|
+
const constToken = this.nextToken();
|
|
211
|
+
return this.parseEnumDeclaration([...modifiers, { kind: SyntaxKind.Unknown, modifierKind: ModifierKind.Const, start: constToken.start, end: constToken.end }]);
|
|
212
|
+
}
|
|
189
213
|
return this.parseVariableStatement(modifiers);
|
|
190
214
|
case TokenKind.FunctionKeyword:
|
|
191
215
|
return this.parseFunctionDeclaration(modifiers);
|
|
@@ -244,9 +268,9 @@ export const statementMethods: StatementMethods = {
|
|
|
244
268
|
},
|
|
245
269
|
|
|
246
270
|
parseVariableDeclaration(this: Parser): VariableDeclaration {
|
|
247
|
-
const name = this.
|
|
271
|
+
const name = this.parseBindingName();
|
|
248
272
|
let exclamation = false;
|
|
249
|
-
if (this.at(TokenKind.Exclamation)) {
|
|
273
|
+
if (name.kind === SyntaxKind.Identifier && this.at(TokenKind.Exclamation)) {
|
|
250
274
|
this.nextToken();
|
|
251
275
|
exclamation = true;
|
|
252
276
|
}
|
package/src/parser/types.ts
CHANGED
|
@@ -243,6 +243,11 @@ export const typeMethods: TypeMethods = {
|
|
|
243
243
|
const literal: NumericLiteral = { kind: SyntaxKind.NumericLiteral, text: `-${num.text}`, value: -Number(num.value ?? 0), start, end: num.end };
|
|
244
244
|
return { kind: SyntaxKind.LiteralType, literal, start, end: num.end };
|
|
245
245
|
}
|
|
246
|
+
case TokenKind.ConstKeyword: {
|
|
247
|
+
// `as const` const assertion: erased like any other type.
|
|
248
|
+
this.nextToken();
|
|
249
|
+
return { kind: SyntaxKind.AnyKeywordType, start, end: token.end };
|
|
250
|
+
}
|
|
246
251
|
case TokenKind.ImportKeyword: {
|
|
247
252
|
// import("...").T - parse loosely and degrade to `any`.
|
|
248
253
|
this.nextToken();
|