| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 | 
							- /*
 
-   Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
 
-   Redistribution and use in source and binary forms, with or without
 
-   modification, are permitted provided that the following conditions are met:
 
-     * Redistributions of source code must retain the above copyright
 
-       notice, this list of conditions and the following disclaimer.
 
-     * Redistributions in binary form must reproduce the above copyright
 
-       notice, this list of conditions and the following disclaimer in the
 
-       documentation and/or other materials provided with the distribution.
 
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
-   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
-   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
-   ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 
-   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
-   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
-   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
-   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
-   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
- */
 
- "use strict";
 
- /* eslint-disable no-underscore-dangle */
 
- /* eslint-disable no-undefined */
 
- const Syntax = require("estraverse").Syntax;
 
- const esrecurse = require("esrecurse");
 
- const Reference = require("./reference");
 
- const Variable = require("./variable");
 
- const PatternVisitor = require("./pattern-visitor");
 
- const definition = require("./definition");
 
- const assert = require("assert");
 
- const ParameterDefinition = definition.ParameterDefinition;
 
- const Definition = definition.Definition;
 
- /**
 
-  * Traverse identifier in pattern
 
-  * @param {Object} options - options
 
-  * @param {pattern} rootPattern - root pattern
 
-  * @param {Refencer} referencer - referencer
 
-  * @param {callback} callback - callback
 
-  * @returns {void}
 
-  */
 
- function traverseIdentifierInPattern(options, rootPattern, referencer, callback) {
 
-     // Call the callback at left hand identifier nodes, and Collect right hand nodes.
 
-     const visitor = new PatternVisitor(options, rootPattern, callback);
 
-     visitor.visit(rootPattern);
 
-     // Process the right hand nodes recursively.
 
-     if (referencer !== null && referencer !== undefined) {
 
-         visitor.rightHandNodes.forEach(referencer.visit, referencer);
 
-     }
 
- }
 
- // Importing ImportDeclaration.
 
- // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-moduledeclarationinstantiation
 
- // https://github.com/estree/estree/blob/master/es6.md#importdeclaration
 
- // FIXME: Now, we don't create module environment, because the context is
 
- // implementation dependent.
 
- class Importer extends esrecurse.Visitor {
 
-     constructor(declaration, referencer) {
 
-         super(null, referencer.options);
 
-         this.declaration = declaration;
 
-         this.referencer = referencer;
 
-     }
 
-     visitImport(id, specifier) {
 
-         this.referencer.visitPattern(id, pattern => {
 
-             this.referencer.currentScope().__define(pattern,
 
-                 new Definition(
 
-                     Variable.ImportBinding,
 
-                     pattern,
 
-                     specifier,
 
-                     this.declaration,
 
-                     null,
 
-                     null
 
-                     ));
 
-         });
 
-     }
 
-     ImportNamespaceSpecifier(node) {
 
-         const local = (node.local || node.id);
 
-         if (local) {
 
-             this.visitImport(local, node);
 
-         }
 
-     }
 
-     ImportDefaultSpecifier(node) {
 
-         const local = (node.local || node.id);
 
-         this.visitImport(local, node);
 
-     }
 
-     ImportSpecifier(node) {
 
-         const local = (node.local || node.id);
 
-         if (node.name) {
 
-             this.visitImport(node.name, node);
 
-         } else {
 
-             this.visitImport(local, node);
 
-         }
 
-     }
 
- }
 
- // Referencing variables and creating bindings.
 
