better arguments aliasing for arrow functions, add it to block binding - fixes #52

This commit is contained in:
Sebastian McKenzie
2014-10-12 15:32:40 +11:00
parent 6a392be338
commit 73c491ecb4
7 changed files with 111 additions and 28 deletions

View File

@@ -19,8 +19,7 @@ exports.ArrowFunctionExpression = function (node) {
exports.FunctionDeclaration =
exports.FunctionExpression = function (node, parent, opts, generateUid) {
var hasArguments = false;
var id;
var argumentsId;
// traverse the function and find all arrow functions
traverse(node, function (node) {
@@ -28,22 +27,15 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) {
// traverse all child nodes of this arrow function and find a sole arguments
// identifier
traverse(node, function (node, parent) {
if (node.type === "Identifier" && node.name === "arguments" &&
parent.type !== "MemberExpression") {
hasArguments = true;
id = id || b.identifier(generateUid("arguments"));
return id;
}
}, traverse.FUNCTION_TYPES);
argumentsId = util.aliasArguments(generateUid, node, argumentsId);
return false;
}, ["FunctionDeclaration", "FunctionExpression"]);
if (hasArguments) {
if (argumentsId) {
util.ensureBlock(node);
node.body.body.unshift(b.variableDeclaration("var", [
b.variableDeclarator(id, b.identifier("arguments"))
b.variableDeclarator(argumentsId, b.identifier("arguments"))
]));
}
};

View File

@@ -23,8 +23,8 @@ var hasLet = function (nodes) {
return has;
};
exports.Program = function (node) {
if (hasLet(node.body)) node.body = buildNode(node.body).node;
exports.Program = function (node, parent, opts, generateUid) {
if (hasLet(node.body)) node.body = buildNode(node.body, generateUid).node;
};
exports.BlockStatement = function (node, parent, opts, generateUid) {
@@ -35,7 +35,7 @@ exports.BlockStatement = function (node, parent, opts, generateUid) {
var body = node.body;
var built = buildNode(node.body, true);
var built = buildNode(node.body, generateUid);
node.body = built.node;
traverse(built.body, function (node) {
@@ -62,13 +62,13 @@ exports.BlockStatement = function (node, parent, opts, generateUid) {
};
var buildForStatement = function (key) {
return function (node, parent) {
return function (node, parent, opts, generateUid) {
if (isLet(node[key])) {
if (parent.type === "LabeledStatement") {
throw util.errorWithNode(parent, "Label statements not supported with block binding yet.");
}
return buildNode(node).node;
return buildNode(node, generateUid).node;
}
};
};
@@ -76,7 +76,7 @@ var buildForStatement = function (key) {
exports.ForOfStatement = exports.ForInStatement = buildForStatement("left");
exports.ForStatement = buildForStatement("init");
var buildNode = function (node) {
var buildNode = function (node, generateUid) {
var nodes = [];
// hoist normal variable declarations
@@ -113,17 +113,27 @@ var buildNode = function (node) {
//
var argumentsId = util.aliasArguments(generateUid, node);
if (argumentsId) {
nodes.push(b.variableDeclaration("var", [
b.variableDeclarator(argumentsId, b.identifier("arguments"))
]));
}
//
var block = b.blockStatement([]);
block.body = node;
var func = b.functionExpression(null, [], block, false);
//
var templateName = "function-call";
if (traverse.hasType(node, "ThisExpression")) templateName += "-this";
if (traverse.hasType(node, "ReturnStatement", traverse.FUNCTION_TYPES)) templateName += "-return";
//
nodes.push(util.template(templateName, {
FUNCTION: func
}, true));

View File

@@ -212,6 +212,28 @@ exports.parse = function (opts, code, callback) {
}
};
exports.aliasArguments = function (generateUid, node, id) {
var isArgumentIdentifier = function (node) {
return node.type === "Identifier" && node.name === "arguments";
};
var getId = function () {
return id = id || b.identifier(generateUid("arguments"));
};
traverse(node, function (node, parent) {
if (isArgumentIdentifier(node) && parent.type !== "MemberExpression") {
return getId();
} else if (node.type === "MemberExpression" && isArgumentIdentifier(node.object)) {
node.object = getId();
} else {
return;
}
}, traverse.FUNCTION_TYPES);
return id;
};
try {
exports.templates = require("../../templates.json");
} catch (err) {