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