- class Referencer extends esrecurse.Visitor {
 
-     constructor(options, scopeManager) {
 
-         super(null, options);
 
-         this.options = options;
 
-         this.scopeManager = scopeManager;
 
-         this.parent = null;
 
-         this.isInnerMethodDefinition = false;
 
-     }
 
-     currentScope() {
 
-         return this.scopeManager.__currentScope;
 
-     }
 
-     close(node) {
 
-         while (this.currentScope() && node === this.currentScope().block) {
 
-             this.scopeManager.__currentScope = this.currentScope().__close(this.scopeManager);
 
-         }
 
-     }
 
-     pushInnerMethodDefinition(isInnerMethodDefinition) {
 
-         const previous = this.isInnerMethodDefinition;
 
-         this.isInnerMethodDefinition = isInnerMethodDefinition;
 
-         return previous;
 
-     }
 
-     popInnerMethodDefinition(isInnerMethodDefinition) {
 
-         this.isInnerMethodDefinition = isInnerMethodDefinition;
 
-     }
 
-     materializeTDZScope(node, iterationNode) {
 
-         // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-forin-div-ofexpressionevaluation-abstract-operation
 
-         // TDZ scope hides the declaration's names.
 
-         this.scopeManager.__nestTDZScope(node, iterationNode);
 
-         this.visitVariableDeclaration(this.currentScope(), Variable.TDZ, iterationNode.left, 0, true);
 
-     }
 
-     materializeIterationScope(node) {
 
-         // Generate iteration scope for upper ForIn/ForOf Statements.
 
-         const letOrConstDecl = node.left;
 
-         this.scopeManager.__nestForScope(node);
 
-         this.visitVariableDeclaration(this.currentScope(), Variable.Variable, letOrConstDecl, 0);
 
-         this.visitPattern(letOrConstDecl.declarations[0].id, pattern => {
 
-             this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
 
-         });
 
-     }
 
-     referencingDefaultValue(pattern, assignments, maybeImplicitGlobal, init) {
 
-         const scope = this.currentScope();
 
-         assignments.forEach(assignment => {
 
-             scope.__referencing(
 
-                 pattern,
 
-                 Reference.WRITE,
 
-                 assignment.right,
 
-                 maybeImplicitGlobal,
 
-                 pattern !== assignment.left,
 
-                 init);
 
-         });
 
-     }
 
-     visitPattern(node, options, callback) {
 
-         if (typeof options === "function") {
 
-             callback = options;
 
-             options = { processRightHandNodes: false };
 
-         }
 
-         traverseIdentifierInPattern(
 
-             this.options,
 
-             node,
 
-             options.processRightHandNodes ? this : null,
 
-             callback);
 
-     }
 
-     visitFunction(node) {
 
-         let i, iz;
 
-         // FunctionDeclaration name is defined in upper scope
 
-         // NOTE: Not referring variableScope. It is intended.
 
-         // Since
 
-         //  in ES5, FunctionDeclaration should be in FunctionBody.
 
-         //  in ES6, FunctionDeclaration should be block scoped.
 
-         if (node.type === Syntax.FunctionDeclaration) {
 
-             // id is defined in upper scope
 
-             this.currentScope().__define(node.id,
 
-                     new Definition(
 
-                         Variable.FunctionName,
 
-                         node.id,
 
-                         node,
 
-                         null,
 
-                         null,
 
-                         null
 
-                     ));
 
-         }
 
-         // FunctionExpression with name creates its special scope;
 
-         // FunctionExpressionNameScope.
 
-         if (node.type === Syntax.FunctionExpression && node.id) {
 
-             this.scopeManager.__nestFunctionExpressionNameScope(node);
 
-         }
 
-         // Consider this function is in the MethodDefinition.
 
-         this.scopeManager.__nestFunctionScope(node, this.isInnerMethodDefinition);
 
-         const that = this;
 
-         /**
 
-          * Visit pattern callback
 
-          * @param {pattern} pattern - pattern
 
-          * @param {Object} info - info
 
-          * @returns {void}
 
-          */
 
-         function visitPatternCallback(pattern, info) {
 
-             that.currentScope().__define(pattern,
 
-                 new ParameterDefinition(
 
-                     pattern,
 
-                     node,
 
-                     i,
 
-                     info.rest
 
-                 ));
 
-             that.referencingDefaultValue(pattern, info.assignments, null, true);
 
-         }
 
-         // Process parameter declarations.
 
-         for (i = 0, iz = node.params.length; i < iz; ++i) {
 
-             this.visitPattern(node.params[i], { processRightHandNodes: true }, visitPatternCallback);
 
-         }
 
-         // if there's a rest argument, add that
 
-         if (node.rest) {
 
-             this.visitPattern({
 
-                 type: "RestElement",
 
-                 argument: node.rest
 
-             }, pattern => {
 
-                 this.currentScope().__define(pattern,
 
-                     new ParameterDefinition(
 
-                         pattern,
 
-                         node,
 
-                         node.params.length,
 
-                         true
 
-                     ));
 
-             });
 
-         }
 
-         // In TypeScript there are a number of function-like constructs which have no body,
 
-         // so check it exists before traversing
 
-         if (node.body) {
 
-             // Skip BlockStatement to prevent creating BlockStatement scope.
 
-             if (node.body.type === Syntax.BlockStatement) {
 
-                 this.visitChildren(node.body);
 
-             } else {
 
-                 this.visit(node.body);
 
-             }
 
-         }
 
-         this.close(node);
 
-     }
 
-     visitClass(node) {
 
-         if (node.type === Syntax.ClassDeclaration) {
 
-             this.currentScope().__define(node.id,
 
-                     new Definition(
 
-                         Variable.ClassName,
 
-                         node.id,
 
-                         node,
 
-                         null,
 
-                         null,
 
-                         null
 
-                     ));
 
-         }
 
-         // FIXME: Maybe consider TDZ.
 
-         this.visit(node.superClass);
 
-         this.scopeManager.__nestClassScope(node);
 
-         if (node.id) {
 
-             this.currentScope().__define(node.id,
 
-                     new Definition(
 
-                         Variable.ClassName,
 
-                         node.id,
 
-                         node
 
-                     ));
 
-         }
 
-         this.visit(node.body);
 
-         this.close(node);
 
-     }
 
-     visitProperty(node) {
 
-         let previous;
 
-         if (node.computed) {
 
-             this.visit(node.key);
 
-         }
 
-         const isMethodDefinition = node.type === Syntax.MethodDefinition;
 
-         if (isMethodDefinition) {
 
-             previous = this.pushInnerMethodDefinition(true);
 
-         }
 
-         this.visit(node.value);
 
-         if (isMethodDefinition) {
 
-             this.popInnerMethodDefinition(previous);
 
-         }
 
-     }
 
-     visitForIn(node) {
 
-         if (node.left.type === Syntax.VariableDeclaration && node.left.kind !== "var") {
 
-             this.materializeTDZScope(node.right, node);
 
-             this.visit(node.right);
 
-             this.close(node.right);
 
-             this.materializeIterationScope(node);
 
-             this.visit(node.body);
 
-             this.close(node);
 
-         } else {
 
-             if (node.left.type === Syntax.VariableDeclaration) {
 
-                 this.visit(node.left);
 
-                 this.visitPattern(node.left.declarations[0].id, pattern => {
 
-                     this.currentScope().__referencing(pattern, Reference.WRITE, node.right, null, true, true);
 
-                 });
 
-             } else {
 
-                 this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
 
-                     let maybeImplicitGlobal = null;
 
-                     if (!this.currentScope().isStrict) {
 
-                         maybeImplicitGlobal = {
 
-                             pattern,
 
-                             node
 
-                         };
 
-                     }
 
-                     this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
 
-                     this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, true, false);
 
-                 });
 
-             }
 
