6 public class SemanticCheck {
10 public SemanticCheck(State state, TypeUtil tu) {
15 public void semanticCheck() {
16 SymbolTable classtable=state.getClassSymbolTable();
17 Iterator it=classtable.getDescriptorsIterator();
18 // Do descriptors first
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());
30 for(Iterator field_it=cd.getFields();field_it.hasNext();) {
31 FieldDescriptor fd=(FieldDescriptor)field_it.next();
32 System.out.println("Checking field: "+fd);
35 for(Iterator method_it=cd.getMethods();method_it.hasNext();) {
36 MethodDescriptor md=(MethodDescriptor)method_it.next();
41 it=classtable.getDescriptorsIterator();
42 // Do descriptors first
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);
52 public void checkTypeDescriptor(TypeDescriptor td) {
56 String name=td.toString();
57 ClassDescriptor field_cd=(ClassDescriptor)state.getClassSymbolTable().get(name);
59 throw new Error("Undefined class "+name);
60 td.setClassDescriptor(field_cd);
66 public void checkField(ClassDescriptor cd, FieldDescriptor fd) {
67 checkTypeDescriptor(fd.getType());
70 public void checkMethod(ClassDescriptor cd, MethodDescriptor md) {
71 /* Check return type */
72 if (!md.isConstructor())
73 if (!md.getReturnType().isVoid())
74 checkTypeDescriptor(md.getReturnType());
76 for(int i=0;i<md.numParameters();i++) {
77 TypeDescriptor param_type=md.getParamType(i);
78 checkTypeDescriptor(param_type);
80 /* Link the naming environments */
81 if (!md.isStatic()) /* Fields aren't accessible directly in a static method, so don't link in this table */
82 md.getParameterTable().setParent(cd.getFieldTable());
85 VarDescriptor thisvd=new VarDescriptor(new TypeDescriptor(cd),"this");
90 public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
91 System.out.println("Processing method:"+md);
92 BlockNode bn=state.getMethodBody(md);
93 checkBlockNode(md, md.getParameterTable(),bn);
96 public void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
97 /* Link in the naming environment */
98 bn.getVarTable().setParent(nametable);
99 for(int i=0;i<bn.size();i++) {
100 BlockStatementNode bsn=bn.get(i);
101 checkBlockStatementNode(md, bn.getVarTable(),bsn);
105 public void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable, BlockStatementNode bsn) {
107 case Kind.BlockExpressionNode:
108 checkBlockExpressionNode(md, nametable,(BlockExpressionNode)bsn);
111 case Kind.DeclarationNode:
112 checkDeclarationNode(md, nametable, (DeclarationNode)bsn);
115 case Kind.IfStatementNode:
116 checkIfStatementNode(md, nametable, (IfStatementNode)bsn);
120 checkLoopNode(md, nametable, (LoopNode)bsn);
123 case Kind.ReturnNode:
124 checkReturnNode(md, nametable, (ReturnNode)bsn);
127 case Kind.SubBlockNode:
128 checkSubBlockNode(md, nametable, (SubBlockNode)bsn);
134 void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable, BlockExpressionNode ben) {
135 checkExpressionNode(md, nametable, ben.getExpression(), null);
138 void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
139 VarDescriptor vd=dn.getVarDescriptor();
140 checkTypeDescriptor(vd.getType());
141 Descriptor d=nametable.get(vd.getSymbol());
143 (d instanceof FieldDescriptor)) {
146 throw new Error(vd.getSymbol()+" defined a second time");
147 if (dn.getExpression()!=null)
148 checkExpressionNode(md, nametable, dn.getExpression(), vd.getType());
151 void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) {
152 checkBlockNode(md, nametable, sbn.getBlockNode());
155 void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) {
156 if (rn.getReturnExpression()!=null)
157 checkExpressionNode(md, nametable, rn.getReturnExpression(), md.getReturnType());
159 if (md.getReturnType()!=null&&!md.getReturnType().isVoid())
160 throw new Error("Need to return something for "+md);
163 void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) {
164 checkExpressionNode(md, nametable, isn.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
165 checkBlockNode(md, nametable, isn.getTrueBlock());
166 if (isn.getFalseBlock()!=null)
167 checkBlockNode(md, nametable, isn.getFalseBlock());
170 void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
172 case Kind.AssignmentNode:
173 checkAssignmentNode(md,nametable,(AssignmentNode)en,td);
176 checkCastNode(md,nametable,(CastNode)en,td);
178 case Kind.CreateObjectNode:
179 checkCreateObjectNode(md,nametable,(CreateObjectNode)en,td);
181 case Kind.FieldAccessNode:
182 checkFieldAccessNode(md,nametable,(FieldAccessNode)en,td);
184 case Kind.ArrayAccessNode:
185 checkArrayAccessNode(md,nametable,(ArrayAccessNode)en,td);
187 case Kind.LiteralNode:
188 checkLiteralNode(md,nametable,(LiteralNode)en,td);
190 case Kind.MethodInvokeNode:
191 checkMethodInvokeNode(md,nametable,(MethodInvokeNode)en,td);
194 checkNameNode(md,nametable,(NameNode)en,td);
197 checkOpNode(md,nametable,(OpNode)en,td);
203 void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn, TypeDescriptor td) {
204 /* Get type descriptor */
205 if (cn.getType()==null) {
206 NameDescriptor typenamed=cn.getTypeName().getName();
207 String typename=typenamed.toString();
208 TypeDescriptor ntd=new TypeDescriptor(typeutil.getClass(typename));
212 /* Check the type descriptor */
213 TypeDescriptor cast_type=cn.getType();
214 checkTypeDescriptor(cast_type);
218 if (!typeutil.isSuperorType(td,cast_type))
219 throw new Error("Cast node returns "+cast_type+", but need "+td);
222 ExpressionNode en=cn.getExpression();
223 checkExpressionNode(md, nametable, en, null);
224 TypeDescriptor etd=en.getType();
225 if (typeutil.isSuperorType(cast_type,etd)) /* Cast trivially succeeds */
228 if (typeutil.isSuperorType(etd,cast_type)) /* Cast may succeed */
231 /* Different branches */
232 /* TODO: change if add interfaces */
233 throw new Error("Cast will always fail\n"+cn.printNode(0));
236 void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan, TypeDescriptor td) {
237 ExpressionNode left=fan.getExpression();
238 checkExpressionNode(md,nametable,left,null);
239 TypeDescriptor ltd=left.getType();
240 String fieldname=fan.getFieldName();
242 FieldDescriptor fd=null;
243 if (ltd.isArray()&&fieldname.equals("length"))
244 fd=FieldDescriptor.arrayLength;
246 fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
248 throw new Error("Unknown field "+fieldname);
251 if (!typeutil.isSuperorType(td,fan.getType()))
252 throw new Error("Field node returns "+fan.getType()+", but need "+td);
255 void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode aan, TypeDescriptor td) {
256 ExpressionNode left=aan.getExpression();
257 checkExpressionNode(md,nametable,left,null);
259 checkExpressionNode(md,nametable,aan.getIndex(),new TypeDescriptor(TypeDescriptor.INT));
260 TypeDescriptor ltd=left.getType();
263 if (!typeutil.isSuperorType(td,aan.getType()))
264 throw new Error("Field node returns "+aan.getType()+", but need "+td);
267 void checkLiteralNode(MethodDescriptor md, SymbolTable nametable, LiteralNode ln, TypeDescriptor td) {
268 /* Resolve the type */
269 Object o=ln.getValue();
270 if (ln.getTypeString().equals("null")) {
271 ln.setType(new TypeDescriptor(TypeDescriptor.NULL));
272 } else if (o instanceof Integer) {
273 ln.setType(new TypeDescriptor(TypeDescriptor.INT));
274 } else if (o instanceof Long) {
275 ln.setType(new TypeDescriptor(TypeDescriptor.LONG));
276 } else if (o instanceof Float) {
277 ln.setType(new TypeDescriptor(TypeDescriptor.FLOAT));
278 } else if (o instanceof Boolean) {
279 ln.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
280 } else if (o instanceof Double) {
281 ln.setType(new TypeDescriptor(TypeDescriptor.DOUBLE));
282 } else if (o instanceof Character) {
283 ln.setType(new TypeDescriptor(TypeDescriptor.CHAR));
284 } else if (o instanceof String) {
285 ln.setType(new TypeDescriptor(typeutil.getClass(TypeUtil.StringClass)));
289 if (!typeutil.isSuperorType(td,ln.getType()))
290 throw new Error("Field node returns "+ln.getType()+", but need "+td);
293 void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
294 NameDescriptor nd=nn.getName();
295 if (nd.getBase()!=null) {
297 /* Rewrite NameNode */
298 ExpressionNode en=translateNameDescriptorintoExpression(nd);
299 nn.setExpression(en);
300 checkExpressionNode(md,nametable,en,td);
302 String varname=nd.toString();
303 Descriptor d=(Descriptor)nametable.get(varname);
305 throw new Error("Name "+varname+" undefined");
307 if (d instanceof VarDescriptor) {
308 nn.setVar((VarDescriptor)d);
309 } else if (d instanceof FieldDescriptor) {
310 nn.setField((FieldDescriptor)d);
311 nn.setVar((VarDescriptor)nametable.get("this")); /* Need a pointer to this */
314 if (!typeutil.isSuperorType(td,nn.getType()))
315 throw new Error("Field node returns "+nn.getType()+", but need "+td);
319 void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
320 checkExpressionNode(md, nametable, an.getSrc() ,td);
321 //TODO: Need check on validity of operation here
322 if (!((an.getDest() instanceof FieldAccessNode)||
323 (an.getDest() instanceof ArrayAccessNode)||
324 (an.getDest() instanceof NameNode)))
325 throw new Error("Bad lside in "+an.printNode(0));
326 checkExpressionNode(md, nametable, an.getDest(), null);
327 if (!typeutil.isSuperorType(an.getDest().getType(),an.getSrc().getType())) {
328 throw new Error("Type of rside ("+an.getSrc().getType()+") not compatible with type of lside ("+an.getDest().getType()+")"+an.printNode(0));
332 void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
333 if (ln.getType()==LoopNode.WHILELOOP||ln.getType()==LoopNode.DOWHILELOOP) {
334 checkExpressionNode(md, nametable, ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
335 checkBlockNode(md, nametable, ln.getBody());
338 /* Link in the initializer naming environment */
339 BlockNode bn=ln.getInitializer();
340 bn.getVarTable().setParent(nametable);
341 for(int i=0;i<bn.size();i++) {
342 BlockStatementNode bsn=bn.get(i);
343 checkBlockStatementNode(md, bn.getVarTable(),bsn);
345 //check the condition
346 checkExpressionNode(md, bn.getVarTable(), ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
347 checkBlockNode(md, bn.getVarTable(), ln.getBody());
348 checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
353 void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable, CreateObjectNode con, TypeDescriptor td) {
354 TypeDescriptor[] tdarray=new TypeDescriptor[con.numArgs()];
355 for(int i=0;i<con.numArgs();i++) {
356 ExpressionNode en=con.getArg(i);
357 checkExpressionNode(md,nametable,en,null);
358 tdarray[i]=en.getType();
361 TypeDescriptor typetolookin=con.getType();
362 checkTypeDescriptor(typetolookin);
363 if ((!typetolookin.isClass())&&(!typetolookin.isArray()))
364 throw new Error("Can't allocate primitive type:"+con.printNode(0));
366 if (!typetolookin.isArray()) {
367 //Array's don't need constructor calls
368 ClassDescriptor classtolookin=typetolookin.getClassDesc();
369 System.out.println("Looking for "+typetolookin.getSymbol());
370 System.out.println(classtolookin.getMethodTable());
372 Set methoddescriptorset=classtolookin.getMethodTable().getSet(typetolookin.getSymbol());
373 MethodDescriptor bestmd=null;
375 for(Iterator methodit=methoddescriptorset.iterator();methodit.hasNext();) {
376 MethodDescriptor currmd=(MethodDescriptor)methodit.next();
377 /* Need correct number of parameters */
378 System.out.println("Examining: "+currmd);
379 if (con.numArgs()!=currmd.numParameters())
381 for(int i=0;i<con.numArgs();i++) {
382 if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
385 /* Method okay so far */
389 if (isMoreSpecific(currmd,bestmd)) {
391 } else if (!isMoreSpecific(bestmd, currmd))
392 throw new Error("No method is most specific");
394 /* Is this more specific than bestmd */
398 throw new Error("No method found for "+con.printNode(0));
399 con.setConstructor(bestmd);
404 /** Check to see if md1 is more specific than md2... Informally
405 if md2 could always be called given the arguments passed into
408 boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
409 /* Checks if md1 is more specific than md2 */
410 if (md1.numParameters()!=md2.numParameters())
412 for(int i=0;i<md1.numParameters();i++) {
413 if (!typeutil.isSuperorType(md2.getParamType(i), md1.getParamType(i)))
416 if (!typeutil.isSuperorType(md2.getReturnType(), md1.getReturnType()))
421 ExpressionNode translateNameDescriptorintoExpression(NameDescriptor nd) {
422 String id=nd.getIdentifier();
423 NameDescriptor base=nd.getBase();
425 return new NameNode(nd);
427 return new FieldAccessNode(translateNameDescriptorintoExpression(base),id);
431 void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable, MethodInvokeNode min, TypeDescriptor td) {
432 /*Typecheck subexpressions
433 and get types for expressions*/
435 TypeDescriptor[] tdarray=new TypeDescriptor[min.numArgs()];
436 for(int i=0;i<min.numArgs();i++) {
437 ExpressionNode en=min.getArg(i);
438 checkExpressionNode(md,nametable,en,null);
439 tdarray[i]=en.getType();
441 TypeDescriptor typetolookin=null;
442 if (min.getExpression()!=null) {
443 checkExpressionNode(md,nametable,min.getExpression(),null);
444 typetolookin=min.getExpression().getType();
445 } else if (min.getBaseName()!=null) {
446 String rootname=min.getBaseName().getRoot();
447 if (nametable.get(rootname)!=null) {
448 //we have an expression
449 min.setExpression(translateNameDescriptorintoExpression(min.getBaseName()));
450 checkExpressionNode(md, nametable, min.getExpression(), null);
451 typetolookin=min.getExpression().getType();
454 ClassDescriptor cd=typeutil.getClass(min.getBaseName().getSymbol());
456 throw new Error(min.getBaseName()+" undefined");
457 typetolookin=new TypeDescriptor(cd);
460 typetolookin=new TypeDescriptor(md.getClassDesc());
462 if (!typetolookin.isClass())
464 ClassDescriptor classtolookin=typetolookin.getClassDesc();
465 System.out.println("Method name="+min.getMethodName());
466 Set methoddescriptorset=classtolookin.getMethodTable().getSet(min.getMethodName());
467 MethodDescriptor bestmd=null;
469 for(Iterator methodit=methoddescriptorset.iterator();methodit.hasNext();) {
470 MethodDescriptor currmd=(MethodDescriptor)methodit.next();
471 /* Need correct number of parameters */
472 if (min.numArgs()!=currmd.numParameters())
474 for(int i=0;i<min.numArgs();i++) {
475 if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
478 /* Method okay so far */
482 if (isMoreSpecific(currmd,bestmd)) {
484 } else if (!isMoreSpecific(bestmd, currmd))
485 throw new Error("No method is most specific");
487 /* Is this more specific than bestmd */
491 throw new Error("No method found for :"+min.printNode(0));
492 min.setMethod(bestmd);
493 /* Check whether we need to set this parameter to implied this */
494 if (!bestmd.isStatic()) {
495 if (min.getExpression()==null) {
496 ExpressionNode en=new NameNode(new NameDescriptor("this"));
497 min.setExpression(en);
498 checkExpressionNode(md, nametable, min.getExpression(), null);
505 void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode on, TypeDescriptor td) {
506 checkExpressionNode(md, nametable, on.getLeft(), null);
507 if (on.getRight()!=null)
508 checkExpressionNode(md, nametable, on.getRight(), null);
509 TypeDescriptor ltd=on.getLeft().getType();
510 TypeDescriptor rtd=on.getRight()!=null?on.getRight().getType():null;
511 TypeDescriptor lefttype=null;
512 TypeDescriptor righttype=null;
513 Operation op=on.getOp();
516 case Operation.LOGIC_OR:
517 case Operation.LOGIC_AND:
518 if (!(ltd.isBoolean()&&rtd.isBoolean()))
522 on.setRightType(rtd);
523 on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
526 case Operation.BIT_OR:
527 case Operation.BIT_XOR:
528 case Operation.BIT_AND:
529 // 5.6.2 Binary Numeric Promotion
530 //TODO unboxing of reference objects
531 if (ltd.isDouble()||rtd.isDouble())
533 else if (ltd.isFloat()||rtd.isFloat())
535 else if (ltd.isLong()||rtd.isLong())
536 lefttype=new TypeDescriptor(TypeDescriptor.LONG);
538 lefttype=new TypeDescriptor(TypeDescriptor.INT);
541 on.setLeftType(lefttype);
542 on.setRightType(righttype);
543 on.setType(lefttype);
546 case Operation.EQUAL:
547 case Operation.NOTEQUAL:
548 // 5.6.2 Binary Numeric Promotion
549 //TODO unboxing of reference objects
550 if (ltd.isBoolean()||rtd.isBoolean()) {
551 if (!(ltd.isBoolean()&&rtd.isBoolean()))
553 righttype=lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
554 } else if (ltd.isPtr()||rtd.isPtr()) {
555 if (!(ltd.isPtr()&&rtd.isPtr()))
559 } else if (ltd.isDouble()||rtd.isDouble())
560 righttype=lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
561 else if (ltd.isFloat()||rtd.isFloat())
562 righttype=lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
563 else if (ltd.isLong()||rtd.isLong())
564 righttype=lefttype=new TypeDescriptor(TypeDescriptor.LONG);
566 righttype=lefttype=new TypeDescriptor(TypeDescriptor.INT);
568 on.setLeftType(lefttype);
569 on.setRightType(righttype);
570 on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
579 // 5.6.2 Binary Numeric Promotion
580 //TODO unboxing of reference objects
581 if (!ltd.isNumber()||!rtd.isNumber())
584 if (ltd.isDouble()||rtd.isDouble())
585 lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
586 else if (ltd.isFloat()||rtd.isFloat())
587 lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
588 else if (ltd.isLong()||rtd.isLong())
589 lefttype=new TypeDescriptor(TypeDescriptor.LONG);
591 lefttype=new TypeDescriptor(TypeDescriptor.INT);
593 on.setLeftType(lefttype);
594 on.setRightType(righttype);
595 on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
599 //TODO: Need special case for strings eventually
606 // 5.6.2 Binary Numeric Promotion
607 //TODO unboxing of reference objects
608 if (!ltd.isNumber()||!rtd.isNumber())
609 throw new Error("Error in "+on.printNode(0));
611 if (ltd.isDouble()||rtd.isDouble())
612 lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);
613 else if (ltd.isFloat()||rtd.isFloat())
614 lefttype=new TypeDescriptor(TypeDescriptor.FLOAT);
615 else if (ltd.isLong()||rtd.isLong())
616 lefttype=new TypeDescriptor(TypeDescriptor.LONG);
618 lefttype=new TypeDescriptor(TypeDescriptor.INT);
620 on.setLeftType(lefttype);
621 on.setRightType(righttype);
622 on.setType(lefttype);
625 case Operation.LEFTSHIFT:
626 case Operation.RIGHTSHIFT:
627 if (!rtd.isIntegerType())
629 //5.6.1 Unary Numeric Promotion
630 if (rtd.isByte()||rtd.isShort()||rtd.isInt())
631 righttype=new TypeDescriptor(TypeDescriptor.INT);
635 on.setRightType(righttype);
636 if (!ltd.isIntegerType())
638 case Operation.UNARYPLUS:
639 case Operation.UNARYMINUS:
640 case Operation.POSTINC:
641 case Operation.POSTDEC:
642 case Operation.PREINC:
643 case Operation.PREDEC:
646 //5.6.1 Unary Numeric Promotion
647 if (ltd.isByte()||ltd.isShort()||ltd.isInt())
648 lefttype=new TypeDescriptor(TypeDescriptor.INT);
651 on.setLeftType(lefttype);
652 on.setType(lefttype);
661 if (!typeutil.isSuperorType(td, on.getType())) {
662 System.out.println(td);
663 System.out.println(on.getType());
664 throw new Error("Type of rside not compatible with type of lside"+on.printNode(0));