You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			248 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			248 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  |   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 */ | ||
|  | 
 | ||
|  | const Scope = require("./scope"); | ||
|  | const assert = require("assert"); | ||
|  | 
 | ||
|  | const GlobalScope = Scope.GlobalScope; | ||
|  | const CatchScope = Scope.CatchScope; | ||
|  | const WithScope = Scope.WithScope; | ||
|  | const ModuleScope = Scope.ModuleScope; | ||
|  | const ClassScope = Scope.ClassScope; | ||
|  | const SwitchScope = Scope.SwitchScope; | ||
|  | const FunctionScope = Scope.FunctionScope; | ||
|  | const ForScope = Scope.ForScope; | ||
|  | const FunctionExpressionNameScope = Scope.FunctionExpressionNameScope; | ||
|  | const BlockScope = Scope.BlockScope; | ||
|  | 
 | ||
|  | /** | ||
|  |  * @class ScopeManager | ||
|  |  */ | ||
|  | class ScopeManager { | ||
|  |     constructor(options) { | ||
|  |         this.scopes = []; | ||
|  |         this.globalScope = null; | ||
|  |         this.__nodeToScope = new WeakMap(); | ||
|  |         this.__currentScope = null; | ||
|  |         this.__options = options; | ||
|  |         this.__declaredVariables = new WeakMap(); | ||
|  |     } | ||
|  | 
 | ||
|  |     __useDirective() { | ||
|  |         return this.__options.directive; | ||
|  |     } | ||
|  | 
 | ||
|  |     __isOptimistic() { | ||
|  |         return this.__options.optimistic; | ||
|  |     } | ||
|  | 
 | ||
|  |     __ignoreEval() { | ||
|  |         return this.__options.ignoreEval; | ||
|  |     } | ||
|  | 
 | ||
|  |     __isNodejsScope() { | ||
|  |         return this.__options.nodejsScope; | ||
|  |     } | ||
|  | 
 | ||
|  |     isModule() { | ||
|  |         return this.__options.sourceType === "module"; | ||
|  |     } | ||
|  | 
 | ||
|  |     isImpliedStrict() { | ||
|  |         return this.__options.impliedStrict; | ||
|  |     } | ||
|  | 
 | ||
|  |     isStrictModeSupported() { | ||
|  |         return this.__options.ecmaVersion >= 5; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Returns appropriate scope for this node.
 | ||
|  |     __get(node) { | ||
|  |         return this.__nodeToScope.get(node); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Get variables that are declared by the node. | ||
|  |      * | ||
|  |      * "are declared by the node" means the node is same as `Variable.defs[].node` or `Variable.defs[].parent`. | ||
|  |      * If the node declares nothing, this method returns an empty array. | ||
|  |      * CAUTION: This API is experimental. See https://github.com/estools/escope/pull/69 for more details.
 | ||
|  |      * | ||
|  |      * @param {Espree.Node} node - a node to get. | ||
|  |      * @returns {Variable[]} variables that declared by the node. | ||
|  |      */ | ||
|  |     getDeclaredVariables(node) { | ||
|  |         return this.__declaredVariables.get(node) || []; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * acquire scope from node. | ||
|  |      * @method ScopeManager#acquire | ||
|  |      * @param {Espree.Node} node - node for the acquired scope. | ||
|  |      * @param {boolean=} inner - look up the most inner scope, default value is false. | ||
|  |      * @returns {Scope?} Scope from node | ||
|  |      */ | ||
|  |     acquire(node, inner) { | ||
|  | 
 | ||
|  |         /** | ||
|  |          * predicate | ||
|  |          * @param {Scope} testScope - scope to test | ||
|  |          * @returns {boolean} predicate | ||
|  |          */ | ||
|  |         function predicate(testScope) { | ||
|  |             if (testScope.type === "function" && testScope.functionExpressionScope) { | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         const scopes = this.__get(node); | ||
|  | 
 | ||
|  |         if (!scopes || scopes.length === 0) { | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Heuristic selection from all scopes.
 | ||
|  |         // If you would like to get all scopes, please use ScopeManager#acquireAll.
 | ||
|  |         if (scopes.length === 1) { | ||
|  |             return scopes[0]; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (inner) { | ||
|  |             for (let i = scopes.length - 1; i >= 0; --i) { | ||
|  |                 const scope = scopes[i]; | ||
|  | 
 | ||
|  |                 if (predicate(scope)) { | ||
|  |                     return scope; | ||
|  |                 } | ||
|  |             } | ||
|  |         } else { | ||
|  |             for (let i = 0, iz = scopes.length; i < iz; ++i) { | ||
|  |                 const scope = scopes[i]; | ||
|  | 
 | ||
|  |                 if (predicate(scope)) { | ||
|  |                     return scope; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return null; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * acquire all scopes from node. | ||
|  |      * @method ScopeManager#acquireAll | ||
|  |      * @param {Espree.Node} node - node for the acquired scope. | ||
|  |      * @returns {Scopes?} Scope array | ||
|  |      */ | ||
|  |     acquireAll(node) { | ||
|  |         return this.__get(node); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * release the node. | ||
|  |      * @method ScopeManager#release | ||
|  |      * @param {Espree.Node} node - releasing node. | ||
|  |      * @param {boolean=} inner - look up the most inner scope, default value is false. | ||
|  |      * @returns {Scope?} upper scope for the node. | ||
|  |      */ | ||
|  |     release(node, inner) { | ||
|  |         const scopes = this.__get(node); | ||
|  | 
 | ||
|  |         if (scopes && scopes.length) { | ||
|  |             const scope = scopes[0].upper; | ||
|  | 
 | ||
|  |             if (!scope) { | ||
|  |                 return null; | ||
|  |             } | ||
|  |             return this.acquire(scope.block, inner); | ||
|  |         } | ||
|  |         return null; | ||
|  |     } | ||
|  | 
 | ||
|  |     attach() { } // eslint-disable-line class-methods-use-this
 | ||
|  | 
 | ||
|  |     detach() { } // eslint-disable-line class-methods-use-this
 | ||
|  | 
 | ||
|  |     __nestScope(scope) { | ||
|  |         if (scope instanceof GlobalScope) { | ||
|  |             assert(this.__currentScope === null); | ||
|  |             this.globalScope = scope; | ||
|  |         } | ||
|  |         this.__currentScope = scope; | ||
|  |         return scope; | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestGlobalScope(node) { | ||
|  |         return this.__nestScope(new GlobalScope(this, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestBlockScope(node) { | ||
|  |         return this.__nestScope(new BlockScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestFunctionScope(node, isMethodDefinition) { | ||
|  |         return this.__nestScope(new FunctionScope(this, this.__currentScope, node, isMethodDefinition)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestForScope(node) { | ||
|  |         return this.__nestScope(new ForScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestCatchScope(node) { | ||
|  |         return this.__nestScope(new CatchScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestWithScope(node) { | ||
|  |         return this.__nestScope(new WithScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestClassScope(node) { | ||
|  |         return this.__nestScope(new ClassScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestSwitchScope(node) { | ||
|  |         return this.__nestScope(new SwitchScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestModuleScope(node) { | ||
|  |         return this.__nestScope(new ModuleScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __nestFunctionExpressionNameScope(node) { | ||
|  |         return this.__nestScope(new FunctionExpressionNameScope(this, this.__currentScope, node)); | ||
|  |     } | ||
|  | 
 | ||
|  |     __isES6() { | ||
|  |         return this.__options.ecmaVersion >= 6; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = ScopeManager; | ||
|  | 
 | ||
|  | /* vim: set sw=4 ts=4 et tw=80 : */ |