babel-plugin-tailcall-optimization
Advanced tools
Comparing version 1.0.9 to 1.0.10
@@ -10,27 +10,3 @@ 'use strict'; | ||
function findTailCalls(fnPath, fnName) { | ||
var inFunctionTraversal = { | ||
ReturnStatement: function ReturnStatement(path) { | ||
if (path.node.argument.type === 'CallExpression' && path.node.argument.callee.name === this.functionName) { | ||
this.tc = path; | ||
} | ||
}, | ||
FunctionDeclaration: function FunctionDeclaration(path) { | ||
this.needsClosure = true; | ||
}, | ||
ArrowFunctionExpression: function ArrowFunctionExpression(path) { | ||
this.needsClosure = true; | ||
}, | ||
FunctionExpression: function FunctionExpression(path) { | ||
this.needsClosure = true; | ||
} | ||
}; | ||
var traverseContext = { tc: null, functionName: fnName }; | ||
fnPath.traverse(inFunctionTraversal, traverseContext); | ||
return { tailCalls: traverseContext.tc, needsClosure: traverseContext.needsClosure }; | ||
} | ||
function optimizeTailCalls(functionPath, tailCall, needsClosure) { | ||
function optimizeTailCalls(functionPath, tailCalls) { | ||
var repeatId = functionPath.scope.generateUidIdentifier('repeat'); | ||
@@ -54,13 +30,15 @@ var repeatDeclaration = t.variableDeclaration('var', [t.variableDeclarator(repeatId, t.booleanLiteral(true))]); | ||
// first we assign to tmp variable... | ||
var assignmentsToTmpInputs = tmpInputVariables.map(function (tmpInputVar, index) { | ||
return t.assignmentExpression('=', tmpInputVar, tailCall.node.argument.arguments[index]); | ||
tailCalls.forEach(function (tailCall) { | ||
// first we assign to tmp variable... | ||
var assignmentsToTmpInputs = tmpInputVariables.map(function (tmpInputVar, index) { | ||
return t.assignmentExpression('=', tmpInputVar, tailCall.node.argument.arguments[index]); | ||
}); | ||
// and then we do a swap | ||
var swapTmpInputWithInput = inputVariables.map(function (inputVar, index) { | ||
return t.assignmentExpression('=', inputVar, tmpInputVariables[index]); | ||
}); | ||
tailCall.replaceWithMultiple([].concat(_toConsumableArray(assignmentsToTmpInputs), _toConsumableArray(swapTmpInputWithInput), [setRepeatToTrue, t.continueStatement()])); | ||
}); | ||
// and then we do a swap | ||
var swapTmpInputWithInput = inputVariables.map(function (inputVar, index) { | ||
return t.assignmentExpression('=', inputVar, tmpInputVariables[index]); | ||
}); | ||
tailCall.replaceWithMultiple([].concat(_toConsumableArray(assignmentsToTmpInputs), _toConsumableArray(swapTmpInputWithInput), [setRepeatToTrue, t.continueStatement()])); | ||
var body = functionPath.get('body'); | ||
@@ -84,3 +62,3 @@ | ||
if (tailCalls) { | ||
if (tailCalls.length > 0 && !needsClosure) { | ||
optimizeTailCalls(path, tailCalls, needsClosure); | ||
@@ -101,3 +79,3 @@ } | ||
if (tailCalls && !needsClosure) { | ||
if (tailCalls.length > 0 && !needsClosure) { | ||
// @todo for now when closure is detected skip TCO - we should implement it also in that case | ||
@@ -119,2 +97,4 @@ optimizeTailCalls(functionBody, tailCalls, needsClosure); | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
var findTailCalls = require('./findTailCalls'); |
{ | ||
"name": "babel-plugin-tailcall-optimization", | ||
"version": "1.0.9", | ||
"version": "1.0.10", | ||
"description": "Tail call optimization for JavaScript!", | ||
@@ -5,0 +5,0 @@ "main": "build/lib.js", |
@@ -8,7 +8,11 @@ # babel-plugin-tailcall-optimization | ||
`npm install babel-plugin-tailcall-optimization --save-dev` | ||
```bash | ||
npm install babel-plugin-tailcall-optimization --save-dev | ||
``` | ||
and add to your `.babelrc`: | ||
`"plugins": ["tailcall-optimization"]` | ||
```js | ||
"plugins": ["tailcall-optimization"] | ||
``` | ||
@@ -18,3 +22,3 @@ | ||
We rewrite functions with tail calls to ones using while loops. Original function with tail call: | ||
``` | ||
```js | ||
function counter (n, acc = 0) { | ||
@@ -30,3 +34,3 @@ if (n === 0) { | ||
gets rewritten to this: | ||
``` | ||
```js | ||
function counter(n, acc = 0) { | ||
@@ -68,2 +72,4 @@ var _repeat = true; | ||
## Known issues | ||
Currently when plugin detects function creation within tailcalled function it does not optimize it. It's releated to this bug in old babel implementation: https://phabricator.babeljs.io/T6869 | ||
Currently when plugin detects function creation within tailcalled function it does not optimize it. It's releated to this bug in old babel implementation: https://phabricator.babeljs.io/T6869 | ||
It does not work for mutual recursive functions. I guess it's not super big problem - even JVM does not do this. |
46088
13
93
72