Charj: improve "include" formatting and add charm++.h by default
[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         this.includes.add("charm++.h");
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     public void alias(
100             CharjAST aliasAST, 
101             CharjAST methodNameAST) {
102         String op = aliasAST.getToken().getText();
103         op = op.substring(1,op.length()-1);
104         String method = methodNameAST.getToken().getText();
105         method = method.substring(1,method.length()-1);
106         alias(op, method);
107     }
108
109     public void alias(
110             String alias, 
111             String methodName) {
112         aliases.put(alias, methodName);
113     }
114
115     public String getMethodNameForOperator(String op) {
116         String name = aliases.get(op);
117         if ( name==null ) {
118             symtab.translator.error(
119                     "no such operator for " + this.name + ": " + op);
120         }
121         return name;
122     }
123
124     /** Using the list of imports, resolve a package name like charj.lang.
125      *  There may be many packages defined and visible to the symbol table
126      *  but this class can only see those packages in the implicit or explicit
127      *  import list.
128      */
129     public PackageScope resolvePackage(String packageName) {
130         return imports.get(packageName);
131     }
132
133     /** To resolve a type in a class, look it up in each imported package 
134      *  including the current package. Classes cannot be defined in the 
135      *  superclass so don't look upwards for types.
136      *
137      *  First check to see if we are resolving enclosing class then
138      *  look for type in each imported package.  If not found in existing
139      *  packges, walk through imported packages again, trying to load from 
140      *  disk.
141      */
142     public ClassSymbol resolveType(String type) {
143         if (debug()) System.out.println(
144                 "ClassSymbol.resolveType(" + type + "): context is " + name +
145                 ":" + members.keySet());
146
147         if (type == null) {
148             return null;
149         }
150
151         if ( name.equals(type) ) {
152             if ( debug() ) System.out.println(
153                     "ClassSymbol.resolveType(" + type + 
154                     "): surrounding class " + name + ":" + members.keySet());
155             return this;
156         }
157
158         // look for type in classes already defined in imported packages
159         for (String packageName : imports.keySet()) {
160             PackageScope pkg = resolvePackage(packageName);
161             ClassSymbol cs = pkg.resolveType(type);
162             if ( cs != null) { // stop looking, found it
163                 if ( debug() ) System.out.println(
164                         "ClassSymbol.resolveType(" + type + 
165                         "): found in context " + name + ":" + 
166                         members.keySet());
167                 return cs;
168             }
169         }
170
171         // not already seen in one of the imported packages, look on disk
172         for (String packageName : imports.keySet()) {
173             PackageScope pkg = resolvePackage(packageName);
174             ClassSymbol cs = symtab.translator.loadType(
175                     pkg.getFullyQualifiedName(), type);
176             if ( cs!=null ) {
177                 pkg.define(type, cs); // add to symbol table
178                 if ( debug() ) System.out.println(
179                         "ClassSymbol.resolveType(" + type +
180                         "): found after loading in context " + name +
181                         ":" + members.keySet());
182                 return cs;
183             }
184         }
185
186         if ( debug() ) System.out.println(
187                 "ClassSymbol.resolveType(" + type + 
188                 "): not in context " + name + ":" + members.keySet());
189         return null;
190     }
191
192     public MethodSymbol resolveMethodLocally(
193             String name, 
194             int numargs) {
195         if ( numargs>0 ) {
196             name += numargs;
197         }
198      
199         Symbol s = members.get(name);
200         if ( s!=null && s.getClass() == MethodSymbol.class ) {
201             return (MethodSymbol)s;
202         }
203
204         return null;
205     }
206
207     public boolean isMethod(String name) {
208         if ( methodNames.contains(name) ) {
209             return true;
210         }
211         if ( getEnclosingScope()!=null ) {
212             return getEnclosingScope().isMethod(name);
213         }
214         return false;
215     }
216
217     public Symbol define(
218             String name, 
219             Symbol sym) {
220         if ( sym instanceof MethodSymbol ) {
221             methodNames.add(sym.name);
222         }
223         return super.define(name, sym);
224     }
225
226     public String toString() {
227         return "ClassSymbol[" + name + "]: " + members;
228     }
229
230     public String getFullyQualifiedName() {
231         String parent = null;
232         if ( scope!=null ) { // in a package?
233             parent = scope.getFullyQualifiedName();
234         }
235         if ( parent!=null ) {
236             return parent+"."+name;
237         }
238         return name;
239     }
240
241     public String getMangledName() {
242         if ( SymbolTable.TYPE_NAMES_TO_MANGLE.contains(name) ) {
243             return "m"+name;
244         }
245         return name;
246     }
247
248     public void addInclude(String includeName) {
249         includes.add(includeName);
250     }
251
252     public String getIncludeString() {
253         String includeString = "";
254         for (String include : includes) {
255             includeString += "#include <" + include + ">\n";
256         }
257         return includeString;
258     }
259
260     public String getNamespaceOpeningString() {
261         Scope currentScope = scope;
262         String namespace = "";
263         while (currentScope.getEnclosingScope() != null) {
264             namespace = "namespace " + currentScope.getScopeName() + " { " + namespace;
265             currentScope = currentScope.getEnclosingScope();
266         }
267         return namespace;
268     }
269
270     public String getNamespaceClosingString() {
271         Scope currentScope = scope;
272         String namespace = "";
273         while (currentScope.getEnclosingScope() != null) {
274             namespace += "} ";
275             currentScope = currentScope.getEnclosingScope();
276         }
277         return namespace;
278     }
279 }