From d28496006e1a6ecb5275e5ab187027cddf82a8ce Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Tue, 4 Nov 2014 12:46:47 +1100 Subject: [PATCH] implement Scope so we can keep track of references to avoid collisions when generating ids --- lib/6to5/file.js | 14 +++++++- lib/6to5/scope.js | 44 +++++++++++++++++++++++ lib/6to5/transformers/_alias-functions.js | 14 ++++---- lib/6to5/transformers/classes.js | 14 ++++---- lib/6to5/transformers/constants.js | 2 +- lib/6to5/transformers/destructuring.js | 20 +++++------ lib/6to5/transformers/for-of.js | 6 ++-- lib/6to5/types/alias-keys.json | 9 +++-- 8 files changed, 91 insertions(+), 32 deletions(-) create mode 100644 lib/6to5/scope.js diff --git a/lib/6to5/file.js b/lib/6to5/file.js index 39c08f83a6..0c93ed0740 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -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, "-"); diff --git a/lib/6to5/scope.js b/lib/6to5/scope.js new file mode 100644 index 0000000000..8954f7eb0f --- /dev/null +++ b/lib/6to5/scope.js @@ -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; +}; diff --git a/lib/6to5/transformers/_alias-functions.js b/lib/6to5/transformers/_alias-functions.js index 91261d1799..eca7e9573b 100644 --- a/lib/6to5/transformers/_alias-functions.js +++ b/lib/6to5/transformers/_alias-functions.js @@ -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); }; diff --git a/lib/6to5/transformers/classes.js b/lib/6to5/transformers/classes.js index e651870d6e..bcc22c1694 100644 --- a/lib/6to5/transformers/classes.js +++ b/lib/6to5/transformers/classes.js @@ -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)); } } diff --git a/lib/6to5/transformers/constants.js b/lib/6to5/transformers/constants.js index 529d6f69f9..7dc60a4bf8 100644 --- a/lib/6to5/transformers/constants.js +++ b/lib/6to5/transformers/constants.js @@ -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); }); diff --git a/lib/6to5/transformers/destructuring.js b/lib/6to5/transformers/destructuring.js index c57f0c7acf..e9f6a072b8 100644 --- a/lib/6to5/transformers/destructuring.js +++ b/lib/6to5/transformers/destructuring.js @@ -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)); } diff --git a/lib/6to5/transformers/for-of.js b/lib/6to5/transformers/for-of.js index 798b1aa35a..fb3752574e 100644 --- a/lib/6to5/transformers/for-of.js +++ b/lib/6to5/transformers/for-of.js @@ -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 }); diff --git a/lib/6to5/types/alias-keys.json b/lib/6to5/types/alias-keys.json index 9917eb42d1..4a476ff0b5 100644 --- a/lib/6to5/types/alias-keys.json +++ b/lib/6to5/types/alias-keys.json @@ -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"],