| 
						 | 
						- /*
 -   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.
 - */
 - 
 - /* eslint-disable no-underscore-dangle */
 - /* eslint-disable no-undefined */
 - 
 - import estraverse from "estraverse";
 - import esrecurse from "esrecurse";
 - import Reference from "./reference.js";
 - import Variable from "./variable.js";
 - import PatternVisitor from "./pattern-visitor.js";
 - import { Definition, ParameterDefinition } from "./definition.js";
 - import assert from "assert";
 - 
 - const { Syntax } = estraverse;
 - 
 - /**
 -  * 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;
 -     }
 - 
 -     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) {
 -         let visitPatternOptions = options;
 -         let visitPatternCallback = callback;
 - 
 -         if (typeof options === "function") {
 -             visitPatternCallback = options;
 -             visitPatternOptions = { processRightHandNodes: false };
 -         }
 - 
 -         traverseIdentifierInPattern(
 -             this.options,
 -             node,
 -             visitPatternOptions.processRightHandNodes ? this : null,
 -             visitPatternCallback
 -         );
 -     }
 - 
 -     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
 -                 ));
 -         }
 - 
 -         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.scopeManager.__nestForScope(node);
 -         }
 - 
 -         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);
 - 
 -         this.close(node);
 -     }
 - 
 -     visitVariableDeclaration(variableTargetScope, type, node, index) {
 - 
 -         const decl = node.declarations[index];
 -         const init = decl.init;
 - 
 -         this.visitPattern(decl.id, { processRightHandNodes: true }, (pattern, info) => {
 -             variableTargetScope.__define(
 -                 pattern,
 -                 new Definition(
 -                     type,
 -                     pattern,
 -                     decl,
 -                     node,
 -                     index,
 -                     node.kind
 -                 )
 -             );
 - 
 -             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.isGlobalReturn()) {
 - 
 -             // 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);
 -     }
 - 
 -     // eslint-disable-next-line class-methods-use-this
 -     PrivateIdentifier() {
 - 
 -         // Do nothing.
 -     }
 - 
 -     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);
 -     }
 - 
 -     PropertyDefinition(node) {
 -         const { computed, key, value } = node;
 - 
 -         if (computed) {
 -             this.visit(key);
 -         }
 -         if (value) {
 -             this.scopeManager.__nestClassFieldInitializerScope(value);
 -             this.visit(value);
 -             this.close(value);
 -         }
 -     }
 - 
 -     StaticBlock(node) {
 -         this.scopeManager.__nestClassStaticBlockScope(node);
 - 
 -         this.visitChildren(node);
 - 
 -         this.close(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);
 -     }
 - 
 -     // TODO: ExportDeclaration doesn't exist. for bc?
 -     ExportDeclaration(node) {
 -         this.visitExportDeclaration(node);
 -     }
 - 
 -     ExportAllDeclaration(node) {
 -         this.visitExportDeclaration(node);
 -     }
 - 
 -     ExportDefaultDeclaration(node) {
 -         this.visitExportDeclaration(node);
 -     }
 - 
 -     ExportNamedDeclaration(node) {
 -         this.visitExportDeclaration(node);
 -     }
 - 
 -     ExportSpecifier(node) {
 - 
 -         // TODO: `node.id` doesn't exist. for bc?
 -         const local = (node.id || node.local);
 - 
 -         this.visit(local);
 -     }
 - 
 -     MetaProperty() { // eslint-disable-line class-methods-use-this
 - 
 -         // do nothing.
 -     }
 - }
 - 
 - export default Referencer;
 - 
 - /* vim: set sw=4 ts=4 et tw=80 : */
 
 
  |