Source code: com/port80/eclipse/csharp/llk/ast/ScopeStack.java
1 //
2 // Copyright(c) 2002, Chris Leung
3 //
4
5 package com.port80.eclipse.csharp.llk.ast;
6
7 import java.util.ArrayList;
8 import java.util.List;
9 import java.util.Set;
10
11 import com.port80.eclipse.csharp.llk.parser.ASTCompilationUnit;
12 import com.port80.eclipse.csharp.llk.parser.ASTRootContext;
13 import com.port80.eclipse.csharp.llk.parser.ILLKMain;
14
15 /**
16 * Scope stack is used by the parser to keep track of the current
17 * lexical scopes and performs symbol lookups.
18 *
19 * . Scope stack from bottom to top:
20 * RootContext scope
21 * CompilationUnit scope
22 * TopLevelClass scope
23 * class/block/method...etc. scopes
24 * ...
25 *
26 * . When a variable is encountered in the statement, its type is
27 * determined by searching the scopes from the top of the scope stack
28 * downwards until it found the variable declaration/definition. If
29 * a scope belongs to an IType (parent!=null), IType would
30 * search the super-class and/or super-interfaces.
31 */
32 public class ScopeStack implements IScopeStack {
33
34 ////////////////////////////////////////////////////////////////////////
35
36 private static final String NAME="ScopeStack";
37 private static final boolean DEBUG = false;
38
39 ////////////////////////////////////////////////////////////////////////
40
41 protected ILLKMain main;
42 protected ILLKScope top = null; /** Current top of stack object. */
43 protected int classLevel = 0; /** Number of IType on stack. */
44 protected List stack = new ArrayList();
45
46 // Constructors ////////////////////////////////////////////////////////
47 //
48
49 public ScopeStack(ILLKMain main) {
50 this.main = main;
51 }
52
53 // Stack interface /////////////////////////////////////////////////////
54 //
55 public void push(Object o) {
56 if (o == null)
57 main.error("o==null");
58 if (!(o instanceof ILLKScope))
59 main.error(NAME+".push(): Expected o instanceof IScope: " + o);
60 if (o instanceof Type)
61 classLevel++;
62 if (size() == 0 && !(o instanceof ASTRootContext))
63 main.error(NAME+".push(): Expected RootContext:" + o);
64 if (size() == 1 && !(o instanceof ASTCompilationUnit))
65 main.error(NAME+".push(): Expected ASTCompilationUnit:" + o);
66 stack.add(o);
67 top = (ILLKScope) o;
68 }
69
70 public ILLKScope pop() {
71 ILLKScope ret = top;
72 if (ret == null)
73 main.error("ASSERT: top != null");
74 if (ret instanceof Type) {
75 if (--classLevel < 0)
76 main.error("classLevel >= 0: " + classLevel + ": " + ret);
77 }
78 stack.remove(stack.size() - 1);
79 if (size() == 0)
80 top = null;
81 else
82 top = (ILLKScope) stack.get(stack.size() - 1);
83 return ret;
84 }
85
86 public boolean empty() {
87 return size() == 0;
88 }
89
90 public ILLKScope peek() {
91 return top;
92 }
93
94 public int size() {
95 return stack.size();
96 }
97
98 public ILLKScope get(int i) {
99 return (ILLKScope) stack.get(i);
100 }
101
102 ////////////////////////////////////////////////////////////////////////
103 //
104
105 public ASTRootContext getRootContext() {
106 return (ASTRootContext) get(0);
107 }
108
109 public ASTCompilationUnit getCompilationUnit() {
110 return (ASTCompilationUnit) get(1);
111 }
112
113 public boolean isClassScope() {
114 return (top != null && top instanceof Type);
115 }
116
117 public int getClassLevel() {
118 return classLevel;
119 }
120
121 public Type getCurrentClass() {
122 for (int i = stack.size() - 1; i >= 0; i--) {
123 Object o = stack.get(i);
124 if (o instanceof Type)
125 return (Type) o;
126 }
127 return null;
128 }
129
130 public Type getTopLevelClass() {
131 for (int i = 0; i < stack.size(); i++) {
132 Object o = stack.get(i);
133 if (o instanceof Type)
134 return (Type) o;
135 }
136 return null;
137 }
138
139 //////////////////// IScope interface ////////////////////
140
141 public String getName() {
142 return top.getName();
143 }
144
145 public Set keySet() {
146 return top.keySet();
147 }
148
149 public ISymbol putSymbol(ISymbol sym) {
150 return top.putSymbol(sym);
151 }
152
153 public ISymbol putType(String key, ISymbol sym) {
154 return top.putType(key, sym);
155 }
156
157 public ISymbol putVar(String key, ISymbol sym) {
158 return top.putVar(key, sym);
159 }
160
161 public ISymbol putMethod(String key, ISymbol sym) {
162 return top.putMethod(key, sym);
163 }
164
165 public void putSymbolList(List aList) {
166 top.putSymbolList(aList);
167 }
168
169 public ISymbol getVar(String varname) {
170 ILLKScope scope;
171 ISymbol ret;
172 for (int i = stack.size() - 1; i >= 0; i--) {
173 scope = (ILLKScope) stack.get(i);
174 ret = scope.getVar(varname);
175 if (ret != null) {
176 if (DEBUG)
177 System.err.println("ScopeStackBase.getVarSymbol(" + varname + ")=" + ret);
178 return ret;
179 }
180 }
181 if (DEBUG)
182 System.err.println("ScopeStackBase.getVarSymbol(" + varname + ") not found.");
183 return null;
184 }
185
186 public ISymbol getMethod(String sig) {
187 ILLKScope scope;
188 ISymbol ret;
189 for (int i = stack.size() - 1; i >= 0; i--) {
190 scope = (ILLKScope) stack.get(i);
191 ret = scope.getMethod(sig);
192 if (ret != null) {
193 if (DEBUG)
194 System.err.println("ScopeStackBase.getMethodSymbol(" + sig + ")=" + ret);
195 return ret;
196 }
197 }
198 if (DEBUG)
199 System.err.println("ScopeStackBase.getMethodSymbol(" + sig + ") not found.");
200 return null;
201 }
202
203 /**
204 * Lookup a type symbol.
205 *
206 * . Accept both simple type name and qualified type name. To lookup a qualified
207 * type name, the first prefix in the qualified name is lookup as a simple name.
208 * Follow suffices are then lookup its prefix's scope. If the first prefix is
209 * not found, try again with the second prefix is concatenated to the first.
210 * If none of the prefix are found, return error (null).
211 *
212 * . Looking up a simple type name is rather complicated because it involve search
213 * through the scope stack, the package and the import list.
214 *
215 * . If a class symbol is not declared in this compilation unit, search
216 * the oneTypeImportList, then the package scope, then onDemandImportList
217 *
218 * @param typename A simple name, qualified name or canonical name.
219 * @return The type object of the symbol.
220 */
221 public ISymbol getType(String typename) {
222 ISymbol ret;
223 int index;
224 // index = typename.indexOf("[L");
225 // if (index >= 0) {
226 // // Try load the member type of an array first.
227 // if (typename.startsWith("[L"))
228 // typename = typename.substring(2);
229 // else
230 // typename = typename.substring(1);
231 // ret = getTypeSymbol(typename);
232 // if (ret == null) {
233 // Msg.warn("ScopeStackBase.getSymbol(): member class of array not found: " + typename);
234 // return null;
235 // }
236 // typename = ((IType) ret).getCanonicalName();
237 // if (typename.startsWith("["))
238 // typename = "[" + typename;
239 // else
240 // typename = "[L" + typename;
241 // ISymbol sym = getSimpleTypeSymbol(typename);
242 // if (sym != null)
243 // return sym;
244 // // Create array type from membertype.
245 // ret = IType.newArrayInstance((IType) ret);
246 // getCompilationUnit().putTypeSymbol(((IType) ret).getCanonicalName(), ret);
247 // return ret;
248 // }
249 //
250 index = typename.indexOf('.');
251 if (index < 0) {
252 // Lookup as simple name.
253 ret = (ISymbol) getSimpleType(typename);
254 if (ret != null)
255 return ret;
256 } else {
257 // Lookup as qualified name.
258 ILLKScope type = null;
259 String enclose = null;
260 String classname = typename;
261 while ((index = classname.indexOf('.')) >= 0) {
262 if (enclose == null)
263 enclose = classname.substring(0, index);
264 else
265 enclose += "." + classname.substring(0, index);
266 classname = classname.substring(index + 1);
267 if (DEBUG)
268 System.err.println(
269 "ScopeStackBase.getTypeSymbol(): enclose="
270 + enclose
271 + ", classname="
272 + classname);
273 if (!(enclose.length() != 0 && classname.length() != 0))
274 main.error("ASSERT: enclose.length() != 0 && classname.length() != 0");
275 if (type == null) {
276 type = (ILLKScope) getSimpleType(enclose);
277 if (type == null)
278 type = (ILLKScope) importType(enclose);
279 if (type == null)
280 return null;
281 } else {
282 type = (ILLKScope) type.getType(enclose);
283 if (type == null)
284 return null;
285 }
286 }
287 ret = type.getType(classname);
288 }
289 return ret;
290 }
291
292 public void dumpScope(String indent) {
293 for (int i = 0; i < stack.size(); i++) {
294 ILLKScope sc = (ILLKScope) stack.get(i);
295 sc.dumpScope(indent);
296 }
297 }
298
299 ////////////////////////////////////////////////////////////////////////
300
301 public ISymbol getSimpleType(String typename) {
302 ISymbol ret = ASTRootContext.getPrimitiveType(typename);
303 if (ret != null)
304 return ret;
305 for (int i = stack.size() - 1; i >= 0; i--) {
306 ILLKScope scope = (ILLKScope) stack.get(i);
307 ret = scope.getType(typename);
308 if (ret != null) {
309 if (DEBUG)
310 System.err.println(
311 "ScopeStackBase.getSimpleTypeSymbol(" + typename + ")=" + ret);
312 return ret;
313 }
314 }
315 return null;
316 }
317
318 public ISymbol importType(String typename) {
319 // ISymbol ret;
320 // String prefix;
321 // String tname;
322 // while (true) {
323 // List oneTypeImport = getCompilationUnit().getOneTypeImport();
324 // List oneTypeSimple = getCompilationUnit().getOneTypeSimple();
325 // for (int i = 0; i < oneTypeImport.size(); i++) {
326 // tname = (String) oneTypeSimple.get(i);
327 // if (typename.equals(tname)) {
328 // tname = (String) oneTypeImport.get(i);
329 // return (ISymbol) findClass(tname);
330 // }
331 // }
332 // // Look in package.
333 // String packagename = getCompilationUnit().getPackageName();
334 // prefix = (packagename == null) ? typename : packagename + "." + typename;
335 // ret = (ISymbol) findClass(prefix);
336 // if (ret != null)
337 // break;
338 // // Lookup as fully qualified name.
339 // ret = (ISymbol) findClass(typename);
340 // if (ret != null)
341 // break;
342 // // Look in onDemandImportList
343 // List onDemandImportList = getCompilationUnit().getOnDemandImport();
344 // for (int i = 0;(ret == null) && (i < onDemandImportList.size()); i++) {
345 // prefix = (String) onDemandImportList.get(i);
346 // ret = (ISymbol) findClass(prefix + "." + typename);
347 // if (ret != null)
348 // break;
349 // }
350 // if (ret != null)
351 // break;
352 // // Look in java.lang
353 // ret = findClass("java.lang." + typename);
354 // break;
355 // }
356 // //
357 // // Class found, make an IType, import symbols and put it into the symbol table.
358 // //
359 // // To avoid search for the full class path again, cache the short class name in
360 // // the compilation unit scope.
361 // if (DEBUG)
362 // System.err.println("ScopeStackBase.importType(" + typename + ")=" + ret);
363 // return ret;
364 return null;
365 }
366
367 // Import class methods ////////////////////////////////////////////////
368
369 /**
370 * Find a class with specified canonical name in this compilation unit.
371 * Load one from the system if not found.
372 */
373 public Type findClass(String canonical_name) {
374 // Msg.trace("findClass(String): " + canonical_name);
375 // if (canonical_name.indexOf("[L") >= 0)
376 // main.error("findClass(String): canonicalname.indexOf(\"[L\")>=0");
377 // ISymbol sym = getCompilationUnit().getTypeSymbol(canonical_name);
378 // if (sym != null)
379 // return (IType) sym;
380 // sym = getRootContext().getTypeSymbol(canonical_name);
381 // if (sym != null)
382 // return (IType) sym;
383 // //
384 // // try {
385 // // Class c = Class.forName(canonicalname);
386 // // return loadClass(c);
387 // // } catch (ClassNotFoundException e) {
388 // // main.error("findClass(String): class not found: " + canonicalname);
389 // // } catch (Exception e) {
390 // // main.error("findClass(String): class name=" + canonicalname, e);
391 // // }
392 return null;
393 }
394
395 /** Find the class definition (IType) for a Class. Create one if
396 * not yet exist.
397 */
398 public Type findClass(Class c) {
399 // String canonicalname = X.cleanClassname(c.getName());
400 // Msg.trace("findClass(Class): " + canonicalname);
401 // ISymbol sym = getCompilationUnit().getTypeSymbol(canonicalname);
402 // if (sym != null)
403 // return (IType) sym;
404 // sym = getRootContext().getTypeSymbol(canonicalname);
405 // if (sym != null)
406 // return (IType) sym;
407 // return loadClass(c);
408 return null;
409 }
410
411 public Type loadClass(Class c) {
412 // String canonicalname = X.cleanClassname(c.getName());
413 // Msg.trace("loadClass(Class): " + canonicalname);
414 // // FIXME: we may need to load array classes here.
415 // IType ret = TypeFactory.newInstance(c, this);
416 // // Load the nested classes.
417 // Msg.trace("loadClass(Class): ret=" + ret);
418 // getCompilationUnit().putTypeSymbol(ret.getCanonicalName(), (ISymbol) ret);
419 // Class[] cs = c.getDeclaredClasses();
420 // for (int i = 0; i < cs.length; i++) {
421 // IType nest = IType.newInstance(cs[i], this);
422 // ret.putTypeSymbol(nest.getSimpleName(), (ISymbol) nest);
423 // getCompilationUnit().putTypeSymbol(nest.getCanonicalName(), (ISymbol) nest);
424 // Msg.trace("loadClass(Class): nested=" + nest);
425 // }
426 // return ret;
427 return null;
428 }
429
430 public Type loadClass(String name) {
431 return null;
432 }
433
434 ////////////////////////////////////////////////////////////////////////
435
436 // /** Convert from class[][] to [[Lclass format. */
437 // private String toJavaArrayTypeName(String arraytypename) {
438 // int index;
439 // String classname = arraytypename;
440 // int dim = 0;
441 // while ((index = classname.lastIndexOf('[')) >= 0) {
442 // classname = classname.substring(index + 1);
443 // dim++;
444 // }
445 // if (dim != 0) {
446 // classname = "L" + classname;
447 // for (int i = 0; i < dim; i++) {
448 // classname = "[" + classname;
449 // }
450 // }
451 // return classname;
452 // }
453
454 ////////////////////////////////////////////////////////////////////////
455 }