Skip to content

Commit 66a29fc

Browse files
committed
Add support for labeled statements to the parser/AST
This is a prerequisite for supporting labeled breaks/continues. Clearly unusable labels, such as `x: let foo = 1;` report an error by default, similar to TS's behavior.
1 parent 40850fe commit 66a29fc

File tree

4 files changed

+112
-28
lines changed

4 files changed

+112
-28
lines changed

src/ast.ts

+32-8
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,10 @@ export abstract class Node {
440440

441441
static createBlockStatement(
442442
statements: Statement[],
443+
label: IdentifierExpression | null,
443444
range: Range
444445
): BlockStatement {
445-
return new BlockStatement(statements, range);
446+
return new BlockStatement(statements, label, range);
446447
}
447448

448449
static createBreakStatement(
@@ -475,9 +476,10 @@ export abstract class Node {
475476
static createDoStatement(
476477
body: Statement,
477478
condition: Expression,
479+
label: IdentifierExpression | null,
478480
range: Range
479481
): DoStatement {
480-
return new DoStatement(body, condition, range);
482+
return new DoStatement(body, condition, label, range);
481483
}
482484

483485
static createEmptyStatement(
@@ -548,9 +550,10 @@ export abstract class Node {
548550
condition: Expression,
549551
ifTrue: Statement,
550552
ifFalse: Statement | null,
553+
label: IdentifierExpression | null,
551554
range: Range
552555
): IfStatement {
553-
return new IfStatement(condition, ifTrue, ifFalse, range);
556+
return new IfStatement(condition, ifTrue, ifFalse, label, range);
554557
}
555558

556559
static createImportStatement(
@@ -607,18 +610,20 @@ export abstract class Node {
607610
condition: Expression | null,
608611
incrementor: Expression | null,
609612
body: Statement,
613+
label: IdentifierExpression | null,
610614
range: Range
611615
): ForStatement {
612-
return new ForStatement(initializer, condition, incrementor, body, range);
616+
return new ForStatement(initializer, condition, incrementor, body, label, range);
613617
}
614618

615619
static createForOfStatement(
616620
variable: Statement,
617621
iterable: Expression,
618622
body: Statement,
623+
label: IdentifierExpression | null,
619624
range: Range
620625
): ForOfStatement {
621-
return new ForOfStatement(variable, iterable, body, range);
626+
return new ForOfStatement(variable, iterable, body, label, range);
622627
}
623628

624629
static createFunctionDeclaration(
@@ -675,9 +680,10 @@ export abstract class Node {
675680
static createSwitchStatement(
676681
condition: Expression,
677682
cases: SwitchCase[],
683+
label: IdentifierExpression | null,
678684
range: Range
679685
): SwitchStatement {
680-
return new SwitchStatement(condition, cases, range);
686+
return new SwitchStatement(condition, cases, label, range);
681687
}
682688

683689
static createSwitchCase(
@@ -700,9 +706,10 @@ export abstract class Node {
700706
catchVariable: IdentifierExpression | null,
701707
catchStatements: Statement[] | null,
702708
finallyStatements: Statement[] | null,
709+
label: IdentifierExpression | null,
703710
range: Range
704711
): TryStatement {
705-
return new TryStatement(bodyStatements, catchVariable, catchStatements, finallyStatements, range);
712+
return new TryStatement(bodyStatements, catchVariable, catchStatements, finallyStatements, label, range);
706713
}
707714

708715
static createTypeDeclaration(
@@ -753,9 +760,10 @@ export abstract class Node {
753760
static createWhileStatement(
754761
condition: Expression,
755762
statement: Statement,
763+
label: IdentifierExpression | null,
756764
range: Range
757765
): WhileStatement {
758-
return new WhileStatement(condition, statement, range);
766+
return new WhileStatement(condition, statement, label, range);
759767
}
760768

761769
/** Tests if this node is a literal of the specified kind. */
@@ -1788,6 +1796,8 @@ export class BlockStatement extends Statement {
17881796
constructor(
17891797
/** Contained statements. */
17901798
public statements: Statement[],
1799+
/** Label, if any. */
1800+
public label: IdentifierExpression | null,
17911801
/** Source range. */
17921802
range: Range
17931803
) {
@@ -1858,6 +1868,8 @@ export class DoStatement extends Statement {
18581868
public body: Statement,
18591869
/** Condition when to repeat. */
18601870
public condition: Expression,
1871+
/** Label, if any. */
1872+
public label: IdentifierExpression | null,
18611873
/** Source range. */
18621874
range: Range
18631875
) {
@@ -2022,6 +2034,8 @@ export class ForStatement extends Statement {
20222034
public incrementor: Expression | null,
20232035
/** Body statement being looped over. */
20242036
public body: Statement,
2037+
/** Label, if any. */
2038+
public label: IdentifierExpression | null,
20252039
/** Source range. */
20262040
range: Range
20272041
) {
@@ -2038,6 +2052,8 @@ export class ForOfStatement extends Statement {
20382052
public iterable: Expression,
20392053
/** Body statement being looped over. */
20402054
public body: Statement,
2055+
/** Label, if any. */
2056+
public label: IdentifierExpression | null,
20412057
/** Source range. */
20422058
range: Range
20432059
) {
@@ -2108,6 +2124,8 @@ export class IfStatement extends Statement {
21082124
public ifTrue: Statement,
21092125
/** Statement executed when condition is `false`. */
21102126
public ifFalse: Statement | null,
2127+
/** Label, if any. */
2128+
public label: IdentifierExpression | null,
21112129
/** Source range. */
21122130
range: Range
21132131
) {
@@ -2258,6 +2276,8 @@ export class SwitchStatement extends Statement {
22582276
public condition: Expression,
22592277
/** Contained cases. */
22602278
public cases: SwitchCase[],
2279+
/** Label, if any. */
2280+
public label: IdentifierExpression | null,
22612281
/** Source range. */
22622282
range: Range
22632283
) {
@@ -2288,6 +2308,8 @@ export class TryStatement extends Statement {
22882308
public catchStatements: Statement[] | null,
22892309
/** Statements being executed afterwards, if a `finally` clause is present. */
22902310
public finallyStatements: Statement[] | null,
2311+
/** Label, if any. */
2312+
public label: IdentifierExpression | null,
22912313
/** Source range. */
22922314
range: Range
22932315
) {
@@ -2382,6 +2404,8 @@ export class WhileStatement extends Statement {
23822404
public condition: Expression,
23832405
/** Body statement being looped over. */
23842406
public body: Statement,
2407+
/** Label, if any. */
2408+
public label: IdentifierExpression | null,
23852409
/** Source range. */
23862410
range: Range
23872411
) {

src/diagnosticMessages.json

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
"A class may only extend another class.": 1311,
126126
"A parameter property cannot be declared using a rest parameter.": 1317,
127127
"A default export can only be used in a module.": 1319,
128+
"A label is not allowed here.": 1344,
128129
"An expression of type '{0}' cannot be tested for truthiness.": 1345,
129130
"An identifier or keyword cannot immediately follow a numeric literal.": 1351,
130131

src/extra/ast.ts

+17
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ export class ASTBuilder {
801801
let sb = this.sb;
802802
let statements = node.statements;
803803
let numStatements = statements.length;
804+
this.visitLabel(node.label);
804805
if (numStatements) {
805806
sb.push("{\n");
806807
let indentLevel = ++this.indentLevel;
@@ -815,6 +816,15 @@ export class ASTBuilder {
815816
}
816817
}
817818

819+
private visitLabel(label: IdentifierExpression | null) {
820+
if (!label) return;
821+
822+
let sb = this.sb;
823+
this.visitIdentifierExpression(label);
824+
sb.push(":\n");
825+
indent(sb, this.indentLevel);
826+
}
827+
818828
visitBreakStatement(node: BreakStatement): void {
819829
let label = node.label;
820830
if (label) {
@@ -908,6 +918,7 @@ export class ASTBuilder {
908918

909919
visitDoStatement(node: DoStatement): void {
910920
let sb = this.sb;
921+
this.visitLabel(node.label);
911922
sb.push("do ");
912923
this.visitNode(node.body);
913924
if (node.body.kind == NodeKind.Block) {
@@ -1070,6 +1081,7 @@ export class ASTBuilder {
10701081

10711082
visitForStatement(node: ForStatement): void {
10721083
let sb = this.sb;
1084+
this.visitLabel(node.label);
10731085
sb.push("for (");
10741086
let initializer = node.initializer;
10751087
if (initializer) {
@@ -1095,6 +1107,7 @@ export class ASTBuilder {
10951107

10961108
visitForOfStatement(node: ForOfStatement): void {
10971109
let sb = this.sb;
1110+
this.visitLabel(node.label);
10981111
sb.push("for (");
10991112
this.visitNode(node.variable);
11001113
sb.push(" of ");
@@ -1205,6 +1218,7 @@ export class ASTBuilder {
12051218

12061219
visitIfStatement(node: IfStatement): void {
12071220
let sb = this.sb;
1221+
this.visitLabel(node.label);
12081222
sb.push("if (");
12091223
this.visitNode(node.condition);
12101224
sb.push(") ");
@@ -1397,6 +1411,7 @@ export class ASTBuilder {
13971411

13981412
visitSwitchStatement(node: SwitchStatement): void {
13991413
let sb = this.sb;
1414+
this.visitLabel(node.label);
14001415
sb.push("switch (");
14011416
this.visitNode(node.condition);
14021417
sb.push(") {\n");
@@ -1418,6 +1433,7 @@ export class ASTBuilder {
14181433

14191434
visitTryStatement(node: TryStatement): void {
14201435
let sb = this.sb;
1436+
this.visitLabel(node.label);
14211437
sb.push("try {\n");
14221438
let indentLevel = ++this.indentLevel;
14231439
let bodyStatements = node.bodyStatements;
@@ -1528,6 +1544,7 @@ export class ASTBuilder {
15281544

15291545
visitWhileStatement(node: WhileStatement): void {
15301546
let sb = this.sb;
1547+
this.visitLabel(node.label);
15311548
sb.push("while (");
15321549
this.visitNode(node.condition);
15331550
let body = node.body;

0 commit comments

Comments
 (0)