Bug fix in array initialization: handle the special case like {{null,null}}
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index 7aa5e3e9a337aceb0967f61dc27e930e1ea27508..7e475f725ab68e6670d770907e59b5f86511f6a6 100644 (file)
 package IR.Tree;
 
 import java.util.*;
+
 import IR.*;
 
 public class SemanticCheck {
   State state;
   TypeUtil typeutil;
+  Stack loopstack;
+  HashSet toanalyze;
+  HashSet completed;
+
 
   public SemanticCheck(State state, TypeUtil tu) {
     this.state=state;
     this.typeutil=tu;
+    this.loopstack=new Stack();
+    this.toanalyze=new HashSet();
+    this.completed=new HashSet();
   }
 
-  public void semanticCheck() {
-    SymbolTable classtable=state.getClassSymbolTable();
-    Iterator it=classtable.getDescriptorsIterator();
-    // Do descriptors first
-    while(it.hasNext()) {
-      ClassDescriptor cd=(ClassDescriptor)it.next();
-      //System.out.println("Checking class: "+cd);
+  public ClassDescriptor getClass(String classname) {
+    ClassDescriptor cd=typeutil.getClass(classname, toanalyze);
+    checkClass(cd);
+    return cd;
+  }
+
+  private void checkClass(ClassDescriptor cd) {
+    if (!completed.contains(cd)) {
+      completed.add(cd);
+      
       //Set superclass link up
       if (cd.getSuper()!=null) {
-       cd.setSuper(typeutil.getClass(cd.getSuper()));
+       cd.setSuper(getClass(cd.getSuper()));
+    if(cd.getSuperDesc().isInterface()) {
+      throw new Error("Error! Class " + cd.getSymbol() + " extends interface " + cd.getSuper());
+    }
        // Link together Field, Method, and Flag tables so classes
        // inherit these from their superclasses
        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));
+          if(!superif.isInterface()) {
+            throw new Error("Error! Class " + cd.getSymbol() + " implements non-interface " + superif.getSymbol());
+          }
+          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();
       }
-    }
-
-    it=classtable.getDescriptorsIterator();
-    // Do descriptors first
-    while(it.hasNext()) {
-      ClassDescriptor cd=(ClassDescriptor)it.next();
-      for(Iterator method_it=cd.getMethods(); method_it.hasNext();) {
-       MethodDescriptor md=(MethodDescriptor)method_it.next();
-       checkMethodBody(cd,md);
+      if((!hasConstructor) && (!cd.isEnum())) {
+        // 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);
       }
     }
+  }
 
-    for(Iterator task_it=state.getTaskSymbolTable().getDescriptorsIterator(); task_it.hasNext();) {
-      TaskDescriptor td=(TaskDescriptor)task_it.next();
-      checkTask(td);
-
+  public void semanticCheck() {
+    SymbolTable classtable=state.getClassSymbolTable();
+    toanalyze.addAll(classtable.getValueSet());
+    toanalyze.addAll(state.getTaskSymbolTable().getValueSet());
+
+    // Do methods next
+    while(!toanalyze.isEmpty()) {
+      Object obj=toanalyze.iterator().next();
+      if (obj instanceof TaskDescriptor) {
+       toanalyze.remove(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);
+       //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();
+         try {
+           checkMethodBody(cd,md);
+         } catch( Error e ) {
+           System.out.println( "Error in "+md );
+           throw e;
+         }
+       }
+      }
     }
   }
 
@@ -64,7 +123,11 @@ public class SemanticCheck {
       return;       /* Done */
     else if (td.isClass()) {
       String name=td.toString();
-      ClassDescriptor field_cd=(ClassDescriptor)state.getClassSymbolTable().get(name);
+      int index = name.lastIndexOf('.');
+      if(index != -1) {
+        name = name.substring(index+1);
+      }
+      ClassDescriptor field_cd=getClass(name);
       if (field_cd==null)
        throw new Error("Undefined class "+name);
       td.setClassDescriptor(field_cd);
@@ -184,8 +247,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());
 
@@ -246,6 +318,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);
@@ -267,7 +343,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;
     }
@@ -310,6 +395,22 @@ 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");
+      Object o = loopstack.peek();
+      if(o instanceof LoopNode) {
+        LoopNode ln=(LoopNode)o;
+        cbn.setLoop(ln);
+      }
+  }
+
   void checkReturnNode(Descriptor d, SymbolTable nametable, ReturnNode rn) {
     if (d instanceof TaskDescriptor)
       throw new Error("Illegal return appears in Task: "+d.getSymbol());
@@ -339,6 +440,61 @@ 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 {
+      loopstack.push(sbn);
+      checkBlockNode(md, nametable, sbn.getSwitchBlockStatement());
+      loopstack.pop();
+      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;
+      
+    case Kind.NameNode:
+      checkNameNode(md,nametable,(NameNode)en,td);
+      return;
+      
+    case Kind.OpNode:
+      checkOpNode(md, nametable, (OpNode)en, td);
+      return;
+    }
+    throw new Error();
+  }
 
   void checkExpressionNode(Descriptor md, SymbolTable nametable, ExpressionNode en, TypeDescriptor td) {
     switch(en.kind()) {
@@ -379,18 +535,38 @@ 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:
+      checkTertiaryNode(md, nametable, (TertiaryNode)en, td);
+      return;
+      
+    case Kind.InstanceOfNode:
+      checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
+      return;
+
+    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) {
       NameDescriptor typenamed=cn.getTypeName().getName();
       String typename=typenamed.toString();
-      TypeDescriptor ntd=new TypeDescriptor(typeutil.getClass(typename));
+      TypeDescriptor ntd=new TypeDescriptor(getClass(typename));
       cn.setType(ntd);
     }
 
@@ -431,12 +607,52 @@ 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.isClassNameRef()) {
+      // the field access is using a class name directly
+      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) {
@@ -445,6 +661,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()))
@@ -469,12 +688,29 @@ public class SemanticCheck {
     } else if (o instanceof Character) {
       ln.setType(new TypeDescriptor(TypeDescriptor.CHAR));
     } else if (o instanceof String) {
-      ln.setType(new TypeDescriptor(typeutil.getClass(TypeUtil.StringClass)));
+      ln.setType(new TypeDescriptor(getClass(TypeUtil.StringClass)));
     }
 
     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) {
@@ -487,15 +723,87 @@ public class SemanticCheck {
       checkExpressionNode(md,nametable,en,td);
     } else {
       String varname=nd.toString();
+      if(varname.equals("this")) {
+        // "this"
+        nn.setVar((VarDescriptor)nametable.get("this")); 
+        return;
+      }
       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 {
+          // check if the var is a static field of the class
+          if(md instanceof MethodDescriptor) {
+            cd = ((MethodDescriptor)md).getClassDesc();
+            FieldDescriptor fd = (FieldDescriptor)cd.getFieldTable().get(varname);
+            if((fd != null) && (fd.isStatic())) {
+              nn.setField(fd);
+              nn.setClassDesc(cd);
+              if (td!=null)
+                if (!typeutil.isSuperorType(td,nn.getType()))
+                  throw new Error("Field node returns "+nn.getType()+", but need "+td);
+              return;
+            } else if(fd != null) {
+              throw new Error("Name "+varname+" should not be used in " + md);
+            }
+          }
+          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");
@@ -506,30 +814,92 @@ 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));
+      }
+    }
+  }
+
+
+  void checkTertiaryNode(Descriptor md, SymbolTable nametable, TertiaryNode tn, TypeDescriptor td) {
+    checkExpressionNode(md, nametable, tn.getCond(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
+    checkExpressionNode(md, nametable, tn.getTrueExpr(), td );
+    checkExpressionNode(md, nametable, tn.getFalseExpr(), td );
+  }
+
+  void checkInstanceOfNode(Descriptor md, SymbolTable nametable, InstanceOfNode tn, TypeDescriptor td) {
+    if (td!=null&&!td.isBoolean())
+      throw new Error("Expecting type "+td+"for instanceof expression");
+    
+    checkTypeDescriptor(tn.getExprType());
+    checkExpressionNode(md, nametable, tn.getExpr(), null);
+  }
+
+  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==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);
+      //out_type.setStatic();
+    }
+    ain.setType(out_type);
   }
 
   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
