Initial implementation of symbols and scopes with symbol table.
[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
14     /** List of all fields and methods */
15     public Map<String, Symbol> members = new LinkedHashMap<String, Symbol>();
16     public Map<String, String> aliases = new LinkedHashMap<String, String>();
17
18     /** The set of method names (without signatures) for this class.  Maps
19      *  to a list of methods with same name but different args
20      protected Map<String, List<MethodSymbol>> methods =
21      new HashMap<String, List<MethodSymbol>>();
22      */
23
24     /** List of unmangled methods for this class. Used to distinguish
25      *  var from method name in expressions.  x = f; // what is f?
26      */
27     protected Set<String> methodNames = new HashSet<String>();
28
29     public boolean hasCopyCtor = false;
30
31     public ClassSymbol(
32             SymbolTable symtab, 
33             String name) 
34     {
35         super(symtab, name);
36         type = this;;
37         for (String pkg : SymbolTable.AUTO_IMPORTS) {
38             importPackage(pkg);
39         }
40     }
41
42     public ClassSymbol(
43             SymbolTable symtab, 
44             String name,
45             ClassSymbol
46             superClass,
47             Scope scope)
48     {
49         this(symtab, name);
50         this.superClass = superClass;
51         this.scope = scope;
52
53         // manually add automatic class methods and symbols here
54     }
55
56     public Scope getEnclosingScope() 
57     {
58         // at root?  Then use enclosing scope
59         if ( superClass==null ) { 
60             return scope;
61         }
62         return superClass;
63     }
64
65     public Map<String, Symbol> getMembers() {
66         return members;
67     }
68
69     /** Importing a package means adding the package to list of "filters"
70      *  used by resolvePackage.  The resolve operation can only see classes
71      *  defined in the imported packages.  This method asks the sym tab if
72      *  it is known before looking at corresponding dir on disk to see if it 
73      *  exists.
74      *
75      *  Return null if this class is not in sym tab and was not found in path.
76      */
77     public PackageScope importPackage(String packageName) 
78     {
79         if (debug()) System.out.println(
80                 "ClassSymbol.importPackage(" + packageName +
81                 "): add to " + toString());
82         
83         PackageScope p = symtab.resolvePackage(packageName);
84         if ( p!=null ) {
85             imports.put(packageName, p);
86             if (debug()) System.out.println(
87                     "ClassSymbol.importPackage(" + packageName + "): known");
88             return p;
89         }
90
91         if ( symtab.translator.findPackage(packageName)!=null ) {
92             p = symtab.definePkg(packageName);
93             imports.put(packageName, p);
94         }
95
96         if ( p==null && debug() ) System.out.println(
97                 "ClassSymbol.importPackage(" + packageName + 
98                 "): dir not found");
99         return p;
100     }
101
102     public void alias(
103             CharjAST aliasAST, 
104             CharjAST methodNameAST) 
105     {
106         String op = aliasAST.getToken().getText();
107         op = op.substring(1,op.length()-1);
108         String method = methodNameAST.getToken().getText();
109         method = method.substring(1,method.length()-1);
110         alias(op, method);
111     }
112
113     public void alias(
114             String alias, 
115             String methodName) 
116     {
117         aliases.put(alias, methodName);
118     }
119
120     public String getMethodNameForOperator(String op) 
121     {
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     {
150         if ( debug() ) System.out.println(
151                 "ClassSymbol.resolveType(" + type + "): context is " + name +
152                 ":" + members.keySet());
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     {
202         if ( numargs>0 ) {
203             name += numargs;
204         }
205      
206         Symbol s = members.get(name);
207         if ( s!=null && s.getClass() == MethodSymbol.class ) {
208             return (MethodSymbol)s;
209         }
210
211         return null;
212     }
213
214     public boolean isMethod(String name) 
215     {
216         if ( methodNames.contains(name) ) {
217             return true;
218         }
219         if ( getEnclosingScope()!=null ) {
220             return getEnclosingScope().isMethod(name);
221         }
222         return false;
223     }
224
225     public Symbol define(
226             String name, 
227             Symbol sym) 
228     {
229         if ( sym instanceof MethodSymbol ) {
230             methodNames.add(sym.name);
231         }
232         return super.define(name, sym);
233     }
234
235     public String toString() {
236         return "ClassSymbol[" + name + "]: " + members;
237     }
238
239     public String getFullyQualifiedName() 
240     {
241         String parent = null;
242         if ( scope!=null ) { // in a package?
243             parent = scope.getFullyQualifiedName();
244         }
245         if ( parent!=null ) {
246             return parent+"::"+name;
247         }
248         return name;
249     }
250
251     public String getFullyQualifiedJavaName() 
252     {
253         String parent = null;
254         if ( scope!=null ) { // in a package?
255             parent = scope.getFullyQualifiedJavaName();
256         }
257         if ( parent!=null ) {
258             return parent+"."+getMangledName();
259         }
260         return name;
261     }
262
263     public String getMangledName() 
264     {
265         if ( SymbolTable.TYPE_NAMES_TO_MANGLE.contains(name) ) {
266             return "m"+name;
267         }
268         return name;
269     }
270
271 }