start of new file
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index a4b24b4546f83d4e6f9a7e4b97bc7c107768d236..816ee712eae68d6d8fd7d74353d1903575c13b93 100644 (file)
@@ -18,7 +18,7 @@ public class SemanticCheck {
        // Do descriptors first
        while(it.hasNext()) {
            ClassDescriptor cd=(ClassDescriptor)it.next();
-           System.out.println("Checking class: "+cd);
+           //System.out.println("Checking class: "+cd);
            //Set superclass link up
            if (cd.getSuper()!=null) {
                cd.setSuper(typeutil.getClass(cd.getSuper()));
@@ -32,7 +32,7 @@ public class SemanticCheck {
            /* 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);
+               //System.out.println("Checking field: "+fd);
                checkField(cd,fd);
            }
 
@@ -57,7 +57,6 @@ public class SemanticCheck {
            checkTask(td);
            
        }
-
     }
 
     public void checkTypeDescriptor(TypeDescriptor td) {
@@ -70,8 +69,10 @@ public class SemanticCheck {
                throw new Error("Undefined class "+name);
            td.setClassDescriptor(field_cd);
            return;
-       }
-       throw new Error();
+       } else if (td.isTag())
+           return;
+       else
+           throw new Error();
     }
 
     public void checkField(ClassDescriptor cd, FieldDescriptor fd) {
@@ -91,7 +92,7 @@ public class SemanticCheck {
        }
     }
 
-    public void checkFlagEffects(TaskDescriptor td, Vector vfe) {
+    public void checkFlagEffects(TaskDescriptor td, Vector vfe, SymbolTable nametable) {
        if (vfe==null)
            return; /* No flag effects to check */
        for(int i=0;i<vfe.size();i++) {
@@ -100,7 +101,7 @@ public class SemanticCheck {
            //Make sure the variable is declared as a parameter to the task
            VarDescriptor vd=(VarDescriptor)td.getParameterTable().get(varname);
            if (vd==null)
-               throw new Error("Parameter "+varname+" in Flag Effects not declared");
+               throw new Error("Parameter "+varname+" in Flag Effects not declared in "+td);
            fe.setVar(vd);
 
            //Make sure it correspods to a class
@@ -120,6 +121,17 @@ public class SemanticCheck {
                    throw new Error("Attempting to modify external flag: "+name);
                flag.setFlag(flag_d);
            }
+           for(int j=0;j<fe.numTagEffects();j++) {
+               TagEffect tag=fe.getTagEffect(j);
+               String name=tag.getName();
+               
+               Descriptor d=(Descriptor)nametable.get(name);
+               if (d==null)
+                   throw new Error("Tag descriptor "+name+" undeclared");
+               else if (!(d instanceof TagVarDescriptor))
+                   throw new Error(name+" is not a tag descriptor");
+               tag.setTag((TagVarDescriptor)d);
+           }
        }
     }
 
@@ -134,10 +146,11 @@ public class SemanticCheck {
            if (!param_type.isClass())
                throw new Error("Cannot have non-object argument to a task");
            ClassDescriptor cd=param_type.getClassDesc();
-           checkFlagExpressionNode(cd, fen);
+           if (fen!=null)
+               checkFlagExpressionNode(cd, fen);
        }
 
-       checkFlagEffects(td, td.getFlagEffects());
+       checkFlagEffects(td, td.getFlagEffects(),td.getParameterTable());
        /* Check that the task code is valid */
        BlockNode bn=state.getMethodBody(td);
        checkBlockNode(td, td.getParameterTable(),bn);
@@ -189,7 +202,18 @@ public class SemanticCheck {
     }
 
     public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
-       System.out.println("Processing method:"+md);
+       ClassDescriptor superdesc=cd.getSuperDesc();
+       if (superdesc!=null) {
+           Set possiblematches=superdesc.getMethodTable().getSet(md.getSymbol());
+           for(Iterator methodit=possiblematches.iterator();methodit.hasNext();) {
+               MethodDescriptor matchmd=(MethodDescriptor)methodit.next();
+               if (md.matches(matchmd)) {
+                   if (matchmd.getModifiers().isFinal()) {
+                       throw new Error("Try to override final method in method:"+md+" declared in  "+cd);
+                   }
+               }
+           }
+       }
        BlockNode bn=state.getMethodBody(md);
        checkBlockNode(md, md.getParameterTable(),bn);
     }
@@ -212,6 +236,10 @@ public class SemanticCheck {
        case Kind.DeclarationNode:
            checkDeclarationNode(md, nametable, (DeclarationNode)bsn);
            return;
+
+       case Kind.TagDeclarationNode:
+           checkTagDeclarationNode(md, nametable, (TagDeclarationNode)bsn);
+           return;
            
        case Kind.IfStatementNode:
            checkIfStatementNode(md, nametable, (IfStatementNode)bsn);
@@ -232,6 +260,10 @@ public class SemanticCheck {
        case Kind.SubBlockNode:
            checkSubBlockNode(md, nametable, (SubBlockNode)bsn);
            return;
+
+       case Kind.AtomicNode:
+           checkAtomicNode(md, nametable, (AtomicNode)bsn);
+           return;
        }
        throw new Error();
     }
@@ -248,15 +280,29 @@ public class SemanticCheck {
            (d instanceof FieldDescriptor)) {
            nametable.add(vd);
        } else
-           throw new Error(vd.getSymbol()+" defined a second time");
+           throw new Error(vd.getSymbol()+" in "+md+" defined a second time");
        if (dn.getExpression()!=null)
            checkExpressionNode(md, nametable, dn.getExpression(), vd.getType());
     }
+
+    void checkTagDeclarationNode(Descriptor md, SymbolTable nametable,  TagDeclarationNode dn) {
+       TagVarDescriptor vd=dn.getTagVarDescriptor();
+       Descriptor d=nametable.get(vd.getSymbol());
+       if ((d==null)||
+           (d instanceof FieldDescriptor)) {
+           nametable.add(vd);
+       } else
+           throw new Error(vd.getSymbol()+" defined a second time");
+    }
     
     void checkSubBlockNode(Descriptor md, SymbolTable nametable, SubBlockNode sbn) {
        checkBlockNode(md, nametable, sbn.getBlockNode());
     }
 
+    void checkAtomicNode(Descriptor md, SymbolTable nametable, AtomicNode sbn) {
+       checkBlockNode(md, nametable, sbn.getBlockNode());
+    }
+
     void checkReturnNode(Descriptor d, SymbolTable nametable, ReturnNode rn) {
        if (d instanceof TaskDescriptor)
            throw new Error("Illegal return appears in Task: "+d.getSymbol());
@@ -276,7 +322,7 @@ public class SemanticCheck {
     void checkTaskExitNode(Descriptor md, SymbolTable nametable, TaskExitNode ten) {
        if (md instanceof MethodDescriptor)
            throw new Error("Illegal taskexit appears in Method: "+md.getSymbol());
-       checkFlagEffects((TaskDescriptor)md, ten.getFlagEffects());
+       checkFlagEffects((TaskDescriptor)md, ten.getFlagEffects(),nametable);
        checkConstraintCheck((TaskDescriptor) md, nametable, ten.getChecks());
     }
 
@@ -367,7 +413,7 @@ public class SemanticCheck {
        else
            fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
        if (fd==null)
-           throw new Error("Unknown field "+fieldname);
+           throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
        fan.setField(fd);
        if (td!=null)
            if (!typeutil.isSuperorType(td,fan.getType()))
@@ -424,14 +470,16 @@ public class SemanticCheck {
            String varname=nd.toString();
            Descriptor d=(Descriptor)nametable.get(varname);
            if (d==null) {
-               throw new Error("Name "+varname+" undefined");
+               throw new Error("Name "+varname+" undefined in: "+md);
            }
            if (d instanceof VarDescriptor) {
-               nn.setVar((VarDescriptor)d);
+               nn.setVar(d);
            } else if (d instanceof FieldDescriptor) {
                nn.setField((FieldDescriptor)d);
                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");
            if (td!=null)
                if (!typeutil.isSuperorType(td,nn.getType()))
                    throw new Error("Field node returns "+nn.getType()+", but need "+td);
@@ -454,6 +502,7 @@ public class SemanticCheck {
            throw new Error("Bad lside in "+an.printNode(0));
        checkExpressionNode(md, nametable, an.getDest(), null);
 
+
        /* We want parameter variables to tasks to be immutable */
        if (md instanceof TaskDescriptor) {
            if (an.getDest() instanceof NameNode) {
@@ -465,6 +514,22 @@ public class SemanticCheck {
            }
        }
        
+       if (an.getDest().getType().isString()&&an.getOperation().getOp()==AssignOperation.PLUSEQ) {
+           //String add
+           ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
+           TypeDescriptor stringtd=new TypeDescriptor(stringcl);
+           NameDescriptor nd=new NameDescriptor("String");
+           NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
+           
+           if (!(an.getSrc().getType().isString()&&(an.getSrc() instanceof OpNode))) {
+               MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
+               rightmin.addArgument(an.getSrc());
+               an.right=rightmin;
+               checkExpressionNode(md, nametable, an.getSrc(), null);
+           }
+       }
+
+       
        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));
        }
@@ -502,6 +567,9 @@ public class SemanticCheck {
        TypeDescriptor typetolookin=con.getType();
        checkTypeDescriptor(typetolookin);
 
+       if (td!=null&&!typeutil.isSuperorType(td, typetolookin))
+           throw new Error(typetolookin + " isn't a "+td);
+
        /* Check flag effects */
        if (con.getFlagEffects()!=null) {
            FlagEffects fe=con.getFlagEffects();
@@ -518,67 +586,88 @@ public class SemanticCheck {
                    throw new Error("Attempting to modify external flag: "+name);
                flag.setFlag(flag_d);
            }
+           for(int j=0;j<fe.numTagEffects();j++) {
+               TagEffect tag=fe.getTagEffect(j);
+               String name=tag.getName();
+               
+               Descriptor d=(Descriptor)nametable.get(name);
+               if (d==null)
+                   throw new Error("Tag descriptor "+name+" undeclared");
+               else if (!(d instanceof TagVarDescriptor))
+                   throw new Error(name+" is not a tag descriptor");
+               tag.setTag((TagVarDescriptor)d);
+           }
        }
 
-
        if ((!typetolookin.isClass())&&(!typetolookin.isArray())) 
            throw new Error("Can't allocate primitive type:"+con.printNode(0));
 
        if (!typetolookin.isArray()) {
            //Array's don't need constructor calls
            ClassDescriptor classtolookin=typetolookin.getClassDesc();
-           System.out.println("Looking for "+typetolookin.getSymbol());
-           System.out.println(classtolookin.getMethodTable());
-           
+
            Set methoddescriptorset=classtolookin.getMethodTable().getSet(typetolookin.getSymbol());
            MethodDescriptor bestmd=null;
        NextMethod:
            for(Iterator methodit=methoddescriptorset.iterator();methodit.hasNext();) {
                MethodDescriptor currmd=(MethodDescriptor)methodit.next();
                /* Need correct number of parameters */
-               System.out.println("Examining: "+currmd);
                if (con.numArgs()!=currmd.numParameters())
                    continue;
                for(int i=0;i<con.numArgs();i++) {
                    if (!typeutil.isSuperorType(currmd.getParamType(i),tdarray[i]))
                        continue NextMethod;
                }
+               /* Local allocations can't call global allocator */
+               if (!con.isGlobal()&&currmd.isGlobal())
+                   continue;
+
                /* Method okay so far */
                if (bestmd==null)
                    bestmd=currmd;
                else {
-                   if (isMoreSpecific(currmd,bestmd)) {
+                   if (typeutil.isMoreSpecific(currmd,bestmd)) {
                        bestmd=currmd;
-                   } else if (!isMoreSpecific(bestmd, currmd))
+                   } else if (con.isGlobal()&&match(currmd, bestmd)) {
+                       if (currmd.isGlobal()&&!bestmd.isGlobal())
+                           bestmd=currmd;
+                       else if (currmd.isGlobal()&&bestmd.isGlobal())
+                           throw new Error();
+                   } else if (!typeutil.isMoreSpecific(bestmd, currmd)) {
                        throw new Error("No method is most specific");
+                   }
                    
                    /* Is this more specific than bestmd */
                }
            }
            if (bestmd==null)
-               throw new Error("No method found for "+con.printNode(0));
+               throw new Error("No method found for "+con.printNode(0)+" in "+md);
            con.setConstructor(bestmd);
        }
     }
 
 
-    /** Check to see if md1 is more specific than md2...  Informally
-       if md2 could always be called given the arguments passed into
-       md1 */
+    /** Check to see if md1 is the same specificity as md2.*/
 
-    boolean isMoreSpecific(MethodDescriptor md1, MethodDescriptor md2) {
+    boolean match(MethodDescriptor md1, MethodDescriptor md2) {
        /* Checks if md1 is more specific than md2 */
        if (md1.numParameters()!=md2.numParameters())
            throw new Error();
        for(int i=0;i<md1.numParameters();i++) {
-           if (!typeutil.isSuperorType(md2.getParamType(i), md1.getParamType(i)))
+           if (!md2.getParamType(i).equals(md1.getParamType(i)))
                return false;
        }
-       if (!typeutil.isSuperorType(md2.getReturnType(), md1.getReturnType()))
+       if (!md2.getReturnType().equals(md1.getReturnType()))
+               return false;
+
+       if (!md2.getClassDesc().equals(md1.getClassDesc()))
                return false;
+
        return true;
     }
 
+
+
     ExpressionNode translateNameDescriptorintoExpression(NameDescriptor nd) {
        String id=nd.getIdentifier();
        NameDescriptor base=nd.getBase();
@@ -605,7 +694,10 @@ public class SemanticCheck {
            typetolookin=min.getExpression().getType();
        } else if (min.getBaseName()!=null) {
            String rootname=min.getBaseName().getRoot();
-           if (nametable.get(rootname)!=null) {
+           if (rootname.equals("super")) {
+               ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
+               typetolookin=new TypeDescriptor(supercd);
+           } else if (nametable.get(rootname)!=null) {
                //we have an expression
                min.setExpression(translateNameDescriptorintoExpression(min.getBaseName()));
                checkExpressionNode(md, nametable, min.getExpression(), null);
@@ -617,6 +709,10 @@ public class SemanticCheck {
                    throw new Error(min.getBaseName()+" undefined");
                typetolookin=new TypeDescriptor(cd);
            }
+       } else if ((md instanceof MethodDescriptor)&&min.getMethodName().equals("super")) {
+           ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
+           min.methodid=supercd.getSymbol();
+           typetolookin=new TypeDescriptor(supercd);
        } else if (md instanceof MethodDescriptor) {
            typetolookin=new TypeDescriptor(((MethodDescriptor)md).getClassDesc());
        } else {
@@ -626,7 +722,7 @@ public class SemanticCheck {
        if (!typetolookin.isClass()) 
            throw new Error("Error with method call to "+min.getMethodName());
        ClassDescriptor classtolookin=typetolookin.getClassDesc();
-       System.out.println("Method name="+min.getMethodName());
+       //System.out.println("Method name="+min.getMethodName());
 
        Set methoddescriptorset=classtolookin.getMethodTable().getSet(min.getMethodName());
        MethodDescriptor bestmd=null;
@@ -644,17 +740,20 @@ public class SemanticCheck {
            if (bestmd==null)
                bestmd=currmd;
            else {
-               if (isMoreSpecific(currmd,bestmd)) {
+               if (typeutil.isMoreSpecific(currmd,bestmd)) {
                    bestmd=currmd;
-               } else if (!isMoreSpecific(bestmd, currmd))
+               } else if (!typeutil.isMoreSpecific(bestmd, currmd))
                    throw new Error("No method is most specific");
                
                /* Is this more specific than bestmd */
            }
        }
        if (bestmd==null)
-           throw new Error("No method found for :"+min.printNode(0));
+           throw new Error("No method found for :"+min.printNode(0)+" in class: " + classtolookin+" in "+md);
        min.setMethod(bestmd);
+
+       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 (min.getExpression()==null) {
@@ -663,7 +762,6 @@ public class SemanticCheck {
                checkExpressionNode(md, nametable, min.getExpression(), null);
            }
        }
-
     }
 
 
@@ -680,14 +778,33 @@ public class SemanticCheck {
        switch(op.getOp()) {
        case Operation.LOGIC_OR:
        case Operation.LOGIC_AND:
-           if (!(ltd.isBoolean()&&rtd.isBoolean()))
+           if (!(rtd.isBoolean()))
+               throw new Error();
+           on.setRightType(rtd);
+       case Operation.LOGIC_NOT:
+           if (!(ltd.isBoolean()))
                throw new Error();
            //no promotion
            on.setLeftType(ltd);
-           on.setRightType(rtd);
+
            on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
            break;
 
+       case Operation.COMP:
+           // 5.6.2 Binary Numeric Promotion
+           //TODO unboxing of reference objects
+           if (ltd.isDouble())
+               throw new Error();
+           else if (ltd.isFloat())
+               throw new Error();
+           else if (ltd.isLong())
+               lefttype=new TypeDescriptor(TypeDescriptor.LONG);
+           else 
+               lefttype=new TypeDescriptor(TypeDescriptor.INT);
+           on.setLeftType(lefttype);
+           on.setType(lefttype);
+           break;
+
        case Operation.BIT_OR:
        case Operation.BIT_XOR:
        case Operation.BIT_AND:
@@ -708,6 +825,14 @@ public class SemanticCheck {
            on.setType(lefttype);
            break;
 
+       case Operation.ISAVAILABLE:
+           if (!(ltd.isPtr())) {
+               throw new Error("Can't use isavailable on non-pointers/non-parameters.");
+           }
+           lefttype=ltd;
+           on.setLeftType(lefttype);
+           on.setType(new TypeDescriptor(TypeDescriptor.BOOLEAN));
+           break;
        case Operation.EQUAL:
        case Operation.NOTEQUAL:
            // 5.6.2 Binary Numeric Promotion
@@ -716,8 +841,8 @@ public class SemanticCheck {
                if (!(ltd.isBoolean()&&rtd.isBoolean()))
                    throw new Error();
                righttype=lefttype=new TypeDescriptor(TypeDescriptor.BOOLEAN);
-           } else if (ltd.isPtr()||ltd.isArray()||rtd.isPtr()||rtd.isArray()) {
-               if (!((ltd.isPtr()||ltd.isArray())&&(rtd.isPtr()||rtd.isArray())))
+           } else if (ltd.isPtr()||rtd.isPtr()) {
+               if (!(ltd.isPtr()&&rtd.isPtr()))
                    throw new Error();
                righttype=rtd;
                lefttype=ltd;
@@ -761,8 +886,30 @@ public class SemanticCheck {
            break;
 
        case Operation.ADD:
-           //TODO: Need special case for strings eventually
-           
+           if (ltd.isString()||rtd.isString()) {
+               ClassDescriptor stringcl=typeutil.getClass(TypeUtil.StringClass);
+               TypeDescriptor stringtd=new TypeDescriptor(stringcl);
+               NameDescriptor nd=new NameDescriptor("String");
+               NameDescriptor valuend=new NameDescriptor(nd, "valueOf");
+               if (!(ltd.isString()&&(on.getLeft() instanceof OpNode))) {
+                   MethodInvokeNode leftmin=new MethodInvokeNode(valuend);
+                   leftmin.addArgument(on.getLeft());
+                   on.left=leftmin;
+                   checkExpressionNode(md, nametable, on.getLeft(), null);
+               }
+
+               if (!(rtd.isString()&&(on.getRight() instanceof OpNode))) {
+                   MethodInvokeNode rightmin=new MethodInvokeNode(valuend);
+                   rightmin.addArgument(on.getRight());
+                   on.right=rightmin;
+                   checkExpressionNode(md, nametable, on.getRight(), null);
+               }
+
+               on.setLeftType(stringtd);
+               on.setRightType(stringtd);
+               on.setType(stringtd);
+               break;
+           }
            
        case Operation.SUB:
        case Operation.MULT:
@@ -789,6 +936,7 @@ public class SemanticCheck {
 
        case Operation.LEFTSHIFT:
        case Operation.RIGHTSHIFT:
+       case Operation.URIGHTSHIFT:
            if (!rtd.isIntegerType())
                throw new Error();
            //5.6.1 Unary Numeric Promotion
@@ -817,7 +965,7 @@ public class SemanticCheck {
            on.setType(lefttype);
            break;
        default:
-           throw new Error();
+           throw new Error(op.toString());
        }
    
        if (td!=null)