forked from mozilla/rhino
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScope.java
More file actions
259 lines (230 loc) · 7.35 KB
/
Copy pathScope.java
File metadata and controls
259 lines (230 loc) · 7.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript.ast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.mozilla.javascript.Node;
import org.mozilla.javascript.Token;
/**
* Represents a scope in the lexical scope chain. Base type for
* all {@link AstNode} implementations that can introduce a new scope.
*/
public class Scope extends Jump {
// Use LinkedHashMap so that the iteration order is the insertion order
protected Map<String,Symbol> symbolTable;
protected Scope parentScope;
protected ScriptNode top; // current script or function scope
private List<Scope> childScopes;
{
this.type = Token.BLOCK;
}
public Scope() {
}
public Scope(int pos) {
this.position = pos;
}
public Scope(int pos, int len) {
this(pos);
this.length = len;
}
public Scope getParentScope() {
return parentScope;
}
/**
* Sets parent scope
*/
public void setParentScope(Scope parentScope) {
this.parentScope = parentScope;
this.top = parentScope == null ? (ScriptNode)this : parentScope.top;
}
/**
* Used only for code generation.
*/
public void clearParentScope() {
this.parentScope = null;
}
/**
* Return a list of the scopes whose parent is this scope.
* @return the list of scopes we enclose, or {@code null} if none
*/
public List<Scope> getChildScopes() {
return childScopes;
}
/**
* Add a scope to our list of child scopes.
* Sets the child's parent scope to this scope.
* @throws IllegalStateException if the child's parent scope is
* non-{@code null}
*/
public void addChildScope(Scope child) {
if (childScopes == null) {
childScopes = new ArrayList<Scope>();
}
childScopes.add(child);
child.setParentScope(this);
}
/**
* Used by the parser; not intended for typical use.
* Changes the parent-scope links for this scope's child scopes
* to the specified new scope. Copies symbols from this scope
* into new scope.
*
* @param newScope the scope that will replace this one on the
* scope stack.
*/
public void replaceWith(Scope newScope) {
if (childScopes != null) {
for (Scope kid : childScopes) {
newScope.addChildScope(kid); // sets kid's parent
}
childScopes.clear();
childScopes = null;
}
if (symbolTable != null && !symbolTable.isEmpty()) {
joinScopes(this, newScope);
}
}
/**
* Returns current script or function scope
*/
public ScriptNode getTop() {
return top;
}
/**
* Sets top current script or function scope
*/
public void setTop(ScriptNode top) {
this.top = top;
}
/**
* Creates a new scope node, moving symbol table information
* from "scope" to the new node, and making "scope" a nested
* scope contained by the new node.
* Useful for injecting a new scope in a scope chain.
*/
public static Scope splitScope(Scope scope) {
Scope result = new Scope(scope.getType());
result.symbolTable = scope.symbolTable;
scope.symbolTable = null;
result.parent = scope.parent;
result.setParentScope(scope.getParentScope());
result.setParentScope(result);
scope.parent = result;
result.top = scope.top;
return result;
}
/**
* Copies all symbols from source scope to dest scope.
*/
public static void joinScopes(Scope source, Scope dest) {
Map<String,Symbol> src = source.ensureSymbolTable();
Map<String,Symbol> dst = dest.ensureSymbolTable();
if (!Collections.disjoint(src.keySet(), dst.keySet())) {
codeBug();
}
for (Map.Entry<String, Symbol> entry: src.entrySet()) {
Symbol sym = entry.getValue();
sym.setContainingTable(dest);
dst.put(entry.getKey(), sym);
}
}
/**
* Returns the scope in which this name is defined
* @param name the symbol to look up
* @return this {@link Scope}, one of its parent scopes, or {@code null} if
* the name is not defined any this scope chain
*/
public Scope getDefiningScope(String name) {
for (Scope s = this; s != null; s = s.parentScope) {
Map<String,Symbol> symbolTable = s.getSymbolTable();
if (symbolTable != null && symbolTable.containsKey(name)) {
return s;
}
}
return null;
}
/**
* Looks up a symbol in this scope.
* @param name the symbol name
* @return the Symbol, or {@code null} if not found
*/
public Symbol getSymbol(String name) {
return symbolTable == null ? null : symbolTable.get(name);
}
/**
* Enters a symbol into this scope.
*/
public void putSymbol(Symbol symbol) {
if (symbol.getName() == null)
throw new IllegalArgumentException("null symbol name");
ensureSymbolTable();
symbolTable.put(symbol.getName(), symbol);
symbol.setContainingTable(this);
top.addSymbol(symbol);
}
/**
* Returns the symbol table for this scope.
* @return the symbol table. May be {@code null}.
*/
public Map<String,Symbol> getSymbolTable() {
return symbolTable;
}
/**
* Sets the symbol table for this scope. May be {@code null}.
*/
public void setSymbolTable(Map<String, Symbol> table) {
symbolTable = table;
}
private Map<String,Symbol> ensureSymbolTable() {
if (symbolTable == null) {
symbolTable = new LinkedHashMap<String,Symbol>(5);
}
return symbolTable;
}
/**
* Returns a copy of the child list, with each child cast to an
* {@link AstNode}.
* @throws ClassCastException if any non-{@code AstNode} objects are
* in the child list, e.g. if this method is called after the code
* generator begins the tree transformation.
*/
public List<AstNode> getStatements() {
List<AstNode> stmts = new ArrayList<AstNode>();
Node n = getFirstChild();
while (n != null) {
stmts.add((AstNode)n);
n = n.getNext();
}
return stmts;
}
@Override
public String toSource(int depth) {
StringBuilder sb = new StringBuilder();
sb.append(makeIndent(depth));
sb.append("{\n");
for (Node kid : this) {
AstNode astNodeKid = (AstNode) kid;
sb.append(astNodeKid.toSource(depth+1));
if(astNodeKid.getType() == Token.COMMENT) {
sb.append("\n");
}
}
sb.append(makeIndent(depth));
sb.append("}\n");
return sb.toString();
}
@Override
public void visit(NodeVisitor v) {
if (v.visit(this)) {
for (Node kid : this) {
((AstNode)kid).visit(v);
}
}
}
}