Further upgrades to semantic checker
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
1 package IR.Tree;
2
3 import java.util.*;
4 import IR.*;
5
6 public class SemanticCheck {
7     State state;
8     TypeUtil typeutil;
9
10     public SemanticCheck(State state, TypeUtil tu) {
11         this.state=state;
12         this.typeutil=tu;
13     }
14
15     public void semanticCheck() {
16         SymbolTable classtable=state.getClassSymbolTable();
17         Iterator it=classtable.getDescriptorsIterator();
18         // Do descriptors first
19         while(it.hasNext()) {
20             ClassDescriptor cd=(ClassDescriptor)it.next();
21             System.out.println("Checking class: "+cd);
22             //Set superclass link up
23             if (cd.getSuper()!=null) {
24                 cd.setSuper(typeutil.getClass(cd.getSuper()));
25                 // Link together Field and Method tables
26                 cd.getFieldTable().setParent(cd.getSuperDesc().getFieldTable());
27                 cd.getMethodTable().setParent(cd.getSuperDesc().getMethodTable());
28             }
29             
30             for(Iterator field_it=cd.getFields();field_it.hasNext();) {
31                 FieldDescriptor fd=(FieldDescriptor)field_it.next();
32                 System.out.println("Checking field: "+fd);
33                 checkField(cd,fd);
34             }
35             for(Iterator method_it=cd.getMethods();method_it.hasNext();) {
36                 MethodDescriptor md=(MethodDescriptor)method_it.next();
37                 checkMethod(cd,md);
38             }
39         }
40
41         it=classtable.getDescriptorsIterator();
42         // Do descriptors first
43         while(it.hasNext()) {
44             ClassDescriptor cd=(ClassDescriptor)it.next();
45             for(Iterator method_it=cd.getMethods();method_it.hasNext();) {
46                 MethodDescriptor md=(MethodDescriptor)method_it.next();
47                 checkMethodBody(cd,md);
48             }
49         }
50     }
51
52     public void checkTypeDescriptor(TypeDescriptor td) {
53         if (td.isPrimitive())
54             return; /* Done */
55         if (td.isClass()) {
56             String name=td.toString();
57             ClassDescriptor field_cd=(ClassDescriptor)state.getClassSymbolTable().get(name);
58             if (field_cd==null)
59                 throw new Error("Undefined class "+name);
60             td.setClassDescriptor(field_cd);
61             return;
62         }
63         throw new Error();
64     }
65
66     public void checkField(ClassDescriptor cd, FieldDescriptor fd) {
67         checkTypeDescriptor(fd.getType());
68     }
69
70     public void checkMethod(ClassDescriptor cd, MethodDescriptor md) {
71         /* Check return type */
72         if (!md.getReturnType().isVoid())
73             checkTypeDescriptor(md.getReturnType());
74         for(int i=0;i<md.numParameters();i++) {
75             TypeDescriptor param_type=md.getParamType(i);
76             checkTypeDescriptor(param_type);
77         }
78         /* Link the naming environments */
79         md.getParameterTable().setParent(cd.getFieldTable());
80     }
81
82     public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
83         BlockNode bn=state.getMethodBody(md);
84         checkBlockNode(md, md.getParameterTable(),bn);
85     }
86     
87     public void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
88         /* Link in the naming environment */
89         bn.getVarTable().setParent(nametable);
90         for(int i=0;i<bn.size();i++) {
91             BlockStatementNode bsn=bn.get(i);
92             checkBlockStatementNode(md, bn.getVarTable(),bsn);
93         }
94     }
95     
96     public void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable, BlockStatementNode bsn) {
97         switch(bsn.kind()) {
98         case Kind.BlockExpressionNode:
99             checkBlockExpressionNode(md, nametable,(BlockExpressionNode)bsn);
100             return;
101
102         case Kind.DeclarationNode:
103             checkDeclarationNode(md, nametable, (DeclarationNode)bsn);
104             return;
105             
106         case Kind.IfStatementNode:
107             checkIfStatementNode(md, nametable, (IfStatementNode)bsn);
108             return;
109             
110         case Kind.LoopNode:
111             checkLoopNode(md, nametable, (LoopNode)bsn);
112             return;
113             
114         case Kind.ReturnNode:
115             checkReturnNode(md, nametable, (ReturnNode)bsn);
116             return;
117
118         case Kind.SubBlockNode:
119             checkSubBlockNode(md, nametable, (SubBlockNode)bsn);
120             return;
121         }
122         throw new Error();
123     }
124
125     void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable, BlockExpressionNode ben) {
126         checkExpressionNode(md, nametable, ben.getExpression(), null);
127     }
128
129     void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable,  DeclarationNode dn) {
130         VarDescriptor vd=dn.getVarDescriptor();
131         checkTypeDescriptor(vd.getType());
132         Descriptor d=nametable.get(vd.getSymbol());
133         if ((d==null)||
134             (d instanceof FieldDescriptor)) {
135             nametable.add(vd);
136         } else
137             throw new Error(vd.getSymbol()+" defined a second time");
138         if (dn.getExpression()!=null)
139             checkExpressionNode(md, nametable, dn.getExpression(), vd.getType());
140     }
141     
142     void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) {
143         checkBlockNode(md, nametable, sbn.getBlockNode());
144     }
145
146     void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) {
147         checkExpressionNode(md, nametable, rn.getReturnExpression(), md.getReturnType());
148     }
149
150     void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) {
151         checkExpressionNode(md, nametable, isn.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
152         checkBlockNode(md, nametable, isn.getTrueBlock());
153         checkBlockNode(md, nametable, isn.getFalseBlock());
154     }
155     
156     void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
157         switch(en.kind()) {
158         case Kind.AssignmentNode:
159             checkAssignmentNode(md,nametable,(AssignmentNode)en,td);
160             return;
161         case Kind.CastNode:
162             checkCastNode(md,nametable,(CastNode)en,td);
163             return;
164         case Kind.CreateObjectNode:
165             checkCreateObjectNode(md,nametable,(CreateObjectNode)en,td);
166             return;
167         case Kind.FieldAccessNode:
168             checkFieldAccessNode(md,nametable,(FieldAccessNode)en,td);
169             return;
170         case Kind.LiteralNode:
171             checkLiteralNode(md,nametable,(LiteralNode)en,td);
172             return;
173         case Kind.MethodInvokeNode:
174             checkMethodInvokeNode(md,nametable,(MethodInvokeNode)en,td);
175             return;
176         case Kind.NameNode:
177             checkNameNode(md,nametable,(NameNode)en,td);
178             return;
179         case Kind.OpNode:
180             checkOpNode(md,nametable,(OpNode)en,td);
181             return;
182         }
183         throw new Error();
184     }
185
186     void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn, TypeDescriptor td) {
187         /* Get type descriptor */
188         if (cn.getType()==null) {
189             NameDescriptor typenamed=cn.getTypeName().getName();
190             String typename=typenamed.toString();
191             TypeDescriptor ntd=new TypeDescriptor(typeutil.getClass(typename));
192             cn.setType(ntd);
193         }
194
195         /* Check the type descriptor */
196         TypeDescriptor cast_type=cn.getType();
197         checkTypeDescriptor(cast_type);
198
199         /* Type check */
200         if (td!=null) {
201             if (!typeutil.isSuperorType(td,cast_type))
202                 throw new Error("Cast node returns "+cast_type+", but need "+td);
203         }
204
205         ExpressionNode en=cn.getExpression();
206         checkExpressionNode(md, nametable, en, null);
207         TypeDescriptor etd=en.getType();
208         if (typeutil.isSuperorType(cast_type,etd)) /* Cast trivially succeeds */
209             return;
210
211         if (typeutil.isSuperorType(etd,cast_type)) /* Cast may succeed */
212             return;
213
214         /* Different branches */
215         /* TODO: change if add interfaces */
216         throw new Error("Cast will always fail\n"+cn.printNode(0));
217     }
218
219     void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan, TypeDescriptor td) {
220         ExpressionNode left=fan.getExpression();
221         checkExpressionNode(md,nametable,left,null);
222         TypeDescriptor ltd=left.getType();
223         String fieldname=fan.getFieldName();
224         FieldDescriptor fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
225         if (fd==null)
226             throw new Error("Unknown field "+fieldname);
227         fan.setField(fd);
228         if (td!=null)
229             if (!typeutil.isSuperorType(td,fan.getType()))
230                 throw new Error("Field node returns "+fan.getType()+", but need "+td);
231     }
232
233     void checkLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode ln, TypeDescriptor td) {
234         /* Resolve the type */
235         Object o=ln.getValue();
236         if (ln.getTypeString().equals("null")) {
237             ln.setType(new TypeDescriptor(TypeDescriptor.NULL));
238         } else if (o instanceof Integer) {
239             ln.setType(new TypeDescriptor(TypeDescriptor.INT));
240         } else if (o instanceof Long) {
241             ln.setType(new TypeDescriptor(TypeDescriptor.LONG));
242         } else if (o instanceof Float) {
243             ln.setType(new TypeDescriptor(TypeDescriptor.FLOAT));
244         } else if (o instanceof Double) {
245             ln.setType(new TypeDescriptor(TypeDescriptor.DOUBLE));
246         } else if (o instanceof Character) {
247             ln.setType(new TypeDescriptor(TypeDescriptor.CHAR));
248         } else if (o instanceof String) {
249             ln.setType(new TypeDescriptor(typeutil.getClass(TypeUtil.StringClass)));
250         } 
251
252         if (td!=null)
253             if (!typeutil.isSuperorType(td,ln.getType()))
254                 throw new Error("Field node returns "+ln.getType()+", but need "+td);
255     }
256
257     void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
258         NameDescriptor nd=nn.getName();
259         String varname=nd.toString();
260         VarDescriptor vd=(VarDescriptor)nametable.get(varname);
261         if (vd==null) {
262             throw new Error("Variable "+varname+" undefined");
263         }
264         nn.setVar(vd);
265         if (td!=null)
266             if (!typeutil.isSuperorType(td,nn.getType()))
267                 throw new Error("Field node returns "+nn.getType()+", but need "+td);
268     }
269
270     void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
271         checkExpressionNode(md, nametable, an.getSrc() ,td);
272         //TODO: Need check on validity of operation here
273         if (!((an.getDest() instanceof FieldAccessNode)||
274               (an.getDest() instanceof NameNode)))
275             throw new Error("Bad lside in "+an.printNode(0));
276         checkExpressionNode(md, nametable, an.getDest(), null);
277         if (!typeutil.isSuperorType(an.getDest().getType(),an.getSrc().getType()))
278             throw new Error("Type of rside not compatible with type of lside"+an.printNode(0));
279     }
280
281     void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
282         if (ln.getType()==LoopNode.WHILELOOP||ln.getType()==LoopNode.DOWHILELOOP) {
283             checkExpressionNode(md, nametable, ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
284             checkBlockNode(md, nametable, ln.getBody());
285         } else {
286             //For loop case
287             /* Link in the initializer naming environment */
288             BlockNode bn=ln.getInitializer();
289             bn.getVarTable().setParent(nametable);
290             for(int i=0;i<bn.size();i++) {
291                 BlockStatementNode bsn=bn.get(i);
292                 checkBlockStatementNode(md, bn.getVarTable(),bsn);
293             }
294             //check the condition
295             checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
296             checkBlockNode(md, bn.getVarTable(), ln.getBody());
297             checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
298         }
299     }
300
301
302     void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable, CreateObjectNode con, TypeDescriptor td) {
303         
304     }
305
306
307     void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable, MethodInvokeNode min, TypeDescriptor td) {
308
309     }
310
311
312     void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on,TypeDescriptor td) {
313     }
314
315
316 }