remove old tail call transformer
This commit is contained in:
parent
7f61c8b65e
commit
47b803ef24
@ -1,116 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
var t = require("../../../types");
|
|
||||||
|
|
||||||
function transformExpression(node, scope, state) {
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
return (function subTransform(node) {
|
|
||||||
switch (node.type) {
|
|
||||||
case "ConditionalExpression":
|
|
||||||
// any value of ternary operator can be final one
|
|
||||||
subTransform(node.consequent);
|
|
||||||
subTransform(node.alternate);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "LogicalExpression":
|
|
||||||
// only right expression can be final and so optimized
|
|
||||||
subTransform(node.right);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "SequenceExpression":
|
|
||||||
// only last element of sequence can be optimized
|
|
||||||
var seq = node.expressions;
|
|
||||||
subTransform(seq[seq.length - 1]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "CallExpression":
|
|
||||||
var callee = node.callee, thisBinding;
|
|
||||||
var args = [callee];
|
|
||||||
|
|
||||||
// bind `this` to object in member expressions
|
|
||||||
if (t.isMemberExpression(callee)) {
|
|
||||||
var object = state.wrapSideEffect(callee.object);
|
|
||||||
callee.object = object.expr;
|
|
||||||
thisBinding = object.ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.arguments.length > 0 || thisBinding) {
|
|
||||||
args.push(t.arrayExpression(node.arguments));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thisBinding) {
|
|
||||||
args.push(thisBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.callee = state.getHelperRef();
|
|
||||||
node.arguments = args;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
})(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
var functionChildrenVisitor = {
|
|
||||||
enter: function (node, parent, scope, state) {
|
|
||||||
if (t.isReturnStatement(node)) {
|
|
||||||
// prevent entrance by current visitor
|
|
||||||
this.skip();
|
|
||||||
// transform return argument into statement if
|
|
||||||
// it contains tail recursion
|
|
||||||
transformExpression(node.argument, scope, state);
|
|
||||||
} else if (t.isFunction(node)) {
|
|
||||||
// inner function's bodies are irrelevant
|
|
||||||
this.skip();
|
|
||||||
} else if (t.isTryStatement(parent)) {
|
|
||||||
if (node === parent.block) {
|
|
||||||
// `try`-blocks can't be optimized
|
|
||||||
this.skip();
|
|
||||||
} else if (parent.finalizer && node !== parent.finalizer) {
|
|
||||||
// `catch` clause followed by `finally` can't be optimized
|
|
||||||
this.skip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var functionVisitor = {
|
|
||||||
enter: function (node, parent, scope, state) {
|
|
||||||
// traverse all child nodes of this function and find `arguments` and `this`
|
|
||||||
scope.traverse(node, functionChildrenVisitor, state);
|
|
||||||
|
|
||||||
return this.skip();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.FunctionDeclaration =
|
|
||||||
exports.FunctionExpression = function (node, parent, scope, file) {
|
|
||||||
var tempId, helperRef;
|
|
||||||
|
|
||||||
var state = {
|
|
||||||
ownerId: node.id,
|
|
||||||
|
|
||||||
getHelperRef: function () {
|
|
||||||
return helperRef = helperRef || file.addHelper("tail-call");
|
|
||||||
},
|
|
||||||
|
|
||||||
wrapSideEffect: function (node) {
|
|
||||||
if (t.isIdentifier(node) || t.isLiteral(node)) {
|
|
||||||
return {expr: node, ref: node};
|
|
||||||
}
|
|
||||||
tempId = tempId || scope.generateUidIdentifier("temp");
|
|
||||||
return {
|
|
||||||
expr: t.assignmentExpression("=", tempId, node),
|
|
||||||
ref: tempId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// traverse the function and look for tail recursion
|
|
||||||
scope.traverse(node, functionVisitor, state);
|
|
||||||
|
|
||||||
if (tempId) {
|
|
||||||
t.ensureBlock(node).body.unshift(t.variableDeclaration("var", [
|
|
||||||
t.variableDeclarator(tempId)
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
console.log(this, arguments);
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
return Math.random() > 0.5 ? f.call(this, n - 1) : f.apply(this, [n - 1]);
|
|
||||||
})(1e6) === "foo";
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
console.log(this, arguments);
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
return Math.random() > 0.5 ? to5Runtime.tailCall(f.call, [this, n - 1], f) : to5Runtime.tailCall(f.apply, [this, [n - 1]], f);
|
|
||||||
})(1000000) === "foo";
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
function f(n) {
|
|
||||||
return n <= 0 ? "foo" : g(n - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function g(n) {
|
|
||||||
return n <= 0 ? "goo" : f(n - 1);
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
function f(n) {
|
|
||||||
return n <= 0 ? "foo" : to5Runtime.tailCall(g, [n - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function g(n) {
|
|
||||||
return n <= 0 ? "goo" : to5Runtime.tailCall(f, [n - 1]);
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
(function f(n) {
|
|
||||||
return n <= 0 ? "foo" : (doSmth(), getTrueValue() && (getFalseValue() || f(n - 1)));
|
|
||||||
})(1e6, true) === "foo";
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
return n <= 0 ? "foo" : (doSmth(), getTrueValue() && (getFalseValue() || to5Runtime.tailCall(f, [n - 1])));
|
|
||||||
})(1000000, true) === "foo";
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"runtime": true,
|
|
||||||
"blacklist": []
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
(function f(n = getDefaultValue(), /* should be undefined after first pass */ m) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
// Should be clean (undefined) on each pass
|
|
||||||
var local;
|
|
||||||
return f(n - 1);
|
|
||||||
})(1e6, true) === "foo";
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
(function f(_x, /* should be undefined after first pass */m) {
|
|
||||||
var n = arguments[0] === undefined ? getDefaultValue() : arguments[0];
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
// Should be clean (undefined) on each pass
|
|
||||||
var local;
|
|
||||||
return to5Runtime.tailCall(f, [n - 1]);
|
|
||||||
})(1000000, true) === "foo";
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
function f() {
|
|
||||||
return getObj().method();
|
|
||||||
}
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
return getFalseValue() || getValue();
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
function f() {
|
|
||||||
var _temp;
|
|
||||||
return to5Runtime.tailCall((_temp = getObj()).method, [], _temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
function g() {
|
|
||||||
return getFalseValue() || to5Runtime.tailCall(getValue);
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return f(n - 1);
|
|
||||||
} catch (e) {}
|
|
||||||
})(1e6) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
throw new Error();
|
|
||||||
} catch (e) {
|
|
||||||
return f(n - 1);
|
|
||||||
}
|
|
||||||
})(1e6) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
throw new Error();
|
|
||||||
} catch (e) {
|
|
||||||
return f(n - 1);
|
|
||||||
} finally {}
|
|
||||||
})(1e6) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {} finally {
|
|
||||||
return f(n - 1);
|
|
||||||
}
|
|
||||||
})(1e6) === "foo";
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return f(n - 1);
|
|
||||||
} catch (e) {}
|
|
||||||
})(1000000) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
throw new Error();
|
|
||||||
} catch (e) {
|
|
||||||
return to5Runtime.tailCall(f, [n - 1]);
|
|
||||||
}
|
|
||||||
})(1000000) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
throw new Error();
|
|
||||||
} catch (e) {
|
|
||||||
return f(n - 1);
|
|
||||||
} finally {}
|
|
||||||
})(1000000) === "foo";
|
|
||||||
|
|
||||||
(function f(n) {
|
|
||||||
if (n <= 0) {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
try {} finally {
|
|
||||||
return to5Runtime.tailCall(f, [n - 1]);
|
|
||||||
}
|
|
||||||
})(1000000) === "foo";
|
|
||||||
Loading…
x
Reference in New Issue
Block a user