As static blocks is compiled as a method without returntype, previous isConstructor...
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index d77cdb6f98e4cee2060e24b8c30253620278f781..692054232d7fc48e7d03db38bf90d2e3d9393737 100644 (file)
@@ -1,6 +1,7 @@
 package IR.Tree;
 
 import java.util.*;
+
 import IR.*;
 
 public class SemanticCheck {
@@ -29,7 +30,6 @@ public class SemanticCheck {
     if (!completed.contains(cd)) {
       completed.add(cd);
       
-      //System.out.println("Checking class: "+cd);
       //Set superclass link up
       if (cd.getSuper()!=null) {
        cd.setSuper(getClass(cd.getSuper()));
@@ -38,18 +38,40 @@ public class SemanticCheck {
        cd.getFieldTable().setParent(cd.getSuperDesc().getFieldTable());
        cd.getMethodTable().setParent(cd.getSuperDesc().getMethodTable());
        cd.getFlagTable().setParent(cd.getSuperDesc().getFlagTable());
+    if(state.MGC) {
+      // TODO add version for normal Java later
+      // Link together Field, Method tables do classes inherit these from 
+      // their ancestor interfaces
+      Vector<String> sifv = cd.getSuperInterface();
+      for(int i = 0; i < sifv.size(); i++) {
+        ClassDescriptor superif = getClass(sifv.elementAt(i));
+        cd.addSuperInterfaces(superif);
+        cd.getFieldTable().addParentIF(superif.getFieldTable());
+        cd.getMethodTable().addParentIF(superif.getMethodTable());
+      }
+    }
       }
       
       /* Check to see that fields are well typed */
       for(Iterator field_it=cd.getFields(); field_it.hasNext();) {
        FieldDescriptor fd=(FieldDescriptor)field_it.next();
-       //System.out.println("Checking field: "+fd);
        checkField(cd,fd);
       }
       
+      boolean hasConstructor = false;
       for(Iterator method_it=cd.getMethods(); method_it.hasNext();) {
        MethodDescriptor md=(MethodDescriptor)method_it.next();
        checkMethod(cd,md);
+    hasConstructor |= md.isConstructor();
+      }
+      if(!hasConstructor) {
+        // add a default constructor for this class
+        MethodDescriptor md = new MethodDescriptor(new Modifiers(Modifiers.PUBLIC),
+            cd.getSymbol(), false);
+        BlockNode bn=new BlockNode();
+        state.addTreeCode(md,bn);
+        cd.addMethod(md);
+        checkMethod(cd,md);
       }
     }
   }
@@ -64,14 +86,27 @@ public class SemanticCheck {
       Object obj=toanalyze.iterator().next();
       if (obj instanceof TaskDescriptor) {
        toanalyze.remove(obj);
-       checkTask((TaskDescriptor)obj);
+       TaskDescriptor td=(TaskDescriptor)obj;
+       try {
+         checkTask(td);
+       } catch( Error e ) {
+           System.out.println( "Error in "+td );
+           throw e;
+       }
       } else {
        ClassDescriptor cd=(ClassDescriptor)obj;
        toanalyze.remove(cd);
-       checkClass(cd);
+       //need to initialize typeutil object here...only place we can
+       //get class descriptors without first calling getclass
+       getClass(cd.getSymbol());
        for(Iterator method_it=cd.getMethods(); method_it.hasNext();) {
          MethodDescriptor md=(MethodDescriptor)method_it.next();
-         checkMethodBody(cd,md);
+         try {
+           checkMethodBody(cd,md);
+         } catch( Error e ) {
+           System.out.println( "Error in "+md );
+           throw e;
+         }
        }
       }
     }
@@ -202,8 +237,17 @@ public class SemanticCheck {
   }
 
   public void checkMethod(ClassDescriptor cd, MethodDescriptor md) {
+    if(state.MGC) {
+      // TODO add version for normal Java later
+      /* Check for abstract methods */
+      if(md.isAbstract()) {
+        if(!cd.isAbstract() && !cd.isInterface()) {
+          throw new Error("Error! The non-abstract Class " + cd.getSymbol() + " contains an abstract method " + md.getSymbol());
+        }
+      }
+    }
     /* Check return type */
-    if (!md.isConstructor())
+    if (!md.isConstructor() && !md.isStaticBlock())
       if (!md.getReturnType().isVoid())
        checkTypeDescriptor(md.getReturnType());
 
@@ -264,6 +308,10 @@ public class SemanticCheck {
     case Kind.IfStatementNode:
       checkIfStatementNode(md, nametable, (IfStatementNode)bsn);
       return;
+      
+    case Kind.SwitchStatementNode:
+      checkSwitchStatementNode(md, nametable, (SwitchStatementNode)bsn);
+      return;
 
     case Kind.LoopNode:
       checkLoopNode(md, nametable, (LoopNode)bsn);
@@ -285,11 +333,16 @@ public class SemanticCheck {
       checkAtomicNode(md, nametable, (AtomicNode)bsn);
       return;
 
+    case Kind.SynchronizedNode:
+      checkSynchronizedNode(md, nametable, (SynchronizedNode)bsn);
+      return;
+
     case Kind.ContinueBreakNode:
        checkContinueBreakNode(md, nametable, (ContinueBreakNode) bsn);
        return;
 
     case Kind.SESENode:
+    case Kind.GenReachNode:
       // do nothing, no semantic check for SESEs
       return;
     }
@@ -332,6 +385,12 @@ public class SemanticCheck {
     checkBlockNode(md, nametable, sbn.getBlockNode());
   }
 
+  void checkSynchronizedNode(Descriptor md, SymbolTable nametable, SynchronizedNode sbn) {
+    checkBlockNode(md, nametable, sbn.getBlockNode());
+    //todo this could be Object
+    checkExpressionNode(md, nametable, sbn.getExpr(), null);
+  }
+
   void checkContinueBreakNode(Descriptor md, SymbolTable nametable, ContinueBreakNode cbn) {
       if (loopstack.empty())
          throw new Error("continue/break outside of loop");
@@ -368,6 +427,51 @@ public class SemanticCheck {
     if (isn.getFalseBlock()!=null)
       checkBlockNode(md, nametable, isn.getFalseBlock());
   }
+  
+  void checkSwitchStatementNode(Descriptor md, SymbolTable nametable, SwitchStatementNode ssn) {
+    checkExpressionNode(md, nametable, ssn.getCondition(), new TypeDescriptor(TypeDescriptor.INT));
+    
+    BlockNode sbn = ssn.getSwitchBody();
+    boolean hasdefault = false;
+    for(int i = 0; i < sbn.size(); i++) {
+      boolean containdefault = checkSwitchBlockNode(md, nametable, (SwitchBlockNode)sbn.get(i));
+      if(hasdefault && containdefault) {
+        throw new Error("Error: duplicate default branch in switch-case statement in Method: " + md.getSymbol());
+      }
+      hasdefault = containdefault;
+    }
+  }
+  
+  boolean checkSwitchBlockNode(Descriptor md, SymbolTable nametable, SwitchBlockNode sbn) {
+    Vector<SwitchLabelNode> slnv = sbn.getSwitchConditions();
+    int defaultb = 0;
+    for(int i = 0; i < slnv.size(); i++) {
+      if(slnv.elementAt(i).isdefault) {
+        defaultb++;
+      } else {
+        checkConstantExpressionNode(md, nametable, slnv.elementAt(i).getCondition(), new TypeDescriptor(TypeDescriptor.INT));
+      }
+    }
+    if(defaultb > 1) {
+      throw new Error("Error: duplicate default branch in switch-case statement in Method: " + md.getSymbol());
+    } else {
+      checkBlockNode(md, nametable, sbn.getSwitchBlockStatement());
+      return (defaultb > 0);
+    }
+  }
+  
+  void checkConstantExpressionNode(Descriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
+    switch(en.kind()) {
+    case Kind.FieldAccessNode:
+      checkFieldAccessNode(md,nametable,(FieldAccessNode)en,td);
+      return;
+     
+    case Kind.LiteralNode:
+      checkLiteralNode(md,nametable,(LiteralNode)en,td);
+      return;
+    }
+    throw new Error();
+  }
 
   void checkExpressionNode(Descriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
     switch(en.kind()) {
@@ -408,7 +512,7 @@ public class SemanticCheck {
       return;
 
     case Kind.OffsetNode:
-      checkOffsetNode(md, nametable, (OffsetNode)en, new TypeDescriptor(TypeDescriptor.OFFSET));
+      checkOffsetNode(md, nametable, (OffsetNode)en, td);
       return;
 
     case Kind.TertiaryNode:
@@ -422,10 +526,18 @@ public class SemanticCheck {
     case Kind.ArrayInitializerNode:
       checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en, td);
       return;
+     
+    case Kind.ClassTypeNode:
+      checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
+      return;
     }
     throw new Error();
   }
 
+  void checkClassTypeNode(Descriptor md, SymbolTable nametable, ClassTypeNode tn, TypeDescriptor td) {
+    checkTypeDescriptor(tn.getType());
+  }
+  
   void checkCastNode(Descriptor md, SymbolTable nametable, CastNode cn, TypeDescriptor td) {
     /* Get type descriptor */
     if (cn.getType()==null) {
@@ -472,12 +584,51 @@ public class SemanticCheck {
       fd=FieldDescriptor.arrayLength;
     else
       fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
+    if(state.MGC) {
+      // TODO add version for normal Java later
+    if(ltd.isStatic()) {
+      if(ltd.getClassDesc().isEnum()) {
+        int value = ltd.getClassDesc().getEnumConstant(fieldname);
+        if(-1 == value) {
+          // check if this field is an enum constant
+          throw new Error(fieldname + " is not an enum constant in "+fan.printNode(0)+" in "+md);
+        }
+        fd = new FieldDescriptor(new Modifiers(Modifiers.PUBLIC|Modifiers.FINAL), new TypeDescriptor(TypeDescriptor.INT), fieldname, null, false);
+        fd.setAsEnum();
+        fd.setEnumValue(value);
+      } else if(fd.isStatic()) {
+        // check if this field is a static field
+        if(fd.getExpressionNode() != null) {
+          checkExpressionNode(md,nametable,fd.getExpressionNode(),null);
+        }
+      } else {
+        throw new Error("Dereference of the non-static field "+ fieldname + " in "+fan.printNode(0)+" in "+md);
+      }
+    } 
+    }
     if (fd==null)
       throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
-    fan.setField(fd);
-    if (td!=null)
+
+    if (fd.getType().iswrapper()) {
+      FieldAccessNode fan2=new FieldAccessNode(left, fieldname);
+      fan2.setField(fd);
+      fan.left=fan2;
+      fan.fieldname="value";
+
+      ExpressionNode leftwr=fan.getExpression();
+      TypeDescriptor ltdwr=leftwr.getType();
+      String fieldnamewr=fan.getFieldName();
+      FieldDescriptor fdwr=(FieldDescriptor) ltdwr.getClassDesc().getFieldTable().get(fieldnamewr);
+      fan.setField(fdwr);
+      if (fdwr==null)
+         throw new Error("Unknown field "+fieldnamewr + " in "+fan.printNode(0)+" in "+md);
+    } else {
+      fan.setField(fd);
+    }
+    if (td!=null) {
       if (!typeutil.isSuperorType(td,fan.getType()))
        throw new Error("Field node returns "+fan.getType()+", but need "+td);
+    }
   }
 
   void checkArrayAccessNode(Descriptor md, SymbolTable nametable, ArrayAccessNode aan, TypeDescriptor td) {
@@ -486,6 +637,9 @@ public class SemanticCheck {
 
     checkExpressionNode(md,nametable,aan.getIndex(),new TypeDescriptor(TypeDescriptor.INT));
     TypeDescriptor ltd=left.getType();
+    if (ltd.dereference().iswrapper()) {
+      aan.wrappertype=((FieldDescriptor)ltd.dereference().getClassDesc().getFieldTable().get("value")).getType();
+    }
 
     if (td!=null)
       if (!typeutil.isSuperorType(td,aan.getType()))
@@ -514,8 +668,25 @@ public class SemanticCheck {
     }
 
     if (td!=null)
-      if (!typeutil.isSuperorType(td,ln.getType()))
-       throw new Error("Field node returns "+ln.getType()+", but need "+td+" in "+md);
+      if (!typeutil.isSuperorType(td,ln.getType())) {
+        Long l = ln.evaluate();
+        if((ln.getType().isByte() || ln.getType().isShort() 
+            || ln.getType().isChar() || ln.getType().isInt()) 
+            && (l != null) 
+            && (td.isByte() || td.isShort() || td.isChar() 
+                || td.isInt() || td.isLong())) {
+          long lnvalue = l.longValue();
+          if((td.isByte() && ((lnvalue > 127) || (lnvalue < -128))) 
+              || (td.isShort() && ((lnvalue > 32767) || (lnvalue < -32768)))
+              || (td.isChar() && ((lnvalue > 65535) || (lnvalue < 0)))
+              || (td.isInt() && ((lnvalue > 2147483647) || (lnvalue < -2147483648)))
+              || (td.isLong() && ((lnvalue > 9223372036854775807L) || (lnvalue < -9223372036854775808L)))) {
+            throw new Error("Field node returns "+ln.getType()+", but need "+td+" in "+md);
+          }
+        } else {
+          throw new Error("Field node returns "+ln.getType()+", but need "+td+" in "+md);
+        }
+      }
   }
 
   void checkNameNode(Descriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
@@ -530,13 +701,65 @@ public class SemanticCheck {
       String varname=nd.toString();
       Descriptor d=(Descriptor)nametable.get(varname);
       if (d==null) {
-       throw new Error("Name "+varname+" undefined in: "+md);
+        if(state.MGC) {
+          // TODO add version for normal Java later
+        ClassDescriptor cd = null;
+        if(((MethodDescriptor)md).isStaticBlock()) {
+          // this is a static block, all the accessed fields should be static field
+          cd = ((MethodDescriptor)md).getClassDesc();
+          SymbolTable fieldtbl = cd.getFieldTable();
+          FieldDescriptor fd=(FieldDescriptor)fieldtbl.get(varname);
+          if((fd == null) || (!fd.isStatic())){
+            // no such field in the class, check if this is a class
+            if(varname.equals("this")) {
+              throw new Error("Error: access this obj in a static block");
+            }
+            cd=getClass(varname);
+            if(cd != null) {
+              // this is a class name
+              nn.setClassDesc(cd);
+              return;
+            } else {
+              throw new Error("Name "+varname+" should not be used in static block: "+md);
+            }
+          } else {
+            // this is a static field
+            nn.setField(fd);
+            nn.setClassDesc(cd);
+            return;
+          }
+        } else {
+          cd=getClass(varname);
+          if(cd != null) {
+            // this is a class name
+            nn.setClassDesc(cd);
+            return;
+          } else {
+            throw new Error("Name "+varname+" undefined in: "+md);
+          }
+        }
+        } else {
+          throw new Error("Name "+varname+" undefined in: "+md);
+        }
       }
       if (d instanceof VarDescriptor) {
        nn.setVar(d);
       } else if (d instanceof FieldDescriptor) {
-       nn.setField((FieldDescriptor)d);
-       nn.setVar((VarDescriptor)nametable.get("this"));        /* Need a pointer to this */
+       FieldDescriptor fd=(FieldDescriptor)d;
+       if (fd.getType().iswrapper()) {
+         String id=nd.getIdentifier();
+         NameDescriptor base=nd.getBase();
+         NameNode n=new NameNode(nn.getName());
+         n.setField(fd);
+         n.setVar((VarDescriptor)nametable.get("this"));        /* Need a pointer to this */
+         FieldAccessNode fan=new FieldAccessNode(n,"value");
+         FieldDescriptor fdval=(FieldDescriptor) fd.getType().getClassDesc().getFieldTable().get("value");
+         fan.setField(fdval);
+         nn.setExpression(fan);
+       } else {
+         nn.setField(fd);
+         nn.setVar((VarDescriptor)nametable.get("this"));        /* Need a pointer to this */
+       }
       } else if (d instanceof TagVarDescriptor) {
        nn.setVar(d);
       } else throw new Error("Wrong type of descriptor");
@@ -547,30 +770,30 @@ public class SemanticCheck {
   }
 
   void checkOffsetNode(Descriptor md, SymbolTable nameTable, OffsetNode ofn, TypeDescriptor td) {
-    TypeDescriptor ltd = ofn.td;
-    //System.out.println("Testing TypeDescriptor ltd = " + ofn.td);
-    String fieldname = ofn.fieldname;
-    //System.out.println("Testing String fieldname = " + ofn.fieldname);
-    Descriptor d = (Descriptor) nameTable.get(fieldname);
-    //System.out.println("Testing Descriptor d = " + d.toString());
-
-    ClassDescriptor cd = null;
+    TypeDescriptor ltd=ofn.td;
     checkTypeDescriptor(ltd);
-    cd = ltd.getClassDesc();
-    ofn.setClassDesc(cd);
-    //System.out.println("Testing for ClassDescriptor cd = " + cd.toString());
-
+    
+    String fieldname = ofn.fieldname;
     FieldDescriptor fd=null;
     if (ltd.isArray()&&fieldname.equals("length")) {
       fd=FieldDescriptor.arrayLength;
     } else {
-      fd=(FieldDescriptor) cd.getFieldTable().get(fieldname);
+      fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
     }
-    //System.out.println("Testing for FieldDescriptor fd = " + fd.toString());
+
     ofn.setField(fd);
+    checkField(ltd.getClassDesc(), fd);
+
     if (fd==null)
       throw new Error("Unknown field "+fieldname + " in "+ofn.printNode(1)+" in "+md);
-    ofn.setType(td);
+
+    if (td!=null) {
+      if (!typeutil.isSuperorType(td, ofn.getType())) {
+       System.out.println(td);
+       System.out.println(ofn.getType());
+       throw new Error("Type of rside not compatible with type of lside"+ofn.printNode(0));
+      }
+    }
   }
 
 
@@ -589,9 +812,49 @@ public class SemanticCheck {
   }
 
   void checkArrayInitializerNode(Descriptor md, SymbolTable nametable, ArrayInitializerNode ain, TypeDescriptor td) {
+    Vector<TypeDescriptor> vec_type = new Vector<TypeDescriptor>();
     for( int i = 0; i < ain.numVarInitializers(); ++i ) {
-      checkExpressionNode(md, nametable, ain.getVarInitializer(i), td); 
+      checkExpressionNode(md, nametable, ain.getVarInitializer(i), td==null?td:td.dereference());
+      vec_type.add(ain.getVarInitializer(i).getType());
+    }
+    // descide the type of this variableInitializerNode
+    TypeDescriptor out_type = vec_type.elementAt(0);
+    for(int i = 1; i < vec_type.size(); i++) {
+      TypeDescriptor tmp_type = vec_type.elementAt(i);
+      if(out_type == null) {
+        if(tmp_type != null) {
+          out_type = tmp_type;
+        }
+      } else if(out_type.isNull()) {
+        if(!tmp_type.isNull() ) {
+          if(!tmp_type.isArray()) {
+            throw new Error("Error: mixed type in var initializer list");
+          } else {
+            out_type = tmp_type;
+          }
+        }
+      } else if(out_type.isArray()) {
+        if(tmp_type.isArray()) {
+          if(tmp_type.getArrayCount() > out_type.getArrayCount()) {
+            out_type = tmp_type;
+          }
+        } else if((tmp_type != null) && (!tmp_type.isNull())) {
+          throw new Error("Error: mixed type in var initializer list");
+        }
+      } else if(out_type.isInt()) {
+        if(!tmp_type.isInt()) {
+          throw new Error("Error: mixed type in var initializer list");
+        }
+      } else if(out_type.isString()) {
+        if(!tmp_type.isString()) {
+          throw new Error("Error: mixed type in var initializer list");
+        }
+      }
+    }
+    if(out_type != null) {
+      out_type = out_type.makeArray(state);
     }
+    ain.setType(out_type);
   }
 
   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
@@ -600,8 +863,7 @@ public class SemanticCheck {
         (an.getOperation().getBaseOp().getOp()!=Operation.POSTINC&&
          an.getOperation().getBaseOp().getOp()!=Operation.POSTDEC))
       postinc=false;
-
-    if (!postinc)
+    if (!postinc)      
       checkExpressionNode(md, nametable, an.getSrc(),td);
     //TODO: Need check on validity of operation here
     if (!((an.getDest() instanceof FieldAccessNode)||
@@ -637,7 +899,23 @@ public class SemanticCheck {
     }
 
     if (!postinc&&!typeutil.isSuperorType(an.getDest().getType(),an.getSrc().getType())) {
-      throw new Error("Type of rside ("+an.getSrc().getType()+") not compatible with type of lside ("+an.getDest().getType()+")"+an.printNode(0));
+      TypeDescriptor dt = an.getDest().getType();
+      TypeDescriptor st = an.getSrc().getType();
+      Long l = an.getSrc().evaluate();
+      if((st.isByte() || st.isShort() || st.isChar() || st.isInt()) 
+          && (l != null) 
+          && (dt.isByte() || dt.isShort() || dt.isChar() || dt.isInt() || dt.isLong())) {
+        long lnvalue = l.longValue();
+        if((dt.isByte() && ((lnvalue > 127) || (lnvalue < -128))) 
+            || (dt.isShort() && ((lnvalue > 32767) || (lnvalue < -32768)))
+            || (dt.isChar() && ((lnvalue > 65535) || (lnvalue < 0)))
+            || (dt.isInt() && ((lnvalue > 2147483647) || (lnvalue < -2147483648)))
+            || (dt.isLong() && ((lnvalue > 9223372036854775807L) || (lnvalue < -9223372036854775808L)))) {
+          throw new Error("Field node returns "+st+", but need "+dt+" in "+md);
+        }
+      } else {
+        throw new Error("Type of rside ("+an.getSrc().getType().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+an.printNode(0));
+      }
     }
   }
 
@@ -677,6 +955,11 @@ public class SemanticCheck {
 
     if (td!=null&&!typeutil.isSuperorType(td, typetolookin))
       throw new Error(typetolookin + " isn't a "+td);
+    
+    /* Check Array Initializers */
+    if(state.MGC && (con.getArrayInitializer() != null)) {
+      checkArrayInitializerNode(md, nametable, con.getArrayInitializer(), td);
+    }
 
     /* Check flag effects */
     if (con.getFlagEffects()!=null) {
@@ -795,11 +1078,17 @@ NextMethod:
       ExpressionNode en=min.getArg(i);
       checkExpressionNode(md,nametable,en,null);
       tdarray[i]=en.getType();
+      if(state.MGC && en.getType().isClass() && en.getType().getClassDesc().isEnum()) {
+        tdarray[i] = new TypeDescriptor(TypeDescriptor.INT);
+      }
     }
     TypeDescriptor typetolookin=null;
     if (min.getExpression()!=null) {
       checkExpressionNode(md,nametable,min.getExpression(),null);
       typetolookin=min.getExpression().getType();
+      //if (typetolookin==null)
+      //throw new Error(md+" has null return type");
+
     } else if (min.getBaseName()!=null) {
       String rootname=min.getBaseName().getRoot();
       if (rootname.equals("super")) {
@@ -985,8 +1274,12 @@ NextMethod:
     case Operation.GTE:
       // 5.6.2 Binary Numeric Promotion
       //TODO unboxing of reference objects
-      if (!ltd.isNumber()||!rtd.isNumber())
-       throw new Error();
+      if (!ltd.isNumber()||!rtd.isNumber()) {
+       if (!ltd.isNumber())
+         throw new Error("Leftside is not number"+on.printNode(0)+"type="+ltd.toPrettyString());
+       if (!rtd.isNumber())
+         throw new Error("Rightside is not number"+on.printNode(0));
+      }
 
       if (ltd.isDouble()||rtd.isDouble())
        lefttype=new TypeDescriptor(TypeDescriptor.DOUBLE);