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

#include <cassert>
#include <string>
#include <algorithm>
#include <iterator>
#include <functional>
#include <set>

#include "SynTree/Declaration.h"
#include "SynTree/Type.h"
#include "SynTree/Expression.h"
#include "SynTree/Initializer.h"
#include "SynTree/Statement.h"
#include "Mangler.h"
#include "CodeGen/OperatorTable.h"

namespace SymTab {

Mangler::Mangler()
  : nextVarNum( 0 ), isTopLevel( true )
{
}

//Mangler::Mangler( const Mangler & )
//  : mangleName(), varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( isTopLevel )
//{
//}
Mangler::Mangler( const Mangler &rhs )
  : mangleName()
{
  varNums = rhs.varNums;
  nextVarNum = rhs.nextVarNum;
  isTopLevel = rhs.isTopLevel;
}

void 
Mangler::mangleDecl(DeclarationWithType *declaration)
{
  bool wasTopLevel = isTopLevel;
  if( isTopLevel ) {
    varNums.clear();
    nextVarNum = 0;
    isTopLevel = false;
  }
  mangleName << "__";
  CodeGen::OperatorInfo opInfo;
  if( operatorLookup( declaration->get_name(), opInfo ) ) {
    mangleName << opInfo.outputName;
  } else {
    mangleName << declaration->get_name();
  }
  mangleName << "__";
  maybeAccept( declaration->get_type(), *this );
  isTopLevel = wasTopLevel;
}

void 
Mangler::visit(ObjectDecl *declaration)
{
  mangleDecl( declaration );
}

void 
Mangler::visit(FunctionDecl *declaration)
{
  mangleDecl( declaration );
}

void 
Mangler::visit(VoidType *voidType)
{
  printQualifiers( voidType );
  mangleName << "v";
}

void 
Mangler::visit(BasicType *basicType)
{
  static const char *btLetter[] = {
    "b",	// Bool
    "c",	// Char
    "Sc",	// SignedChar
    "Uc",	// UnsignedChar
    "s",	// ShortSignedInt
    "Us",	// ShortUnsignedInt
    "i",	// SignedInt
    "Ui",	// UnsignedInt
    "l",	// LongSignedInt
    "Ul",	// LongUnsignedInt
    "q",	// LongLongSignedInt
    "Uq",	// LongLongUnsignedInt
    "f",	// Float
    "d",	// Double
    "r",	// LongDouble
    "Xf",	// FloatComplex
    "Xd",	// DoubleComplex
    "Xr",	// LongDoubleComplex
    "If",	// FloatImaginary
    "Id",	// DoubleImaginary
    "Ir",	// LongDoubleImaginary
  };
  
  printQualifiers( basicType );
  mangleName << btLetter[ basicType->get_kind() ];
}

void 
Mangler::visit(PointerType *pointerType)
{
  printQualifiers( pointerType );
  mangleName << "P";
  maybeAccept( pointerType->get_base(), *this );
}

void 
Mangler::visit(ArrayType *arrayType)
{
  // TODO: encode dimension
  printQualifiers( arrayType );
  mangleName << "A0";
  maybeAccept( arrayType->get_base(), *this );
}

namespace {
  inline std::list< Type* >
  getTypes( const std::list< DeclarationWithType* > decls )
  {
    std::list< Type* > ret;
    std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
                    std::mem_fun( &DeclarationWithType::get_type ) );
    return ret;
  }
}

void 
Mangler::visit(FunctionType *functionType)
{
  printQualifiers( functionType );
  mangleName << "F";
  std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
  acceptAll( returnTypes, *this );
  mangleName << "_";
  std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
  acceptAll( paramTypes, *this );
  mangleName << "_";
}

void 
Mangler::mangleRef(ReferenceToType *refType, std::string prefix)
{
  printQualifiers( refType );
  mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();
}

void 
Mangler::visit(StructInstType *aggregateUseType)
{
  mangleRef( aggregateUseType, "s" );
}

void 
Mangler::visit(UnionInstType *aggregateUseType)
{
  mangleRef( aggregateUseType, "u" );
}

void 
Mangler::visit(EnumInstType *aggregateUseType)
{
  mangleRef( aggregateUseType, "e" );
}

void 
Mangler::visit(TypeInstType *typeInst)
{
  VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
  if( varNum == varNums.end() ) {
    mangleRef( typeInst, "t" );
  } else {
    printQualifiers( typeInst );
    std::ostrstream numStream;
    numStream << varNum->second.first;
    mangleName << (numStream.pcount() + 1);
    switch( (TypeDecl::Kind)varNum->second.second ) {
    case TypeDecl::Any:
      mangleName << "t";
      break;
    case TypeDecl::Dtype:
      mangleName << "d";
      break;
    case TypeDecl::Ftype:
      mangleName << "f";
      break;
    }
    mangleName << std::string( numStream.str(), numStream.pcount() );
  }
}

void 
Mangler::visit(TupleType *tupleType)
{
  printQualifiers( tupleType );
  mangleName << "T";
  acceptAll( tupleType->get_types(), *this );
  mangleName << "_";
}

void 
Mangler::visit(TypeDecl *decl)
{
  static const char *typePrefix[] = { "BT", "BD", "BF" };
  mangleName << typePrefix[ decl->get_kind() ] << ( decl->get_name().length() + 1 ) << decl->get_name();
}

void
printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os )
{
  for( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
    os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
  }
}

void 
Mangler::printQualifiers( Type *type )
{
  if( !type->get_forall().empty() ) {
    std::list< std::string > assertionNames;
    int tcount = 0, dcount = 0, fcount = 0;
    mangleName << "A";
    for( std::list< TypeDecl* >::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
      switch( (*i)->get_kind() ) {
      case TypeDecl::Any:
        tcount++;
        break;
      case TypeDecl::Dtype:
        dcount++;
        break;
      case TypeDecl::Ftype:
        fcount++;
        break;
      }
      varNums[ (*i)->get_name() ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
      for( std::list< DeclarationWithType* >::iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
        Mangler sub_mangler;
        sub_mangler.nextVarNum = nextVarNum;
        sub_mangler.isTopLevel = false;
        sub_mangler.varNums = varNums;
        (*assert)->accept( sub_mangler );
        assertionNames.push_back( std::string( sub_mangler.mangleName.str(), sub_mangler.mangleName.pcount() ) );
      }
    }
    mangleName << tcount << "_" << dcount << "_" << fcount << "_";
    std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
    mangleName << "_";
  }
  if( type->get_isConst() ) {
    mangleName << "C";
  }
  if( type->get_isVolatile() ) {
    mangleName << "V";
  }
  if( type->get_isRestrict() ) {
    mangleName << "R";
  }
  if( type->get_isLvalue() ) {
    mangleName << "L";
  }
}


} // namespace SymTab