-             this.visit(node.right);
 
-             this.visit(node.body);
 
-         }
 
-     }
 
-     visitVariableDeclaration(variableTargetScope, type, node, index, fromTDZ) {
 
-         // If this was called to initialize a TDZ scope, this needs to make definitions, but doesn't make references.
 
-         const decl = node.declarations[index];
 
-         const init = decl.init;
 
-         this.visitPattern(decl.id, { processRightHandNodes: !fromTDZ }, (pattern, info) => {
 
-             variableTargetScope.__define(pattern,
 
-                 new Definition(
 
-                     type,
 
-                     pattern,
 
-                     decl,
 
-                     node,
 
-                     index,
 
-                     node.kind
 
-                 ));
 
-             if (!fromTDZ) {
 
-                 this.referencingDefaultValue(pattern, info.assignments, null, true);
 
-             }
 
-             if (init) {
 
-                 this.currentScope().__referencing(pattern, Reference.WRITE, init, null, !info.topLevel, true);
 
-             }
 
-         });
 
-     }
 
-     AssignmentExpression(node) {
 
-         if (PatternVisitor.isPattern(node.left)) {
 
-             if (node.operator === "=") {
 
-                 this.visitPattern(node.left, { processRightHandNodes: true }, (pattern, info) => {
 
-                     let maybeImplicitGlobal = null;
 
-                     if (!this.currentScope().isStrict) {
 
-                         maybeImplicitGlobal = {
 
-                             pattern,
 
-                             node
 
-                         };
 
-                     }
 
-                     this.referencingDefaultValue(pattern, info.assignments, maybeImplicitGlobal, false);
 
-                     this.currentScope().__referencing(pattern, Reference.WRITE, node.right, maybeImplicitGlobal, !info.topLevel, false);
 
-                 });
 
-             } else {
 
-                 this.currentScope().__referencing(node.left, Reference.RW, node.right);
 
-             }
 
-         } else {
 
-             this.visit(node.left);
 
-         }
 
-         this.visit(node.right);
 
-     }
 
