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 }