Skip to content

Commit 723e0a8

Browse files
committed
Finished tail call optimizer
1 parent 6940eef commit 723e0a8

File tree

1 file changed

+29
-28
lines changed

1 file changed

+29
-28
lines changed

src/BabelPlugin.js

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
function Plugin(babel) {
22
const t = babel.types;
33
const tryStack = [];
4-
const finalStack = [];
54
// Traverses specific expression types and marks a CallExpression in tail position
65
function markTailCall(expr) {
76
if (expr.type === "CallExpression") {
87
expr.isTailCall = true;
98
} else if (expr.type === "SequenceExpression" && expr.expressions.length > 0) {
109
return markTailCall(expr.expressions[expr.expressions.length - 1]);
1110
} else if (expr.type === "LogicalExpression") {
12-
if (expr.operator === "&&" || expr.operator === "||") {
11+
if (expr.operator === "&&" || expr.operator === "||")
1312
return markTailCall(expr.right);
14-
}
1513
} else if (expr.type === "ConditionalExpression") {
1614
markTailCall(expr.consequent);
1715
return markTailCall(expr.alternate);
1816
}
1917
}
18+
function addTailCallBool(seqExp) {
19+
seqExp.expressions[0].argument.arguments.push(t.booleanLiteral(true));
20+
}
2021
// HzTokens are unique single-instance objects for wrapping user instructions and data.
2122
// Type 1: Invocation Tokens,
2223
// Wrap userland functors and any operands needed to invoke them.
@@ -407,19 +408,19 @@ function Plugin(babel) {
407408
}
408409
if (isTailCall) {
409410
if (tryStack.length > 0) {
410-
const inTryCatch = tryStack[tryStack.length - 1];
411-
if (path.getFunctionParent().node === inTryCatch.function.node) {
412-
if (finalStack.length > 0) {
413-
const inFinalizer = finalStack[finalStack.length - 1];
414-
if ("finalizer" in inTryCatch.node && inFinalizer === inTryCatch.node.finalizer) {
415-
path.node.expressions[0].argument.arguments.push(t.booleanLiteral(true));
416-
}
411+
const tryData = tryStack[tryStack.length - 1];
412+
if (path.getFunctionParent().node === tryData.functionParent) {
413+
if (
414+
tryData.blockType === "finalizer"
415+
|| tryData.blockType === "catch"
416+
) {
417+
addTailCallBool(path.node);
417418
}
418419
} else {
419-
path.node.expressions[0].argument.arguments.push(t.booleanLiteral(true));
420+
addTailCallBool(path.node);
420421
}
421422
} else {
422-
path.node.expressions[0].argument.arguments.push(t.booleanLiteral(true));
423+
addTailCallBool(path.node);
423424
}
424425
}
425426
path.skip();
@@ -449,27 +450,27 @@ function Plugin(babel) {
449450
"BlockStatement": {
450451
// Records entry into the "finalizer" block of a TryStatement
451452
enter: function (path) {
452-
if (tryStack.length > 0) {
453+
if (tryStack.length > 0 && tryStack[tryStack.length - 1].blockType === null) {
453454
const stmtParent = path.getStatementParent();
454-
if (
455-
stmtParent.node.type === "TryStatement"
456-
&& "finalizer" in stmtParent.node
457-
&& stmtParent.node.finalizer === path.node
458-
) {
459-
finalStack.push(path.node);
455+
if (stmtParent.node.type === "TryStatement") {
456+
if (stmtParent.node.finalizer === path.node)
457+
tryStack[tryStack.length - 1].blockType = "finalizer";
458+
else if (stmtParent.node.handler.body === path.node)
459+
tryStack[tryStack.length - 1].blockType = "catch";
460460
}
461461
}
462462
},
463463
// Records exit out of the "finalizer" block of a TryStatement
464464
exit: function (path) {
465-
if (tryStack.length > 0 && finalStack.length > 0) {
465+
if (tryStack.length > 0 && tryStack[tryStack.length - 1].blockType !== null) {
466466
const stmtParent = path.getStatementParent();
467-
if (
468-
stmtParent.node.type === "TryStatement"
469-
&& "finalizer" in stmtParent.node
470-
&& stmtParent.node.finalizer === path.node
471-
) {
472-
finalStack.pop();
467+
if (stmtParent.node.type === "TryStatement") {
468+
if (
469+
stmtParent.node.finalizer === path.node
470+
|| stmtParent.node.handler.body === path.node
471+
) {
472+
tryStack[tryStack.length - 1].blockType = null;
473+
}
473474
}
474475
}
475476
}
@@ -478,8 +479,8 @@ function Plugin(babel) {
478479
// Records entry into a TryStatement
479480
enter: function (path) {
480481
tryStack.push({
481-
node: path.node,
482-
function: path.getFunctionParent()
482+
functionParent: path.getFunctionParent().node,
483+
blockType: null
483484
});
484485
},
485486
// Records exit out of a TryStatement

0 commit comments

Comments
 (0)