loop code
[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     Stack loopstack;
10
11
12   public SemanticCheck(State state, TypeUtil tu) {
13     this.state=state;
14     this.typeutil=tu;
15     this.loopstack=new Stack();
16   }
17
18   public void semanticCheck() {
19     SymbolTable classtable=state.getClassSymbolTable();
20     Iterator it=classtable.getDescriptorsIterator();
21     // Do descriptors first
22     while(it.hasNext()) {
23       ClassDescriptor cd=(ClassDescriptor)it.next();
24       //System.out.println("Checking class: "+cd);
25       //Set superclass link up
26       if (cd.getSuper()!=null) {
27         cd.setSuper(typeutil.getClass(cd.getSuper()));
28         // Link together Field, Method, and Flag tables so classes
29         // inherit these from their superclasses
30         cd.getFieldTable().setParent(cd.getSuperDesc().getFieldTable());
31         cd.getMethodTable().setParent(cd.getSuperDesc().getMethodTable());
32         cd.getFlagTable().setParent(cd.getSuperDesc().getFlagTable());
33       }
34
35       /* Check to see that fields are well typed */
36       for(Iterator field_it=cd.getFields(); field_it.hasNext();) {
37         FieldDescriptor fd=(FieldDescriptor)field_it.next();
38         //System.out.println("Checking field: "+fd);
39         checkField(cd,fd);
40       }
41
42       for(Iterator method_it=cd.getMethods(); method_it.hasNext();) {
43         MethodDescriptor md=(MethodDescriptor)method_it.next();
44         checkMethod(cd,md);
45       }
46     }
47
48     it=classtable.getDescriptorsIterator();
49     // Do descriptors first
50     while(it.hasNext()) {
51       ClassDescriptor cd=(ClassDescriptor)it.next();
52       for(Iterator method_it=cd.getMethods(); method_it.hasNext();) {
53         MethodDescriptor md=(MethodDescriptor)method_it.next();
54         checkMethodBody(cd,md);
55       }
56     }
57
58     for(Iterator task_it=state.getTaskSymbolTable().getDescriptorsIterator(); task_it.hasNext();) {
59       TaskDescriptor td=(TaskDescriptor)task_it.next();
60       checkTask(td);
61
62     }
63   }
64
65   public void checkTypeDescriptor(TypeDescriptor td) {
66     if (td.isPrimitive())
67       return;       /* Done */
68     else if (td.isClass()) {
69       String name=td.toString();
70       ClassDescriptor field_cd=(ClassDescriptor)state.getClassSymbolTable().get(name);
71       if (field_cd==null)
72         throw new Error("Undefined class "+name);
73       td.setClassDescriptor(field_cd);
74       return;
75     } else if (td.isTag())
76       return;
77     else
78       throw new Error();
79   }
80
81   public void checkField(ClassDescriptor cd, FieldDescriptor fd) {
82     checkTypeDescriptor(fd.getType());
83   }
84
85   public void checkConstraintCheck(TaskDescriptor td, SymbolTable nametable, Vector ccs) {
86     if (ccs==null)
87       return;       /* No constraint checks to check */
88     for(int i=0; i<ccs.size(); i++) {
89       ConstraintCheck cc=(ConstraintCheck) ccs.get(i);
90
91       for(int j=0; j<cc.numArgs(); j++) {
92         ExpressionNode en=cc.getArg(j);
93         checkExpressionNode(td,nametable,en,null);
94       }
95     }
96   }
97
98   public void checkFlagEffects(TaskDescriptor td, Vector vfe, SymbolTable nametable) {
99     if (vfe==null)
100       return;       /* No flag effects to check */
101     for(int i=0; i<vfe.size(); i++) {
102       FlagEffects fe=(FlagEffects) vfe.get(i);
103       String varname=fe.getName();
104       //Make sure the variable is declared as a parameter to the task
105       VarDescriptor vd=(VarDescriptor)td.getParameterTable().get(varname);
106       if (vd==null)
107         throw new Error("Parameter "+varname+" in Flag Effects not declared in "+td);
108       fe.setVar(vd);
109
110       //Make sure it correspods to a class
111       TypeDescriptor type_d=vd.getType();
112       if (!type_d.isClass())
113         throw new Error("Cannot have non-object argument for flag_effect");
114
115       ClassDescriptor cd=type_d.getClassDesc();
116       for(int j=0; j<fe.numEffects(); j++) {
117         FlagEffect flag=fe.getEffect(j);
118         String name=flag.getName();
119         FlagDescriptor flag_d=(FlagDescriptor)cd.getFlagTable().get(name);
120         //Make sure the flag is declared
121         if (flag_d==null)
122           throw new Error("Flag descriptor "+name+" undefined in class: "+cd.getSymbol());
123         if (flag_d.getExternal())
124           throw new Error("Attempting to modify external flag: "+name);
125         flag.setFlag(flag_d);
126       }
127       for(int j=0; j<fe.numTagEffects(); j++) {
128         TagEffect tag=fe.getTagEffect(j);
129         String name=tag.getName();
130
131         Descriptor d=(Descriptor)nametable.get(name);
132         if (d==null)
133           throw new Error("Tag descriptor "+name+" undeclared");
134         else if (!(d instanceof TagVarDescriptor))
135           throw new Error(name+" is not a tag descriptor");
136         tag.setTag((TagVarDescriptor)d);
137       }
138     }
139   }
140
141   public void checkTask(TaskDescriptor td) {
142     for(int i=0; i<td.numParameters(); i++) {
143       /* Check that parameter is well typed */
144       TypeDescriptor param_type=td.getParamType(i);
145       checkTypeDescriptor(param_type);
146
147       /* Check the parameter's flag expression is well formed */
148       FlagExpressionNode fen=td.getFlag(td.getParameter(i));
149       if (!param_type.isClass())
150         throw new Error("Cannot have non-object argument to a task");
151       ClassDescriptor cd=param_type.getClassDesc();
152       if (fen!=null)
153         checkFlagExpressionNode(cd, fen);
154     }
155
156     checkFlagEffects(td, td.getFlagEffects(),td.getParameterTable());
157     /* Check that the task code is valid */
158     BlockNode bn=state.getMethodBody(td);
159     checkBlockNode(td, td.getParameterTable(),bn);
160   }
161
162   public void checkFlagExpressionNode(ClassDescriptor cd, FlagExpressionNode fen) {
163     switch(fen.kind()) {
164     case Kind.FlagOpNode:
165     {
166       FlagOpNode fon=(FlagOpNode)fen;
167       checkFlagExpressionNode(cd, fon.getLeft());
168       if (fon.getRight()!=null)
169         checkFlagExpressionNode(cd, fon.getRight());
170       break;
171     }
172
173     case Kind.FlagNode:
174     {
175       FlagNode fn=(FlagNode)fen;
176       String name=fn.getFlagName();
177       FlagDescriptor fd=(FlagDescriptor)cd.getFlagTable().get(name);
178       if (fd==null)
179         throw new Error("Undeclared flag: "+name);
180       fn.setFlag(fd);
181       break;
182     }
183
184     default:
185       throw new Error("Unrecognized FlagExpressionNode");
186     }
187   }
188
189   public void checkMethod(ClassDescriptor cd, MethodDescriptor md) {
190     /* Check return type */
191     if (!md.isConstructor())
192       if (!md.getReturnType().isVoid())
193         checkTypeDescriptor(md.getReturnType());
194
195     for(int i=0; i<md.numParameters(); i++) {
196       TypeDescriptor param_type=md.getParamType(i);
197       checkTypeDescriptor(param_type);
198     }
199     /* Link the naming environments */
200     if (!md.isStatic())     /* Fields aren't accessible directly in a static method, so don't link in this table */
201       md.getParameterTable().setParent(cd.getFieldTable());
202     md.setClassDesc(cd);
203     if (!md.isStatic()) {
204       VarDescriptor thisvd=new VarDescriptor(new TypeDescriptor(cd),"this");
205       md.setThis(thisvd);
206     }
207   }
208
209   public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
210     ClassDescriptor superdesc=cd.getSuperDesc();
211     if (superdesc!=null) {
212       Set possiblematches=superdesc.getMethodTable().getSet(md.getSymbol());
213       for(Iterator methodit=possiblematches.iterator(); methodit.hasNext();) {
214         MethodDescriptor matchmd=(MethodDescriptor)methodit.next();
215         if (md.matches(matchmd)) {
216           if (matchmd.getModifiers().isFinal()) {
217             throw new Error("Try to override final method in method:"+md+" declared in  "+cd);
218           }
219         }
220       }
221     }
222     BlockNode bn=state.getMethodBody(md);
223     checkBlockNode(md, md.getParameterTable(),bn);
224   }
225
226   public void checkBlockNode(Descriptor md, SymbolTable nametable, BlockNode bn) {
227     /* Link in the naming environment */
228     bn.getVarTable().setParent(nametable);
229     for(int i=0; i<bn.size(); i++) {
230       BlockStatementNode bsn=bn.get(i);
231       checkBlockStatementNode(md, bn.getVarTable(),bsn);
232     }
233   }
234
235   public void checkBlockStatementNode(Descriptor md, SymbolTable nametable, BlockStatementNode bsn) {
236     switch(bsn.kind()) {
237     case Kind.BlockExpressionNode:
238       checkBlockExpressionNode(md, nametable,(BlockExpressionNode)bsn);
239       return;
240
241     case Kind.DeclarationNode:
242       checkDeclarationNode(md, nametable, (DeclarationNode)bsn);
243       return;
244
245     case Kind.TagDeclarationNode:
246       checkTagDeclarationNode(md, nametable, (TagDeclarationNode)bsn);
247       return;
248
249     case Kind.IfStatementNode:
250       checkIfStatementNode(md, nametable, (IfStatementNode)bsn);
251       return;
252
253     case Kind.LoopNode:
254       checkLoopNode(md, nametable, (LoopNode)bsn);
255       return;
256
257     case Kind.ReturnNode:
258       checkReturnNode(md, nametable, (ReturnNode)bsn);
259       return;
260
261     case Kind.TaskExitNode:
262       checkTaskExitNode(md, nametable, (TaskExitNode)bsn);
263       return;
264
265     case Kind.SubBlockNode:
266       checkSubBlockNode(md, nametable, (SubBlockNode)bsn);
267       return;
268
269     case Kind.AtomicNode:
270       checkAtomicNode(md, nametable, (AtomicNode)bsn);
271       return;
272
273     case Kind.ContinueBreakNode:
274         checkContinueBreakNode(md, nametable, (ContinueBreakNode) bsn);
275         return;
276
277     case Kind.SESENode:
278       // do nothing, no semantic check for SESEs
279       return;
280     }
281
282     throw new Error();
283   }
284
285   void checkBlockExpressionNode(Descriptor md, SymbolTable nametable, BlockExpressionNode ben) {
286     checkExpressionNode(md, nametable, ben.getExpression(), null);
287   }
288
289   void checkDeclarationNode(Descriptor md, SymbolTable nametable,  DeclarationNode dn) {
290     VarDescriptor vd=dn.getVarDescriptor();
291     checkTypeDescriptor(vd.getType());
292     Descriptor d=nametable.get(vd.getSymbol());
293     if ((d==null)||
294         (d instanceof FieldDescriptor)) {
295       nametable.add(vd);
296     } else
297       throw new Error(vd.getSymbol()+" in "+md+" defined a second time");
298     if (dn.getExpression()!=null)
299       checkExpressionNode(md, nametable, dn.getExpression(), vd.getType());
300   }
301
302   void checkTagDeclarationNode(Descriptor md, SymbolTable nametable,  TagDeclarationNode dn) {
303     TagVarDescriptor vd=dn.getTagVarDescriptor();
304     Descriptor d=nametable.get(vd.getSymbol());
305     if ((d==null)||
306         (d instanceof FieldDescriptor)) {
307       nametable.add(vd);
308     } else
309       throw new Error(vd.getSymbol()+" defined a second time");
310   }
311
312   void checkSubBlockNode(Descriptor md, SymbolTable nametable, SubBlockNode sbn) {
313     checkBlockNode(md, nametable, sbn.getBlockNode());
314   }
315
316   void checkAtomicNode(Descriptor md, SymbolTable nametable, AtomicNode sbn) {
317     checkBlockNode(md, nametable, sbn.getBlockNode());
318   }
319
320   void checkContinueBreakNode(Descriptor md, SymbolTable nametable, ContinueBreakNode cbn) {
321       if (loopstack.empty())
322           throw new Error("continue/break outside of loop");
323       LoopNode ln=(LoopNode)loopstack.peek();
324       cbn.setLoop(ln);
325   }
326
327   void checkReturnNode(Descriptor d, SymbolTable nametable, ReturnNode rn) {
328     if (d instanceof TaskDescriptor)
329       throw new Error("Illegal return appears in Task: "+d.getSymbol());
330     MethodDescriptor md=(MethodDescriptor)d;
331     if (rn.getReturnExpression()!=null)
332       if (md.getReturnType()==null)
333         throw new Error("Constructor can't return something.");
334       else if (md.getReturnType().isVoid())
335         throw new Error(md+" is void");
336       else
337         checkExpressionNode(md, nametable, rn.getReturnExpression(), md.getReturnType());
338     else
339     if (md.getReturnType()!=null&&!md.getReturnType().isVoid())
340       throw new Error("Need to return something for "+md);
341   }
342
343   void checkTaskExitNode(Descriptor md, SymbolTable nametable, TaskExitNode ten) {
344     if (md instanceof MethodDescriptor)
345       throw new Error("Illegal taskexit appears in Method: "+md.getSymbol());
346     checkFlagEffects((TaskDescriptor)md, ten.getFlagEffects(),nametable);
347     checkConstraintCheck((TaskDescriptor) md, nametable, ten.getChecks());
348   }
349
350   void checkIfStatementNode(Descriptor md, SymbolTable nametable, IfStatementNode isn) {
351     checkExpressionNode(md, nametable, isn.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
352     checkBlockNode(md, nametable, isn.getTrueBlock());
353     if (isn.getFalseBlock()!=null)
354       checkBlockNode(md, nametable, isn.getFalseBlock());
355   }
356
357   void checkExpressionNode(Descriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
358     switch(en.kind()) {
359     case Kind.AssignmentNode:
360       checkAssignmentNode(md,nametable,(AssignmentNode)en,td);
361       return;
362
363     case Kind.CastNode:
364       checkCastNode(md,nametable,(CastNode)en,td);
365       return;
366
367     case Kind.CreateObjectNode:
368       checkCreateObjectNode(md,nametable,(CreateObjectNode)en,td);
369       return;
370
371     case Kind.FieldAccessNode:
372       checkFieldAccessNode(md,nametable,(FieldAccessNode)en,td);
373       return;
374
375     case Kind.ArrayAccessNode:
376       checkArrayAccessNode(md,nametable,(ArrayAccessNode)en,td);
377       return;
378
379     case Kind.LiteralNode:
380       checkLiteralNode(md,nametable,(LiteralNode)en,td);
381       return;
382
383     case Kind.MethodInvokeNode:
384       checkMethodInvokeNode(md,nametable,(MethodInvokeNode)en,td);
385       return;
386
387     case Kind.NameNode:
388       checkNameNode(md,nametable,(NameNode)en,td);
389       return;
390
391     case Kind.OpNode:
392       checkOpNode(md,nametable,(OpNode)en,td);
393       return;
394
395     case Kind.OffsetNode:
396       checkOffsetNode(md, nametable, (OffsetNode)en, new TypeDescriptor(TypeDescriptor.OFFSET));
397       return;
398     }
399     throw new Error();
400   }
401
402   void checkCastNode(Descriptor md, SymbolTable nametable, CastNode cn, TypeDescriptor td) {
403     /* Get type descriptor */
404     if (cn.getType()==null) {
405       NameDescriptor typenamed=cn.getTypeName().getName();
406       String typename=typenamed.toString();
407       TypeDescriptor ntd=new TypeDescriptor(typeutil.getClass(typename));
408       cn.setType(ntd);
409     }
410
411     /* Check the type descriptor */
412     TypeDescriptor cast_type=cn.getType();
413     checkTypeDescriptor(cast_type);
414
415     /* Type check */
416     if (td!=null) {
417       if (!typeutil.isSuperorType(td,cast_type))
418         throw new Error("Cast node returns "+cast_type+", but need "+td);
419     }
420
421     ExpressionNode en=cn.getExpression();
422     checkExpressionNode(md, nametable, en, null);
423     TypeDescriptor etd=en.getType();
424     if (typeutil.isSuperorType(cast_type,etd))     /* Cast trivially succeeds */
425       return;
426
427     if (typeutil.isSuperorType(etd,cast_type))     /* Cast may succeed */
428       return;
429     if (typeutil.isCastable(etd, cast_type))
430       return;
431
432     /* Different branches */
433     /* TODO: change if add interfaces */
434     throw new Error("Cast will always fail\n"+cn.printNode(0));
435   }
436
437   void checkFieldAccessNode(Descriptor md, SymbolTable nametable, FieldAccessNode fan, TypeDescriptor td) {
438     ExpressionNode left=fan.getExpression();
439     checkExpressionNode(md,nametable,left,null);
440     TypeDescriptor ltd=left.getType();
441     String fieldname=fan.getFieldName();
442
443     FieldDescriptor fd=null;
444     if (ltd.isArray()&&fieldname.equals("length"))
445       fd=FieldDescriptor.arrayLength;
446     else
447       fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
448     if (fd==null)
449       throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
450     fan.setField(fd);
451     if (td!=null)
452       if (!typeutil.isSuperorType(td,fan.getType()))
453         throw new Error("Field node returns "+fan.getType()+", but need "+td);
454   }
455
456   void checkArrayAccessNode(Descriptor md, SymbolTable nametable, ArrayAccessNode aan, TypeDescriptor td) {
457     ExpressionNode left=aan.getExpression();
458     checkExpressionNode(md,nametable,left,null);
459
460     checkExpressionNode(md,nametable,aan.getIndex(),new TypeDescriptor(TypeDescriptor.INT));
461     TypeDescriptor ltd=left.getType();
462
463     if (td!=null)
464       if (!typeutil.isSuperorType(td,aan.getType()))
465         throw new Error("Field node returns "+aan.getType()+", but need "+td);
466   }
467
468   void checkLiteralNode(Descriptor md, SymbolTable nametable, LiteralNode ln, TypeDescriptor td) {
469     /* Resolve the type */
470     Object o=ln.getValue();
471     if (ln.getTypeString().equals("null")) {
472       ln.setType(new TypeDescriptor(TypeDescriptor.NULL));
473     } else if (o instanceof Integer) {
474       ln.setType(new TypeDescriptor(TypeDescriptor.INT));
475     } else if (o instanceof Long) {
476       ln.setType(new TypeDescriptor(TypeDescriptor.LONG));
477     } else if (o instanceof Float) {
478       ln.setType(new TypeDescriptor(TypeDescriptor.FLOAT));
479     } else if (o instanceof Boolean) {
480       ln.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
481     } else if (o instanceof Double) {
482       ln.setType(new TypeDescriptor(TypeDescriptor.DOUBLE));
483     } else if (o instanceof Character) {
484       ln.setType(new TypeDescriptor(TypeDescriptor.CHAR));
485     } else if (o instanceof String) {
486       ln.setType(new TypeDescriptor(typeutil.getClass(TypeUtil.StringClass)));
487     }
488
489     if (td!=null)
490       if (!typeutil.isSuperorType(td,ln.getType()))
491         throw new Error("Field node returns "+ln.getType()+", but need "+td+" in "+md);
492   }
493
494   void checkNameNode(Descriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
495     NameDescriptor nd=nn.getName();
496     if (nd.getBase()!=null) {
497       /* Big hack */
498       /* Rewrite NameNode */
499       ExpressionNode en=translateNameDescriptorintoExpression(nd);
500       nn.setExpression(en);
501       checkExpressionNode(md,nametable,en,td);
502     } else {
503       String varname=nd.toString();
504       Descriptor d=(Descriptor)nametable.get(varname);
505       if (d==null) {
506         throw new Error("Name "+varname+" undefined in: "+md);
507       }
508       if (d instanceof VarDescriptor) {
509         nn.setVar(d);
510       } else if (d instanceof FieldDescriptor) {
511         nn.setField((FieldDescriptor)d);
512         nn.setVar((VarDescriptor)nametable.get("this"));        /* Need a pointer to this */
513       } else if (d instanceof TagVarDescriptor) {
514         nn.setVar(d);
515       } else throw new Error("Wrong type of descriptor");
516       if (td!=null)
517         if (!typeutil.isSuperorType(td,nn.getType()))
518           throw new Error("Field node returns "+nn.getType()+", but need "+td);
519     }
520   }
521
522   void checkOffsetNode(Descriptor md, SymbolTable nameTable, OffsetNode ofn, TypeDescriptor td) {
523     TypeDescriptor ltd = ofn.td;
524     //System.out.println("Testing TypeDescriptor ltd = " + ofn.td);
525     String fieldname = ofn.fieldname;
526     //System.out.println("Testing String fieldname = " + ofn.fieldname);
527     Descriptor d = (Descriptor) nameTable.get(fieldname);
528     //System.out.println("Testing Descriptor d = " + d.toString());
529
530     ClassDescriptor cd = null;
531     checkTypeDescriptor(ltd);
532     cd = ltd.getClassDesc();
533     ofn.setClassDesc(cd);
534     //System.out.println("Testing for ClassDescriptor cd = " + cd.toString());
535
536     FieldDescriptor fd=null;
537     if (ltd.isArray()&&fieldname.equals("length")) {
538       fd=FieldDescriptor.arrayLength;
539     } else {
540       fd=(FieldDescriptor) cd.getFieldTable().get(fieldname);
541     }
542     //System.out.println("Testing for FieldDescriptor fd = " + fd.toString());
543     ofn.setField(fd);
544     if (fd==null)
545       throw new Error("Unknown field "+fieldname + " in "+ofn.printNode(1)+" in "+md);
546     ofn.setType(td);
547   }
548
549   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
550     boolean postinc=true;
551     if (an.getOperation().getBaseOp()==null||
552         (an.getOperation().getBaseOp().getOp()!=Operation.POSTINC&&
553          an.getOperation().getBaseOp().getOp()!=Operation.POSTDEC))
554       postinc=false;
555
556     if (!postinc)
557       checkExpressionNode(md, nametable, an.getSrc(),td);
558     //TODO: Need check on validity of operation here
559     if (!((an.getDest() instanceof FieldAccessNode)||
560           (an.getDest() instanceof ArrayAccessNode)||
561           (an.getDest() instanceof NameNode)))
562       throw new Error("Bad lside in "+an.printNode(0));
563     checkExpressionNode(md, nametable, an.getDest(), null);
564
565     /* We want parameter variables to tasks to be immutable */
566     if (md instanceof TaskDescriptor) {
567       if (an.getDest() instanceof NameNode) {
568         NameNode nn=(NameNode)an.getDest();
569         if (nn.getVar()!=null) {
570           if (((TaskDescriptor)md).getParameterTable().contains(nn.getVar().getSymbol()))
571             throw new Error("Can't modify parameter "+nn.getVar()+ " to task "+td.getSymbol());
572         }
573       }
574     }
575
576     if (an.getDest().getType().isString()&&an.getOperation().getOp()==AssignOperation.PLUSEQ) {
577       //String add
578       ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
579       TypeDescriptor stringtd=new TypeDescriptor(stringcl);
580       NameDescriptor nd=new NameDescriptor("String");
581       NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
582
583       if (!(an.getSrc().getType().isString()&&(an.getSrc() instanceof OpNode))) {
584         MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
585         rightmin.addArgument(an.getSrc());
586         an.right=rightmin;
587         checkExpressionNode(md, nametable, an.getSrc(), null);
588       }
589     }
590
591     if (!postinc&&!typeutil.isSuperorType(an.getDest().getType(),an.getSrc().getType())) {
592       throw new Error("Type of rside ("+an.getSrc().getType()+") not compatible with type of lside ("+an.getDest().getType()+")"+an.printNode(0));
593     }
594   }
595
596   void checkLoopNode(Descriptor md, SymbolTable nametable, LoopNode ln) {
597       loopstack.push(ln);
598     if (ln.getType()==LoopNode.WHILELOOP||ln.getType()==LoopNode.DOWHILELOOP) {
599       checkExpressionNode(md, nametable, ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
600       checkBlockNode(md, nametable, ln.getBody());
601     } else {
602       //For loop case
603       /* Link in the initializer naming environment */
604       BlockNode bn=ln.getInitializer();
605       bn.getVarTable().setParent(nametable);
606       for(int i=0; i<bn.size(); i++) {
607         BlockStatementNode bsn=bn.get(i);
608         checkBlockStatementNode(md, bn.getVarTable(),bsn);
609       }
610       //check the condition
611       checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
612       checkBlockNode(md, bn.getVarTable(), ln.getBody());
613       checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
614     }
615     loopstack.pop();
616   }
617
618
619   void checkCreateObjectNode(Descriptor md, SymbolTable nametable, CreateObjectNode con, TypeDescriptor td) {
620     TypeDescriptor[] tdarray=new TypeDescriptor[con.numArgs()];
621     for(int i=0; i<con.numArgs(); i++) {
622       ExpressionNode en=con.getArg(i);
623       checkExpressionNode(md,nametable,en,null);
624       tdarray[i]=en.getType();
625     }
626
627     TypeDescriptor typetolookin=con.getType();
628     checkTypeDescriptor(typetolookin);
629
630     if (td!=null&&!typeutil.isSuperorType(td, typetolookin))
631       throw new Error(typetolookin + " isn't a "+td);
632
633     /* Check flag effects */
634     if (con.getFlagEffects()!=null) {
635       FlagEffects fe=con.getFlagEffects();
636       ClassDescriptor cd=typetolookin.getClassDesc();
637
638       for(int j=0; j<fe.numEffects(); j++) {
639         FlagEffect flag=fe.getEffect(j);
640         String name=flag.getName();
641         FlagDescriptor flag_d=(FlagDescriptor)cd.getFlagTable().get(name);
642         //Make sure the flag is declared
643         if (flag_d==null)
644           throw new Error("Flag descriptor "+name+" undefined in class: "+cd.getSymbol());
645         if (flag_d.getExternal())
646           throw new Error("Attempting to modify external flag: "+name);
647         flag.setFlag(flag_d);
648       }
649       for(int j=0; j<fe.numTagEffects(); j++) {
650         TagEffect tag=fe.getTagEffect(j);
651         String name=tag.getName();
652
653         Descriptor d=(Descriptor)nametable.get(name);
654         if (d==null)
655           throw new Error("Tag descriptor "+name+" undeclared");
656         else if (!(d instanceof TagVarDescriptor))
657           throw new Error(name+" is not a tag descriptor");
658         tag.setTag((TagVarDescriptor)d);
659       }
660     }
661
662     if ((!typetolookin.isClass())&&(!typetolookin.isArray()))
663       throw new Error("Can't allocate primitive type:"+con.printNode(0));
664
665     if (!typetolookin.isArray()) {
666       //Array's don't need constructor calls
667       ClassDescriptor classtolookin=typetolookin.getClassDesc();
668
669       Set methoddescriptorset=classtolookin.getMethodTable().getSet(typetolookin.getSymbol());
670       MethodDescriptor bestmd=null;
671 NextMethod:
672       for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
673         MethodDescriptor currmd=(MethodDescriptor)methodit.next();
674         /* Need correct number of parameters */
675         if (con.numArgs()!=currmd.numParameters())
676           continue;
677         for(int i=0; i<con.numArgs(); i++) {
678           if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
679             continue NextMethod;
680         }
681         /* Local allocations can't call global allocator */
682         if (!con.isGlobal()&&currmd.isGlobal())
683           continue;
684
685         /* Method okay so far */
686         if (bestmd==null)
687           bestmd=currmd;
688         else {
689           if (typeutil.isMoreSpecific(currmd,bestmd)) {
690             bestmd=currmd;
691           } else if (con.isGlobal()&&match(currmd, bestmd)) {
692             if (currmd.isGlobal()&&!bestmd.isGlobal())
693               bestmd=currmd;
694             else if (currmd.isGlobal()&&bestmd.isGlobal())
695               throw new Error();
696           } else if (!typeutil.isMoreSpecific(bestmd, currmd)) {
697             throw new Error("No method is most specific");
698           }
699
700           /* Is this more specific than bestmd */
701         }
702       }
703       if (bestmd==null)
704         throw new Error("No method found for "+con.printNode(0)+" in "+md);
705       con.setConstructor(bestmd);
706     }
707   }
708
709
710   /** Check to see if md1 is the same specificity as md2.*/
711
712   boolean match(MethodDescriptor md1, MethodDescriptor md2) {
713     /* Checks if md1 is more specific than md2 */
714     if (md1.numParameters()!=md2.numParameters())
715       throw new Error();
716     for(int i=0; i<md1.numParameters(); i++) {
717       if (!md2.getParamType(i).equals(md1.getParamType(i)))
718         return false;
719     }
720     if (!md2.getReturnType().equals(md1.getReturnType()))
721       return false;
722
723     if (!md2.getClassDesc().equals(md1.getClassDesc()))
724       return false;
725
726     return true;
727   }
728
729
730
731   ExpressionNode translateNameDescriptorintoExpression(NameDescriptor nd) {
732     String id=nd.getIdentifier();
733     NameDescriptor base=nd.getBase();
734     if (base==null)
735       return new NameNode(nd);
736     else
737       return new FieldAccessNode(translateNameDescriptorintoExpression(base),id);
738   }
739
740
741   void checkMethodInvokeNode(Descriptor md, SymbolTable nametable, MethodInvokeNode min, TypeDescriptor td) {
742     /*Typecheck subexpressions
743        and get types for expressions*/
744
745     TypeDescriptor[] tdarray=new TypeDescriptor[min.numArgs()];
746     for(int i=0; i<min.numArgs(); i++) {
747       ExpressionNode en=min.getArg(i);
748       checkExpressionNode(md,nametable,en,null);
749       tdarray[i]=en.getType();
750     }
751     TypeDescriptor typetolookin=null;
752     if (min.getExpression()!=null) {
753       checkExpressionNode(md,nametable,min.getExpression(),null);
754       typetolookin=min.getExpression().getType();
755     } else if (min.getBaseName()!=null) {
756       String rootname=min.getBaseName().getRoot();
757       if (rootname.equals("super")) {
758         ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
759         typetolookin=new TypeDescriptor(supercd);
760       } else if (nametable.get(rootname)!=null) {
761         //we have an expression
762         min.setExpression(translateNameDescriptorintoExpression(min.getBaseName()));
763         checkExpressionNode(md, nametable, min.getExpression(), null);
764         typetolookin=min.getExpression().getType();
765       } else {
766         //we have a type
767         ClassDescriptor cd=typeutil.getClass(min.getBaseName().getSymbol());
768         if (cd==null)
769           throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
770         typetolookin=new TypeDescriptor(cd);
771       }
772     } else if ((md instanceof MethodDescriptor)&&min.getMethodName().equals("super")) {
773       ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
774       min.methodid=supercd.getSymbol();
775       typetolookin=new TypeDescriptor(supercd);
776     } else if (md instanceof MethodDescriptor) {
777       typetolookin=new TypeDescriptor(((MethodDescriptor)md).getClassDesc());
778     } else {
779       /* If this a task descriptor we throw an error at this point */
780       throw new Error("Unknown method call to "+min.getMethodName()+"in task"+md.getSymbol());
781     }
782     if (!typetolookin.isClass())
783       throw new Error("Error with method call to "+min.getMethodName());
784     ClassDescriptor classtolookin=typetolookin.getClassDesc();
785     //System.out.println("Method name="+min.getMethodName());
786
787     Set methoddescriptorset=classtolookin.getMethodTable().getSet(min.getMethodName());
788     MethodDescriptor bestmd=null;
789 NextMethod:
790     for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
791       MethodDescriptor currmd=(MethodDescriptor)methodit.next();
792       /* Need correct number of parameters */
793       if (min.numArgs()!=currmd.numParameters())
794         continue;
795       for(int i=0; i<min.numArgs(); i++) {
796         if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
797           continue NextMethod;
798       }
799       /* Method okay so far */
800       if (bestmd==null)
801         bestmd=currmd;
802       else {
803         if (typeutil.isMoreSpecific(currmd,bestmd)) {
804           bestmd=currmd;
805         } else if (!typeutil.isMoreSpecific(bestmd, currmd))
806           throw new Error("No method is most specific");
807
808         /* Is this more specific than bestmd */
809       }
810     }
811     if (bestmd==null)
812       throw new Error("No method found for :"+min.printNode(0)+" in class: " + classtolookin+" in "+md);
813     min.setMethod(bestmd);
814
815     if ((td!=null)&&(min.getType()!=null)&&!typeutil.isSuperorType(td,  min.getType()))
816       throw new Error(min.getType()+ " is not equal to or a subclass of "+td);
817     /* Check whether we need to set this parameter to implied this */
818     if (!bestmd.isStatic()) {
819       if (min.getExpression()==null) {
820         ExpressionNode en=new NameNode(new NameDescriptor("this"));
821         min.setExpression(en);
822         checkExpressionNode(md, nametable, min.getExpression(), null);
823       }
824     }
825   }
826
827
828   void checkOpNode(Descriptor md, SymbolTable nametable, OpNode on, TypeDescriptor td) {
829     checkExpressionNode(md, nametable, on.getLeft(), null);
830     if (on.getRight()!=null)
831       checkExpressionNode(md, nametable, on.getRight(), null);
832     TypeDescriptor ltd=on.getLeft().getType();
833     TypeDescriptor rtd=on.getRight()!=null ? on.getRight().getType() : null;
834     TypeDescriptor lefttype=null;
835     TypeDescriptor righttype=null;
836     Operation op=on.getOp();
837
838     switch(op.getOp()) {
839     case Operation.LOGIC_OR:
840     case Operation.LOGIC_AND:
841       if (!(rtd.isBoolean()))
842         throw new Error();
843       on.setRightType(rtd);
844
845     case Operation.LOGIC_NOT:
846       if (!(ltd.isBoolean()))
847         throw new Error();
848       //no promotion
849       on.setLeftType(ltd);
850
851       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
852       break;
853
854     case Operation.COMP:
855       // 5.6.2 Binary Numeric Promotion
856       //TODO unboxing of reference objects
857       if (ltd.isDouble())
858         throw new Error();
859       else if (ltd.isFloat())
860         throw new Error();
861       else if (ltd.isLong())
862         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
863       else
864         lefttype=new TypeDescriptor(TypeDescriptor.INT);
865       on.setLeftType(lefttype);
866       on.setType(lefttype);
867       break;
868
869     case Operation.BIT_OR:
870     case Operation.BIT_XOR:
871     case Operation.BIT_AND:
872       // 5.6.2 Binary Numeric Promotion
873       //TODO unboxing of reference objects
874       if (ltd.isDouble()||rtd.isDouble())
875         throw new Error();
876       else if (ltd.isFloat()||rtd.isFloat())
877         throw new Error();
878       else if (ltd.isLong()||rtd.isLong())
879         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
880       // 090205 hack for boolean
881       else if (ltd.isBoolean()||rtd.isBoolean())
882         lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
883       else
884         lefttype=new TypeDescriptor(TypeDescriptor.INT);
885       righttype=lefttype;
886
887       on.setLeftType(lefttype);
888       on.setRightType(righttype);
889       on.setType(lefttype);
890       break;
891
892     case Operation.ISAVAILABLE:
893       if (!(ltd.isPtr())) {
894         throw new Error("Can't use isavailable on non-pointers/non-parameters.");
895       }
896       lefttype=ltd;
897       on.setLeftType(lefttype);
898       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
899       break;
900
901     case Operation.EQUAL:
902     case Operation.NOTEQUAL:
903       // 5.6.2 Binary Numeric Promotion
904       //TODO unboxing of reference objects
905       if (ltd.isBoolean()||rtd.isBoolean()) {
906         if (!(ltd.isBoolean()&&rtd.isBoolean()))
907           throw new Error();
908         righttype=lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
909       } else if (ltd.isPtr()||rtd.isPtr()) {
910         if (!(ltd.isPtr()&&rtd.isPtr()))
911           throw new Error();
912         righttype=rtd;
913         lefttype=ltd;
914       } else if (ltd.isDouble()||rtd.isDouble())
915         righttype=lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
916       else if (ltd.isFloat()||rtd.isFloat())
917         righttype=lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
918       else if (ltd.isLong()||rtd.isLong())
919         righttype=lefttype=new TypeDescriptor(TypeDescriptor.LONG);
920       else
921         righttype=lefttype=new TypeDescriptor(TypeDescriptor.INT);
922
923       on.setLeftType(lefttype);
924       on.setRightType(righttype);
925       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
926       break;
927
928
929
930     case Operation.LT:
931     case Operation.GT:
932     case Operation.LTE:
933     case Operation.GTE:
934       // 5.6.2 Binary Numeric Promotion
935       //TODO unboxing of reference objects
936       if (!ltd.isNumber()||!rtd.isNumber())
937         throw new Error();
938
939       if (ltd.isDouble()||rtd.isDouble())
940         lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
941       else if (ltd.isFloat()||rtd.isFloat())
942         lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
943       else if (ltd.isLong()||rtd.isLong())
944         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
945       else
946         lefttype=new TypeDescriptor(TypeDescriptor.INT);
947       righttype=lefttype;
948       on.setLeftType(lefttype);
949       on.setRightType(righttype);
950       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
951       break;
952
953     case Operation.ADD:
954       if (ltd.isString()||rtd.isString()) {
955         ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
956         TypeDescriptor stringtd=new TypeDescriptor(stringcl);
957         NameDescriptor nd=new NameDescriptor("String");
958         NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
959         if (!(ltd.isString()&&(on.getLeft() instanceof OpNode))) {
960           MethodInvokeNode leftmin=new MethodInvokeNode(valuend);
961           leftmin.addArgument(on.getLeft());
962           on.left=leftmin;
963           checkExpressionNode(md, nametable, on.getLeft(), null);
964         }
965
966         if (!(rtd.isString()&&(on.getRight() instanceof OpNode))) {
967           MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
968           rightmin.addArgument(on.getRight());
969           on.right=rightmin;
970           checkExpressionNode(md, nametable, on.getRight(), null);
971         }
972
973         on.setLeftType(stringtd);
974         on.setRightType(stringtd);
975         on.setType(stringtd);
976         break;
977       }
978
979     case Operation.SUB:
980     case Operation.MULT:
981     case Operation.DIV:
982     case Operation.MOD:
983       // 5.6.2 Binary Numeric Promotion
984       //TODO unboxing of reference objects
985       if (ltd.isArray()||rtd.isArray()||!ltd.isNumber()||!rtd.isNumber())
986         throw new Error("Error in "+on.printNode(0));
987
988       if (ltd.isDouble()||rtd.isDouble())
989         lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
990       else if (ltd.isFloat()||rtd.isFloat())
991         lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
992       else if (ltd.isLong()||rtd.isLong())
993         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
994       else
995         lefttype=new TypeDescriptor(TypeDescriptor.INT);
996       righttype=lefttype;
997       on.setLeftType(lefttype);
998       on.setRightType(righttype);
999       on.setType(lefttype);
1000       break;
1001
1002     case Operation.LEFTSHIFT:
1003     case Operation.RIGHTSHIFT:
1004     case Operation.URIGHTSHIFT:
1005       if (!rtd.isIntegerType())
1006         throw new Error();
1007       //5.6.1 Unary Numeric Promotion
1008       if (rtd.isByte()||rtd.isShort()||rtd.isInt())
1009         righttype=new TypeDescriptor(TypeDescriptor.INT);
1010       else
1011         righttype=rtd;
1012
1013       on.setRightType(righttype);
1014       if (!ltd.isIntegerType())
1015         throw new Error();
1016
1017     case Operation.UNARYPLUS:
1018     case Operation.UNARYMINUS:
1019       /*        case Operation.POSTINC:
1020           case Operation.POSTDEC:
1021           case Operation.PREINC:
1022           case Operation.PREDEC:*/
1023       if (!ltd.isNumber())
1024         throw new Error();
1025       //5.6.1 Unary Numeric Promotion
1026       if (ltd.isByte()||ltd.isShort()||ltd.isInt())
1027         lefttype=new TypeDescriptor(TypeDescriptor.INT);
1028       else
1029         lefttype=ltd;
1030       on.setLeftType(lefttype);
1031       on.setType(lefttype);
1032       break;
1033
1034     default:
1035       throw new Error(op.toString());
1036     }
1037
1038     if (td!=null)
1039       if (!typeutil.isSuperorType(td, on.getType())) {
1040         System.out.println(td);
1041         System.out.println(on.getType());
1042         throw new Error("Type of rside not compatible with type of lside"+on.printNode(0));
1043       }
1044   }
1045 }