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