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