//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// Mangler.cc --
//
// Author           : Richard C. Bilson
// Created On       : Sun May 17 21:40:29 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Fri Mar 17 09:40:01 2017
// Update Count     : 20
//

#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 {
	std::string Mangler::mangleType( Type *ty ) {
		Mangler mangler( false, true );
		maybeAccept( ty, mangler );
		return mangler.get_mangleName();
	}

	Mangler::Mangler( bool mangleOverridable, bool typeMode )
		: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ) {}

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

	void Mangler::mangleDecl( DeclarationWithType *declaration ) {
		bool wasTopLevel = isTopLevel;
		if ( isTopLevel ) {
			varNums.clear();
			nextVarNum = 0;
			isTopLevel = false;
		} // if
		mangleName << "__";
		CodeGen::OperatorInfo opInfo;
		if ( operatorLookup( declaration->get_name(), opInfo ) ) {
			mangleName << opInfo.outputName;
		} else {
			mangleName << declaration->get_name();
		} // if
		mangleName << "__";
		maybeAccept( declaration->get_type(), *this );
		if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
			// want to be able to override autogenerated and intrinsic routines,
			// so they need a different name mangling
			if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
				mangleName << "autogen__";
			} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
				mangleName << "intrinsic__";
			} else {
				// if we add another kind of overridable function, this has to change
				assert( false );
			} // if
		}
		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::mangleGenericRef( ReferenceToType *refType, std::string prefix ) {
		printQualifiers( refType );

		std::ostringstream oldName( mangleName.str() );
		mangleName.clear();

		mangleName << prefix << refType->get_name();

		std::list< Expression* >& params = refType->get_parameters();
		if ( ! params.empty() ) {
			mangleName << "_";
			for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) {
				TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
				assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str());
				maybeAccept( paramType->get_type(), *this );
			}
			mangleName << "_";
		}

		oldName << mangleName.str().length() << mangleName.str();
		mangleName.str( oldName.str() );
	}

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

	void Mangler::visit( UnionInstType *aggregateUseType ) {
		if ( typeMode ) mangleGenericRef( aggregateUseType, "u" );
		else 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::ostringstream numStream;
			numStream << varNum->second.first;
			switch ( (TypeDecl::Kind )varNum->second.second ) {
			  case TypeDecl::Any:
				mangleName << "t";
				break;
			  case TypeDecl::Dtype:
				mangleName << "d";
				break;
			  case TypeDecl::Ftype:
				mangleName << "f";
				break;
				case TypeDecl::Ttype:
				mangleName << "tVARGS";
				break;
				default:
				assert( false );
			} // switch
			mangleName << numStream.str();
		} // if
	}

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

	void Mangler::visit( VarArgsType *varArgsType ) {
		printQualifiers( varArgsType );
		mangleName << "VARGS";
	}

	void Mangler::visit( ZeroType *zeroType ) {
		mangleName << "Z";
	}

	void Mangler::visit( OneType *oneType ) {
		mangleName << "O";
	}

	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;
		} // for
	}

	void Mangler::printQualifiers( Type *type ) {
		// skip if not including qualifiers
		if ( typeMode ) return;

		if ( ! type->get_forall().empty() ) {
			std::list< std::string > assertionNames;
			int tcount = 0, dcount = 0, fcount = 0, vcount = 0;
			mangleName << "A";
			for ( Type::ForallList::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;
				  case TypeDecl::Ttype:
					vcount++;
					break;
				  default:
					assert( false );
				} // switch
				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( mangleOverridable, typeMode );
					sub_mangler.nextVarNum = nextVarNum;
					sub_mangler.isTopLevel = false;
					sub_mangler.varNums = varNums;
					(*assert)->accept( sub_mangler );
					assertionNames.push_back( sub_mangler.mangleName.str() );
				} // for
			} // for
			mangleName << tcount << "_" << dcount << "_" << fcount << "_" << vcount << "_";
			std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
			mangleName << "_";
		} // if
		if ( type->get_const() ) {
			mangleName << "C";
		} // if
		if ( type->get_volatile() ) {
			mangleName << "V";
		} // if
		// Removed due to restrict not affecting function compatibility in GCC
//		if ( type->get_isRestrict() ) {
//			mangleName << "R";
//		} // if
		if ( type->get_lvalue() ) {
			mangleName << "L";
		} // if
		if ( type->get_atomic() ) {
			mangleName << "A";
		} // if
	}
} // namespace SymTab

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
