001    import java.util.Collection;
002    import java.util.ArrayList;
003    
004    aspect ErrorCheck {
005      syn lazy Collection Program.errors() {
006        Collection c = new ArrayList();
007        collectErrors(c);
008        return c;
009      }
010    
011      // generic traversal that collects errors in AST
012      public void ASTNode.collectErrors(Collection c) {
013        for(int i = 0; i < getNumChild(); i++)
014          getChild(i).collectErrors(c);
015      }
016    
017      // add an error msg associated with a certain context
018      protected void ASTNode.error(Collection c, String s) {
019        //c.add(getLine(getStart()) + ": " + s);
020        c.add(s);
021      }
022    
023      // add error for incompatible assignment
024      public void AssignStmt.collectErrors(Collection c) {
025        super.collectErrors(c);
026        if(!getValue().type().isSubtypeOf(getVariable().type()))
027          error(c, "Can not assign a variable of type " + getVariable().type().getName() +
028            " to a value of type " + getValue().type().getName());
029      }
030      
031      // add error for cyclic class hierarchy
032      public void ClassDecl.collectErrors(Collection c) {
033        super.collectErrors(c);
034        if(hasCycleOnSuperclassChain())
035          error(c, "Cyclic inheritance chain for class " + getName());
036      }
037    
038      // add error for non-boolean condition in while
039      public void WhileStmt.collectErrors(Collection c) {
040        super.collectErrors(c);
041        if(!getCondition().type().isSubtypeOf(booleanType()))
042          error(c, "Condition must be a boolean expression");
043        if(!getCondition().isValue())
044          error(c, "Condition must be a value");
045      }
046    
047      // add error for the first unbound name in a, possibly qualified, name 
048      public void IdUse.collectErrors(Collection c) {
049        super.collectErrors(c);
050        if(decl().isUnknown() && (!isQualified() || !qualifier().type().isUnknown()))
051          error(c, "Unknown identifier " + getName());
052      }
053    
054      // TODO: maybe move these attributes to another module?
055      eq Program.getBlock().isQualified() = false;
056      eq Program.getPredefinedType(int i).isQualified() = false;
057      eq Dot.getIdUse().isQualified() = true;
058      inh boolean IdUse.isQualified();
059      inh boolean TypeDecl.isQualified();
060    
061      eq Program.getBlock().qualifier() {
062        throw new Error("Can not compute qualifier for non qualified names");
063      }
064      eq Program.getPredefinedType(int i).qualifier() {
065        throw new Error("Can not compute qualifier for non qualified names");
066      }
067      eq Dot.getIdUse().qualifier() = getObjectReference();
068      inh Access IdUse.qualifier();
069      inh Access TypeDecl.qualifier();
070    
071    }