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