better control flow for tco continuation - fixes #850 and fixes #822

This commit is contained in:
Sebastian McKenzie 2015-02-21 12:27:24 +11:00
parent 8d92a75190
commit 6220fd9fc3
9 changed files with 55 additions and 43 deletions

View File

@ -1,3 +1,4 @@
{
FUNCTION_ID:while (true) BLOCK
var AGAIN_ID = true;
FUNCTION_ID: while (AGAIN_ID) BLOCK
}

View File

@ -1,23 +0,0 @@
(function () {
function Tail(func, args, context) {
this.func = func;
this.args = args;
this.context = context;
}
Tail.prototype._isTailDescriptor = true;
var isRunning = false;
return function (func, args, context) {
var result = new Tail(func, args, context);
if (!isRunning) {
isRunning = true;
do {
result = result.func.apply(result.context, result.args);
} while (result instanceof Tail || (result && result._isTailDescriptor));
isRunning = false;
}
return result;
};
})()

View File

@ -40,6 +40,10 @@ TailCallTransformer.prototype.getFunctionId = function () {
return this.functionId = this.functionId || this.scope.generateUidIdentifier("function");
};
TailCallTransformer.prototype.getAgainId = function () {
return this.againId = this.againId || this.scope.generateUidIdentifier("again");
};
TailCallTransformer.prototype.getParams = function () {
var params = this.params;
@ -112,9 +116,12 @@ TailCallTransformer.prototype.run = function () {
body.unshift(t.variableDeclaration("var", paramDecls));
}
body.push(t.returnStatement());
body.unshift(t.expressionStatement(
t.assignmentExpression("=", this.getAgainId(), t.literal(false)))
);
node.body = util.template("tail-call-body", {
AGAIN_ID: this.getAgainId(),
THIS_ID: this.thisId,
ARGUMENTS_ID: this.argumentsId,
FUNCTION_ID: this.getFunctionId(),
@ -288,6 +295,9 @@ TailCallTransformer.prototype.subTransformCallExpression = function (node) {
}
}
body.push(t.expressionStatement(
t.assignmentExpression("=", this.getAgainId(), t.literal(true))
));
body.push(t.continueStatement(this.getFunctionId()));
return body;

View File

@ -4,7 +4,10 @@
var _this = this,
_arguments = arguments;
_function: while (true) {
var _again = true;
_function: while (_again) {
_again = false;
var n = _x;
if (n <= 0) {
@ -14,10 +17,12 @@
if (Math.random() > 0.5) {
_arguments = [_x = n - 1];
_again = true;
continue _function;
} else {
_arguments = [_x = n - 1];
_again = true;
continue _function;
}return;
}
}
})(1000000) === "foo";

View File

@ -1,10 +1,14 @@
"use strict";
function f() {
_function: while (true) {
var _again = true;
_function: while (_again) {
_again = false;
if (true) {} else {
_again = true;
continue _function;
}
return;
}
}

View File

@ -3,7 +3,10 @@
(function f(_x) {
var _left;
_function: while (true) {
var _again = true;
_function: while (_again) {
_again = false;
var n = _x;
if (n <= 0) {
return "foo";
@ -19,7 +22,8 @@
}
_x = n - 1;
_again = true;
continue _function;
}return;
}
}
})(1000000, true) === "foo";

View File

@ -2,16 +2,19 @@
function fact(_x2) {
var _arguments = arguments;
var _again = true;
_function: while (true) {
_function: while (_again) {
_again = false;
var n = _x2;
acc = undefined;
var acc = _arguments[1] === undefined ? 1 : _arguments[1];
if (n > 1) {
_arguments = [_x2 = n - 1, acc * n];
_again = true;
continue _function;
} else {
return acc;
}return;
}
}
}

View File

@ -2,10 +2,12 @@
(function f(_x2) {
var _arguments = arguments;
var _again = true;
_function: while (true) {
_function: while (_again) {
var g = function g() {};
_again = false;
var n = _x2;
m = local1 = local2 = local3 = undefined;
var m = _arguments[1] === undefined ? getDefaultValue() : _arguments[1];
@ -21,7 +23,7 @@
// `g` should be function here on each pass
g = 123;
_arguments = [_x2 = n - 1];
_again = true;
continue _function;
return;
}
})(1000000, true) === "foo";

View File

@ -11,7 +11,10 @@
})(1000000) === "foo";
(function f(_x) {
_function: while (true) {
var _again = true;
_function: while (_again) {
_again = false;
var n = _x;
if (n <= 0) {
@ -22,9 +25,9 @@
throw new Error();
} catch (e) {
_x = n - 1;
_again = true;
continue _function;
}
return;
}
})(1000000) === "foo";
@ -41,7 +44,10 @@
})(1000000) === "foo";
(function f(_x) {
_function: while (true) {
var _again = true;
_function: while (_again) {
_again = false;
var n = _x;
if (n <= 0) {
@ -50,8 +56,8 @@
try {} finally {
_x = n - 1;
_again = true;
continue _function;
}
return;
}
})(1000000) === "foo";