support a bit more java
[IRC.git] / Robust / src / IR / TypeUtil.java
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         return bestmd;
125     }
126
127     public void createFullTable() {
128         subclasstable=new Hashtable();
129     
130         Iterator classit=state.getClassSymbolTable().getDescriptorsIterator();
131         while(classit.hasNext()) {
132             ClassDescriptor cd=(ClassDescriptor)classit.next();
133             ClassDescriptor tmp=cd.getSuperDesc();
134             
135             while(tmp!=null) {
136                 if (!subclasstable.containsKey(tmp))
137                     subclasstable.put(tmp,new HashSet());
138                 HashSet hs=(HashSet)subclasstable.get(tmp);
139                 hs.add(cd);
140                 tmp=tmp.getSuperDesc();
141             }
142         }
143     }
144
145     public Set getSubClasses(ClassDescriptor cd) {
146         return (Set)subclasstable.get(cd);
147     }
148
149     public ClassDescriptor getSuper(ClassDescriptor cd) {
150         return (ClassDescriptor)supertable.get(cd);
151     }
152
153     public boolean isCastable(TypeDescriptor original, TypeDescriptor casttype) {
154         if (original.isChar()&&
155             (casttype.isByte()||
156              casttype.isShort()))
157             return true;
158
159         if (casttype.isChar()&&
160             (original.isByte()||
161              original.isShort()||
162              original.isInt()||
163              original.isLong()||
164              original.isFloat()||
165              original.isDouble()))
166             return true;
167             
168         return false;
169     }
170
171     public boolean isSuperorType(TypeDescriptor possiblesuper, TypeDescriptor cd2) {
172         //Matching type are always okay
173         if (possiblesuper.equals(cd2))
174             return true;
175
176         if ((possiblesuper.isTag() && !cd2.isTag())||
177             (!possiblesuper.isTag() && cd2.isTag()))
178             return false;
179
180         //Handle arrays
181         if (cd2.isArray()||possiblesuper.isArray()) {
182             // Object is super class of all arrays
183             if (possiblesuper.getSymbol().equals(ObjectClass)&&!possiblesuper.isArray())
184                 return true;
185
186             // If we have the same dimensionality of arrays & both are classes, we can default to the normal test
187             if (cd2.isClass()&&possiblesuper.isClass()
188                 &&(possiblesuper.getArrayCount()==cd2.getArrayCount())&&
189                 isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc()))
190                 return true;
191
192             // Object is superclass of all array classes
193             if (possiblesuper.getSymbol().equals(ObjectClass)&&cd2.isClass()
194                 &&(possiblesuper.getArrayCount()<cd2.getArrayCount()))
195                 return true;
196
197             return false;
198         }
199
200         if (possiblesuper.isClass()&&
201              cd2.isClass())
202             return isSuperorType(possiblesuper.getClassDesc(), cd2.getClassDesc());
203         else if (possiblesuper.isClass()&&
204                  cd2.isNull())
205             return true;
206         else if (possiblesuper.isNull())
207             throw new Error(); //not sure when this case would occur
208         else if (possiblesuper.isPrimitive()&&
209                  cd2.isPrimitive()) {
210             ///Primitive widenings from 5.1.2
211             if (cd2.isByte()&&(possiblesuper.isByte()||possiblesuper.isShort()||
212                                possiblesuper.isInt()||possiblesuper.isLong()||
213                                possiblesuper.isFloat()||possiblesuper.isDouble()))
214                 return true;
215             if (cd2.isShort()&&(possiblesuper.isShort()||
216                                 possiblesuper.isInt()||possiblesuper.isLong()||
217                                 possiblesuper.isFloat()||possiblesuper.isDouble()))
218                 return true;
219             if (cd2.isChar()&&(possiblesuper.isChar()||
220                                possiblesuper.isInt()||possiblesuper.isLong()||
221                                possiblesuper.isFloat()||possiblesuper.isDouble()))
222                 return true;
223             if (cd2.isInt()&&(possiblesuper.isInt()||possiblesuper.isLong()||
224                               possiblesuper.isFloat()||possiblesuper.isDouble()))
225                 return true;
226             if (cd2.isLong()&&(possiblesuper.isLong()||
227                                possiblesuper.isFloat()||possiblesuper.isDouble()))
228                 return true;
229             if (cd2.isFloat()&&(possiblesuper.isFloat()||possiblesuper.isDouble()))
230                 return true;
231             if (cd2.isDouble()&&possiblesuper.isDouble())
232                 
233                 return true;
234             if (cd2.isBoolean()&&possiblesuper.isBoolean())
235                 return true;
236             
237             return false;
238         } else if (possiblesuper.isPrimitive()&&(!possiblesuper.isArray())&&
239                    cd2.isPtr())
240             return false;
241         else if (cd2.isPrimitive()&&(!cd2.isArray())&&
242                  possiblesuper.isPtr())
243             return false;
244         else
245             throw new Error("Case not handled:"+possiblesuper+" "+cd2);
246     }
247
248     
249     public boolean isSuperorType(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
250         if (possiblesuper==cd2)
251             return true;
252         else
253             return isSuper(possiblesuper, cd2);
254     }
255
256     private boolean isSuper(ClassDescriptor possiblesuper, ClassDescriptor cd2) {
257         while(cd2!=null) {
258             cd2=getSuper(cd2);
259             if (cd2==possiblesuper)
260                 return true;
261         }
262         return false;
263     }
264 }