diff --git a/lib/6to5/transformation/templates/tail-call-body.js b/lib/6to5/transformation/templates/tail-call-body.js index c2366a8cb6..2b6d268851 100644 --- a/lib/6to5/transformation/templates/tail-call-body.js +++ b/lib/6to5/transformation/templates/tail-call-body.js @@ -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; diff --git a/lib/6to5/transformation/transformers/es6/tail-call.js b/lib/6to5/transformation/transformers/es6/tail-call.js index b8dfba2418..426a23fc2c 100644 --- a/lib/6to5/transformation/transformers/es6/tail-call.js +++ b/lib/6to5/transformation/transformers/es6/tail-call.js @@ -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, }); diff --git a/test/fixtures/transformation/es6-tail-call/call-apply/expected.js b/test/fixtures/transformation/es6-tail-call/call-apply/expected.js index 56732fe861..240150ccdc 100755 --- a/test/fixtures/transformation/es6-tail-call/call-apply/expected.js +++ b/test/fixtures/transformation/es6-tail-call/call-apply/expected.js @@ -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"; \ No newline at end of file diff --git a/test/fixtures/transformation/es6-tail-call/expressions/expected.js b/test/fixtures/transformation/es6-tail-call/expressions/expected.js index b00fec1a5b..0ac2e1625c 100755 --- a/test/fixtures/transformation/es6-tail-call/expressions/expected.js +++ b/test/fixtures/transformation/es6-tail-call/expressions/expected.js @@ -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"; \ No newline at end of file diff --git a/test/fixtures/transformation/es6-tail-call/recursion/expected.js b/test/fixtures/transformation/es6-tail-call/recursion/expected.js index 1f5e8fcaf5..a38d339867 100755 --- a/test/fixtures/transformation/es6-tail-call/recursion/expected.js +++ b/test/fixtures/transformation/es6-tail-call/recursion/expected.js @@ -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"; \ No newline at end of file diff --git a/test/fixtures/transformation/es6-tail-call/try-catch/expected.js b/test/fixtures/transformation/es6-tail-call/try-catch/expected.js index cc8434fd01..fc4ac975cf 100755 --- a/test/fixtures/transformation/es6-tail-call/try-catch/expected.js +++ b/test/fixtures/transformation/es6-tail-call/try-catch/expected.js @@ -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"; \ No newline at end of file