//
// 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 "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
#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>, public WithGuards {
				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( TraitInstType * inst );
				void postvisit( TupleType * tupleType );
				void postvisit( VarArgsType * varArgsType );
				void postvisit( ZeroType * zeroType );
				void postvisit( OneType * oneType );
				void postvisit( QualifiedType * qualType );

				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
				bool inFunctionType = false;    ///< Include type qualifiers if false.
				bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type

			  public:
				Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 
					int nextVarNum, const VarMapType& varNums );

			  private:
				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 ) {}
			
			Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams, 
				int nextVarNum, const VarMapType& varNums )
				: varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ), 
				mangleOverridable( mangleOverridable ), typeMode( typeMode ), 
				mangleGenericParams( mangleGenericParams ) {}

			void Mangler::mangleDecl( DeclarationWithType * declaration ) {
				bool wasTopLevel = isTopLevel;
				if ( isTopLevel ) {
					varNums.clear();
					nextVarNum = 0;
					isTopLevel = false;
				} // if
				mangleName << Encoding::manglePrefix;
				CodeGen::OperatorInfo opInfo;
				if ( operatorLookup( declaration->get_name(), opInfo ) ) {
					mangleName << opInfo.outputName.size() << opInfo.outputName;
				} else {
					mangleName << declaration->name.size() << declaration->name;
				} // if
				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 << Encoding::autogen;
					} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
						mangleName << Encoding::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 << Encoding::void_t;
			}

			void Mangler::postvisit( BasicType * basicType ) {
				printQualifiers( basicType );
				assertf( basicType->get_kind() < BasicType::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->get_kind() );
				mangleName << Encoding::basicTypes[ basicType->get_kind() ];
			}

			void Mangler::postvisit( PointerType * pointerType ) {
				printQualifiers( pointerType );
				// mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
				if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName << Encoding::pointer;
				maybeAccept( pointerType->base, *visitor );
			}

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

			void Mangler::postvisit( ReferenceType * refType ) {
				// don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
				// Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
				// by pretending every reference type is a function parameter.
				GuardValue( inFunctionType );
				inFunctionType = true;
				printQualifiers( refType );
				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 << Encoding::function;
				// turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
				// since qualifiers on outermost parameter type do not differentiate function types, e.g.,
				// void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different
				GuardValue( inFunctionType );
				inFunctionType = true;
				std::list< Type* > returnTypes = getTypes( functionType->returnVals );
				if (returnTypes.empty()) mangleName << Encoding::void_t;
				else acceptAll( returnTypes, *visitor );
				mangleName << "_";
				std::list< Type* > paramTypes = getTypes( functionType->parameters );
				acceptAll( paramTypes, *visitor );
				mangleName << "_";
			}

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

				mangleName << prefix << refType->name.length() << refType->name;

				if ( mangleGenericParams ) {
					std::list< Expression* >& params = refType->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", toCString(*param));
							maybeAccept( paramType->type, *visitor );
						}
						mangleName << "_";
					}
				}
			}

			void Mangler::postvisit( StructInstType * aggregateUseType ) {
				mangleRef( aggregateUseType, Encoding::struct_t );
			}

			void Mangler::postvisit( UnionInstType * aggregateUseType ) {
				mangleRef( aggregateUseType, Encoding::union_t );
			}

			void Mangler::postvisit( EnumInstType * aggregateUseType ) {
				mangleRef( aggregateUseType, Encoding::enum_t );
			}

			void Mangler::postvisit( TypeInstType * typeInst ) {
				VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
				if ( varNum == varNums.end() ) {
					mangleRef( typeInst, Encoding::type );
				} else {
					printQualifiers( typeInst );
					// Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
					//   forall(dtype T) void f(T);
					//   forall(dtype S) void f(S);
					// are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
					// are first found and prefixing with the appropriate encoding for the type class.
					assertf( varNum->second.second < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
					mangleName << Encoding::typeVariables[varNum->second.second] << varNum->second.first;
				} // if
			}

			void Mangler::postvisit( TraitInstType * inst ) {
				printQualifiers( inst );
				mangleName << inst->name.size() << inst->name;
			}

			void Mangler::postvisit( TupleType * tupleType ) {
				printQualifiers( tupleType );
				mangleName << Encoding::tuple << tupleType->types.size();
				acceptAll( tupleType->types, *visitor );
			}

			void Mangler::postvisit( VarArgsType * varArgsType ) {
				printQualifiers( varArgsType );
				static const std::string vargs = "__builtin_va_list";
				mangleName << Encoding::type << vargs.size() << vargs;
			}

			void Mangler::postvisit( ZeroType * ) {
				mangleName << Encoding::zero;
			}

			void Mangler::postvisit( OneType * ) {
				mangleName << Encoding::one;
			}

			void Mangler::postvisit( QualifiedType * qualType ) {
				bool inqual = inQualifiedType;
				if (! inqual ) {
					// N marks the start of a qualified type
					inQualifiedType = true;
					mangleName << Encoding::qualifiedTypeStart;
				}
				maybeAccept( qualType->parent, *visitor );
				maybeAccept( qualType->child, *visitor );
				if ( ! inqual ) {
					// E marks the end of a qualified type
					inQualifiedType = false;
					mangleName << Encoding::qualifiedTypeEnd;
				}
			}

			void Mangler::postvisit( TypeDecl * decl ) {
				// TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
				// fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
				// Note: The current scheme may already work correctly for this case, I have not thought about this deeply
				// and the case has not yet come up in practice. Alternatively, if not then this code can be removed
				// aside from the assert false.
				assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
				assertf( decl->get_kind() < TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->get_kind() );
				mangleName << Encoding::typeVariables[ decl->get_kind() ] << ( decl->name.length() ) << 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 dcount = 0, fcount = 0, vcount = 0, acount = 0;
					mangleName << Encoding::forall;
					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::make_pair( 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, nextVarNum, varNums );
							(*assert)->accept( sub_mangler );
							assertionNames.push_back( sub_mangler.pass.get_mangleName() );
							acount++;
						} // for
					} // for
					mangleName << dcount << "_" << fcount << "_" << vcount << "_" << acount << "_";
					std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
					mangleName << "_";
				} // if
				if ( ! inFunctionType ) {
					// these qualifiers do not distinguish the outermost type of a function parameter
					if ( type->get_const() ) {
						mangleName << Encoding::qualifiers.at(Type::Const);
					} // if
					if ( type->get_volatile() ) {
						mangleName << Encoding::qualifiers.at(Type::Volatile);
					} // if
					// Removed due to restrict not affecting function compatibility in GCC
					// if ( type->get_isRestrict() ) {
					// 	mangleName << "E";
					// } // if
					if ( type->get_atomic() ) {
						mangleName << Encoding::qualifiers.at(Type::Atomic);
					} // if
				}
				if ( type->get_mutex() ) {
					mangleName << Encoding::qualifiers.at(Type::Mutex);
				} // if
				if ( type->get_lvalue() ) {
					// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
					mangleName << Encoding::qualifiers.at(Type::Lvalue);
				}

				if ( inFunctionType ) {
					// turn off inFunctionType so that types can be differentiated for nested qualifiers
					GuardValue( inFunctionType );
					inFunctionType = false;
				}
			}
		}	// namespace
	} // namespace Mangler
} // namespace SymTab

namespace Mangle {
	std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
		#warning unimplemented
		assert( decl && mode.val && false );
		return "";
	}
} // namespace Mangle

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