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