//
// 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.
//
// ScrubTyVars.cc --
//
// Author           : Richard C. Bilson
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Tue May 19 16:42:42 2015
// Update Count     : 2
//

#include <sstream>
#include <string>

#include "GenPoly.h"
#include "ScrubTyVars.h"

#include "SynTree/Mutator.h"
#include "SynTree/Type.h"
#include "SynTree/Expression.h"

namespace GenPoly {
	Type * ScrubTyVars::mutate( TypeInstType *typeInst ) {
		TyVarMap::const_iterator tyVar = tyVars.find( typeInst->get_name() );
		if ( tyVar != tyVars.end() ) {
			switch ( tyVar->second.kind ) {
			  case TypeDecl::Any:
			  case TypeDecl::Dtype:
			  case TypeDecl::Ttype:
				{
					PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( typeInst->get_qualifiers() ) );
					delete typeInst;
					return ret;
				}
			  case TypeDecl::Ftype:
				delete typeInst;
				return new PointerType( Type::Qualifiers(), new FunctionType( Type::Qualifiers(), true ) );
			} // switch
		} // if
		return typeInst;
	}

	Type * ScrubTyVars::mutateAggregateType( Type *ty ) {
		if ( shouldScrub( ty ) ) {
			PointerType *ret = new PointerType( Type::Qualifiers(), new VoidType( ty->get_qualifiers() ) );
			delete ty;
			return ret;
		}
		return ty;
	}

	Type * ScrubTyVars::mutate( StructInstType *structInst ) {
		return mutateAggregateType( structInst );
	}

	Type * ScrubTyVars::mutate( UnionInstType *unionInst ) {
		return mutateAggregateType( unionInst );
	}

	Expression * ScrubTyVars::mutate( SizeofExpr *szeof ) {
		// sizeof( T ) => _sizeof_T parameter, which is the size of T
		if ( Type *dynType = shouldScrub( szeof->get_type() ) ) {
			Expression *expr = new NameExpr( sizeofName( mangleType( dynType ) ) );
			return expr;
		} else {
			return Mutator::mutate( szeof );
		} // if
	}

	Expression * ScrubTyVars::mutate( AlignofExpr *algnof ) {
		// alignof( T ) => _alignof_T parameter, which is the alignment of T
		if ( Type *dynType = shouldScrub( algnof->get_type() ) ) {
			Expression *expr = new NameExpr( alignofName( mangleType( dynType ) ) );
			return expr;
		} else {
			return Mutator::mutate( algnof );
		} // if
	}

	Type * ScrubTyVars::mutate( PointerType *pointer ) {
//		// special case of shouldScrub that takes all TypeInstType pointer bases, even if they're not dynamic
// 		Type *base = pointer->get_base();
// 		Type *dynType = 0;
// 		if ( dynamicOnly ) {
// 			if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( base ) ) {
// 				if ( tyVars.find( typeInst->get_name() ) != tyVars.end() ) { dynType = typeInst; }
// 			} else {
// 				dynType = isDynType( base, tyVars );
// 			}
// 		} else {
// 			dynType = isPolyType( base, tyVars );
// 		}
// 		if ( dynType ) {
		if ( Type *dynType = shouldScrub( pointer->get_base() ) ) {
			Type *ret = dynType->acceptMutator( *this );
			ret->get_qualifiers() += pointer->get_qualifiers();
			pointer->set_base( 0 );
			delete pointer;
			return ret;
		}
		return Mutator::mutate( pointer );
	}
} // namespace GenPoly

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