-     CatchClause(node) {
 
-         this.scopeManager.__nestCatchScope(node);
 
-         this.visitPattern(node.param, { processRightHandNodes: true }, (pattern, info) => {
 
-             this.currentScope().__define(pattern,
 
-                 new Definition(
 
-                     Variable.CatchClause,
 
-                     node.param,
 
-                     node,
 
-                     null,
 
-                     null,
 
-                     null
 
-                 ));
 
-             this.referencingDefaultValue(pattern, info.assignments, null, true);
 
-         });
 
-         this.visit(node.body);
 
-         this.close(node);
 
-     }
 
-     Program(node) {
 
-         this.scopeManager.__nestGlobalScope(node);
 
-         if (this.scopeManager.__isNodejsScope()) {
 
-             // Force strictness of GlobalScope to false when using node.js scope.
 
-             this.currentScope().isStrict = false;
 
-             this.scopeManager.__nestFunctionScope(node, false);
 
-         }
 
-         if (this.scopeManager.__isES6() && this.scopeManager.isModule()) {
 
-             this.scopeManager.__nestModuleScope(node);
 
-         }
 
-         if (this.scopeManager.isStrictModeSupported() && this.scopeManager.isImpliedStrict()) {
 
-             this.currentScope().isStrict = true;
 
-         }
 
-         this.visitChildren(node);
 
-         this.close(node);
 
-     }
 
-     Identifier(node) {
 
-         this.currentScope().__referencing(node);
 
-     }
 
-     UpdateExpression(node) {
 
-         if (PatternVisitor.isPattern(node.argument)) {
 
-             this.currentScope().__referencing(node.argument, Reference.RW, null);
 
-         } else {
 
-             this.visitChildren(node);
 
-         }
 
-     }
 
-     MemberExpression(node) {
 
-         this.visit(node.object);
 
-         if (node.computed) {
 
-             this.visit(node.property);
 
-         }
 
-     }
 
-     Property(node) {
 
-         this.visitProperty(node);
 
-     }
 
-     MethodDefinition(node) {
 
-         this.visitProperty(node);
 
-     }
 
-     BreakStatement() {} // eslint-disable-line class-methods-use-this
 
-     ContinueStatement() {} // eslint-disable-line class-methods-use-this
 
-     LabeledStatement(node) {
 
-         this.visit(node.body);
 
-     }
 
-     ForStatement(node) {
 
-         // Create ForStatement declaration.
 
-         // NOTE: In ES6, ForStatement dynamically generates
 
-         // per iteration environment. However, escope is
 
-         // a static analyzer, we only generate one scope for ForStatement.
 
-         if (node.init && node.init.type === Syntax.VariableDeclaration && node.init.kind !== "var") {
 
-             this.scopeManager.__nestForScope(node);
 
-         }
 
-         this.visitChildren(node);
 
-         this.close(node);
 
-     }
 
