implement Scope so we can keep track of references to avoid collisions when generating ids

This commit is contained in:
Sebastian McKenzie
2014-11-04 12:46:47 +11:00
parent 5f9710e61f
commit d28496006e
8 changed files with 91 additions and 32 deletions

View File

@@ -134,7 +134,19 @@ File.prototype.generate = function () {
return result;
};
File.prototype.generateUid = function (name) {
File.prototype.generateUid = function (name, scope) {
if (scope) {
var uid;
do {
uid = this._generateUid(name);
} while (scope.has(uid));
return uid;
} else {
return this._generateUid(name);
}
};
File.prototype._generateUid = function (name) {
// replace all non-valid identifiers with dashes
name = name.replace(/[^a-zA-Z0-9]/g, "-");

44
lib/6to5/scope.js Normal file
View File

@@ -0,0 +1,44 @@
module.exports = Scope;
var traverse = require("./traverse");
var t = require("./types");
var _ = require("lodash");
function Scope(parent, block) {
this.parent = parent;
var ids = [];
if (t.isBlockStatement(block)) {
_.each(block.body, function (node) {
if (t.isVariableDeclaration(node)) {
ids = ids.concat(t.getIds(node));
}
});
}
if (t.isProgram(block) || t.isFunction(block)) {
traverse(block, function (node) {
if (t.isVariableDeclaration(node)) {
ids = ids.concat(t.getIds(node));
} else if (t.isFunction(node)) {
return false;
}
});
}
if (t.isFunction(block)) {
_.each(block.params, function (param) {
ids = ids.concat(t.getIds(param));
});
}
this.ids = ids;
}
Scope.prototype.has = function (id) {
if (!id) return false;
if (_.contains(this.ids, id)) return true;
if (this.parent) return this.parent.has(id);
return false;
};

View File

@@ -1,16 +1,16 @@
var traverse = require("../traverse");
var t = require("../types");
var go = function (getBody, node, file) {
var go = function (getBody, node, file, scope) {
var argumentsId;
var thisId;
var getArgumentsId = function () {
return argumentsId = argumentsId || t.identifier(file.generateUid("arguments"));
return argumentsId = argumentsId || t.identifier(file.generateUid("arguments", scope));
};
var getThisId = function () {
return thisId = thisId || t.identifier(file.generateUid("this"));
return thisId = thisId || t.identifier(file.generateUid("this", scope));
};
// traverse the function and find all alias functions so we can alias
@@ -70,16 +70,16 @@ var go = function (getBody, node, file) {
}
};
exports.Program = function (node, parent, file) {
exports.Program = function (node, parent, file, scope) {
go(function () {
return node.body;
}, node, file);
}, node, file, scope);
};
exports.FunctionDeclaration =
exports.FunctionExpression = function (node, parent, file) {
exports.FunctionExpression = function (node, parent, file, scope) {
go(function () {
t.ensureBlock(node);
return node.body.body;
}, node, file);
}, node, file, scope);
};

View File

@@ -3,14 +3,14 @@ var util = require("../util");
var t = require("../types");
var _ = require("lodash");
exports.ClassDeclaration = function (node, parent, file) {
exports.ClassDeclaration = function (node, parent, file, scope) {
return t.variableDeclaration("var", [
t.variableDeclarator(node.id, buildClass(node, file))
t.variableDeclarator(node.id, buildClass(node, file, scope))
]);
};
exports.ClassExpression = function (node, parent, file) {
return buildClass(node, file);
exports.ClassExpression = function (node, parent, file, scope) {
return buildClass(node, file, scope);
};
var getMemberExpressionObject = function (node) {
@@ -20,9 +20,9 @@ var getMemberExpressionObject = function (node) {
return node;
};
var buildClass = function (node, file) {
var buildClass = function (node, file, scope) {
var superName = node.superClass;
var className = node.id || t.identifier(file.generateUid("class"));
var className = node.id || t.identifier(file.generateUid("class", scope));
var superClassArgument = node.superClass;
var superClassCallee = node.superClass;
@@ -32,7 +32,7 @@ var buildClass = function (node, file) {
superClassArgument = superClassCallee = getMemberExpressionObject(superName);
} else if (!t.isIdentifier(superName)) {
superClassArgument = superName;
superClassCallee = superName = t.identifier(file.generateUid("ref"));
superClassCallee = superName = t.identifier(file.generateUid("ref", scope));
}
}

View File

@@ -19,7 +19,7 @@ exports.ForStatement = function (node, parent, file) {
_.each(node.body, function (child) {
if (child && t.isVariableDeclaration(child) && child.kind === "const") {
_.each(child.declarations, function (declar) {
_.each(util.getIds(declar.id), function (name) {
_.each(t.getIds(declar.id), function (name) {
check(declar, name);
constants.push(name);
});

View File

@@ -45,7 +45,7 @@ var pushArrayPattern = function (kind, nodes, pattern, parentId) {
});
};
var pushPattern = function (kind, nodes, pattern, parentId, file) {
var pushPattern = function (kind, nodes, pattern, parentId, file, scope) {
if (parentId.type !== "MemberExpression" && parentId.type !== "Identifier") {
var key = t.identifier(file.generateUid("ref"));
@@ -60,14 +60,14 @@ var pushPattern = function (kind, nodes, pattern, parentId, file) {
};
exports.ForInStatement =
exports.ForOfStatement = function (node, parent, file) {
exports.ForOfStatement = function (node, parent, file, scope) {
var declar = node.left;
if (declar.type !== "VariableDeclaration") return;
var pattern = declar.declarations[0].id;
if (!t.isPattern(pattern)) return;
var key = t.identifier(file.generateUid("ref"));
var key = t.identifier(file.generateUid("ref", scope));
node.left = t.variableDeclaration(declar.kind, [
t.variableDeclarator(key, null)
]);
@@ -82,7 +82,7 @@ exports.ForOfStatement = function (node, parent, file) {
block.body = nodes.concat(block.body);
};
exports.Function = function (node, parent, file) {
exports.Function = function (node, parent, file, scope) {
var nodes = [];
var hasDestructuring = false;
@@ -91,8 +91,8 @@ exports.Function = function (node, parent, file) {
if (!t.isPattern(pattern)) return pattern;
hasDestructuring = true;
var parentId = t.identifier(file.generateUid("ref"));
pushPattern("var", nodes, pattern, parentId, file);
var parentId = t.identifier(file.generateUid("ref", scope));
pushPattern("var", nodes, pattern, parentId, file, scope);
return parentId;
});
@@ -104,7 +104,7 @@ exports.Function = function (node, parent, file) {
block.body = nodes.concat(block.body);
};
exports.ExpressionStatement = function (node, parent, file) {
exports.ExpressionStatement = function (node, parent, file, scope) {
var expr = node.expression;
if (expr.type !== "AssignmentExpression") return;
@@ -112,7 +112,7 @@ exports.ExpressionStatement = function (node, parent, file) {
var nodes = [];
var ref = t.identifier(file.generateUid("ref"));
var ref = t.identifier(file.generateUid("ref", scope));
nodes.push(t.variableDeclaration("var", [
t.variableDeclarator(ref, expr.right)
]));
@@ -122,7 +122,7 @@ exports.ExpressionStatement = function (node, parent, file) {
return nodes;
};
exports.VariableDeclaration = function (node, parent, file) {
exports.VariableDeclaration = function (node, parent, file, scope) {
if (t.isForInStatement(parent)) return;
var nodes = [];
@@ -140,7 +140,7 @@ exports.VariableDeclaration = function (node, parent, file) {
var patternId = declar.init;
var pattern = declar.id;
if (t.isPattern(pattern) && patternId) {
pushPattern(node.kind, nodes, pattern, patternId, file);
pushPattern(node.kind, nodes, pattern, patternId, file, scope);
} else {
nodes.push(buildVariableAssign(node.kind, declar.id, declar.init));
}

View File

@@ -1,11 +1,11 @@
var util = require("../util");
var t = require("../types");
exports.ForOfStatement = function (node, parent, file) {
exports.ForOfStatement = function (node, parent, file, scope) {
var left = node.left;
var declar;
var stepKey = t.identifier(file.generateUid("step"));
var stepKey = t.identifier(file.generateUid("step", scope));
var stepValueId = t.memberExpression(stepKey, t.identifier("value"));
if (t.isIdentifier(left)) {
@@ -19,7 +19,7 @@ exports.ForOfStatement = function (node, parent, file) {
}
var node2 = util.template("for-of", {
ITERATOR_KEY: file.generateUid("iterator"),
ITERATOR_KEY: file.generateUid("iterator", scope),
STEP_KEY: stepKey,
OBJECT: node.right
});

View File

@@ -1,7 +1,10 @@
{
"ArrowFunctionExpression": ["Function"],
"FunctionDeclaration": ["Function"],
"FunctionExpression": ["Function"],
"ArrowFunctionExpression": ["Scope", "Function"],
"FunctionDeclaration": ["Scope", "Function"],
"FunctionExpression": ["Scope", "Function"],
"BlockStatement": ["Scope"],
"Program": ["Scope"],
"LogicalExpression": ["Binary"],
"BinaryExpression": ["Binary"],