Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

break: Add support for labeled statements, breaks, and continues #2891

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
CountBleck committed Dec 17, 2024
commit 66a29fc6df1550c9ae9ce456c212da3a804b8fac
40 changes: 32 additions & 8 deletions src/ast.ts
Original file line number Diff line number Diff line change
@@ -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(
@@ -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(
@@ -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(
@@ -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(
@@ -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(
@@ -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(
@@ -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. */
@@ -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
) {
@@ -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
) {
@@ -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
) {
@@ -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
) {
@@ -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
) {
@@ -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
) {
@@ -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
) {
@@ -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
) {
1 change: 1 addition & 0 deletions src/diagnosticMessages.json
Original file line number Diff line number Diff line change
@@ -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,

17 changes: 17 additions & 0 deletions src/extra/ast.ts
Original file line number Diff line number Diff line change
@@ -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;
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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 ");
@@ -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(") ");
@@ -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");
@@ -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;
@@ -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;
Loading