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