//
// 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 : Mon Sep 25 15:49:26 2017
// Update Count     : 23
//
#include "Mangler.h"

#include <algorithm>                // for copy, transform
#include <cassert>                  // for assert, assertf
#include <functional>               // for const_mem_fun_t, mem_fun
#include <iterator>                 // for ostream_iterator, back_insert_ite...
#include <list>                     // for _List_iterator, list, _List_const...
#include <string>                   // for string, char_traits, operator<<

#include "CodeGen/OperatorTable.h"  // for OperatorInfo, operatorLookup
#include "Common/PassVisitor.h"
#include "Common/SemanticError.h"   // for SemanticError
#include "Common/utility.h"         // for toString
#include "Parser/LinkageSpec.h"     // for Spec, isOverridable, AutoGen, Int...
#include "SynTree/Declaration.h"    // for TypeDecl, DeclarationWithType
#include "SynTree/Expression.h"     // for TypeExpr, Expression, operator<<
#include "SynTree/Type.h"           // for Type, ReferenceToType, Type::Fora...

namespace SymTab {
	namespace Mangler {
		namespace {
			/// Mangles names to a unique C identifier
			struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler> {
				Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
				Mangler( const Mangler & ) = delete;

				void previsit( BaseSyntaxNode * ) { visit_children = false; }

				void postvisit( ObjectDecl * declaration );
				void postvisit( FunctionDecl * declaration );
				void postvisit( TypeDecl * declaration );

				void postvisit( VoidType * voidType );
				void postvisit( BasicType * basicType );
				void postvisit( PointerType * pointerType );
				void postvisit( ArrayType * arrayType );
				void postvisit( ReferenceType * refType );
				void postvisit( FunctionType * functionType );
				void postvisit( StructInstType * aggregateUseType );
				void postvisit( UnionInstType * aggregateUseType );
				void postvisit( EnumInstType * aggregateUseType );
				void postvisit( TypeInstType * aggregateUseType );
				void postvisit( TupleType * tupleType );
				void postvisit( VarArgsType * varArgsType );
				void postvisit( ZeroType * zeroType );
				void postvisit( OneType * oneType );

				std::string get_mangleName() { return mangleName.str(); }
			  private:
				std::ostringstream mangleName;  ///< Mangled name being constructed
				typedef std::map< std::string, std::pair< int, int > > VarMapType;
				VarMapType varNums;             ///< Map of type variables to indices
				int nextVarNum;                 ///< Next type variable index
				bool isTopLevel;                ///< Is the Mangler at the top level
				bool mangleOverridable;         ///< Specially mangle overridable built-in methods
				bool typeMode;                  ///< Produce a unique mangled name for a type
				bool mangleGenericParams;       ///< Include generic parameters in name mangling if true

				void mangleDecl( DeclarationWithType *declaration );
				void mangleRef( ReferenceToType *refType, std::string prefix );

				void printQualifiers( Type *type );
			}; // Mangler
		} // namespace

		std::string mangle( BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
			PassVisitor<Mangler> mangler( mangleOverridable, typeMode, mangleGenericParams );
			maybeAccept( decl, mangler );
			return mangler.pass.get_mangleName();
		}

		std::string mangleType( Type * ty ) {
			PassVisitor<Mangler> mangler( false, true, true );
			maybeAccept( ty, mangler );
			return mangler.pass.get_mangleName();
		}

		std::string mangleConcrete( Type * ty ) {
			PassVisitor<Mangler> mangler( false, false, false );
			maybeAccept( ty, mangler );
			return mangler.pass.get_mangleName();
		}

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

			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(), *visitor );
				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 && "unknown overrideable linkage" );
					} // if
				}
				isTopLevel = wasTopLevel;
			}

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

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

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

			void Mangler::postvisit( 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
					"w",	// SignedInt128
					"Uw",	// UnsignedInt128
				};

				printQualifiers( basicType );
				mangleName << btLetter[ basicType->get_kind() ];
			}

			void Mangler::postvisit( PointerType * pointerType ) {
				printQualifiers( pointerType );
				mangleName << "P";
				maybeAccept( pointerType->base, *visitor );
			}

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

			void Mangler::postvisit( ReferenceType * refType ) {
				printQualifiers( refType );
				mangleName << "R";
				maybeAccept( refType->base, *visitor );
			}

			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::postvisit( FunctionType * functionType ) {
				printQualifiers( functionType );
				mangleName << "F";
				std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
				acceptAll( returnTypes, *visitor );
				mangleName << "_";
				std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
				acceptAll( paramTypes, *visitor );
				mangleName << "_";
			}

			void Mangler::mangleRef( ReferenceToType * refType, std::string prefix ) {
				printQualifiers( refType );

				mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();

				if ( mangleGenericParams ) {
					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(), *visitor );
						}
						mangleName << "_";
					}
				}
			}

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

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

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

			void Mangler::postvisit( 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::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::postvisit( TupleType * tupleType ) {
				printQualifiers( tupleType );
				mangleName << "T";
				acceptAll( tupleType->types, *visitor );
				mangleName << "_";
			}

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

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

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

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

			__attribute__((unused)) 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->forall.begin(); i != type->forall.end(); ++i ) {
						switch ( (*i)->get_kind() ) {
						  case TypeDecl::Dtype:
							dcount++;
							break;
						  case TypeDecl::Ftype:
							fcount++;
							break;
						  case TypeDecl::Ttype:
							vcount++;
							break;
						  default:
							assert( false );
						} // switch
						varNums[ (*i)->name ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
						for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
							PassVisitor<Mangler> sub_mangler( mangleOverridable, typeMode, mangleGenericParams );
							sub_mangler.pass.nextVarNum = nextVarNum;
							sub_mangler.pass.isTopLevel = false;
							sub_mangler.pass.varNums = varNums;
							(*assert)->accept( sub_mangler );
							assertionNames.push_back( sub_mangler.pass.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
				if ( type->get_mutex() ) {
					mangleName << "M";
				} // if
				// Removed due to restrict not affecting function compatibility in GCC
		//		if ( type->get_isRestrict() ) {
		//			mangleName << "E";
		//		} // if
				if ( type->get_lvalue() ) {
					// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
					mangleName << "L";
				}
				if ( type->get_atomic() ) {
					mangleName << "A";
				} // if
			}
		}	// namespace
	} // namespace Mangler
} // namespace SymTab

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