-     ClassExpression(node) {
 
-         this.visitClass(node);
 
-     }
 
-     ClassDeclaration(node) {
 
-         this.visitClass(node);
 
-     }
 
-     CallExpression(node) {
 
-         // Check this is direct call to eval
 
-         if (!this.scopeManager.__ignoreEval() && node.callee.type === Syntax.Identifier && node.callee.name === "eval") {
 
-             // NOTE: This should be `variableScope`. Since direct eval call always creates Lexical environment and
 
-             // let / const should be enclosed into it. Only VariableDeclaration affects on the caller's environment.
 
-             this.currentScope().variableScope.__detectEval();
 
-         }
 
-         this.visitChildren(node);
 
-     }
 
-     BlockStatement(node) {
 
-         if (this.scopeManager.__isES6()) {
 
-             this.scopeManager.__nestBlockScope(node);
 
-         }
 
-         this.visitChildren(node);
 
-         this.close(node);
 
-     }
 
-     ThisExpression() {
 
-         this.currentScope().variableScope.__detectThis();
 
-     }
 
-     WithStatement(node) {
 
-         this.visit(node.object);
 
-         // Then nest scope for WithStatement.
 
-         this.scopeManager.__nestWithScope(node);
 
-         this.visit(node.body);
 
-         this.close(node);
 
-     }
 
-     VariableDeclaration(node) {
 
-         const variableTargetScope = (node.kind === "var") ? this.currentScope().variableScope : this.currentScope();
 
-         for (let i = 0, iz = node.declarations.length; i < iz; ++i) {
 
-             const decl = node.declarations[i];
 
-             this.visitVariableDeclaration(variableTargetScope, Variable.Variable, node, i);
 
-             if (decl.init) {
 
-                 this.visit(decl.init);
 
-             }
 
-         }
 
-     }
 
-     // sec 13.11.8
 
-     SwitchStatement(node) {
 
-         this.visit(node.discriminant);
 
-         if (this.scopeManager.__isES6()) {
 
-             this.scopeManager.__nestSwitchScope(node);
 
-         }
 
-         for (let i = 0, iz = node.cases.length; i < iz; ++i) {
 
-             this.visit(node.cases[i]);
 
-         }
 
-         this.close(node);
 
-     }
 
-     FunctionDeclaration(node) {
 
-         this.visitFunction(node);
 
-     }
 
-     FunctionExpression(node) {
 
-         this.visitFunction(node);
 
-     }
 
-     ForOfStatement(node) {
 
-         this.visitForIn(node);
 
-     }
 
-     ForInStatement(node) {
 
-         this.visitForIn(node);
 
-     }
 
-     ArrowFunctionExpression(node) {
 
-         this.visitFunction(node);
 
-     }
 
-     ImportDeclaration(node) {
 
-         assert(this.scopeManager.__isES6() && this.scopeManager.isModule(), "ImportDeclaration should appear when the mode is ES6 and in the module context.");
 
-         const importer = new Importer(node, this);
 
-         importer.visit(node);
 
-     }
 
-     visitExportDeclaration(node) {
 
-         if (node.source) {
 
-             return;
 
-         }
 
-         if (node.declaration) {
 
-             this.visit(node.declaration);
 
-             return;
 
-         }
 
-         this.visitChildren(node);
 
-     }
 
-     ExportDeclaration(node) {
 
-         this.visitExportDeclaration(node);
 
-     }
 
-     ExportNamedDeclaration(node) {
 
-         this.visitExportDeclaration(node);
 
-     }
 
-     ExportSpecifier(node) {
 
-         const local = (node.id || node.local);
 
-         this.visit(local);
 
-     }
 
-     MetaProperty() { // eslint-disable-line class-methods-use-this
 
-         // do nothing.
 
-     }
 
- }
 
- module.exports = Referencer;
 
- /* vim: set sw=4 ts=4 et tw=80 : */
 
 
  |