use a template in tail call transformer - @RReverser
This commit is contained in:
13
lib/6to5/transformation/templates/tail-call-body.js
Normal file
13
lib/6to5/transformation/templates/tail-call-body.js
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
var ARGUMENTS_ID = arguments,
|
||||
THIS_ID = this,
|
||||
SHOULD_CONTINUE_ID,
|
||||
RESULT_ID;
|
||||
|
||||
do {
|
||||
SHOULD_CONTINUE_ID = false;
|
||||
RESULT_ID = FUNCTION.apply(THIS_ID, ARGUMENTS_ID);
|
||||
} while(SHOULD_CONTINUE_ID);
|
||||
|
||||
return RESULT_ID;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
var t = require("../../../types");
|
||||
var util = require("../../../util");
|
||||
var t = require("../../../types");
|
||||
|
||||
function returnBlock(expr) {
|
||||
return t.blockStatement([t.returnStatement(expr)]);
|
||||
@@ -17,6 +18,7 @@ function transformExpression(node, scope, state) {
|
||||
if (!callConsequent && !callAlternate) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if ternary operator had tail recursion in value, convert to optimized if-statement
|
||||
node.type = "IfStatement";
|
||||
node.consequent = callConsequent ? t.toBlock(callConsequent) : returnBlock(node.consequent);
|
||||
@@ -33,6 +35,7 @@ function transformExpression(node, scope, state) {
|
||||
if (!callRight) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cache left value as it might have side-effects
|
||||
var leftId = state.getLeftId();
|
||||
var testExpr = t.assignmentExpression(
|
||||
@@ -47,16 +50,19 @@ function transformExpression(node, scope, state) {
|
||||
|
||||
case "SequenceExpression":
|
||||
var seq = node.expressions;
|
||||
|
||||
// only last element can be optimized
|
||||
var lastCall = subTransform(seq[seq.length - 1]);
|
||||
if (!lastCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove converted expression from sequence
|
||||
// and convert to regular expression if needed
|
||||
if (--seq.length === 1) {
|
||||
node = seq[0];
|
||||
}
|
||||
|
||||
return [t.expressionStatement(node)].concat(lastCall);
|
||||
|
||||
case "CallExpression":
|
||||
@@ -68,12 +74,15 @@ function transformExpression(node, scope, state) {
|
||||
case "call":
|
||||
args = t.arrayExpression(node.arguments.slice(1));
|
||||
break;
|
||||
|
||||
case "apply":
|
||||
args = node.arguments[1] || t.identifier("undefined");
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
thisBinding = node.arguments[0];
|
||||
callee = callee.object;
|
||||
}
|
||||
@@ -91,11 +100,13 @@ function transformExpression(node, scope, state) {
|
||||
state.getArgumentsId(),
|
||||
args || t.arrayExpression(node.arguments)
|
||||
)),
|
||||
|
||||
t.expressionStatement(t.assignmentExpression(
|
||||
"=",
|
||||
state.getThisId(),
|
||||
thisBinding || t.identifier("undefined")
|
||||
)),
|
||||
|
||||
t.returnStatement(t.assignmentExpression(
|
||||
"=",
|
||||
state.getShouldContinueId(),
|
||||
@@ -152,15 +163,19 @@ exports.FunctionExpression = function (node, parent, scope) {
|
||||
var state = {
|
||||
hasTailRecursion: false,
|
||||
ownerId: ownerId,
|
||||
|
||||
getArgumentsId: function () {
|
||||
return argumentsId = argumentsId || scope.generateUidIdentifier("arguments");
|
||||
},
|
||||
|
||||
getThisId: function () {
|
||||
return thisId = thisId || scope.generateUidIdentifier("this");
|
||||
},
|
||||
|
||||
getShouldContinueId: function () {
|
||||
return shouldContinueId = shouldContinueId || scope.generateUidIdentifier("shouldContinue");
|
||||
},
|
||||
|
||||
getLeftId: function () {
|
||||
return leftId = leftId || scope.generateUidIdentifier("left");
|
||||
}
|
||||
@@ -182,32 +197,11 @@ exports.FunctionExpression = function (node, parent, scope) {
|
||||
var resultId = scope.generateUidIdentifier("result");
|
||||
state.getShouldContinueId();
|
||||
|
||||
node.body = t.blockStatement([
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(argumentsId, t.identifier("arguments")),
|
||||
t.variableDeclarator(thisId, t.thisExpression()),
|
||||
t.variableDeclarator(shouldContinueId),
|
||||
t.variableDeclarator(resultId)
|
||||
]),
|
||||
t.doWhileStatement(t.blockStatement([
|
||||
t.expressionStatement(t.assignmentExpression(
|
||||
"=",
|
||||
shouldContinueId,
|
||||
t.literal(false)
|
||||
)),
|
||||
t.expressionStatement(t.assignmentExpression(
|
||||
"=",
|
||||
resultId,
|
||||
t.callExpression(
|
||||
t.memberExpression(
|
||||
t.functionExpression(null, node.params, block),
|
||||
t.identifier("apply"),
|
||||
false
|
||||
),
|
||||
[thisId, argumentsId]
|
||||
)
|
||||
))
|
||||
]), shouldContinueId),
|
||||
t.returnStatement(resultId)
|
||||
]);
|
||||
node.body = util.template("tail-call-body", {
|
||||
SHOULD_CONTINUE_ID: shouldContinueId,
|
||||
ARGUMENTS_ID: argumentsId,
|
||||
RESULT_ID: resultId,
|
||||
FUNCTION: t.functionExpression(null, node.params, block),
|
||||
THIS_ID: thisId,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user