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