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