//
// 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.
//
// FunctionChecker.cc -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Sat Jun 13 08:17:19 2015
// Update Count     : 4
//

#include "FunctionChecker.h"
#include "FunctionFixer.h"
#include "Common/SemanticError.h"

#include <algorithm>
#include <iostream>
#include <cassert>

namespace Tuples {
	using namespace std;

	void checkFunctions( std::list< Declaration * > translationUnit ) {
		FunctionChecker fchk( true );
		TupleDistrib td;
		FunctionFixer ff;

		mutateAll( translationUnit , fchk );
		mutateAll( translationUnit , ff );
		mutateAll( translationUnit , td );
		return;
	}

	FunctionChecker::FunctionChecker( bool _topLevel, UniqueName *_nameGen ) : topLevel( _topLevel ), nameGen( _nameGen ) {
		if ( topLevel ) {
			assert( ! nameGen );
			nameGen = new UniqueName("_MVR_");
		} else
			assert( nameGen );
	}

	FunctionChecker::~FunctionChecker() {
		if ( topLevel ) {
			delete nameGen;
			nameGen = 0;
		}
	}

	Statement* FunctionChecker::mutate( ExprStmt *exprStmt ) {
		exprStmt->set_expr( maybeMutate( exprStmt->get_expr(), *this ) );
		if ( ! tempExpr.empty() ) {
			assert ( ! temporaries.empty() );
			CompoundStmt *newBlock = new CompoundStmt( std::list< Label >() );
			// declarations
			for ( std::list< ObjectDecl *>::iterator d = temporaries.begin(); d != temporaries.end(); ++d )
				newBlock->get_kids().push_back( new DeclStmt( std::list<Label>(), *d ) );
			// new expression statements
			for ( std::list< Expression *>::iterator e = tempExpr.begin(); e != tempExpr.end(); ++e )
				newBlock->get_kids().push_back( new ExprStmt( std::list<Label>(), *e ) );

			newBlock->get_kids().push_back( exprStmt );
			return newBlock;
		} else
			return exprStmt;
	}

	Expression* FunctionChecker::mutate( ApplicationExpr *applicationExpr ) {
		if ( topLevel )
			; // In top level of Functionchecker

		if ( applicationExpr->get_results().size() > 1 ) {
			for ( std::list< Type *>::iterator res = applicationExpr->get_results().begin(); res != applicationExpr->get_results().end(); res++ )
				temporaries.push_back( new ObjectDecl( nameGen->newName(), DeclarationNode::Auto, LinkageSpec::AutoGen, 0, (*res )->clone(), 0 ) );

			assert( ! temporaries.empty() );
		}

		applicationExpr->set_function(  maybeMutate( applicationExpr->get_function(), *this ) );

		std::list< Expression * > newArgs;
		for ( std::list< Expression *>::iterator e = applicationExpr->get_args().begin(); e != applicationExpr->get_args().end(); ++e ) {
			FunctionChecker rec( false, nameGen );
			(*e )->acceptMutator( rec );

			if ( ! rec.temporaries.empty() ) {
				TupleExpr *lhs = new TupleExpr;
				std::list< Expression * > &tmem = lhs->get_exprs();
				for ( std::list<ObjectDecl *>::iterator d = rec.temporaries.begin();  d != rec.temporaries.end(); ++d ) {
					tmem.push_back( new VariableExpr( *d ) );
					newArgs.push_back( new VariableExpr( *d ) );
				}

				// construct tuple assignment
				std::list<Expression *> args;
				args.push_back( new AddressExpr( lhs ) );
				args.push_back( *e );
				tempExpr.push_back( new UntypedExpr( new NameExpr("?=?"), args ) );

				temporaries.splice( temporaries.end(), rec.temporaries );
			} else
				newArgs.push_back( *e );
			// percolate to recursive calls
		}

		applicationExpr->get_args().clear();
		std::copy( newArgs.begin(), newArgs.end(), back_inserter( applicationExpr->get_args()) );

		return applicationExpr;
	}

	Expression* TupleDistrib::mutate( UntypedExpr *expr ) {
		if (  NameExpr *assgnop = dynamic_cast< NameExpr * >( expr->get_function()) ) {
			if ( assgnop->get_name() == std::string("?=?") ) {
				std::list<Expression *> &args = expr->get_args();
				assert( args.size() == 2 );
				//if args.front() points to a tuple and if args.back() is already resolved
				if ( AddressExpr *addr = dynamic_cast<AddressExpr *>( args.front()) )
					if ( TupleExpr *lhs = dynamic_cast<TupleExpr *>( addr->get_arg()) )
						if ( ApplicationExpr *rhs = dynamic_cast<ApplicationExpr *>( args.back() ) ) {
							for ( std::list<Expression *>::iterator tc = lhs->get_exprs().begin(); tc != lhs->get_exprs().end(); ++tc )
								rhs->get_args().push_back( new AddressExpr( *tc ) );
							return rhs; // XXX
						} // if
			} else
				assert( false ); // It's not an assignment, shouldn't be here
		} // if
		return expr;
	}

}

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