fix for alokika's bug
[IRC.git] / Robust / src / IR / TypeUtil.java
1 package IR;
2 import java.util.*;
3 import IR.Tree.*;
4 import java.io.File;
5 import Main.Main;
6
7 public class TypeUtil {
8   public static final String StringClass="String";
9   public static final String ObjectClass="Object";
10   public static final String StartupClass="StartupObject";
11   public static final String TagClass="TagDescriptor";
12   public static final String ThreadClass="Thread";
13   State state;
14   Hashtable supertable;
15   Hashtable subclasstable;
16   BuildIR bir;
17
18   public TypeUtil(State state, BuildIR bir) {
19     this.state=state;
20     this.bir=bir;
21     createTables();
22   }
23
24   public void addNewClass(String cl, Set todo) {
25     for(int i=0;i<state.classpath.size();i++) {
26       String path=(String)state.classpath.get(i);
27       File f=new File(path, cl+".java");
28       if (f.exists()) {
29         try {
30           ParseNode pn=Main.readSourceFile(state, f.getCanonicalPath());
31           bir.buildtree(pn, todo);
32           return;
33         } catch (Exception e) {
34           throw new Error(e);
35         }
36       }
37     }
38     throw new Error("Couldn't find class "+cl);
39   }
40
41
42
43   public ClassDescriptor getClass(String classname) {
44     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
45     return cd;
46   }
47
48   public ClassDescriptor getClass(String classname, HashSet todo) {
49     ClassDescriptor cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
50     if (cd==null) {
51       //have to find class
52       addNewClass(classname, todo);
53       cd=(ClassDescriptor)state.getClassSymbolTable().get(classname);
54       System.out.println("Build class:"+cd);
55       todo.add(cd);
56     }
57     if (!supertable.containsKey(cd)) {
58       String superc=cd.getSuper();
59       if (superc!=null) {
60         ClassDescriptor cd_super=getClass(superc, todo);
61         supertable.put(cd,cd_super);
62       }
63     }
64     return cd;
65   }
66
67   private void createTables() {
68     supertable=new Hashtable();
69   }
70
71   public ClassDescriptor getMainClass() {
72     return getClass(state.main);
73   }
74
75   public MethodDescriptor getRun() {
76     ClassDescriptor cd=getClass(TypeUtil.ThreadClass);
77     for(Iterator methodit=cd.getMethodTable().getSet("run").iterator(); methodit.hasNext();) {
78       MethodDescriptor md=(MethodDescriptor) methodit.next();
79       if (md.numParameters()!=0||md.getModifiers().isStatic())
80         continue;
81       return md;
82     }
83     throw new Error("Can't find Thread.run");
84   }
85
86   public MethodDescriptor getMain() {
87     ClassDescriptor cd=getMainClass();
88     Set mainset=cd.getMethodTable().getSet("main");
89     for(Iterator mainit=mainset.iterator(); mainit.hasNext();) {
90       MethodDescriptor md=(MethodDescriptor)mainit.next();
91       if (md.numParameters()!=1)
92         continue;
93       Descriptor pd=md.getParameter(0);
94       TypeDescriptor tpd=(pd instanceof TagVarDescriptor) ? ((TagVarDescriptor)pd).getType() : ((VarDescriptor)pd)
95                           .getType();
96       if (tpd.getArrayCount()!=1)
97         continue;
98       if (!tpd.getSymbol().equals("String"))
99         continue;
100
101       if (!md.getModifiers().isStatic())
102         throw new Error("Error: Non static main");
103       return md;
104     }
105     throw new Error(cd+" has no main");
106   }
107
108   /** Check to see if md1 is more specific than md2...  Informally
109       if md2 could always be called given the arguments passed into
110       md1 */
111
112   public boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
113     /* Checks if md1 is more specific than md2 */
114     if (md1.numParameters()!=md2.numParameters())
115       throw new Error();
116     for(int i=0; i<md1.numParameters(); i++) {
117       if (!this.isSuperorType(md2.getParamType(i), md1.getParamType(i)))
118         return false;
119     }
120     if (md1.getReturnType()==null||md2.getReturnType()==null) {
121         if (md1.getReturnType()!=md2.getReturnType())
122             return false;
123     } else
124         if (!this.isSuperorType(md2.getReturnType(), md1.getReturnType()))
125             return false;
126
127     if (!this.isSuperorType(md2.getClassDesc(), md1.getClassDesc()))
128       return false;
129
130     return true;
131   }
132
133   public MethodDescriptor getMethod(ClassDescriptor cd, String name, TypeDescriptor[] types) {
134     Set methoddescriptorset=cd.getMethodTable().getSet(name);
135     MethodDescriptor bestmd=null;
136 NextMethod:
137     for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
138       MethodDescriptor currmd=(MethodDescriptor)methodit.next();
139       /* Need correct number of parameters */
140       if (types.length!=currmd.numParameters())
141         continue;
142       for(int i=0; i<types.length; i++) {
143         if (!this.isSuperorType(currmd.getParamType(i),types[i]))
144           continue NextMethod;
145       }
146       /* Method okay so far */
147       if (bestmd==null)
148         bestmd=currmd;
149       else {
150         if (isMoreSpecific(currmd,bestmd)) {
151           bestmd=currmd;
152         } else if (!isMoreSpecific(bestmd, currmd))
153           throw new Error("No method is most specific");
154
155         /* Is this more specific than bestmd */
156       }
157     }
158     if (bestmd==null)
159       throw new Error("Could find: "+name + " in "+cd);
160
161     return bestmd;
162   }
163
164   public void createFullTable() {
165     subclasstable=new Hashtable();
166
167     Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
168     while(classit.hasNext()) {
169       ClassDescriptor cd=(ClassDescriptor)classit.next();
170       ClassDescriptor tmp=cd.getSuperDesc();
171
172       while(tmp!=null) {
173         if (!subclasstable.containsKey(tmp))
174           subclasstable.put(tmp,new HashSet());
175         HashSet hs=(HashSet)subclasstable.get(tmp);
176         hs.add(cd);
177         tmp=tmp.getSuperDesc();
178       }
179     }
180   }
181
182   public Set getSubClasses(ClassDescriptor cd) {
183     return (Set)subclasstable.get(cd);
184   }
185
186   public ClassDescriptor getSuper(ClassDescriptor cd) {
187     return (ClassDescriptor)supertable.get(cd);
188   }
189
190   public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
191     if (original.isChar()&&
192         (casttype.isByte()||
193          casttype.isShort()))
194       return true;
195
196     if (casttype.isChar()&&
197         (original.isByte()||
198          original.isShort()||
199          original.isInt()||
200          original.isLong()||
201          original.isFloat()||
202          original.isDouble()))
203       return true;
204
205     return false;
206   }
207
208   public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
209     if (possiblesuper.isOffset() || cd2.isOffset()) return true;
210     //Matching type are always okay
211     if (possiblesuper.equals(cd2))
212       return true;
213
214     if ((possiblesuper.isTag() && !cd2.isTag())||
215         (!possiblesuper.isTag() && cd2.isTag()))
216       return false;
217
218     //Handle arrays
219     if (cd2.isArray()||possiblesuper.isArray()) {
220       // Object is super class of all arrays
221       if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
222         return true;
223
224       // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
225       if (cd2.isClass()&&possiblesuper.isClass()
226           &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
227           isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
228         return true;
229
230       // Object is superclass of all array classes
231       if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
232           &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
233         return true;
234
235       //Allow arraytype=null statements
236       if (possiblesuper.isArray()&&cd2.isNull())
237         return true;
238
239       return false;
240     }
241
242     if (possiblesuper.isClass()&&
243         cd2.isClass())
244       return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
245     else if (possiblesuper.isClass()&&
246              cd2.isNull())
247       return true;
248     else if (possiblesuper.isNull())
249       throw new Error();       //not sure when this case would occur
250     else if (possiblesuper.isPrimitive()&&
251              cd2.isPrimitive()) {
252       ///Primitive widenings from 5.1.2
253       if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
254                          possiblesuper.isInt()||possiblesuper.isLong()||
255                          possiblesuper.isFloat()||possiblesuper.isDouble()))
256         return true;
257       if (cd2.isShort()&&(possiblesuper.isShort()||
258                           possiblesuper.isInt()||possiblesuper.isLong()||
259                           possiblesuper.isFloat()||possiblesuper.isDouble()))
260         return true;
261       if (cd2.isChar()&&(possiblesuper.isChar()||
262                          possiblesuper.isInt()||possiblesuper.isLong()||
263                          possiblesuper.isFloat()||possiblesuper.isDouble()))
264         return true;
265       if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
266                         possiblesuper.isFloat()||possiblesuper.isDouble()))
267         return true;
268       if (cd2.isLong()&&(possiblesuper.isLong()||
269                          possiblesuper.isFloat()||possiblesuper.isDouble()))
270         return true;
271       if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
272         return true;
273       if (cd2.isDouble()&&possiblesuper.isDouble())
274
275         return true;
276       if (cd2.isBoolean()&&possiblesuper.isBoolean())
277         return true;
278
279       return false;
280     } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
281                cd2.isPtr())
282       return false;
283     else if (cd2.isPrimitive()&&(!cd2.isArray())&&
284              possiblesuper.isPtr())
285       return false;
286     else
287       throw new Error("Case not handled:"+possiblesuper+" "+cd2);
288   }
289
290
291   public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
292     if (possiblesuper==cd2)
293       return true;
294     else
295       return isSuper(possiblesuper, cd2);
296   }
297
298   private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
299
300     while(cd2!=null) {
301       cd2=getSuper(cd2);
302       if (cd2==possiblesuper)
303         return true;
304     }
305     return false;
306   }
307 }