//
// 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.
//
// RenameVars.cc --
//
// Author           : Richard C. Bilson
// Created On       : Sun May 17 12:05:18 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Wed Mar  2 17:36:32 2016
// Update Count     : 5
//

#include <sstream>

#include "RenameVars.h"
#include "SynTree/Visitor.h"
#include "SynTree/Type.h"
#include "SynTree/Declaration.h"
#include "SynTree/Expression.h"

namespace ResolvExpr {
	RenameVars global_renamer;

	RenameVars::RenameVars() : level( 0 ) {
		mapStack.push_front( std::map< std::string, std::string >() );
	}

	void RenameVars::reset() {
		level = 0;
	}

	void RenameVars::visit( VoidType *voidType ) {
		typeBefore( voidType );
		typeAfter( voidType );
	}

	void RenameVars::visit( BasicType *basicType ) {
		typeBefore( basicType );
		typeAfter( basicType );
	}

	void RenameVars::visit( PointerType *pointerType ) {
		typeBefore( pointerType );
		maybeAccept( pointerType->get_base(), *this );
		typeAfter( pointerType );
	}

	void RenameVars::visit( ArrayType *arrayType ) {
		typeBefore( arrayType );
		maybeAccept( arrayType->get_dimension(), *this );
		maybeAccept( arrayType->get_base(), *this );
		typeAfter( arrayType );
	}

	void RenameVars::visit( FunctionType *functionType ) {
		typeBefore( functionType );
		acceptAll( functionType->get_returnVals(), *this );
		acceptAll( functionType->get_parameters(), *this );
		typeAfter( functionType );
	}

	void RenameVars::visit( StructInstType *aggregateUseType ) {
		typeBefore( aggregateUseType );
		acceptAll( aggregateUseType->get_parameters(), *this );
		typeAfter( aggregateUseType );
	}

	void RenameVars::visit( UnionInstType *aggregateUseType ) {
		typeBefore( aggregateUseType );
		acceptAll( aggregateUseType->get_parameters(), *this );
		typeAfter( aggregateUseType );
	}

	void RenameVars::visit( EnumInstType *aggregateUseType ) {
		typeBefore( aggregateUseType );
		acceptAll( aggregateUseType->get_parameters(), *this );
		typeAfter( aggregateUseType );
	}

	void RenameVars::visit( TraitInstType *aggregateUseType ) {
		typeBefore( aggregateUseType );
		acceptAll( aggregateUseType->get_parameters(), *this );
		acceptAll( aggregateUseType->get_members(), *this );
		typeAfter( aggregateUseType );
	}

	void RenameVars::visit( TypeInstType *instType ) {
		typeBefore( instType );
		std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->get_name() );
		if ( i != mapStack.front().end() ) {
			instType->set_name( i->second );
		} else {
		} // if
		acceptAll( instType->get_parameters(), *this );
		typeAfter( instType );
	}

	void RenameVars::visit( TupleType *tupleType ) {
		typeBefore( tupleType );
		acceptAll( tupleType->get_types(), *this );
		typeAfter( tupleType );
	}

	void RenameVars::visit( VarArgsType *varArgsType ) {
		typeBefore( varArgsType );
		typeAfter( varArgsType );
	}

	void RenameVars::visit( ZeroType *zeroType ) {
		typeBefore( zeroType );
		typeAfter( zeroType );
	}

	void RenameVars::visit( OneType *oneType ) {
		typeBefore( oneType );
		typeAfter( oneType );
	}

	void RenameVars::typeBefore( Type *type ) {
		if ( ! type->get_forall().empty() ) {
			// copies current name mapping into new mapping
			mapStack.push_front( mapStack.front() );
			// renames all "forall" type names to `_${level}_${name}'
			for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
				std::ostringstream output;
				output << "_" << level << "_" << (*i)->get_name();
				std::string newname( output.str() );
				mapStack.front()[ (*i)->get_name() ] = newname;
				(*i)->set_name( newname );
				// ditto for assertion names, the next level in
				level++;
				acceptAll( (*i)->get_assertions(), *this );
			} // for
		} // if
	}

	void RenameVars::typeAfter( Type *type ) {
		// clears name mapping added by typeBefore()
		if ( ! type->get_forall().empty() ) {
			mapStack.pop_front();
		} // if
	}

} // namespace ResolvExpr

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