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