Skip to content

Commit

Permalink
Add support for labeled statements to the parser/AST
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
CountBleck committed Dec 17, 2024
1 parent 40850fe commit 66a29fc
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 28 deletions.
40 changes: 32 additions & 8 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,10 @@ export abstract class Node {

static createBlockStatement(
statements: Statement[],
label: IdentifierExpression | null,
range: Range
): BlockStatement {
return new BlockStatement(statements, range);
return new BlockStatement(statements, label, range);
}

static createBreakStatement(
Expand Down Expand Up @@ -475,9 +476,10 @@ export abstract class Node {
static createDoStatement(
body: Statement,
condition: Expression,
label: IdentifierExpression | null,
range: Range
): DoStatement {
return new DoStatement(body, condition, range);
return new DoStatement(body, condition, label, range);
}

static createEmptyStatement(
Expand Down Expand Up @@ -548,9 +550,10 @@ export abstract class Node {
condition: Expression,
ifTrue: Statement,
ifFalse: Statement | null,
label: IdentifierExpression | null,
range: Range
): IfStatement {
return new IfStatement(condition, ifTrue, ifFalse, range);
return new IfStatement(condition, ifTrue, ifFalse, label, range);
}

static createImportStatement(
Expand Down Expand Up @@ -607,18 +610,20 @@ export abstract class Node {
condition: Expression | null,
incrementor: Expression | null,
body: Statement,
label: IdentifierExpression | null,
range: Range
): ForStatement {
return new ForStatement(initializer, condition, incrementor, body, range);
return new ForStatement(initializer, condition, incrementor, body, label, range);
}

static createForOfStatement(
variable: Statement,
iterable: Expression,
body: Statement,
label: IdentifierExpression | null,
range: Range
): ForOfStatement {
return new ForOfStatement(variable, iterable, body, range);
return new ForOfStatement(variable, iterable, body, label, range);
}

static createFunctionDeclaration(
Expand Down Expand Up @@ -675,9 +680,10 @@ export abstract class Node {
static createSwitchStatement(
condition: Expression,
cases: SwitchCase[],
label: IdentifierExpression | null,
range: Range
): SwitchStatement {
return new SwitchStatement(condition, cases, range);
return new SwitchStatement(condition, cases, label, range);
}

static createSwitchCase(
Expand All @@ -700,9 +706,10 @@ export abstract class Node {
catchVariable: IdentifierExpression | null,
catchStatements: Statement[] | null,
finallyStatements: Statement[] | null,
label: IdentifierExpression | null,
range: Range
): TryStatement {
return new TryStatement(bodyStatements, catchVariable, catchStatements, finallyStatements, range);
return new TryStatement(bodyStatements, catchVariable, catchStatements, finallyStatements, label, range);
}

static createTypeDeclaration(
Expand Down Expand Up @@ -753,9 +760,10 @@ export abstract class Node {
static createWhileStatement(
condition: Expression,
statement: Statement,
label: IdentifierExpression | null,
range: Range
): WhileStatement {
return new WhileStatement(condition, statement, range);
return new WhileStatement(condition, statement, label, range);
}

/** Tests if this node is a literal of the specified kind. */
Expand Down Expand Up @@ -1788,6 +1796,8 @@ export class BlockStatement extends Statement {
constructor(
/** Contained statements. */
public statements: Statement[],
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -1858,6 +1868,8 @@ export class DoStatement extends Statement {
public body: Statement,
/** Condition when to repeat. */
public condition: Expression,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -2022,6 +2034,8 @@ export class ForStatement extends Statement {
public incrementor: Expression | null,
/** Body statement being looped over. */
public body: Statement,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand All @@ -2038,6 +2052,8 @@ export class ForOfStatement extends Statement {
public iterable: Expression,
/** Body statement being looped over. */
public body: Statement,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -2108,6 +2124,8 @@ export class IfStatement extends Statement {
public ifTrue: Statement,
/** Statement executed when condition is `false`. */
public ifFalse: Statement | null,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -2258,6 +2276,8 @@ export class SwitchStatement extends Statement {
public condition: Expression,
/** Contained cases. */
public cases: SwitchCase[],
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -2288,6 +2308,8 @@ export class TryStatement extends Statement {
public catchStatements: Statement[] | null,
/** Statements being executed afterwards, if a `finally` clause is present. */
public finallyStatements: Statement[] | null,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down Expand Up @@ -2382,6 +2404,8 @@ export class WhileStatement extends Statement {
public condition: Expression,
/** Body statement being looped over. */
public body: Statement,
/** Label, if any. */
public label: IdentifierExpression | null,
/** Source range. */
range: Range
) {
Expand Down
1 change: 1 addition & 0 deletions src/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"A class may only extend another class.": 1311,
"A parameter property cannot be declared using a rest parameter.": 1317,
"A default export can only be used in a module.": 1319,
"A label is not allowed here.": 1344,
"An expression of type '{0}' cannot be tested for truthiness.": 1345,
"An identifier or keyword cannot immediately follow a numeric literal.": 1351,

Expand Down
17 changes: 17 additions & 0 deletions src/extra/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ export class ASTBuilder {
let sb = this.sb;
let statements = node.statements;
let numStatements = statements.length;
this.visitLabel(node.label);
if (numStatements) {
sb.push("{\n");
let indentLevel = ++this.indentLevel;
Expand All @@ -815,6 +816,15 @@ export class ASTBuilder {
}
}

private visitLabel(label: IdentifierExpression | null) {
if (!label) return;

let sb = this.sb;
this.visitIdentifierExpression(label);
sb.push(":\n");
indent(sb, this.indentLevel);
}

visitBreakStatement(node: BreakStatement): void {
let label = node.label;
if (label) {
Expand Down Expand Up @@ -908,6 +918,7 @@ export class ASTBuilder {

visitDoStatement(node: DoStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("do ");
this.visitNode(node.body);
if (node.body.kind == NodeKind.Block) {
Expand Down Expand Up @@ -1070,6 +1081,7 @@ export class ASTBuilder {

visitForStatement(node: ForStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("for (");
let initializer = node.initializer;
if (initializer) {
Expand All @@ -1095,6 +1107,7 @@ export class ASTBuilder {

visitForOfStatement(node: ForOfStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("for (");
this.visitNode(node.variable);
sb.push(" of ");
Expand Down Expand Up @@ -1205,6 +1218,7 @@ export class ASTBuilder {

visitIfStatement(node: IfStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("if (");
this.visitNode(node.condition);
sb.push(") ");
Expand Down Expand Up @@ -1397,6 +1411,7 @@ export class ASTBuilder {

visitSwitchStatement(node: SwitchStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("switch (");
this.visitNode(node.condition);
sb.push(") {\n");
Expand All @@ -1418,6 +1433,7 @@ export class ASTBuilder {

visitTryStatement(node: TryStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("try {\n");
let indentLevel = ++this.indentLevel;
let bodyStatements = node.bodyStatements;
Expand Down Expand Up @@ -1528,6 +1544,7 @@ export class ASTBuilder {

visitWhileStatement(node: WhileStatement): void {
let sb = this.sb;
this.visitLabel(node.label);
sb.push("while (");
this.visitNode(node.condition);
let body = node.body;
Expand Down
Loading

0 comments on commit 66a29fc

Please sign in to comment.