// Northeaster University. College of Computer Science.
//
//	J-SEM-CHECK (Part1)
//
//  Developers:  Stanislav Paltis (stas)
//		 Virginia Magan (jinni)
//		 Arkadiy Sukharenko (ark)
//
//  COM 1205
//  Last date modified: 03/11/97
//
//
//
// ****** CLASSES ******
//
ClassGraph
{   (@
     // Class methods:
     //
     	void check_parameters() throws Exception
      	{
           System.out.println("\n Checking that every parameterized class is consistently defined and used ...\n");
	   RightChecker right_c = new RightChecker(null, new ComplexContainer());
           LeftChecker left_c = new LeftChecker(null, new ComplexContainer());
	   this.check_right(right_c);
           this.check_left(left_c);
           
	   for (int i = 0; i < right_c.get_rcon().size(); i+=2)
           {
		int location = left_c.get_lcon().indexOf(right_c.get_rcon().elementAt(i));
		if (location == -1)
		    System.out.println("    J-Sem-Check:Error: Class " + right_c.get_rcon().elementAt(i) +
					" is not defined on the left hand side!");
		else
		    if (!right_c.get_rcon().elementAt(i+1).equals(left_c.get_lcon().elementAt(location+1)))
			System.out.println("    J-Sem-Check:Error: Number of parameters of the Class "+
						right_c.get_rcon().elementAt(i) + " do not match!");
	   }
       	}    
	void check_right(RightChecker rc) { this.tr(rc); }
        void check_left(LeftChecker lc) { this.tl(lc); }
  	void check_repetition() {
    	    SimpleChecker sc = new SimpleChecker();
            this.trepet(sc);
  	}
   	void lookAtClasses () throws Exception
   	{
   		ClassCollector  cc = new ClassCollector(new ClassContainer(), new ClassContainer(), new Integer(0));
   		this.allClassNames (cc);
   		PartCollector pc = new PartCollector(cc.get_lparams(), cc.get_pparams());
   		Vector allClasses = pc.get_lparts();
   		allClasses.addElement("Ident");
   		allClasses.addElement("Integer");
   		allClasses.addElement("String");
   		allClasses.addElement("Text");
   		allClasses.addElement("Double");
   		this.allParamClasses (pc);
   		ParamCollector  ac = new ParamCollector(new ClassContainer());
   		this.allPClassNames (ac);
   		ActualPCollector apc = new ActualPCollector(ac.get_aparams());
  		this.allActualPClasses (apc);
  
   	}
       @)
   
   // Traversals:
   //
   traversal tr(RightChecker rc)
   {
       bypassing ParamClassName
       to ClassSpec;
   }

   traversal tl(LeftChecker lc)
   {
       bypassing ClassParts
       to ParamClassName;
   }

   traversal trepet(SimpleChecker sc)  
   { 
       bypassing ConstOrAltClass 
       to RepetitionClass ; 
   }
   traversal allClassNames(ClassCollector cc)
   {
        bypassing ClassParts to ClassName;
   } 
  
   traversal allParamClasses(PartCollector pc)  
   {
       bypassing ParamClassName to ClassName;
   }
           
   traversal allPClassNames(ParamCollector ac)
   {
       bypassing {ClassParts, ->ParamClassName,classname,*} to ClassName;
   }
      
   traversal allActualPClasses (ActualPCollector apc)
   {     
       bypassing {SuperClass,Interface,SubClass,->*,actual_parameters,*}
       to ClassSpec;
   }

}


RepetitionClass
{  (@
        void go_deeper(){
                DeeperVisitor dv = new DeeperVisitor(null, new Integer(0));
                this.tdeeper(dv);
        }
   @)
   traversal tdeeper(DeeperVisitor dv) {to ClassName; }
}


ClassSpec 
{  (@ 
   void count_right(RightCounter rcnt) { this.trr(rcnt);}
   void ActualParamNames() 
   {
       TranspVisitor tv = new TranspVisitor();
       this.tjin(tv);
       int r = tv.size();
       if (r >1)
           System.out.println("   J-Sem-Check: Error: Formal Parameteres in class " + 
				this.get_classname().get_name() + 
				" cannot be a parameterized class!");
    }
   @)
  
   traversal trr (RightCounter rcnt) {to ClassName;}
   traversal tjin (TranspVisitor tv) {to ClassName; }
}


ParamClassName
{
  (@ void count_left(LeftCounter lcnt) { this.tll(lcnt);} @)
  traversal tll (LeftCounter lcnt) {to ClassName;}
}


