//
// 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.
//
// Processor.cc -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Tue May 19 16:23:10 2015
// Update Count     : 2
//

#include <vector>
#include <algorithm>

#include "Processor.h"
#include "SynTree/Declaration.h"

namespace Designators {
	Matcher::Matcher( const std::list< DeclarationWithType * > &decls ) {
		int cnt = 0;
		for ( std::list< DeclarationWithType * >::const_iterator i = decls.begin();
			  i != decls.end(); i++, cnt++ ) {
			std::string newName = (*i)->get_name();
			if ( table.find( newName ) == table.end() ) {
				table.insert( std::pair<std::string, int>(newName, cnt) );
				order.push_back( newName );
				declarations.push_back( *i );
				alternatives.push_back( 0 );
			} // if
		} // for
	}

	template< class InputIterator >
	bool Matcher::add(InputIterator begin, InputIterator end, ResolvExpr::Alternative &alt ) {
		while ( begin != end ) {
			if ( table.find( *begin ) != table.end() )
				alternatives[ table[ *begin ] ] = new ResolvExpr::Alternative(alt);
			else
				return false;
			begin++;
		} // while
		return true;
	}

	template< class InputIterator, class OutputIterator >
	bool Matcher::slice(InputIterator begin, InputIterator end, OutputIterator out ) {
		while ( begin != end )
			if ( table.find( *begin ) != table.end() )
				*out++ = declarations [ table[ *begin++ ] ];
			else
				return false; // throw 0;
		return true;
	}

	template< class OutputIterator >
	bool Matcher::get_reorderedCall( OutputIterator out ) {
		// fill call with defaults, if need be
		for (Matcher::iterator o = begin(); o != end(); o++ )
			if ( alternatives[ table[ *o ] ] == 0 )
				return false;
			else
				out++ = *alternatives[table[ *o ]];
		return true;
	}

	bool fixDesignations( ResolvExpr::AlternativeFinder &finder, Expression *designation ) {
		// Distribute `designation' over alternatives contained in `finder'
		if ( ! designation) return false;
		else
			for ( ResolvExpr::AlternativeFinder::iterator alt = finder.begin(); alt != finder.end(); alt++ )
				alt->expr->set_argName( designation );
		return true;
	}

	template < class OutputIterator >
	bool extractNames( Expression *expr, OutputIterator out, Matcher matcher ) {
		Expression *designator = expr->get_argName();
		if ( designator == 0 ) return false;

		if ( NameExpr *ndes = dynamic_cast<NameExpr *>(designator) )
			out++ = ndes->get_name();
		else if ( TupleExpr *tdes = dynamic_cast<TupleExpr *>(designator) ) {
			std::cerr << "Tuple designation" << std::endl;
//      ObjectDecl *decl = extractTupleV(matcher, tdes); // xxx
			// transform?
			for ( std::list< Expression * >::iterator n = tdes->get_exprs().begin();
				  n != tdes->get_exprs().end(); n++ ) {

				if ( NameExpr *name = dynamic_cast<NameExpr *>(*n) )
					out++ = name->get_name();
				else
					// flatten nested Tuples
					throw SemanticError( "Invalid tuple designation." );
			} // for
		} // if
		return true;
	}

	std::string extractName( Expression *expr ) /* throw NoNameExtraction */ {
		if ( NameExpr *name = dynamic_cast< NameExpr *>(expr) )
			return name->get_name();
		else /* if () */
			throw 0;
	}

	DeclarationWithType *gensym( DeclarationWithType *, std::string prefix ) {
		return 0;
	}

	ObjectDecl *extractTupleV( Matcher matcher, TupleExpr *nmTuple ) {
		// extract a subtuple of the function `fun' argument list, corresponding to the tuple of names requested by
		// `nmTuple'.
		std::list< Expression * > &exprs = nmTuple->get_exprs();
		std::cerr << "In extractTupleV, the tuple has " << exprs.size() << " components." << std::endl;
		std::list< std::string > names;
		std::transform( exprs.begin(), exprs.end(), back_inserter(names), extractName );
		std::list< DeclarationWithType * > decls;
		matcher.slice( names.begin(), names.end(), back_inserter(decls) );
		//std::for_each( decls.begin(), decls.end(), gensym );
		std::cerr << "Returning declaration with " << decls.size() << " components." << std::endl;

		return 0;//new ObjectDecl()
	}

	void check_alternative( FunctionType *fun, ResolvExpr::AltList &args ) {
		using namespace ResolvExpr;

		Matcher matcher( fun->get_parameters() );
		for ( AltList::iterator a = args.begin(); a != args.end(); a++ ) {
			std::list< std::string > actNames;
			if ( ! extractNames( a->expr, back_inserter(actNames), matcher ) ) {
				return; // not a designated call, leave alternative alone
			} else {
				// see if there's a match
				matcher.add( actNames.begin(), actNames.end(), *a );
			} // if
		} // for
		//AltList newArgs;
		args.clear();
		matcher.get_reorderedCall( back_inserter(args) );

		return;
	}
#if 0
	void pruneAlternatives( Expression *expr, ResolvExpr::AlternativeFinder &finder ) {
		if ( expr->get_argName() != 0 ) {
			// Looking at designated expression
			using namespace ResolvExpr;
			AltList &alternatives = finder.get_alternatives();
			std::cerr << "Now printing alternatives: " << std::endl;
			for ( AltList::iterator a = alternatives.begin(); a != alternatives.end(); a++ )
				a->expr->print( std::cerr );
			//std::cerr << "Looking for constructions of length no more than: " << tdes->get_exprs().size() << "." << std::endl;
		}
		return;
	}
#endif // 0
} // namespaces Designators

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