added tertiary expression
[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     case Kind.TertiaryNode:
400       checkTertiaryNode(md, nametable, (TertiaryNode)en, td);
401       return;
402     }
403     throw new Error();
404   }
405
406   void checkCastNode(Descriptor md, SymbolTable nametable, CastNode cn, TypeDescriptor td) {
407     /* Get type descriptor */
408     if (cn.getType()==null) {
409       NameDescriptor typenamed=cn.getTypeName().getName();
410       String typename=typenamed.toString();
411       TypeDescriptor ntd=new TypeDescriptor(typeutil.getClass(typename));
412       cn.setType(ntd);
413     }
414
415     /* Check the type descriptor */
416     TypeDescriptor cast_type=cn.getType();
417     checkTypeDescriptor(cast_type);
418
419     /* Type check */
420     if (td!=null) {
421       if (!typeutil.isSuperorType(td,cast_type))
422         throw new Error("Cast node returns "+cast_type+", but need "+td);
423     }
424
425     ExpressionNode en=cn.getExpression();
426     checkExpressionNode(md, nametable, en, null);
427     TypeDescriptor etd=en.getType();
428     if (typeutil.isSuperorType(cast_type,etd))     /* Cast trivially succeeds */
429       return;
430
431     if (typeutil.isSuperorType(etd,cast_type))     /* Cast may succeed */
432       return;
433     if (typeutil.isCastable(etd, cast_type))
434       return;
435
436     /* Different branches */
437     /* TODO: change if add interfaces */
438     throw new Error("Cast will always fail\n"+cn.printNode(0));
439   }
440
441   void checkFieldAccessNode(Descriptor md, SymbolTable nametable, FieldAccessNode fan, TypeDescriptor td) {
442     ExpressionNode left=fan.getExpression();
443     checkExpressionNode(md,nametable,left,null);
444     TypeDescriptor ltd=left.getType();
445     String fieldname=fan.getFieldName();
446
447     FieldDescriptor fd=null;
448     if (ltd.isArray()&&fieldname.equals("length"))
449       fd=FieldDescriptor.arrayLength;
450     else
451       fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
452     if (fd==null)
453       throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
454     fan.setField(fd);
455     if (td!=null)
456       if (!typeutil.isSuperorType(td,fan.getType()))
457         throw new Error("Field node returns "+fan.getType()+", but need "+td);
458   }
459
460   void checkArrayAccessNode(Descriptor md, SymbolTable nametable, ArrayAccessNode aan, TypeDescriptor td) {
461     ExpressionNode left=aan.getExpression();
462     checkExpressionNode(md,nametable,left,null);
463
464     checkExpressionNode(md,nametable,aan.getIndex(),new TypeDescriptor(TypeDescriptor.INT));
465     TypeDescriptor ltd=left.getType();
466
467     if (td!=null)
468       if (!typeutil.isSuperorType(td,aan.getType()))
469         throw new Error("Field node returns "+aan.getType()+", but need "+td);
470   }
471
472   void checkLiteralNode(Descriptor md, SymbolTable nametable, LiteralNode ln, TypeDescriptor td) {
473     /* Resolve the type */
474     Object o=ln.getValue();
475     if (ln.getTypeString().equals("null")) {
476       ln.setType(new TypeDescriptor(TypeDescriptor.NULL));
477     } else if (o instanceof Integer) {
478       ln.setType(new TypeDescriptor(TypeDescriptor.INT));
479     } else if (o instanceof Long) {
480       ln.setType(new TypeDescriptor(TypeDescriptor.LONG));
481     } else if (o instanceof Float) {
482       ln.setType(new TypeDescriptor(TypeDescriptor.FLOAT));
483     } else if (o instanceof Boolean) {
484       ln.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
485     } else if (o instanceof Double) {
486       ln.setType(new TypeDescriptor(TypeDescriptor.DOUBLE));
487     } else if (o instanceof Character) {
488       ln.setType(new TypeDescriptor(TypeDescriptor.CHAR));
489     } else if (o instanceof String) {
490       ln.setType(new TypeDescriptor(typeutil.getClass(TypeUtil.StringClass)));
491     }
492
493     if (td!=null)
494       if (!typeutil.isSuperorType(td,ln.getType()))
495         throw new Error("Field node returns "+ln.getType()+", but need "+td+" in "+md);
496   }
497
498   void checkNameNode(Descriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
499     NameDescriptor nd=nn.getName();
500     if (nd.getBase()!=null) {
501       /* Big hack */
502       /* Rewrite NameNode */
503       ExpressionNode en=translateNameDescriptorintoExpression(nd);
504       nn.setExpression(en);
505       checkExpressionNode(md,nametable,en,td);
506     } else {
507       String varname=nd.toString();
508       Descriptor d=(Descriptor)nametable.get(varname);
509       if (d==null) {
510         throw new Error("Name "+varname+" undefined in: "+md);
511       }
512       if (d instanceof VarDescriptor) {
513         nn.setVar(d);
514       } else if (d instanceof FieldDescriptor) {
515         nn.setField((FieldDescriptor)d);
516         nn.setVar((VarDescriptor)nametable.get("this"));        /* Need a pointer to this */
517       } else if (d instanceof TagVarDescriptor) {
518         nn.setVar(d);
519       } else throw new Error("Wrong type of descriptor");
520       if (td!=null)
521         if (!typeutil.isSuperorType(td,nn.getType()))
522           throw new Error("Field node returns "+nn.getType()+", but need "+td);
523     }
524   }
525
526   void checkOffsetNode(Descriptor md, SymbolTable nameTable, OffsetNode ofn, TypeDescriptor td) {
527     TypeDescriptor ltd = ofn.td;
528     //System.out.println("Testing TypeDescriptor ltd = " + ofn.td);
529     String fieldname = ofn.fieldname;
530     //System.out.println("Testing String fieldname = " + ofn.fieldname);
531     Descriptor d = (Descriptor) nameTable.get(fieldname);
532     //System.out.println("Testing Descriptor d = " + d.toString());
533
534     ClassDescriptor cd = null;
535     checkTypeDescriptor(ltd);
536     cd = ltd.getClassDesc();
537     ofn.setClassDesc(cd);
538     //System.out.println("Testing for ClassDescriptor cd = " + cd.toString());
539
540     FieldDescriptor fd=null;
541     if (ltd.isArray()&&fieldname.equals("length")) {
542       fd=FieldDescriptor.arrayLength;
543     } else {
544       fd=(FieldDescriptor) cd.getFieldTable().get(fieldname);
545     }
546     //System.out.println("Testing for FieldDescriptor fd = " + fd.toString());
547     ofn.setField(fd);
548     if (fd==null)
549       throw new Error("Unknown field "+fieldname + " in "+ofn.printNode(1)+" in "+md);
550     ofn.setType(td);
551   }
552
553
554   void checkTertiaryNode(Descriptor md, SymbolTable nametable, TertiaryNode tn, TypeDescriptor td) {
555     checkExpressionNode(md, nametable, tn.getCond(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
556     checkExpressionNode(md, nametable, tn.getTrueExpr(), td );
557     checkExpressionNode(md, nametable, tn.getFalseExpr(), td );
558   }
559
560
561   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
562     boolean postinc=true;
563     if (an.getOperation().getBaseOp()==null||
564         (an.getOperation().getBaseOp().getOp()!=Operation.POSTINC&&
565          an.getOperation().getBaseOp().getOp()!=Operation.POSTDEC))
566       postinc=false;
567
568     if (!postinc)
569       checkExpressionNode(md, nametable, an.getSrc(),td);
570     //TODO: Need check on validity of operation here
571     if (!((an.getDest() instanceof FieldAccessNode)||
572           (an.getDest() instanceof ArrayAccessNode)||
573           (an.getDest() instanceof NameNode)))
574       throw new Error("Bad lside in "+an.printNode(0));
575     checkExpressionNode(md, nametable, an.getDest(), null);
576
577     /* We want parameter variables to tasks to be immutable */
578     if (md instanceof TaskDescriptor) {
579       if (an.getDest() instanceof NameNode) {
580         NameNode nn=(NameNode)an.getDest();
581         if (nn.getVar()!=null) {
582           if (((TaskDescriptor)md).getParameterTable().contains(nn.getVar().getSymbol()))
583             throw new Error("Can't modify parameter "+nn.getVar()+ " to task "+td.getSymbol());
584         }
585       }
586     }
587
588     if (an.getDest().getType().isString()&&an.getOperation().getOp()==AssignOperation.PLUSEQ) {
589       //String add
590       ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
591       TypeDescriptor stringtd=new TypeDescriptor(stringcl);
592       NameDescriptor nd=new NameDescriptor("String");
593       NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
594
595       if (!(an.getSrc().getType().isString()&&(an.getSrc() instanceof OpNode))) {
596         MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
597         rightmin.addArgument(an.getSrc());
598         an.right=rightmin;
599         checkExpressionNode(md, nametable, an.getSrc(), null);
600       }
601     }
602
603     if (!postinc&&!typeutil.isSuperorType(an.getDest().getType(),an.getSrc().getType())) {
604       throw new Error("Type of rside ("+an.getSrc().getType()+") not compatible with type of lside ("+an.getDest().getType()+")"+an.printNode(0));
605     }
606   }
607
608   void checkLoopNode(Descriptor md, SymbolTable nametable, LoopNode ln) {
609       loopstack.push(ln);
610     if (ln.getType()==LoopNode.WHILELOOP||ln.getType()==LoopNode.DOWHILELOOP) {
611       checkExpressionNode(md, nametable, ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
612       checkBlockNode(md, nametable, ln.getBody());
613     } else {
614       //For loop case
615       /* Link in the initializer naming environment */
616       BlockNode bn=ln.getInitializer();
617       bn.getVarTable().setParent(nametable);
618       for(int i=0; i<bn.size(); i++) {
619         BlockStatementNode bsn=bn.get(i);
620         checkBlockStatementNode(md, bn.getVarTable(),bsn);
621       }
622       //check the condition
623       checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
624       checkBlockNode(md, bn.getVarTable(), ln.getBody());
625       checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
626     }
627     loopstack.pop();
628   }
629
630
631   void checkCreateObjectNode(Descriptor md, SymbolTable nametable, CreateObjectNode con, TypeDescriptor td) {
632     TypeDescriptor[] tdarray=new TypeDescriptor[con.numArgs()];
633     for(int i=0; i<con.numArgs(); i++) {
634       ExpressionNode en=con.getArg(i);
635       checkExpressionNode(md,nametable,en,null);
636       tdarray[i]=en.getType();
637     }
638
639     TypeDescriptor typetolookin=con.getType();
640     checkTypeDescriptor(typetolookin);
641
642     if (td!=null&&!typeutil.isSuperorType(td, typetolookin))
643       throw new Error(typetolookin + " isn't a "+td);
644
645     /* Check flag effects */
646     if (con.getFlagEffects()!=null) {
647       FlagEffects fe=con.getFlagEffects();
648       ClassDescriptor cd=typetolookin.getClassDesc();
649
650       for(int j=0; j<fe.numEffects(); j++) {
651         FlagEffect flag=fe.getEffect(j);
652         String name=flag.getName();
653         FlagDescriptor flag_d=(FlagDescriptor)cd.getFlagTable().get(name);
654         //Make sure the flag is declared
655         if (flag_d==null)
656           throw new Error("Flag descriptor "+name+" undefined in class: "+cd.getSymbol());
657         if (flag_d.getExternal())
658           throw new Error("Attempting to modify external flag: "+name);
659         flag.setFlag(flag_d);
660       }
661       for(int j=0; j<fe.numTagEffects(); j++) {
662         TagEffect tag=fe.getTagEffect(j);
663         String name=tag.getName();
664
665         Descriptor d=(Descriptor)nametable.get(name);
666         if (d==null)
667           throw new Error("Tag descriptor "+name+" undeclared");
668         else if (!(d instanceof TagVarDescriptor))
669           throw new Error(name+" is not a tag descriptor");
670         tag.setTag((TagVarDescriptor)d);
671       }
672     }
673
674     if ((!typetolookin.isClass())&&(!typetolookin.isArray()))
675       throw new Error("Can't allocate primitive type:"+con.printNode(0));
676
677     if (!typetolookin.isArray()) {
678       //Array's don't need constructor calls
679       ClassDescriptor classtolookin=typetolookin.getClassDesc();
680
681       Set methoddescriptorset=classtolookin.getMethodTable().getSet(typetolookin.getSymbol());
682       MethodDescriptor bestmd=null;
683 NextMethod:
684       for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
685         MethodDescriptor currmd=(MethodDescriptor)methodit.next();
686         /* Need correct number of parameters */
687         if (con.numArgs()!=currmd.numParameters())
688           continue;
689         for(int i=0; i<con.numArgs(); i++) {
690           if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
691             continue NextMethod;
692         }
693         /* Local allocations can't call global allocator */
694         if (!con.isGlobal()&&currmd.isGlobal())
695           continue;
696
697         /* Method okay so far */
698         if (bestmd==null)
699           bestmd=currmd;
700         else {
701           if (typeutil.isMoreSpecific(currmd,bestmd)) {
702             bestmd=currmd;
703           } else if (con.isGlobal()&&match(currmd, bestmd)) {
704             if (currmd.isGlobal()&&!bestmd.isGlobal())
705               bestmd=currmd;
706             else if (currmd.isGlobal()&&bestmd.isGlobal())
707               throw new Error();
708           } else if (!typeutil.isMoreSpecific(bestmd, currmd)) {
709             throw new Error("No method is most specific");
710           }
711
712           /* Is this more specific than bestmd */
713         }
714       }
715       if (bestmd==null)
716         throw new Error("No method found for "+con.printNode(0)+" in "+md);
717       con.setConstructor(bestmd);
718     }
719   }
720
721
722   /** Check to see if md1 is the same specificity as md2.*/
723
724   boolean match(MethodDescriptor md1, MethodDescriptor md2) {
725     /* Checks if md1 is more specific than md2 */
726     if (md1.numParameters()!=md2.numParameters())
727       throw new Error();
728     for(int i=0; i<md1.numParameters(); i++) {
729       if (!md2.getParamType(i).equals(md1.getParamType(i)))
730         return false;
731     }
732     if (!md2.getReturnType().equals(md1.getReturnType()))
733       return false;
734
735     if (!md2.getClassDesc().equals(md1.getClassDesc()))
736       return false;
737
738     return true;
739   }
740
741
742
743   ExpressionNode translateNameDescriptorintoExpression(NameDescriptor nd) {
744     String id=nd.getIdentifier();
745     NameDescriptor base=nd.getBase();
746     if (base==null)
747       return new NameNode(nd);
748     else
749       return new FieldAccessNode(translateNameDescriptorintoExpression(base),id);
750   }
751
752
753   void checkMethodInvokeNode(Descriptor md, SymbolTable nametable, MethodInvokeNode min, TypeDescriptor td) {
754     /*Typecheck subexpressions
755        and get types for expressions*/
756
757     TypeDescriptor[] tdarray=new TypeDescriptor[min.numArgs()];
758     for(int i=0; i<min.numArgs(); i++) {
759       ExpressionNode en=min.getArg(i);
760       checkExpressionNode(md,nametable,en,null);
761       tdarray[i]=en.getType();
762     }
763     TypeDescriptor typetolookin=null;
764     if (min.getExpression()!=null) {
765       checkExpressionNode(md,nametable,min.getExpression(),null);
766       typetolookin=min.getExpression().getType();
767     } else if (min.getBaseName()!=null) {
768       String rootname=min.getBaseName().getRoot();
769       if (rootname.equals("super")) {
770         ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
771         typetolookin=new TypeDescriptor(supercd);
772       } else if (nametable.get(rootname)!=null) {
773         //we have an expression
774         min.setExpression(translateNameDescriptorintoExpression(min.getBaseName()));
775         checkExpressionNode(md, nametable, min.getExpression(), null);
776         typetolookin=min.getExpression().getType();
777       } else {
778         //we have a type
779         ClassDescriptor cd=typeutil.getClass(min.getBaseName().getSymbol());
780         if (cd==null)
781           throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
782         typetolookin=new TypeDescriptor(cd);
783       }
784     } else if ((md instanceof MethodDescriptor)&&min.getMethodName().equals("super")) {
785       ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
786       min.methodid=supercd.getSymbol();
787       typetolookin=new TypeDescriptor(supercd);
788     } else if (md instanceof MethodDescriptor) {
789       typetolookin=new TypeDescriptor(((MethodDescriptor)md).getClassDesc());
790     } else {
791       /* If this a task descriptor we throw an error at this point */
792       throw new Error("Unknown method call to "+min.getMethodName()+"in task"+md.getSymbol());
793     }
794     if (!typetolookin.isClass())
795       throw new Error("Error with method call to "+min.getMethodName());
796     ClassDescriptor classtolookin=typetolookin.getClassDesc();
797     //System.out.println("Method name="+min.getMethodName());
798
799     Set methoddescriptorset=classtolookin.getMethodTable().getSet(min.getMethodName());
800     MethodDescriptor bestmd=null;
801 NextMethod:
802     for(Iterator methodit=methoddescriptorset.iterator(); methodit.hasNext();) {
803       MethodDescriptor currmd=(MethodDescriptor)methodit.next();
804       /* Need correct number of parameters */
805       if (min.numArgs()!=currmd.numParameters())
806         continue;
807       for(int i=0; i<min.numArgs(); i++) {
808         if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
809           continue NextMethod;
810       }
811       /* Method okay so far */
812       if (bestmd==null)
813         bestmd=currmd;
814       else {
815         if (typeutil.isMoreSpecific(currmd,bestmd)) {
816           bestmd=currmd;
817         } else if (!typeutil.isMoreSpecific(bestmd, currmd))
818           throw new Error("No method is most specific");
819
820         /* Is this more specific than bestmd */
821       }
822     }
823     if (bestmd==null)
824       throw new Error("No method found for :"+min.printNode(0)+" in class: " + classtolookin+" in "+md);
825     min.setMethod(bestmd);
826
827     if ((td!=null)&&(min.getType()!=null)&&!typeutil.isSuperorType(td,  min.getType()))
828       throw new Error(min.getType()+ " is not equal to or a subclass of "+td);
829     /* Check whether we need to set this parameter to implied this */
830     if (!bestmd.isStatic()) {
831       if (min.getExpression()==null) {
832         ExpressionNode en=new NameNode(new NameDescriptor("this"));
833         min.setExpression(en);
834         checkExpressionNode(md, nametable, min.getExpression(), null);
835       }
836     }
837   }
838
839
840   void checkOpNode(Descriptor md, SymbolTable nametable, OpNode on, TypeDescriptor td) {
841     checkExpressionNode(md, nametable, on.getLeft(), null);
842     if (on.getRight()!=null)
843       checkExpressionNode(md, nametable, on.getRight(), null);
844     TypeDescriptor ltd=on.getLeft().getType();
845     TypeDescriptor rtd=on.getRight()!=null ? on.getRight().getType() : null;
846     TypeDescriptor lefttype=null;
847     TypeDescriptor righttype=null;
848     Operation op=on.getOp();
849
850     switch(op.getOp()) {
851     case Operation.LOGIC_OR:
852     case Operation.LOGIC_AND:
853       if (!(rtd.isBoolean()))
854         throw new Error();
855       on.setRightType(rtd);
856
857     case Operation.LOGIC_NOT:
858       if (!(ltd.isBoolean()))
859         throw new Error();
860       //no promotion
861       on.setLeftType(ltd);
862
863       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
864       break;
865
866     case Operation.COMP:
867       // 5.6.2 Binary Numeric Promotion
868       //TODO unboxing of reference objects
869       if (ltd.isDouble())
870         throw new Error();
871       else if (ltd.isFloat())
872         throw new Error();
873       else if (ltd.isLong())
874         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
875       else
876         lefttype=new TypeDescriptor(TypeDescriptor.INT);
877       on.setLeftType(lefttype);
878       on.setType(lefttype);
879       break;
880
881     case Operation.BIT_OR:
882     case Operation.BIT_XOR:
883     case Operation.BIT_AND:
884       // 5.6.2 Binary Numeric Promotion
885       //TODO unboxing of reference objects
886       if (ltd.isDouble()||rtd.isDouble())
887         throw new Error();
888       else if (ltd.isFloat()||rtd.isFloat())
889         throw new Error();
890       else if (ltd.isLong()||rtd.isLong())
891         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
892       // 090205 hack for boolean
893       else if (ltd.isBoolean()||rtd.isBoolean())
894         lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
895       else
896         lefttype=new TypeDescriptor(TypeDescriptor.INT);
897       righttype=lefttype;
898
899       on.setLeftType(lefttype);
900       on.setRightType(righttype);
901       on.setType(lefttype);
902       break;
903
904     case Operation.ISAVAILABLE:
905       if (!(ltd.isPtr())) {
906         throw new Error("Can't use isavailable on non-pointers/non-parameters.");
907       }
908       lefttype=ltd;
909       on.setLeftType(lefttype);
910       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
911       break;
912
913     case Operation.EQUAL:
914     case Operation.NOTEQUAL:
915       // 5.6.2 Binary Numeric Promotion
916       //TODO unboxing of reference objects
917       if (ltd.isBoolean()||rtd.isBoolean()) {
918         if (!(ltd.isBoolean()&&rtd.isBoolean()))
919           throw new Error();
920         righttype=lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
921       } else if (ltd.isPtr()||rtd.isPtr()) {
922         if (!(ltd.isPtr()&&rtd.isPtr()))
923           throw new Error();
924         righttype=rtd;
925         lefttype=ltd;
926       } else if (ltd.isDouble()||rtd.isDouble())
927         righttype=lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
928       else if (ltd.isFloat()||rtd.isFloat())
929         righttype=lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
930       else if (ltd.isLong()||rtd.isLong())
931         righttype=lefttype=new TypeDescriptor(TypeDescriptor.LONG);
932       else
933         righttype=lefttype=new TypeDescriptor(TypeDescriptor.INT);
934
935       on.setLeftType(lefttype);
936       on.setRightType(righttype);
937       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
938       break;
939
940
941
942     case Operation.LT:
943     case Operation.GT:
944     case Operation.LTE:
945     case Operation.GTE:
946       // 5.6.2 Binary Numeric Promotion
947       //TODO unboxing of reference objects
948       if (!ltd.isNumber()||!rtd.isNumber())
949         throw new Error();
950
951       if (ltd.isDouble()||rtd.isDouble())
952         lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
953       else if (ltd.isFloat()||rtd.isFloat())
954         lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
955       else if (ltd.isLong()||rtd.isLong())
956         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
957       else
958         lefttype=new TypeDescriptor(TypeDescriptor.INT);
959       righttype=lefttype;
960       on.setLeftType(lefttype);
961       on.setRightType(righttype);
962       on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
963       break;
964
965     case Operation.ADD:
966       if (ltd.isString()||rtd.isString()) {
967         ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
968         TypeDescriptor stringtd=new TypeDescriptor(stringcl);
969         NameDescriptor nd=new NameDescriptor("String");
970         NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
971         if (!(ltd.isString()&&(on.getLeft() instanceof OpNode))) {
972           MethodInvokeNode leftmin=new MethodInvokeNode(valuend);
973           leftmin.addArgument(on.getLeft());
974           on.left=leftmin;
975           checkExpressionNode(md, nametable, on.getLeft(), null);
976         }
977
978         if (!(rtd.isString()&&(on.getRight() instanceof OpNode))) {
979           MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
980           rightmin.addArgument(on.getRight());
981           on.right=rightmin;
982           checkExpressionNode(md, nametable, on.getRight(), null);
983         }
984
985         on.setLeftType(stringtd);
986         on.setRightType(stringtd);
987         on.setType(stringtd);
988         break;
989       }
990
991     case Operation.SUB:
992     case Operation.MULT:
993     case Operation.DIV:
994     case Operation.MOD:
995       // 5.6.2 Binary Numeric Promotion
996       //TODO unboxing of reference objects
997       if (ltd.isArray()||rtd.isArray()||!ltd.isNumber()||!rtd.isNumber())
998         throw new Error("Error in "+on.printNode(0));
999
1000       if (ltd.isDouble()||rtd.isDouble())
1001         lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
1002       else if (ltd.isFloat()||rtd.isFloat())
1003         lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
1004       else if (ltd.isLong()||rtd.isLong())
1005         lefttype=new TypeDescriptor(TypeDescriptor.LONG);
1006       else
1007         lefttype=new TypeDescriptor(TypeDescriptor.INT);
1008       righttype=lefttype;
1009       on.setLeftType(lefttype);
1010       on.setRightType(righttype);
1011       on.setType(lefttype);
1012       break;
1013
1014     case Operation.LEFTSHIFT:
1015     case Operation.RIGHTSHIFT:
1016     case Operation.URIGHTSHIFT:
1017       if (!rtd.isIntegerType())
1018         throw new Error();
1019       //5.6.1 Unary Numeric Promotion
1020       if (rtd.isByte()||rtd.isShort()||rtd.isInt())
1021         righttype=new TypeDescriptor(TypeDescriptor.INT);
1022       else
1023         righttype=rtd;
1024
1025       on.setRightType(righttype);
1026       if (!ltd.isIntegerType())
1027         throw new Error();
1028
1029     case Operation.UNARYPLUS:
1030     case Operation.UNARYMINUS:
1031       /*        case Operation.POSTINC:
1032           case Operation.POSTDEC:
1033           case Operation.PREINC:
1034           case Operation.PREDEC:*/
1035       if (!ltd.isNumber())
1036         throw new Error();
1037       //5.6.1 Unary Numeric Promotion
1038       if (ltd.isByte()||ltd.isShort()||ltd.isInt())
1039         lefttype=new TypeDescriptor(TypeDescriptor.INT);
1040       else
1041         lefttype=ltd;
1042       on.setLeftType(lefttype);
1043       on.setType(lefttype);
1044       break;
1045
1046     default:
1047       throw new Error(op.toString());
1048     }
1049
1050     if (td!=null)
1051       if (!typeutil.isSuperorType(td, on.getType())) {
1052         System.out.println(td);
1053         System.out.println(on.getType());
1054         throw new Error("Type of rside not compatible with type of lside"+on.printNode(0));
1055       }
1056   }
1057 }