2930ee8c5906640fff87ee695f4c0becbe706280
[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             if ( debug() ) System.out.println( "Looking for type " +
161                     type + " in package " + packageName);
162             PackageScope pkg = resolvePackage(packageName);
163             ClassSymbol cs = pkg.resolveType(type);
164             if ( cs != null) { // stop looking, found it
165                 if ( debug() ) System.out.println(
166                         "ClassSymbol.resolveType(" + type + 
167                         "): found in context " + name + ":" + 
168                         members.keySet());
169                 return cs;
170             }
171         }
172
173         // not already seen in one of the imported packages, look on disk
174         for (String packageName : imports.keySet()) {
175             PackageScope pkg = resolvePackage(packageName);
176             ClassSymbol cs = symtab.translator.loadType(
177                     pkg.getFullyQualifiedName(), type);
178             if ( cs!=null ) {
179                 pkg.define(type, cs); // add to symbol table
180                 if ( debug() ) System.out.println(
181                         "ClassSymbol.resolveType(" + type +
182                         "): found after loading in context " + name +
183                         ":" + members.keySet());
184                 return cs;
185             }
186         }
187
188         if ( debug() ) System.out.println(
189                 "ClassSymbol.resolveType(" + type + 
190                 "): not in context " + name + ":" + members.keySet());
191         return null;
192     }
193
194     public MethodSymbol resolveMethodLocally(
195             String name, 
196             int numargs) {
197         if ( numargs>0 ) {
198             name += numargs;
199         }
200      
201         Symbol s = members.get(name);
202         if ( s!=null && s.getClass() == MethodSymbol.class ) {
203             return (MethodSymbol)s;
204         }
205
206         return null;
207     }
208
209     public boolean isMethod(String name) {
210         if ( methodNames.contains(name) ) {
211             return true;
212         }
213         if ( getEnclosingScope()!=null ) {
214             return getEnclosingScope().isMethod(name);
215         }
216         return false;
217     }
218
219     public Symbol define(
220             String name, 
221             Symbol sym) {
222         if ( sym instanceof MethodSymbol ) {
223             methodNames.add(sym.name);
224         }
225         return super.define(name, sym);
226     }
227
228     public String toString() {
229         return "ClassSymbol[" + name + "]: " + members;
230     }
231
232     public String getFullyQualifiedName() {
233         String parent = null;
234         if ( scope!=null ) { // in a package?
235             parent = scope.getFullyQualifiedName();
236         }
237         if ( parent!=null ) {
238             return parent+"."+name;
239         }
240         return name;
241     }
242
243     public String getMangledName() {
244         if ( SymbolTable.TYPE_NAMES_TO_MANGLE.contains(name) ) {
245             return "m"+name;
246         }
247         return name;
248     }
249
250     public void addInclude(String includeName) {
251         includes.add(includeName);
252     }
253
254     public String getIncludeString() {
255         String includeString = "";
256         for (String include : includes) {
257             includeString += "#include <" + include + ">\n";
258         }
259         return includeString;
260     }
261
262     public List<String> getPackageNames()
263     {
264         List<String> list = new ArrayList<String>();
265         for(Scope currentScope = scope;
266                 currentScope.getEnclosingScope() != null;
267                 currentScope = currentScope.getEnclosingScope()) {
268             list.add(currentScope.getScopeName());
269         }
270         return list;
271     }
272 }