From a9405e5e809cd77ec5684f3d9ff4ad4c8b197b82 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Tue, 3 Feb 2015 19:33:32 +1100 Subject: [PATCH] clean up scope API --- lib/6to5/file.js | 2 +- .../helpers/explode-assignable-expression.js | 4 +- .../transformation/helpers/name-method.js | 4 +- lib/6to5/transformation/modules/_default.js | 2 +- .../transformers/es6/block-scoping-tdz.js | 2 +- .../transformers/es6/block-scoping.js | 6 +- .../transformers/es6/constants.js | 2 +- .../transformers/es6/parameters.default.js | 4 +- .../transformers/other/self-contained.js | 2 +- .../validation/undeclared-variable-check.js | 6 +- lib/6to5/traverse/scope.js | 77 +++++++++++++------ 11 files changed, 69 insertions(+), 42 deletions(-) diff --git a/lib/6to5/file.js b/lib/6to5/file.js index f0e6da985b..44d0a7794b 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -407,7 +407,7 @@ File.prototype.generateUid = function (name, scope) { do { uid = this._generateUid(name, i); i++; - } while (scope.has(uid)); + } while (scope.hasReference(uid)); return uid; }; diff --git a/lib/6to5/transformation/helpers/explode-assignable-expression.js b/lib/6to5/transformation/helpers/explode-assignable-expression.js index 3c637c4f56..ada6216287 100644 --- a/lib/6to5/transformation/helpers/explode-assignable-expression.js +++ b/lib/6to5/transformation/helpers/explode-assignable-expression.js @@ -5,7 +5,7 @@ var t = require("../../types"); var getObjRef = function (node, nodes, file, scope) { var ref; if (t.isIdentifier(node)) { - if (scope.has(node.name, true)) { + if (scope.hasBinding(node.name)) { // this variable is declared in scope so we can be 100% sure // that evaluating it multiple times wont trigger a getter // or something else @@ -18,7 +18,7 @@ var getObjRef = function (node, nodes, file, scope) { } else if (t.isMemberExpression(node)) { ref = node.object; - if (t.isIdentifier(ref) && scope.has(ref.name)) { + if (t.isIdentifier(ref) && scope.hasReference(ref.name)) { // the object reference that we need to save is locally declared // so as per the previous comment we can be 100% sure evaluating // it multiple times will be safe diff --git a/lib/6to5/transformation/helpers/name-method.js b/lib/6to5/transformation/helpers/name-method.js index 4581f28137..c1876859f9 100644 --- a/lib/6to5/transformation/helpers/name-method.js +++ b/lib/6to5/transformation/helpers/name-method.js @@ -14,7 +14,7 @@ var visitor = { // check that we don't have a local variable declared as that removes the need // for the wrapper - var localDeclar = scope.get(state.id, true); + var localDeclar = scope.getBinding(state.id); if (localDeclar !== state.outerDeclar) return; state.selfReference = true; @@ -32,7 +32,7 @@ exports.property = function (node, file, scope) { var state = { id: id, selfReference: false, - outerDeclar: scope.get(id, true), + outerDeclar: scope.getBinding(id), }; traverse(node, visitor, scope, state); diff --git a/lib/6to5/transformation/modules/_default.js b/lib/6to5/transformation/modules/_default.js index 300c12ab18..4d46305f25 100644 --- a/lib/6to5/transformation/modules/_default.js +++ b/lib/6to5/transformation/modules/_default.js @@ -147,7 +147,7 @@ DefaultFormatter.prototype.remapExportAssignment = function (node) { DefaultFormatter.prototype.isLocalReference = function (node, scope) { var localExports = this.localExports; var name = node.name; - return t.isIdentifier(node) && localExports[name] && localExports[name] === scope.get(name, true); + return t.isIdentifier(node) && localExports[name] && localExports[name] === scope.getBinding(name); }; DefaultFormatter.prototype.getModuleName = function () { diff --git a/lib/6to5/transformation/transformers/es6/block-scoping-tdz.js b/lib/6to5/transformation/transformers/es6/block-scoping-tdz.js index bdb36fa30b..d9b11b8923 100644 --- a/lib/6to5/transformation/transformers/es6/block-scoping-tdz.js +++ b/lib/6to5/transformation/transformers/es6/block-scoping-tdz.js @@ -11,7 +11,7 @@ var visitor = { if (!declared) return; // declared node is different in this scope - if (scope.get(node.name, true) !== declared) return; + if (scope.getBinding(node.name) !== declared) return; var declaredLoc = declared.loc; var referenceLoc = node.loc; diff --git a/lib/6to5/transformation/transformers/es6/block-scoping.js b/lib/6to5/transformation/transformers/es6/block-scoping.js index dc5dad4020..5e8b87b879 100644 --- a/lib/6to5/transformation/transformers/es6/block-scoping.js +++ b/lib/6to5/transformation/transformers/es6/block-scoping.js @@ -110,7 +110,7 @@ function replace(node, parent, scope, context, remaps) { var remap = remaps[node.name]; if (!remap) return; - var own = scope.get(node.name, true); + var own = scope.getBinding(node.name); if (own === remap.node) { node.name = remap.uid; } else { @@ -149,7 +149,7 @@ BlockScoping.prototype.remap = function () { // this is the defining identifier of a declaration var ref = letRefs[key]; - if (scope.parentHas(key)) { + if (scope.parentHasReference(key)) { var uid = scope.generateUidIdentifier(ref.name).name; ref.name = uid; @@ -227,7 +227,7 @@ var letReferenceFunctionVisitor = { // this scope has a variable with the same name so it couldn't belong // to our let scope - if (scope.hasOwn(node.name, true)) return; + if (scope.hasOwnBinding(node.name)) return; // not a part of our scope if (!state.letReferences[node.name]) return; diff --git a/lib/6to5/transformation/transformers/es6/constants.js b/lib/6to5/transformation/transformers/es6/constants.js index ce245c63b0..dcedaa222f 100644 --- a/lib/6to5/transformation/transformers/es6/constants.js +++ b/lib/6to5/transformation/transformers/es6/constants.js @@ -21,7 +21,7 @@ var visitor = { // constant so we can just ignore it if (id === constant) continue; - var localBinding = scope.get(key, true); + var localBinding = scope.getBinding(key); if (localBinding !== constant) continue; throw state.file.errorWithNode(id, key + " is read-only"); diff --git a/lib/6to5/transformation/transformers/es6/parameters.default.js b/lib/6to5/transformation/transformers/es6/parameters.default.js index 00f2d47f3f..20184cfee9 100644 --- a/lib/6to5/transformation/transformers/es6/parameters.default.js +++ b/lib/6to5/transformation/transformers/es6/parameters.default.js @@ -13,7 +13,7 @@ var hasDefaults = function (node) { var iifeVisitor = { enter: function (node, parent, scope, context, state) { - if (t.isReferencedIdentifier(node, parent) && state.scope.hasOwn(node.name)) { + if (t.isReferencedIdentifier(node, parent) && state.scope.hasOwnReference(node.name)) { state.iife = true; context.stop(); } @@ -48,7 +48,7 @@ exports.Function = function (node, parent, scope) { node.params[i] = scope.generateUidIdentifier("x"); if (!state.iife) { - if (t.isIdentifier(right) && scope.hasOwn(right.name)) { + if (t.isIdentifier(right) && scope.hasOwnReference(right.name)) { state.iife = true; } else { traverse(right, iifeVisitor, scope, state); diff --git a/lib/6to5/transformation/transformers/other/self-contained.js b/lib/6to5/transformation/transformers/other/self-contained.js index 9212d14c05..4f60e3d015 100644 --- a/lib/6to5/transformation/transformers/other/self-contained.js +++ b/lib/6to5/transformation/transformers/other/self-contained.js @@ -35,7 +35,7 @@ var astVisitor = { context.skip(); return t.prependToMemberExpression(node, file.get("coreIdentifier")); } - } else if (t.isReferencedIdentifier(node, parent) && !t.isMemberExpression(parent) && contains(ALIASABLE_CONSTRUCTORS, node.name) && !scope.get(node.name, true)) { + } else if (t.isReferencedIdentifier(node, parent) && !t.isMemberExpression(parent) && contains(ALIASABLE_CONSTRUCTORS, node.name) && !scope.getBinding(node.name)) { // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise return t.memberExpression(file.get("coreIdentifier"), node); } else if (t.isCallExpression(node)) { diff --git a/lib/6to5/transformation/transformers/validation/undeclared-variable-check.js b/lib/6to5/transformation/transformers/validation/undeclared-variable-check.js index af3b9e88f4..919d417f2f 100644 --- a/lib/6to5/transformation/transformers/validation/undeclared-variable-check.js +++ b/lib/6to5/transformation/transformers/validation/undeclared-variable-check.js @@ -7,19 +7,19 @@ exports.optional = true; exports.Identifier = function (node, parent, scope, context, file) { if (!t.isReferenced(node, parent)) return; - if (scope.has(node.name, true)) return; + if (scope.hasBinding(node.name)) return; var msg = "Reference to undeclared variable"; // get the closest declaration to offer as a suggestion // the variable name may have just been mistyped - var declarations = scope.getAllDeclarations(); + var bindings = scope.getAllBindings(); var closest; var shortest = -1; - for (var name in declarations) { + for (var name in bindings) { var distance = levenshtein(node.name, name); if (distance <= 0 || distance > 3) continue; if (distance <= shortest) continue; diff --git a/lib/6to5/traverse/scope.js b/lib/6to5/traverse/scope.js index 340ad5c125..333cabc367 100644 --- a/lib/6to5/traverse/scope.js +++ b/lib/6to5/traverse/scope.js @@ -14,7 +14,7 @@ var has = require("lodash/object/has"); var t = require("../types"); /** - * This searches the current "scope" and collects all references/declarations + * This searches the current "scope" and collects all references/bindings * within. * * @param {Node} block @@ -31,8 +31,9 @@ function Scope(block, parentBlock, parent, file) { this.block = block; var info = this.getInfo(); - this.references = info.references; - this.declarations = info.declarations; + + this.references = info.references; + this.bindings = info.bindings; this.declarationKinds = info.declarationKinds; } @@ -113,7 +114,7 @@ Scope.prototype.generateUidBasedOnNode = function (parent) { */ Scope.prototype.generateTempBasedOnNode = function (node) { - if (t.isIdentifier(node) && this.has(node.name, true)) { + if (t.isIdentifier(node) && this.hasBinding(node.name)) { return null; } @@ -154,7 +155,7 @@ var functionVariableVisitor = { var programReferenceVisitor = { enter: function (node, parent, scope, context, add) { - if (t.isReferencedIdentifier(node, parent) && !scope.has(node.name)) { + if (t.isReferencedIdentifier(node, parent) && !scope.hasReference(node.name)) { add(node, true); } } @@ -177,8 +178,10 @@ Scope.prototype.getInfo = function () { if (block._scopeInfo) return block._scopeInfo; var info = block._scopeInfo = {}; - var references = info.references = object(); - var declarations = info.declarations = object(); + + var bindings = info.bindings = object(); + var references = info.references = object(); + var types = info.types = object(); var declarationKinds = info.declarationKinds = { "var": object(), "let": object(), @@ -197,7 +200,7 @@ Scope.prototype.getInfo = function () { } } - extend(declarations, ids); + extend(bindings, ids); var kinds = declarationKinds[node.kind]; if (kinds) extend(kinds, ids); @@ -312,7 +315,7 @@ Scope.prototype.addDeclarationToFunctionScope = function (kind, node) { var scope = this.getFunctionParent(); var ids = t.getBindingIdentifiers(node); - extend(scope.declarations, ids); + extend(scope.bindings, ids); extend(scope.references, ids); // this ignores the duplicate declaration logic specified in `getInfo` @@ -334,17 +337,17 @@ Scope.prototype.getFunctionParent = function () { }; /** - * Walks the scope tree and gathers **all** declarations. + * Walks the scope tree and gathers **all** bindings. * * @returns {Object} */ -Scope.prototype.getAllDeclarations = function () { +Scope.prototype.getAllBindings = function () { var ids = object(); var scope = this; do { - defaults(ids, scope.declarations); + defaults(ids, scope.bindings); scope = scope.parent; } while (scope); @@ -377,8 +380,8 @@ Scope.prototype.getAllDeclarationsOfKind = function (kind) { * @param {Boolean} [decl] */ -Scope.prototype.get = function (id, decl) { - return id && (this.getOwn(id, decl) || this.parentGet(id, decl)); +Scope.prototype.getReference = function (id, decl) { + return id && (this.getOwnReference(id, decl) || this.parentGetReference(id, decl)); }; /** @@ -388,9 +391,9 @@ Scope.prototype.get = function (id, decl) { * @param {Boolean} [decl] */ -Scope.prototype.getOwn = function (id, decl) { +Scope.prototype.getOwnReference = function (id, decl) { var refs = this.references; - if (decl) refs = this.declarations; + if (decl) refs = this.bindings; return has(refs, id) && refs[id]; }; @@ -401,8 +404,8 @@ Scope.prototype.getOwn = function (id, decl) { * @param {Boolean} [decl] */ -Scope.prototype.parentGet = function (id, decl) { - return this.parent && this.parent.get(id, decl); +Scope.prototype.parentGetReference = function (id, decl) { + return this.parent && this.parent.getReference(id, decl); }; /** @@ -413,10 +416,10 @@ Scope.prototype.parentGet = function (id, decl) { * @returns {Boolean} */ -Scope.prototype.has = function (id, decl) { +Scope.prototype.hasReference = function (id, decl) { if (!id) return false; - if (this.hasOwn(id, decl)) return true; - if (this.parentHas(id, decl)) return true; + if (this.hasOwnReference(id, decl)) return true; + if (this.parentHasReference(id, decl)) return true; if (contains(Scope.defaultDeclarations, id)) return true; return false; }; @@ -429,8 +432,8 @@ Scope.prototype.has = function (id, decl) { * @returns {Boolean} */ -Scope.prototype.hasOwn = function (id, decl) { - return !!this.getOwn(id, decl); +Scope.prototype.hasOwnReference = function (id, decl) { + return !!this.getOwnReference(id, decl); }; /** @@ -441,6 +444,30 @@ Scope.prototype.hasOwn = function (id, decl) { * @returns {Boolean} */ -Scope.prototype.parentHas = function (id, decl) { - return this.parent && this.parent.has(id, decl); +Scope.prototype.parentHasReference = function (id, decl) { + return this.parent && this.parent.hasReference(id, decl); +}; + +Scope.prototype.getBinding = function (id) { + return this.getReference(id, true); +}; + +Scope.prototype.hasBinding = function (id) { + return this.hasReference(id, true); +}; + +Scope.prototype.getOwnBinding = function (id) { + return this.getOwnReference(id, true); +}; + +Scope.prototype.hasOwnBinding = function (id) { + return this.hasOwnReference(id, true); +}; + +Scope.prototype.parentGetBinding = function (id) { + return this.parentGetReference(id, true); +}; + +Scope.prototype.parentHasBinding = function (id) { + return this.parentHasReference(id, true); };