Skip to content

Commit

Permalink
Properly track whether break/continue apply to an inner switch or loop (
Browse files Browse the repository at this point in the history
closes #49)
  • Loading branch information
rpetrich committed Nov 20, 2021
1 parent 65791b9 commit d27a1eb
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 17 deletions.
70 changes: 53 additions & 17 deletions async-to-promises.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ interface BreakContinueItem {
identifier: Identifier;
name?: string;
path: NodePath<Statement>;
isAsync: boolean;
}

interface ForToIdentifier {
Expand Down Expand Up @@ -2800,6 +2801,7 @@ export default function ({
exitIdentifier?: Identifier;
breakIdentifiers: BreakContinueItem[];
usedIdentifiers: BreakContinueItem[];
switchCount: number;
}> = {
Function: skipNode,
ReturnStatement(path) {
Expand Down Expand Up @@ -2846,32 +2848,62 @@ export default function ({
}
}
},
SwitchStatement: {
enter() {
this.switchCount++;
},
exit() {
this.switchCount--;
},
},
Loop: {
enter(path) {
const parent = path.parentPath;
this.breakIdentifiers.unshift({
identifier: types.identifier("break"),
path,
name: parent.isLabeledStatement() ? parent.node.label.name : undefined,
isAsync: false,
});
},
exit() {
this.breakIdentifiers.shift();
},
},
BreakStatement(path) {
const replace = returnStatement(undefined, path.node);
const label = path.node.label;
const index = label
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
: 0;
if (index !== -1 && this.breakIdentifiers.length) {
const used = this.breakIdentifiers.slice(0, index + 1);
if (used.length) {
pushMissing(this.usedIdentifiers, used);
path.replaceWithMultiple([
types.expressionStatement(setBreakIdentifiers(used, this.pluginState)),
replace,
]);
return;
if (label || this.switchCount === 0) {
const index = label
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
: 0;
const replace = returnStatement(undefined, path.node);
if (index !== -1 && this.breakIdentifiers.length) {
if (!this.breakIdentifiers[index].isAsync) {
return;
}
const used = this.breakIdentifiers.slice(0, index + 1);
if (used.length) {
pushMissing(this.usedIdentifiers, used);
path.replaceWithMultiple([
types.expressionStatement(setBreakIdentifiers(used, this.pluginState)),
replace,
]);
return;
}
}
path.replaceWith(replace);
}
path.replaceWith(replace);
},
ContinueStatement(path) {
const replace = returnStatement(undefined, path.node);
const label = path.node.label;
const index = label
? this.breakIdentifiers.findIndex((breakIdentifier) => breakIdentifier.name === label.name)
: 0;
const replace = returnStatement(undefined, path.node);
if (index !== -1 && this.breakIdentifiers.length) {
if (!this.breakIdentifiers[index].isAsync) {
return;
}
const used = this.breakIdentifiers.slice(0, index);
if (used.length) {
pushMissing(this.usedIdentifiers, used);
Expand Down Expand Up @@ -2912,6 +2944,7 @@ export default function ({
exitIdentifier,
breakIdentifiers: breakContinueStackForPath(path),
usedIdentifiers,
switchCount: 0,
};
path.traverse(replaceReturnsAndBreaksVisitor, state);
// Add declarations for any new identifiers
Expand Down Expand Up @@ -3014,9 +3047,9 @@ export default function ({
}

// Build the break/continue stack for a path
function breakContinueStackForPath(path: NodePath) {
function breakContinueStackForPath(path: NodePath): BreakContinueItem[] {
let current: NodePath | null = path;
const result = [];
const result = [] as BreakContinueItem[];
while (current && !current.isFunction()) {
if (current.isLoop() || current.isSwitchStatement()) {
const breaks = pathsBreak(current);
Expand All @@ -3029,13 +3062,15 @@ export default function ({
identifier: breakIdentifierForPath(current),
name: current.parentPath.node.label.name,
path: current.parentPath,
isAsync: true,
});
}
current = current.parentPath;
} else if (simpleReferences.length) {
result.push({
identifier: breakIdentifierForPath(current),
path: current,
isAsync: true,
});
}
}
Expand All @@ -3046,6 +3081,7 @@ export default function ({
identifier: breakIdentifierForPath(current.get("body")),
name: current.node.label.name,
path: current,
isAsync: true,
});
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/break in switch statement/hoisted.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/break in switch statement/inlined.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions tests/break in switch statement/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
async function() {
await sleep(1000)
const errorCode = 2;

let message = 'Something wrong';

switch (errorCode) {
case 2:
message = "Error 2";
break;
}

for (;;) {
break;
}

alert(message);
}
3 changes: 3 additions & 0 deletions tests/break in switch statement/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"supportedBabels": ["babel 7"]
}
1 change: 1 addition & 0 deletions tests/break in switch statement/output.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d27a1eb

Please sign in to comment.