//
// 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.
//
// MLEMutator.h --
//
// Author           : Rodolfo G. Esteves
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Sat Jul 22 09:19:59 2017
// Update Count     : 35
//

#pragma once

#include <list>                    // for list
#include <map>                     // for map
#include <string>                  // for string

#include "Common/PassVisitor.h"
#include "Common/SemanticError.h"  // for SemanticError
#include "SynTree/Label.h"         // for Label
#include "SynTree/Mutator.h"       // for Mutator
#include "SynTree/SynTree.h"       // for Visitor Nodes

namespace ControlStruct {
	class LabelGenerator;

	class MLEMutator : public WithVisitorRef<MLEMutator>, public WithShortCircuiting {
		class Entry;

	  public:
		MLEMutator( std::map<Label, Statement *> *t, LabelGenerator *gen = 0 ) : targetTable( t ), breakLabel(std::string("")), generator( gen ) {}
		~MLEMutator();

		void premutate( CompoundStmt *cmpndStmt );
		Statement * postmutate( BranchStmt *branchStmt ) throw ( SemanticError );
		void premutate( WhileStmt *whileStmt );
		Statement * postmutate( WhileStmt *whileStmt );
		void premutate( ForStmt *forStmt );
		Statement * postmutate( ForStmt *forStmt );
		void premutate( CaseStmt *caseStmt );
		void premutate( IfStmt *ifStmt );
		Statement * postmutate( IfStmt *ifStmt );
		void premutate( SwitchStmt *switchStmt );
		Statement * postmutate( SwitchStmt *switchStmt );

		Statement *mutateLoop( Statement *bodyLoop, Entry &e );

		Label &get_breakLabel() { return breakLabel; }
		void set_breakLabel( Label newValue ) { breakLabel = newValue; }
	  private:
		class Entry {
		  public:
			explicit Entry( Statement *_loop, Label _breakExit, Label _contExit = Label("") ) :
				loop( _loop ), breakExit( _breakExit ), contExit( _contExit ), breakUsed(false), contUsed(false) {}

			bool operator==( const Statement *stmt ) { return loop == stmt; }
			bool operator!=( const Statement *stmt ) { return loop != stmt; }

			bool operator==( const Entry &other ) { return loop == other.get_controlStructure(); }

			Statement *get_controlStructure() const { return loop; }

			Label useContExit() { contUsed = true; return contExit; }
			Label useBreakExit() { breakUsed = true; return breakExit; }

			bool isContUsed() const { return contUsed; }
			bool isBreakUsed() const { return breakUsed; }
		  private:
			Statement *loop;
			Label breakExit, contExit;
			bool breakUsed, contUsed;
		};

		std::map< Label, Statement * > *targetTable;
		std::list< Entry > enclosingControlStructures;
		Label breakLabel;
		LabelGenerator *generator;

		template< typename LoopClass >
		void prehandleLoopStmt( LoopClass * loopStmt );

		template< typename LoopClass >
		Statement * posthandleLoopStmt( LoopClass * loopStmt );

		void fixBlock( std::list< Statement * > &kids );
	};
} // namespace ControlStruct

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