//
// 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.
//
// AssignExpand.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:16:39 2015
// Update Count     : 4
//

#include <ctime>
#include <cstdlib>

#include <list>
#include <cassert>
#include <algorithm>

#include "AssignExpand.h"

#include "Parser/ParseNode.h"

#include "SynTree/Type.h"
#include "SynTree/Declaration.h"
#include "SynTree/Expression.h"
#include "SynTree/Statement.h"

namespace Tuples {
	AssignExpander::AssignExpander() : temporaryNamer("__tpl") {}

	Statement *AssignExpander::mutate( ExprStmt *exprStmt ) {
		replace.clear();
		extra.clear();
		extra2.clear();
		exprStmt->set_expr( maybeMutate( exprStmt->get_expr(), *this ) );

		CompoundStmt *newSt = 0;
		if ( ! extra.empty() ) {
			if ( ! newSt )
				newSt= new CompoundStmt(std::list<Label>());

			newSt->get_kids().splice(newSt->get_kids().end(), extra);
		} // if

		if ( ! extra2.empty() ) {
			if ( ! newSt )
				newSt= new CompoundStmt(std::list<Label>());

			newSt->get_kids().splice(newSt->get_kids().end(), extra2);
		}

		if ( ! replace.empty() ) {
			if ( ! newSt )
				newSt= new CompoundStmt(std::list<Label>());

			for ( std::list<Expression *>::iterator r = replace.begin(); r != replace.end(); r++ )
				newSt->get_kids().push_back( new ExprStmt( std::list<Label>(), *r ));
		}

		if ( newSt ) return newSt; else return exprStmt;
	}

	Expression *AssignExpander::mutate( SolvedTupleExpr *tupleExpr ) {
		/* 
		   std::list<Expression *> &exprs = tupleExpr->get_exprs();

		   if ( tupleExpr->get_type() == SolvedTupleExpr::MASS ) {
		   // extract lhs of assignments, assert that rhs is the same, create temporaries
		   assert ( ! exprs.empty());
		   ApplicationExpr *ap1 = dynamic_cast< ApplicationExpr * >( exprs.front() );
		   std::list<Expression *> &args = ap1->get_args();
		   assert(args.size() == 2);
		   std::list<Type *> &temp_types = args.back()->get_results();
		   assert(temp_types.size() == 1);
		   extra.push_back(new DeclStmt( std::list<Label>(), new ObjectDecl(temporaryNamer.newName(), Declaration::Auto, LinkageSpec::C, 0, temp_types.front(), 0 ) ));

		   for ( std::list<Expression *>::iterator e = exprs.begin(); e != exprs.end(); e++ ) {
		   ApplicationExpr *ap = dynamic_cast< ApplicationExpr * >( *e );
		   assert( ap != 0 );
		   replace.push_back(ap);
		   }

		   return tupleExpr;
		   } else if ( tupleExpr->get_type() == SolvedTupleExpr::MULTIPLE ||
		   tupleExpr->get_type() == SolvedTupleExpr::MASS ) */ {
			std::list<Expression *> &comps = tupleExpr->get_exprs();
			for ( std::list<Expression *>::iterator i = comps.begin(); i != comps.end(); ++i ) {
				std::list<Statement *> decls;
				std::list<Statement *> temps;
				std::list<Statement *> assigns;
				if ( ApplicationExpr *app = dynamic_cast< ApplicationExpr * >(*i) ) {
					assert( app->get_args().size() == 2 );

					Expression *lhsT = app->get_args().front();
					Expression *rhsT = app->get_args().back();
					// after the round of type analysis this should be true
					assert( lhsT->get_results().size() == 1 );
					assert( rhsT->get_results().size() == 1 );
					// declare temporaries
					ObjectDecl *lhs = new ObjectDecl( temporaryNamer.newName("_lhs_"), DeclarationNode::NoStorageClass, LinkageSpec::Intrinsic, 0,
													  lhsT->get_results().front(), 0 );
					decls.push_back( new DeclStmt( std::list< Label >(), lhs ) );
					ObjectDecl *rhs = new ObjectDecl( temporaryNamer.newName("_rhs_"), DeclarationNode::NoStorageClass, LinkageSpec::Intrinsic, 0,
													  rhsT->get_results().front(), 0);
					decls.push_back( new DeclStmt( std::list< Label >(), rhs ));


					// create temporary for lhs, assign address
					UntypedExpr *assgnL = new UntypedExpr( new NameExpr( "?=?" ) );
					assgnL->get_args().push_back( new VariableExpr( lhs ) );
					assgnL->get_args().push_back( lhsT );
					temps.push_back( new ExprStmt(std::list<Label>(), assgnL) );

					// create temporary for rhs, assign value
					UntypedExpr *assgnR = new UntypedExpr( new NameExpr( "?=?" ) );
					assgnR->get_args().push_back( new VariableExpr( rhs ) );
					assgnR->get_args().push_back( rhsT );
					temps.push_back( new ExprStmt(std::list<Label>(), assgnR) );

					// assign rhs to lhs
					UntypedExpr *assgn = new UntypedExpr( new NameExpr( "?=?" ) );
					UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
					deref->get_args().push_back( new VariableExpr( lhs ) );
					assgn->get_args().push_back( deref );
					assgn->get_args().push_back( new VariableExpr( rhs ) );
					assigns.push_back( new ExprStmt(std::list<Label>(), assgn) );
				} else
					throw CompilerError("Solved Tuple should contain only assignment statements");
	  
				extra.splice( extra.begin(), decls );
				extra.splice( extra.end(), temps );
				extra2.splice( extra2.end(), assigns );
			} // for
			return tupleExpr;
		}
		throw 0; // shouldn't be here
	}
} // namespace Tuples

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