a1e17906dbc483076f4c5f919fdb982cf18e9cb6
[charm.git] / src / langs / charj / src / charj / translator / ClassSymbol.java
1
2 package charj.translator;
3
4 import java.util.*;
5
6 public class ClassSymbol extends SymbolWithScope implements Scope {
7
8     public ClassSymbol superClass;
9     public List<String> interfaceImpls;
10
11     Map<String, PackageScope> imports = 
12         new LinkedHashMap<String, PackageScope>();
13     List<String> includes = new ArrayList<String>();
14
15     /** Record of all fields and methods */
16     public Map<String, Symbol> members = new LinkedHashMap<String, Symbol>();
17     public Map<String, VariableSymbol> fields = new LinkedHashMap<String, VariableSymbol>();
18     public Map<String, MethodSymbol> methods = new LinkedHashMap<String, MethodSymbol>();
19
20     public boolean hasCopyCtor = false;
21
22     public ClassSymbol(
23             SymbolTable symtab, 
24             String name) {
25         super(symtab, name);
26         type = this;
27         for (String pkg : SymbolTable.AUTO_IMPORTS) {
28             importPackage(pkg);
29         }
30     }
31
32     public ClassSymbol(
33             SymbolTable symtab, 
34             String name,
35             ClassSymbol superClass,
36             Scope scope) {
37         this(symtab, name);
38         this.superClass = superClass;
39         this.scope = scope;
40
41         // manually add automatic class methods and symbols here
42         this.includes.add("charm++.h");
43     }
44
45     public Scope getEnclosingScope() {
46         // at root?  Then use enclosing scope
47         if ( superClass==null ) { 
48             return scope;
49         }
50         return superClass;
51     }
52
53     public Map<String, Symbol> getMembers() {
54         return members;
55     }
56
57     /** Importing a package means adding the package to list of "filters"
58      *  used by resolvePackage.  The resolve operation can only see classes
59      *  defined in the imported packages.  This method asks the sym tab if
60      *  it is known before looking at corresponding dir on disk to see if it 
61      *  exists.
62      *
63      *  Return null if this class is not in sym tab and was not found in path.
64      */
65     public PackageScope importPackage(String packageName) {
66         if (debug()) System.out.println(
67                 "ClassSymbol.importPackage(" + packageName +
68                 "): add to " + toString());
69         
70         PackageScope p = symtab.resolvePackage(packageName);
71         if ( p!=null ) {
72             imports.put(packageName, p);
73             if (debug()) System.out.println(
74                     "ClassSymbol.importPackage(" + packageName + "): known");
75             return p;
76         }
77
78         if ( symtab.translator.findPackage(packageName) != null ) {
79             p = symtab.definePackage(packageName);
80             imports.put(packageName, p);
81         }
82
83         if ( p==null && debug() ) System.out.println(
84                 "ClassSymbol.importPackage(" + packageName + 
85                 "): dir not found");
86         return p;
87     }
88
89     /** Using the list of imports, resolve a package name like charj.lang.
90      *  There may be many packages defined and visible to the symbol table
91      *  but this class can only see those packages in the implicit or explicit
92      *  import list.
93      */
94     public PackageScope resolvePackage(String packageName) {
95         return imports.get(packageName);
96     }
97
98     /** To resolve a type in a class, look it up in each imported package 
99      *  including the current package. Classes cannot be defined in the 
100      *  superclass so don't look upwards for types.
101      *
102      *  First check to see if we are resolving enclosing class then
103      *  look for type in each imported package.  If not found in existing
104      *  packges, walk through imported packages again, trying to load from 
105      *  disk.
106      */
107     public ClassSymbol resolveType(String type) {
108         if (debug()) System.out.println(
109                 "ClassSymbol.resolveType(" + type + "): context is " + name +
110                 ":" + members.keySet());
111
112         if (type == null) {
113             return null;
114         }
115
116         if ( name.equals(type) ) {
117             if ( debug() ) System.out.println(
118                     "ClassSymbol.resolveType(" + type + 
119                     "): surrounding class " + name + ":" + members.keySet());
120             return this;
121         }
122
123         // look for type in classes already defined in imported packages
124         for (String packageName : imports.keySet()) {
125             if ( debug() ) System.out.println( "Looking for type " +
126                     type + " in package " + packageName);
127             PackageScope pkg = resolvePackage(packageName);
128             ClassSymbol cs = pkg.resolveType(type);
129             if ( cs != null) { // stop looking, found it
130                 if ( debug() ) System.out.println(
131                         "ClassSymbol.resolveType(" + type + 
132                         "): found in context " + name + ":" + 
133                         members.keySet());
134                 return cs;
135             }
136         }
137
138         // not already seen in one of the imported packages, look on disk
139         for (String packageName : imports.keySet()) {
140             PackageScope pkg = resolvePackage(packageName);
141             ClassSymbol cs = symtab.translator.loadType(
142                     pkg.getFullyQualifiedName(), type);
143             if ( cs!=null ) {
144                 pkg.define(type, cs); // add to symbol table
145                 if ( debug() ) System.out.println(
146                         "ClassSymbol.resolveType(" + type +
147                         "): found after loading in context " + name +
148                         ":" + members.keySet());
149                 return cs;
150             }
151         }
152
153         if ( debug() ) System.out.println(
154                 "ClassSymbol.resolveType(" + type + 
155                 "): not in context " + name + ":" + members.keySet());
156         return null;
157     }
158
159     public MethodSymbol resolveMethodLocally(
160             String name, 
161             int numargs) {
162         if (numargs > 0) {
163             name += numargs;
164         }
165      
166         return methods.get(name);
167     }
168
169     public boolean isMethod(String name) {
170         if ( methods.containsKey(name) ) {
171             return true;
172         }
173         if ( getEnclosingScope()!=null ) {
174             return getEnclosingScope().isMethod(name);
175         }
176         return false;
177     }
178
179     public Symbol define(
180             String name, 
181             Symbol sym) {
182         members.put(name, sym);
183         if (sym instanceof MethodSymbol) {
184             methods.put(name, (MethodSymbol)sym);
185         } else if (sym instanceof VariableSymbol) {
186             fields.put(name, (VariableSymbol)sym);
187         }
188         return super.define(name, sym);
189     }
190
191     public String toString() {
192         return "ClassSymbol[" + name + "]: " + members;
193     }
194
195     public String getFullyQualifiedName() {
196         String parent = null;
197         if ( scope!=null ) { // in a package?
198             parent = scope.getFullyQualifiedName();
199         }
200         if ( parent!=null ) {
201             return parent+"::"+name;
202         }
203         return name;
204     }
205
206     public void addInclude(String includeName) {
207         includes.add(includeName);
208     }
209
210     public String getIncludeString() {
211         String includeString = "";
212         for (String include : includes) {
213             includeString += "#include <" + include + ">\n";
214         }
215         return includeString;
216     }
217
218     public List<String> getPackageNames()
219     {
220         List<String> list = new ArrayList<String>();
221         for(Scope currentScope = scope;
222                 currentScope.getEnclosingScope() != null;
223                 currentScope = currentScope.getEnclosingScope()) {
224             list.add(currentScope.getScopeName());
225         }
226         return list;
227     }
228
229     private Set<ClassSymbol> getMemberTypes()
230     {
231         Set<ClassSymbol> types = new HashSet<ClassSymbol>();
232         for (Map.Entry<String, VariableSymbol> entry : fields.entrySet()) {
233             types.add(((VariableSymbol)entry.getValue()).type);
234         }
235         return types;
236     }
237
238     public List<String> getMemberTypeNames()
239     {
240         if (debug()) System.out.println("Looking for type names...");
241         if (debug()) System.out.println("Found " + fields.size() + " fields...");
242         List<String> names = new ArrayList<String>();
243         for (ClassSymbol c : getMemberTypes()) {
244             names.add(c.getFullyQualifiedName());
245             if (debug()) System.out.println("Found type " + c.getFullyQualifiedName());
246         }
247         return names;
248     }
249
250     public String getName()
251     {
252         return name;
253     }
254 }