Projekt

Obecné

Profil

Stáhnout (7.28 KB) Statistiky
| Větev: | Revize:
1
/*
2
  Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
3

    
4
  Redistribution and use in source and binary forms, with or without
5
  modification, are permitted provided that the following conditions are met:
6

    
7
    * Redistributions of source code must retain the above copyright
8
      notice, this list of conditions and the following disclaimer.
9
    * Redistributions in binary form must reproduce the above copyright
10
      notice, this list of conditions and the following disclaimer in the
11
      documentation and/or other materials provided with the distribution.
12

    
13
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
17
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
*/
24
"use strict";
25

    
26
/* eslint-disable no-underscore-dangle */
27

    
28
const Scope = require("./scope");
29
const assert = require("assert");
30

    
31
const GlobalScope = Scope.GlobalScope;
32
const CatchScope = Scope.CatchScope;
33
const WithScope = Scope.WithScope;
34
const ModuleScope = Scope.ModuleScope;
35
const ClassScope = Scope.ClassScope;
36
const SwitchScope = Scope.SwitchScope;
37
const FunctionScope = Scope.FunctionScope;
38
const ForScope = Scope.ForScope;
39
const FunctionExpressionNameScope = Scope.FunctionExpressionNameScope;
40
const BlockScope = Scope.BlockScope;
41

    
42
/**
43
 * @class ScopeManager
44
 */
45
class ScopeManager {
46
    constructor(options) {
47
        this.scopes = [];
48
        this.globalScope = null;
49
        this.__nodeToScope = new WeakMap();
50
        this.__currentScope = null;
51
        this.__options = options;
52
        this.__declaredVariables = new WeakMap();
53
    }
54

    
55
    __useDirective() {
56
        return this.__options.directive;
57
    }
58

    
59
    __isOptimistic() {
60
        return this.__options.optimistic;
61
    }
62

    
63
    __ignoreEval() {
64
        return this.__options.ignoreEval;
65
    }
66

    
67
    __isNodejsScope() {
68
        return this.__options.nodejsScope;
69
    }
70

    
71
    isModule() {
72
        return this.__options.sourceType === "module";
73
    }
74

    
75
    isImpliedStrict() {
76
        return this.__options.impliedStrict;
77
    }
78

    
79
    isStrictModeSupported() {
80
        return this.__options.ecmaVersion >= 5;
81
    }
82

    
83
    // Returns appropriate scope for this node.
84
    __get(node) {
85
        return this.__nodeToScope.get(node);
86
    }
87

    
88
    /**
89
     * Get variables that are declared by the node.
90
     *
91
     * "are declared by the node" means the node is same as `Variable.defs[].node` or `Variable.defs[].parent`.
92
     * If the node declares nothing, this method returns an empty array.
93
     * CAUTION: This API is experimental. See https://github.com/estools/escope/pull/69 for more details.
94
     *
95
     * @param {Espree.Node} node - a node to get.
96
     * @returns {Variable[]} variables that declared by the node.
97
     */
98
    getDeclaredVariables(node) {
99
        return this.__declaredVariables.get(node) || [];
100
    }
101

    
102
    /**
103
     * acquire scope from node.
104
     * @method ScopeManager#acquire
105
     * @param {Espree.Node} node - node for the acquired scope.
106
     * @param {boolean=} inner - look up the most inner scope, default value is false.
107
     * @returns {Scope?} Scope from node
108
     */
109
    acquire(node, inner) {
110

    
111
        /**
112
         * predicate
113
         * @param {Scope} testScope - scope to test
114
         * @returns {boolean} predicate
115
         */
116
        function predicate(testScope) {
117
            if (testScope.type === "function" && testScope.functionExpressionScope) {
118
                return false;
119
            }
120
            return true;
121
        }
122

    
123
        const scopes = this.__get(node);
124

    
125
        if (!scopes || scopes.length === 0) {
126
            return null;
127
        }
128

    
129
        // Heuristic selection from all scopes.
130
        // If you would like to get all scopes, please use ScopeManager#acquireAll.
131
        if (scopes.length === 1) {
132
            return scopes[0];
133
        }
134

    
135
        if (inner) {
136
            for (let i = scopes.length - 1; i >= 0; --i) {
137
                const scope = scopes[i];
138

    
139
                if (predicate(scope)) {
140
                    return scope;
141
                }
142
            }
143
        } else {
144
            for (let i = 0, iz = scopes.length; i < iz; ++i) {
145
                const scope = scopes[i];
146

    
147
                if (predicate(scope)) {
148
                    return scope;
149
                }
150
            }
151
        }
152

    
153
        return null;
154
    }
155

    
156
    /**
157
     * acquire all scopes from node.
158
     * @method ScopeManager#acquireAll
159
     * @param {Espree.Node} node - node for the acquired scope.
160
     * @returns {Scopes?} Scope array
161
     */
162
    acquireAll(node) {
163
        return this.__get(node);
164
    }
165

    
166
    /**
167
     * release the node.
168
     * @method ScopeManager#release
169
     * @param {Espree.Node} node - releasing node.
170
     * @param {boolean=} inner - look up the most inner scope, default value is false.
171
     * @returns {Scope?} upper scope for the node.
172
     */
173
    release(node, inner) {
174
        const scopes = this.__get(node);
175

    
176
        if (scopes && scopes.length) {
177
            const scope = scopes[0].upper;
178

    
179
            if (!scope) {
180
                return null;
181
            }
182
            return this.acquire(scope.block, inner);
183
        }
184
        return null;
185
    }
186

    
187
    attach() { } // eslint-disable-line class-methods-use-this
188

    
189
    detach() { } // eslint-disable-line class-methods-use-this
190

    
191
    __nestScope(scope) {
192
        if (scope instanceof GlobalScope) {
193
            assert(this.__currentScope === null);
194
            this.globalScope = scope;
195
        }
196
        this.__currentScope = scope;
197
        return scope;
198
    }
199

    
200
    __nestGlobalScope(node) {
201
        return this.__nestScope(new GlobalScope(this, node));
202
    }
203

    
204
    __nestBlockScope(node) {
205
        return this.__nestScope(new BlockScope(this, this.__currentScope, node));
206
    }
207

    
208
    __nestFunctionScope(node, isMethodDefinition) {
209
        return this.__nestScope(new FunctionScope(this, this.__currentScope, node, isMethodDefinition));
210
    }
211

    
212
    __nestForScope(node) {
213
        return this.__nestScope(new ForScope(this, this.__currentScope, node));
214
    }
215

    
216
    __nestCatchScope(node) {
217
        return this.__nestScope(new CatchScope(this, this.__currentScope, node));
218
    }
219

    
220
    __nestWithScope(node) {
221
        return this.__nestScope(new WithScope(this, this.__currentScope, node));
222
    }
223

    
224
    __nestClassScope(node) {
225
        return this.__nestScope(new ClassScope(this, this.__currentScope, node));
226
    }
227

    
228
    __nestSwitchScope(node) {
229
        return this.__nestScope(new SwitchScope(this, this.__currentScope, node));
230
    }
231

    
232
    __nestModuleScope(node) {
233
        return this.__nestScope(new ModuleScope(this, this.__currentScope, node));
234
    }
235

    
236
    __nestFunctionExpressionNameScope(node) {
237
        return this.__nestScope(new FunctionExpressionNameScope(this, this.__currentScope, node));
238
    }
239

    
240
    __isES6() {
241
        return this.__options.ecmaVersion >= 6;
242
    }
243
}
244

    
245
module.exports = ScopeManager;
246

    
247
/* vim: set sw=4 ts=4 et tw=80 : */
(6-6/8)