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