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

#include <cassert>

#include "SynTree/Declaration.h"
#include "ResolvExpr/typeops.h"
#include "Indexer.h"
#include "Mangler.h"
#include "IdTable.h"
#include "SemanticError.h"

using std::string;

namespace SymTab {

IdTable::IdTable()
  : scopeLevel( 0 )
{
}

void 
IdTable::enterScope()
{
  scopeLevel++;
}

void 
IdTable::leaveScope()
{
  for( OuterTableType::iterator outer = table.begin(); outer != table.end(); ++outer ) {
    for( InnerTableType::iterator inner = outer->second.begin(); inner != outer->second.end(); ++inner ) {
      std::stack< DeclEntry >& entry = inner->second;
      if( !entry.empty() && entry.top().second == scopeLevel ) {
        entry.pop();
      }
    }
  }
      
  scopeLevel--;
  assert( scopeLevel >= 0 );
}

void 
IdTable::addDecl( DeclarationWithType *decl )
{
  const string &name = decl->get_name();
  string manglename;
  if( decl->get_linkage() == LinkageSpec::C ) {
    manglename = name;
  } else {
    manglename = Mangler::mangle( decl );
  }
  InnerTableType &declTable = table[ name ];
  InnerTableType::iterator it = declTable.find( manglename );
  if( it == declTable.end() ) {
    declTable[ manglename ].push( DeclEntry( decl, scopeLevel ) );
  } else {
    std::stack< DeclEntry >& entry = it->second;
    if( !entry.empty() && entry.top().second == scopeLevel ) {
      if( decl->get_linkage() != LinkageSpec::C || ResolvExpr::typesCompatible( decl->get_type(), entry.top().first->get_type(), Indexer() ) ) {
        FunctionDecl *newentry = dynamic_cast< FunctionDecl* >( decl );
        FunctionDecl *old = dynamic_cast< FunctionDecl* >( entry.top().first );
        if( newentry && old && newentry->get_statements() && old->get_statements() ) {
          throw SemanticError( "duplicate function definition for ", decl );
        } else {
          ObjectDecl *newobj = dynamic_cast< ObjectDecl* >( decl );
          ObjectDecl *oldobj = dynamic_cast< ObjectDecl* >( entry.top().first );
          if( newobj && oldobj && newobj->get_init() && oldobj->get_init() ) {
            throw SemanticError( "duplicate definition for ", decl );
          }
        }
      } else {
        throw SemanticError( "duplicate definition for ", decl );
      }
    } else {
      declTable[ manglename ].push( DeclEntry( decl, scopeLevel ) );
    }
  }
  for( InnerTableType::const_iterator i = declTable.begin(); i != declTable.end(); ++i ) {
    if( !i->second.empty() && i->second.top().first->get_linkage() == LinkageSpec::C && declTable.size() > 1 ) {
      throw SemanticError( "invalid overload of C function ", i->second.top().first );
    }
  }
}

void 
IdTable::lookupId( const std::string &id, std::list< DeclarationWithType* >& decls ) const
{
  OuterTableType::const_iterator outer = table.find( id );
  if( outer == table.end() ) return;
  const InnerTableType &declTable = outer->second;
  for( InnerTableType::const_iterator it = declTable.begin(); it != declTable.end(); ++it ) {
    const std::stack< DeclEntry >& entry = it->second;
    if( !entry.empty() ) {
      decls.push_back( entry.top().first );
    }
  }
}

void 
IdTable::dump( std::ostream &os ) const
{
  for( OuterTableType::const_iterator outer = table.begin(); outer != table.end(); ++outer ) {
    for( InnerTableType::const_iterator inner = outer->second.begin(); inner != outer->second.end(); ++inner ) {
      const std::stack< DeclEntry >& entry = inner->second;
      if( !entry.empty() && entry.top().second == scopeLevel ) {
        os << outer->first << " (" << inner->first << ") (" << scopeLevel << ")" << std::endl;
      }
    }
  }
}


} // namespace SymTab
