/*
 * This file is part of the Cforall project
 *
 * $Id: Occurs.cc,v 1.2 2005/08/29 20:14:16 rcbilson Exp $
 *
 */

#include <set>
#include <algorithm>
#include <iterator>
#include "SynTree/Type.h"
#include "SynTree/Visitor.h"
#include "TypeEnvironment.h"


namespace ResolvExpr {

class Occurs : public Visitor
{
public:
  Occurs( std::string varName, const TypeEnvironment &env );
  
  bool get_result() const { return result; }

  virtual void visit( TypeInstType *typeInst );

private:
  bool result;
  std::set< std::string > eqvVars;
  const TypeEnvironment &env;
};

bool
occurs( Type *type, std::string varName, const TypeEnvironment &env )
{
  Occurs occur( varName, env );
  type->accept( occur );
  return occur.get_result();
}

Occurs::Occurs( std::string varName, const TypeEnvironment &env )
  : result( false ), env( env )
{
  EqvClass eqvClass;
  if( env.lookup( varName, eqvClass ) ) {
    eqvVars = eqvClass.vars;
  } else {
    eqvVars.insert( varName );
  }
}

void 
Occurs::visit( TypeInstType *typeInst )
{
  EqvClass eqvClass;
///   std::cout << "searching for vars: ";
///   std::copy( eqvVars.begin(), eqvVars.end(), std::ostream_iterator< std::string >( std::cout, " " ) );
///   std::cout << std::endl;
  if( eqvVars.find( typeInst->get_name() ) != eqvVars.end() ) {
    result = true;
  } else if( env.lookup( typeInst->get_name(), eqvClass ) ) {
    if( eqvClass.type ) {
///       std::cout << typeInst->get_name() << " is bound to";
///       eqvClass.type->print( std::cout );
///       std::cout << std::endl;
      eqvClass.type->accept( *this );
    }
  }
}

} // namespace ResolvExpr
