Charj: improved error message and added pupping for proxy types
[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         if (sym == null) {
193             System.out.println("ClassSymbol.define: Uh oh, defining null symbol");
194         }
195         members.put(name, sym);
196         if (sym instanceof MethodSymbol) {
197             methods.put(name, (MethodSymbol)sym);
198         } else if (sym instanceof VariableSymbol) {
199             fields.put(name, (VariableSymbol)sym);
200         }
201         return super.define(name, sym);
202     }
203
204     public String toString() {
205         return "ClassSymbol[" + name + "]: " + members;
206     }
207
208     public String getFullyQualifiedName() {
209         String parent = null;
210         if ( scope!=null ) { // in a package?
211             parent = scope.getFullyQualifiedName();
212         }
213         if ( parent!=null ) {
214             return parent+"::"+name;
215         }
216         return name;
217     }
218
219     public void addInclude(String includeName) {
220         includes.add(includeName);
221     }
222
223     public void getUsings(String usingName) {
224         usings.add(usingName);
225     }
226
227     public List<String> getIncludes()
228     {
229         return includes;
230     }
231
232     public List<String> getUsings()
233     {
234         return usings;
235     }
236
237     public List<String> getPackageNames()
238     {
239         List<String> list = new ArrayList<String>();
240         for(Scope currentScope = scope;
241                 currentScope.getEnclosingScope() != null;
242                 currentScope = currentScope.getEnclosingScope()) {
243             list.add(currentScope.getScopeName());
244         }
245         return list;
246     }
247
248     private Set<ClassSymbol> getMemberTypes()
249     {
250         Set<ClassSymbol> types = new HashSet<ClassSymbol>();
251         for (Map.Entry<String, VariableSymbol> entry : fields.entrySet()) {
252             // note: type info may be null for unknown types, but this might
253             // need to be changed at some point.
254             ClassSymbol type = ((VariableSymbol)entry.getValue()).type;
255             if (type != null) types.add(type);
256         }
257         return types;
258     }
259
260     public List<String> getMemberTypeNames()
261     {
262         List<String> names = new ArrayList<String>();
263         for (ClassSymbol c : getMemberTypes()) {
264             if (c.isPrimitive) continue;
265             names.add(c.getName());
266         }
267         return names;
268     }
269
270     public String getName()
271     {
272         return name;
273     }
274 }