// ****** MAIN ******
//
Main 
{   (@
    static public void main(String args[]) throws Exception 
    {
        System.out.println("\n Starting J-Sem-Check. \n");
        Runtime rt = Runtime.getRuntime();
        rt.traceMethodCalls( true );
        ClassGraph a = ClassGraph.parse(System.in);
        a.lookAtClasses();
        a.check_repetition();
        a.check_parameters();
        System.out.println("J-Sem-Check complete.");
    }
    @)
}


// ****** VISITORS ******
//

// Visitors used for part 2.
// 

SimpleChecker 
{
    before ClassGraph
	(@ 
	    System.out.println("\n Checking that two class names on the right " +
                                          "hand side of every repetition production " +
                                          "are identical...");
	    System.out.println();
	@)

    before RepetitionClass (@ host.go_deeper(); @)
}


DeeperVisitor
{

   before ->*,actual_parameters,* (@ level = new Integer (level.intValue() + 1); @)
   after ->*,actual_parameters,* (@ level = new Integer (level.intValue() - 1); @)

    before ClassName
    (@
        if (carried == null)
                carried = host;
        else
        {
                if ((!carried.get_name().toString().equals(host.get_name().toString()))
			&& (this.get_level().intValue() == 0)) 
                        System.out.println("    J-Sem-Check: Error: Not identical class instances (" +
                                                carried.get_name() + " and " + host.get_name() +
                                                ") on the right hand side of repetition production!" );
        }
   @)
}

// Visitors used for part 3.                                                             
//                          

RightChecker
{
     before ClassSpec
	(@ 
	    if (host.get_actual_parameters() != null)
	    {
		  RightCounter right_cnt = new RightCounter(new Integer(0), null, new Integer(0));
		  host.count_right(right_cnt);
		  rcon.addElement(right_cnt.get_classik().get_name().toString());
                  rcon.addElement(right_cnt.get_nparams());
	    }
	@)
}


LeftChecker
{
     before ParamClassName
        (@
            if (host.get_parameters() != null)
            {
                  LeftCounter left_cnt = new LeftCounter(new Integer(-1), null);
                  host.count_left(left_cnt);
                  lcon.addElement(left_cnt.get_classik().get_name().toString());
                  lcon.addElement(left_cnt.get_nparams());
            }
        @)   
}


RightCounter
{
   before ->*,actual_parameters,* (@ level = new Integer (level.intValue() + 1); @)
   after ->*,actual_parameters,* (@ level = new Integer (level.intValue() - 1); @)

   before ClassName
   (@
	if (this.get_level().intValue() == 1)
	    nparams = new Integer (nparams.intValue() + 1);
	if (this.get_classik() == null)
	    this.set_classik(host);
    @)
}


LeftCounter
{
   before ClassName  
   (@
        nparams = new Integer (nparams.intValue() + 1);
        if (this.get_classik() == null)
            this.set_classik(host);
    @)
}

// Visitors for part 1 & 4
//
ClassCollector {

  before ClassGraph (@
        System.out.println("\n Checking that every class is defined exactly once ...\n "); @)
      
   before ->*,parameters,* (@ level = new Integer (level.intValue() + 1); @)
   after ->*,parameters,* (@ level = new Integer (level.intValue() - 1); @)


  before ClassName (@
        Vector namessofar = this.get_lparams();
        Vector param_name = this.get_pparams();
        Ident thisclass = host.get_name();
        // We have a vector of classes we have seen, and an ident of this class name.
	if (this.get_level().intValue() == 0)
            if (namessofar.contains(thisclass))
               System.out.println ("    J-Sem-Check: Error: Class " + thisclass + " has been defined more than once!");
            else
               namessofar.addElement(thisclass);
  	else
            if (!param_name.contains(thisclass))
               param_name.addElement(thisclass);

  @)
}
    
PartCollector {
       
  before ClassGraph (@
        System.out.println("\n Checking that every class is defined at least once ...\n "); @)
   
  before ClassName (@
        Vector allnames = this.get_lparts();
        Vector paramnames = this.get_pparts();
        Ident tclass = host.get_name();
        if (!(allnames.contains(tclass) || paramnames.contains(tclass)))
            System.out.println ("     J-Sem-Check: Error: Class " + tclass + " has not been defined!");    
@)
}
    
ParamCollector {
 
  before ClassGraph (@
  System.out.println("\n Checking that formal parameters are not used as parameterized classes...\n "); @)
   
  before ClassName (@
      Vector cnames = this.get_aparams();
      Ident thclass = host.get_name();
      if (!cnames.contains(thclass))
          cnames.addElement(thclass);
 @)
}

ActualPCollector {
              
  before ClassSpec (@
    Vector pnames = this.get_aparts();
    Ident ptclass = host.get_classname().get_name();  
    if (pnames.contains(ptclass))  
       host.ActualParamNames();
    else
       ;
 @)
}


TranspVisitor {
   before ClassName (@
   this.addElement(host.get_name());
 @)
}