clean up tail call transformer

This commit is contained in:
Sebastian McKenzie 2015-02-08 22:47:50 +11:00
parent 9020a21ba2
commit ee5cb8d9ed
6 changed files with 166 additions and 155 deletions

View File

@ -4,9 +4,11 @@
SHOULD_CONTINUE_ID,
RESULT_ID;
var CALLEE_ID = FUNCTION;
do {
SHOULD_CONTINUE_ID = false;
RESULT_ID = FUNCTION.apply(THIS_ID, ARGUMENTS_ID);
RESULT_ID = CALLEE_ID.apply(THIS_ID, ARGUMENTS_ID);
} while(SHOULD_CONTINUE_ID);
return RESULT_ID;

View File

@ -43,9 +43,11 @@ function transformExpression(node, scope, state) {
leftId,
node.left
);
if (node.operator === "&&") {
testExpr = t.unaryExpression("!", testExpr);
}
return [t.ifStatement(testExpr, returnBlock(leftId))].concat(callRight);
case "SequenceExpression":
@ -122,21 +124,17 @@ var functionChildrenVisitor = {
if (t.isReturnStatement(node)) {
// prevent entrance by current visitor
this.skip();
// transform return argument into statement if
// it contains tail recursion
return transformExpression(node.argument, scope, state);
} else if (t.isFunction(node)) {
return this.skip();
this.skip();
} else if (t.isTryStatement(parent)) {
if (node === parent.block) {
return this.skip();
} else if (node === parent.finalizer) {
return;
} else {
if (parent.finalizer) {
this.skip();
}
return;
this.skip();
} else if (parent.finalizer && node !== parent.finalizer) {
this.skip();
}
}
}
@ -201,6 +199,7 @@ exports.FunctionExpression = function (node, parent, scope) {
SHOULD_CONTINUE_ID: shouldContinueId,
ARGUMENTS_ID: argumentsId,
RESULT_ID: resultId,
CALLEE_ID: scope.generateUidIdentifier("callee"),
FUNCTION: t.functionExpression(null, node.params, block),
THIS_ID: thisId,
});

View File

@ -1,27 +1,29 @@
"use strict";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
do {
_shouldContinue = false;
_result = (function (n) {
if (n <= 0) {
console.log(this, arguments);
return "foo";
}
if (Math.random() > 0.5) {
_arguments = [n - 1];
_this = this;
return _shouldContinue = true;
} else {
_arguments = [n - 1];
_this = this;
return _shouldContinue = true;
}
}).apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000) === "foo";
"use strict";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
var _callee = function (n) {
if (n <= 0) {
console.log(this, arguments);
return "foo";
}
if (Math.random() > 0.5) {
_arguments = [n - 1];
_this = this;
return _shouldContinue = true;
} else {
_arguments = [n - 1];
_this = this;
return _shouldContinue = true;
}
};
do {
_shouldContinue = false;
_result = _callee.apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000) === "foo";

View File

@ -1,30 +1,32 @@
"use strict";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
do {
_shouldContinue = false;
_result = (function (n) {
var _left;
if (n <= 0) {
return "foo";
} else {
doSmth();
if (!(_left = getTrueValue())) {
return _left;
}
if (_left = getFalseValue()) {
return _left;
}
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
}).apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000, true) === "foo";
"use strict";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
var _callee = function (n) {
var _left;
if (n <= 0) {
return "foo";
} else {
doSmth();
if (!(_left = getTrueValue())) {
return _left;
}
if (_left = getFalseValue()) {
return _left;
}
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
};
do {
_shouldContinue = false;
_result = _callee.apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000, true) === "foo";

View File

@ -1,23 +1,25 @@
"use strict";
(function f(_x, /* should be undefined after first pass */m) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
do {
_shouldContinue = false;
_result = (function (_x, m) {
var n = arguments[0] === undefined ? getDefaultValue() : arguments[0];
if (n <= 0) {
return "foo";
}
// Should be clean (undefined) on each pass
var local;
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}).apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000, true) === "foo";
"use strict";
(function f(_x, /* should be undefined after first pass */m) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
var _callee = function (_x, m) {
var n = arguments[0] === undefined ? getDefaultValue() : arguments[0];
if (n <= 0) {
return "foo";
}
// Should be clean (undefined) on each pass
var local;
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
};
do {
_shouldContinue = false;
_result = _callee.apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000, true) === "foo";

View File

@ -1,65 +1,69 @@
"use strict";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
return f(n - 1);
} catch (e) {}
})(1000000) === "foo";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
do {
_shouldContinue = false;
_result = (function (n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
}).apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(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) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
do {
_shouldContinue = false;
_result = (function (n) {
if (n <= 0) {
return "foo";
}
try {} finally {
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
}).apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000) === "foo";
"use strict";
(function f(n) {
if (n <= 0) {
return "foo";
}
try {
return f(n - 1);
} catch (e) {}
})(1000000) === "foo";
(function f(n) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
var _callee = function (n) {
if (n <= 0) {
return "foo";
}
try {
throw new Error();
} catch (e) {
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
};
do {
_shouldContinue = false;
_result = _callee.apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(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) {
var _arguments = arguments,
_this = this,
_shouldContinue,
_result;
var _callee = function (n) {
if (n <= 0) {
return "foo";
}
try {} finally {
_arguments = [n - 1];
_this = undefined;
return _shouldContinue = true;
}
};
do {
_shouldContinue = false;
_result = _callee.apply(_this, _arguments);
} while (_shouldContinue);
return _result;
})(1000000) === "foo";