//
// 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.
//
// BasicInit.h -- 
//
// 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:32:21 2015
// Update Count     : 3
//

#ifndef _BASINIT_H_
#define _BASINIT_H_

#include <list>

#include "SynTree/Visitor.h"
#include "SymTab/Indexer.h"

#include "SynTree/Type.h"
#include "SynTree/Initializer.h"
#include "SynTree/Expression.h"
#include "NameInCollection.h"
#include "NameAssociation.h"

namespace InitTweak {
	bool isDeclStmtP(Statement *stmt);

	class BreakInitializer;
	class BreakDesignator;

	class BasicInit: public Mutator {
	  public:
		BasicInit() : bindings( 0 ) {}
		BasicInit( SymTab::Indexer &_index ) : bindings( 0 ), index( _index ) {}
		BasicInit( const BasicInit &other ) {
			bindings = other.get_bindings();
			index = other.index;
		}

		~BasicInit() { /* delete bindings; bindings = 0; */ }

		NameAssociation< Expression *, BreakInitializer > *get_bindings() const { return bindings; }
		void set_bindings( NameAssociation< Expression *, BreakInitializer > *newValue ) {
			bindings = newValue;
		}

		bool has_bindings() {
			return ( get_bindings() != 0 || ! stmts.empty() );
		}

		virtual ObjectDecl     *mutate( ObjectDecl *objectDecl )
			{ index.visit( objectDecl ); return objectDecl; }
		virtual TypeDecl       *mutate( TypeDecl *typeDecl )
			{ index.visit( typeDecl ); return typeDecl; }
		virtual TypedefDecl    *mutate( TypedefDecl *typeDecl )
			{ index.visit( typeDecl ); return typeDecl; }
		virtual StructDecl     *mutate( StructDecl *aggregateDecl )
			{ index.visit( aggregateDecl ); return aggregateDecl; }
		virtual UnionDecl      *mutate( UnionDecl *aggregateDecl )
			{ index.visit( aggregateDecl ); return aggregateDecl; }
		virtual EnumDecl       *mutate( EnumDecl *aggregateDecl )
			{ index.visit( aggregateDecl ); return aggregateDecl; }

		virtual Type           *mutate( StructInstType *aggrInst )
			{ index.visit( aggrInst ); return aggrInst; }
		virtual Type           *mutate( UnionInstType *aggrInst )
			{ index.visit( aggrInst ); return aggrInst; }

		virtual CompoundStmt   *mutate(CompoundStmt *compoundStmt);
		virtual Statement *mutate(DeclStmt *declStmt);

		std::list< Statement *> get_statements() const { return stmts;  }

		static void build_statements( NameAssociation< Expression *, BreakInitializer > *assoc, std::string aggName, std::list< Statement *> &stmts );
	  private:
		NameAssociation< Expression *, BreakInitializer > *bindings;
		Statement *assignFromDecl( DeclStmt *declStmt );
		SymTab::Indexer index;
		std::list< Statement *> stmts;

		class Classify {
		  public:
			enum TypeKind { NULL_T, SINGLE_T, COMPOUND_T };
			enum InitKind { NULL_I, SINGLE_I, COMPOUND_I };

			static TypeKind type( Type * );
			static InitKind initializer( Initializer *);

			static NameInCollection *declaration( ObjectDecl *objdecl, SymTab::Indexer *index );
			static std::list< Statement * >
			matchInit( NameInCollection *, ObjectDecl *, Initializer * );
			static Statement *constructAssgn( std::string membname, ObjectDecl *toInit, SingleInit *sinit );

			// static std::list< Statement * > constructListAssgn( NameAssociation<Expression *, BreakDesignator > assoc );
		};
	};

	class BreakInitializer {
		enum InitKind { EMPTY, SINGLE, COMPOUND };

		class BreakDesignator;
		typedef BreakDesignator NameSplitter;

	  public:
		typedef std::list<Initializer *>::iterator element_iterator;
		typedef std::list< NameSplitter >::iterator name_iterator;

		BreakInitializer ( Initializer *_init ) : kind( EMPTY ), sinit(0), cinit(0) {
			std::list<Expression *> temp;

			if ( ( sinit=dynamic_cast< SingleInit * >(_init) ) != 0 ) {
				kind = SINGLE;
				temp = sinit->get_designators();
			} else if ( ( cinit=dynamic_cast< ListInit * >(_init) ) != 0 ) {
				kind = COMPOUND;
				temp = cinit->get_designators();
			} // if

			std::transform( temp.begin(), temp.end(), std::back_inserter( designators ), ctor_noptr<NameSplitter, Expression *> );
		}

		//BreakInitializer( const BreakInitializer &other ) { this.col = other.col; }
		~BreakInitializer () {}

		BreakInitializer set_name( NameSplitter &name ) {
			designators.clear();
			designators.push_back( name );

			return *this;
		}

		element_iterator element_begin() {
			assert( cinit != 0 );
			return cinit->begin_initializers();
		}
		element_iterator element_end() {
			assert( cinit != 0 );
			return cinit->end_initializers();
		}

		name_iterator names_begin() { return designators.begin(); }
		name_iterator names_end() { return designators.end(); }

		int names_size() const { return designators.size(); }

		bool has_index() const { return ! designators.empty(); }
		bool is_single() const { return kind == SINGLE; }
		bool is_composite() const { return kind == COMPOUND;  }

		Expression *get_value() {
			switch ( kind ) {
			  case EMPTY:
				return 0;
				break;
			  case SINGLE:
				return sinit->get_value();
				break;
			  case COMPOUND:
				assert(false);
				break;
			  default:
				assert(false);
			} // switch
			return 0;
		}
		// attributes
	  private:
		InitKind kind;
		SingleInit *sinit;
		ListInit *cinit;
		std::list< BreakDesignator > designators;
		// helper classes
	  public:
		class BreakDesignator {
		  public:
			BreakDesignator( Expression *exp ) {
				Expression *prfx = exp;
				UntypedMemberExpr *me = 0;

				do {
					if ( (me=dynamic_cast< UntypedMemberExpr * >( prfx )) == 0 ) break;
					blown_struct.push_front( me->get_member() );
					prfx = me->get_aggregate();
				} while ( prfx != 0 );

				NameExpr *ne;
				if ( (ne=dynamic_cast< NameExpr * >( prfx )) != 0 ) 
					blown_struct.push_front( ne->get_name() );
			}

			BreakDesignator( std::string name ) {
				blown_struct.push_front( name );
			}

			bool is_flat() const { return blown_struct.size() == 1; }
			bool is_nested() const { return blown_struct.size() > 1; }

			std::string get_name() { return blown_struct.front(); }

			BreakDesignator &name_remainder() {
				blown_struct.pop_front();
				return *this;
			}

		  private:
			std::list< std::string > blown_struct;
		};
	};
} // namespace InitTweak

#endif // _BASINIT_H_

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