UNPKG

3.02 kBJavaScriptView Raw
1"use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }Object.defineProperty(exports, "__esModule", {value: true});
2
3
4
5var _tokenizer = require('./parser/tokenizer');
6
7var _types = require('./parser/tokenizer/types');
8
9
10/**
11 * Traverse the given tokens and modify them if necessary to indicate that some names shadow global
12 * variables.
13 */
14 function identifyShadowedGlobals(
15 tokens,
16 scopes,
17 globalNames,
18) {
19 if (!hasShadowedGlobals(tokens, globalNames)) {
20 return;
21 }
22 markShadowedGlobals(tokens, scopes, globalNames);
23} exports.default = identifyShadowedGlobals;
24
25/**
26 * We can do a fast up-front check to see if there are any declarations to global names. If not,
27 * then there's no point in computing scope assignments.
28 */
29function hasShadowedGlobals(tokens, globalNames) {
30 for (const token of tokens.tokens) {
31 if (
32 token.type === _types.TokenType.name &&
33 _tokenizer.isDeclaration.call(void 0, token) &&
34 globalNames.has(tokens.identifierNameForToken(token))
35 ) {
36 return true;
37 }
38 }
39 return false;
40}
41
42function markShadowedGlobals(
43 tokens,
44 scopes,
45 globalNames,
46) {
47 const scopeStack = [];
48 let scopeIndex = scopes.length - 1;
49 // Scopes were generated at completion time, so they're sorted by end index, so we can maintain a
50 // good stack by going backwards through them.
51 for (let i = tokens.tokens.length - 1; ; i--) {
52 while (scopeStack.length > 0 && scopeStack[scopeStack.length - 1].startTokenIndex === i + 1) {
53 scopeStack.pop();
54 }
55 while (scopeIndex >= 0 && scopes[scopeIndex].endTokenIndex === i + 1) {
56 scopeStack.push(scopes[scopeIndex]);
57 scopeIndex--;
58 }
59 // Process scopes after the last iteration so we can make sure we pop all of them.
60 if (i < 0) {
61 break;
62 }
63
64 const token = tokens.tokens[i];
65 const name = tokens.identifierNameForToken(token);
66 if (scopeStack.length > 1 && token.type === _types.TokenType.name && globalNames.has(name)) {
67 if (_tokenizer.isBlockScopedDeclaration.call(void 0, token)) {
68 markShadowedForScope(scopeStack[scopeStack.length - 1], tokens, name);
69 } else if (_tokenizer.isFunctionScopedDeclaration.call(void 0, token)) {
70 let stackIndex = scopeStack.length - 1;
71 while (stackIndex > 0 && !scopeStack[stackIndex].isFunctionScope) {
72 stackIndex--;
73 }
74 if (stackIndex < 0) {
75 throw new Error("Did not find parent function scope.");
76 }
77 markShadowedForScope(scopeStack[stackIndex], tokens, name);
78 }
79 }
80 }
81 if (scopeStack.length > 0) {
82 throw new Error("Expected empty scope stack after processing file.");
83 }
84}
85
86function markShadowedForScope(scope, tokens, name) {
87 for (let i = scope.startTokenIndex; i < scope.endTokenIndex; i++) {
88 const token = tokens.tokens[i];
89 if (token.type === _types.TokenType.name && tokens.identifierNameForToken(token) === name) {
90 token.shadowsGlobal = true;
91 }
92 }
93}