As static blocks is compiled as a method without returntype, previous isConstructor...
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index ba82bb1ba9f47dbfe45c7005e9e4294061c80c40..692054232d7fc48e7d03db38bf90d2e3d9393737 100644 (file)
@@ -58,9 +58,20 @@ public class SemanticCheck {
        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);
       }
     }
   }
@@ -236,7 +247,7 @@ public class SemanticCheck {
       }
     }
     /* Check return type */
-    if (!md.isConstructor())
+    if (!md.isConstructor() && !md.isStaticBlock())
       if (!md.getReturnType().isVoid())
        checkTypeDescriptor(md.getReturnType());
 
@@ -297,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);
@@ -412,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()) {
@@ -466,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) {
@@ -514,13 +582,26 @@ public class SemanticCheck {
     FieldDescriptor fd=null;
     if (ltd.isArray()&&fieldname.equals("length"))
       fd=FieldDescriptor.arrayLength;
-    else 
+    else
       fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
     if(state.MGC) {
       // TODO add version for normal Java later
     if(ltd.isStatic()) {
-      // check if this field is a static field
-      if(!fd.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);
       }
     } 
@@ -587,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) {
@@ -611,9 +709,19 @@ public class SemanticCheck {
           cd = ((MethodDescriptor)md).getClassDesc();
           SymbolTable fieldtbl = cd.getFieldTable();
           FieldDescriptor fd=(FieldDescriptor)fieldtbl.get(varname);
-          if((fd == null) || (!fd.isStatic()) || (!fd.isVolatile())){
-            // no such field in the class or it is not a static field
-            throw new Error("Name "+varname+" should not be used in static block: "+md);
+          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);
@@ -704,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) {
@@ -751,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().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+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));
+      }
     }
   }
 
@@ -791,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) {
@@ -909,6 +1078,9 @@ 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) {