@@ -538,8 +908,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)||
@@ -561,7 +930,7 @@ public class SemanticCheck {
 
     if (an.getDest().getType().isString()&&an.getOperation().getOp()==AssignOperation.PLUSEQ) {
       //String add
-      ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
+      ClassDescriptor stringcl=getClass(TypeUtil.StringClass);
       TypeDescriptor stringtd=new TypeDescriptor(stringcl);
       NameDescriptor nd=new NameDescriptor("String");
       NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
@@ -575,11 +944,45 @@ 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();
+      if(an.getSrc().kind() == Kind.ArrayInitializerNode) {
+        if(dt.getArrayCount() != st.getArrayCount()) {
+          throw new Error("Type of rside ("+an.getSrc().getType().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+an.printNode(0));
+        } else {
+          do {
+            dt = dt.dereference();
+            st = st.dereference();
+          } while(dt.isArray());
+          if((st.isByte() || st.isShort() || st.isChar() || st.isInt()) 
+              && (dt.isByte() || dt.isShort() || dt.isChar() || dt.isInt() || dt.isLong())) {
+            return;
+          } else {
+            throw new Error("Type of rside ("+an.getSrc().getType().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+an.printNode(0));
+          }
+        }
+      } else {
+        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("Type of rside ("+an.getSrc().getType().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+an.printNode(0));
+          }
+        } else {
+          throw new Error("Type of rside ("+an.getSrc().getType().toPrettyString()+") not compatible with type of lside ("+an.getDest().getType().toPrettyString()+")"+an.printNode(0));
+        }
+      }
     }
   }
 
   void checkLoopNode(Descriptor md, SymbolTable nametable, LoopNode ln) {
+      loopstack.push(ln);
     if (ln.getType()==LoopNode.WHILELOOP||ln.getType()==LoopNode.DOWHILELOOP) {
       checkExpressionNode(md, nametable, ln.getCondition(), new TypeDescriptor(TypeDescriptor.BOOLEAN));
       checkBlockNode(md, nametable, ln.getBody());
@@ -597,6 +1000,7 @@ public class SemanticCheck {
       checkBlockNode(md, bn.getVarTable(), ln.getBody());
       checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
     }
+    loopstack.pop();
   }
 
 
@@ -613,6 +1017,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) {
@@ -726,32 +1135,79 @@ NextMethod:
     /*Typecheck subexpressions
        and get types for expressions*/
 
+    boolean isstatic = false;
+    if(state.MGC) {
+      if((md instanceof MethodDescriptor) && ((MethodDescriptor)md).isStatic()) {
+        isstatic = true;
+      }
+    }
     TypeDescriptor[] tdarray=new TypeDescriptor[min.numArgs()];
     for(int i=0; i<min.numArgs(); i++) {
       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")) {
        ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
        typetolookin=new TypeDescriptor(supercd);
+      } else if (rootname.equals("this")) {
+        if(isstatic) {
+          throw new Error("use this object in static method md = "+ md.toString());
+        }
+        ClassDescriptor cd=((MethodDescriptor)md).getClassDesc();
+        typetolookin=new TypeDescriptor(cd);
       } else if (nametable.get(rootname)!=null) {
        //we have an expression
        min.setExpression(translateNameDescriptorintoExpression(min.getBaseName()));
        checkExpressionNode(md, nametable, min.getExpression(), null);
        typetolookin=min.getExpression().getType();
       } else {
-       //we have a type
-       ClassDescriptor cd=typeutil.getClass(min.getBaseName().getSymbol());
-       if (cd==null)
-         throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
-       typetolookin=new TypeDescriptor(cd);
+        if(state.MGC) {
+          if(!min.getBaseName().getSymbol().equals("System.out")) {
+            ExpressionNode nn = translateNameDescriptorintoExpression(min.getBaseName());
+            checkExpressionNode(md, nametable, nn, null);
+            typetolookin = nn.getType();
+            if(!((nn.kind()== Kind.NameNode) && (((NameNode)nn).getField() == null)
+                && (((NameNode)nn).getVar() == null) && (((NameNode)nn).getExpression() == null))) {
+              // this is not a pure class name, need to add to 
+              min.setExpression(nn);
+            }
+          } else {
+            //we have a type
+            ClassDescriptor cd = null;
+            //if (min.getBaseName().getSymbol().equals("System.out"))
+            cd=getClass("System");
+            /*else {
+            cd=getClass(min.getBaseName().getSymbol());
+          }*/
+            if (cd==null)
+              throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
+            typetolookin=new TypeDescriptor(cd);
+          }
+        } else {
+          // we have a type
+          ClassDescriptor cd = null;
+          if (min.getBaseName().getSymbol().equals("System.out"))
+            cd=getClass("System");
+          else {
+            cd=getClass(min.getBaseName().getSymbol());
+          }
+          if (cd==null)
+            throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
+          typetolookin=new TypeDescriptor(cd);
+        }
       }
     } else if ((md instanceof MethodDescriptor)&&min.getMethodName().equals("super")) {
       ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
@@ -778,7 +1234,12 @@ NextMethod:
        continue;
       for(int i=0; i<min.numArgs(); i++) {
        if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
-         continue NextMethod;
+      if(state.MGC && ((!tdarray[i].isArray() &&( tdarray[i].isInt() || tdarray[i].isLong())) 
+          && currmd.getParamType(i).isClass() && currmd.getParamType(i).getClassDesc().getSymbol().equals("Object"))) {
+        // primitive parameters vs object
+      } else {
+        continue NextMethod;
+      }
       }
       /* Method okay so far */
       if (bestmd==null)
@@ -799,13 +1260,39 @@ NextMethod:
     if ((td!=null)&&(min.getType()!=null)&&!typeutil.isSuperorType(td,  min.getType()))
       throw new Error(min.getType()+ " is not equal to or a subclass of "+td);
     /* Check whether we need to set this parameter to implied this */
-    if (!bestmd.isStatic()) {
+    if (! isstatic && !bestmd.isStatic()) {
       if (min.getExpression()==null) {
        ExpressionNode en=new NameNode(new NameDescriptor("this"));
        min.setExpression(en);
        checkExpressionNode(md, nametable, min.getExpression(), null);
       }
     }
+    
+    if(state.MGC) {
+      /* Check if we need to wrap primitive paratmeters to objects */
+      for(int i=0; i<min.numArgs(); i++) {
+        if(!tdarray[i].isArray() && (tdarray[i].isInt() || tdarray[i].isLong())
+            && min.getMethod().getParamType(i).isClass() && min.getMethod().getParamType(i).getClassDesc().getSymbol().equals("Object")) {
+          // Shall wrap this primitive parameter as a object
+          ExpressionNode exp = min.getArg(i);
+          TypeDescriptor ptd = null;
+          NameDescriptor nd=null;
+          if(exp.getType().isInt()) {
+            nd = new NameDescriptor("Integer");
+            ptd = state.getTypeDescriptor(nd);
+          } else if(exp.getType().isLong()) {
+            nd = new NameDescriptor("Long");
+            ptd = state.getTypeDescriptor(nd);
+          }
+          boolean isglobal = false;
+          String disjointId = null;
+          CreateObjectNode con=new CreateObjectNode(ptd, isglobal, disjointId);
+          con.addArgument(exp);
+          checkExpressionNode(md, nametable, con, null);
+          min.setArgument(con, i);
+        }
+      }
+    }
   }
 
 
@@ -891,8 +1378,11 @@ NextMethod:
          throw new Error();
        righttype=lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
       } else if (ltd.isPtr()||rtd.isPtr()) {
-       if (!(ltd.isPtr()&&rtd.isPtr()))
-         throw new Error();
+       if (!(ltd.isPtr()&&rtd.isPtr())) {
+      if(!rtd.isEnum()) {
+        throw new Error();
+      }
+    }
        righttype=rtd;
        lefttype=ltd;
       } else if (ltd.isDouble()||rtd.isDouble())
@@ -917,8 +1407,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);
@@ -936,7 +1430,7 @@ NextMethod:
 
     case Operation.ADD:
       if (ltd.isString()||rtd.isString()) {
-       ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
+       ClassDescriptor stringcl=getClass(TypeUtil.StringClass);
        TypeDescriptor stringtd=new TypeDescriptor(stringcl);
        NameDescriptor nd=new NameDescriptor("String");
        NameDescriptor valuend=new NameDescriptor(nd, "valueOf");