/* $Id$ 
 *
 * Generate intermediate code, loop specific parts.
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __GC_LOOPS_HPP_INCLUDED
#define __GC_LOOPS_HPP_INCLUDED

#include <map>
#include "intermediate/container/CodeContainer.hpp"
#include "intermediate/operands/Operand.hpp"
#include "frontend/ast/LoopStat.hpp"

namespace ast {

//! generic class to iterate in a while loop manner
/** This class can be used to generate code in a while-loop like manner.
 *  high level semantics:
 *
 *  initializeCounter();
 *  while (checkCondition()) {
 *  	loopBody();
 *  	incCounter();
 *  }
 *
 *  if/goto pseudo-code:
 *
 *  	initializeCounter();
 *  loopCheck:
 *  	if ! checkCondition() goto loopDone
 *  	loopBody();
 *  loopInc:
 *  	loopInc();
 *  	goto loopCheck;
 *  loopDone:
 */
class WhileIterate {
public:
	//! c'tor
	/** @param container current code container to add code to.
	 */
	WhileIterate(intermediate::CodeContainer &container);

	//! dummy d'tor
	virtual ~WhileIterate();

	//! generate code for the iteration
	/** not meant to be overloaded. */
	void addIteration(void);

protected:
	//! generate code to initialize the counter
	virtual void initializeCounter(void) = 0;

	//! generate code to check the condition
	/** in case the condition is false, jump to loopDone to exit the
	 *  loop.
	 */
	virtual void checkCondition(void) = 0;

	//! generate code for the loop body
	/** the following labels can be used:
	 *  loopInc for a continue semantic
	 *  loopDone for a break semantic
	 */
	virtual void loopBody(void) = 0;

	//! generate code to increase the counter
	virtual void incCounter(void) = 0;

	//! CodeContainer to add generated code to.
	intermediate::CodeContainer &cc;

public:
	/** Label after which the counters are increased
	 *  jump here from the body, to implement a continue semantic.
	 */
	intermediate::Label *loopInc;

	/** Label when the loop has finished.
	 *  jump here from the body, to implement a break semantic.
	 */
	intermediate::Label *loopDone;

private:
	//! generate code for the iteration.
	/** Here, the iteration scheme is defined. Basically, this is just
	 *  a call from addIteration, only enforcing that the iteration scheme
	 *  is not to be modified in subclasses.
	 */
	void genIterateCode(void);
	
	//! Label of the loop condition
	intermediate::Label *loopCheck;
};

//! iterate over a for statement.
class ForLoopIterate : public WhileIterate {
public:
	//! c'tor
	/** @param condition code container to append generated code to.
	 *  @param counter Operand referring to the loop induction variable.
	 *  @param initializer Operand containing the initial counter value.
	 *  @param rightBound right bound of the loop (not necessary upper
	 *         bound).
	 *  @param isAscending true, if the loop is a "TO" loop, false for a 
	 *         "DOWNTO" loop.
	 */
	ForLoopIterate(
		intermediate::CodeContainer &container,
		intermediate::Operand &counter,
		intermediate::Operand &initializer,
		intermediate::Operand &rightBound,
		bool isAscending
		) : 	WhileIterate(container),
			cnt(counter),
			init(initializer),
			rbound(rightBound),
			isAsc(isAscending) {}

protected:
	//! generate code to initialize the counter
	virtual void initializeCounter(void);

	//! generate code to check the condition
	/** in case the condition is false, jump to loopDone to exit the
	 *  loop.
	 */
	virtual void checkCondition(void);

	//! generate code to increase the counter
	virtual void incCounter(void);

	//! counter operand.
	intermediate::Operand &cnt;

	//! initial value of the counter.
	intermediate::Operand &init;

	//! right bound of the loop (inclusive)
	intermediate::Operand &rbound;

	//! is the loop ascending?
	bool isAsc;
};

//! registry containing a mapping between LoopStat AST nodes and WhileIterate
/** This registry can be used to lookup intermediate code loop iterations from
 *  next and exit statements.
 */
class LoopRegistry {
public:
	/** remember a loop statement with the corresponding iterate class.
	 *  @param node AST node
	 *  @param iterate corresponding iterate instance.
	 */
	void rememberLoop(LoopStat *node, WhileIterate *iterate) {
		this->knownLoops[node] = iterate;
	}

	/** forget a mapping between loop statement and corresponding iterate
	 *  class.
	 *  @param node loop statement node to forget.
	 */
	void forgetLoop(LoopStat *node) {
		std::map<LoopStat *, WhileIterate*>::iterator i = 
			this->knownLoops.find(node);
		assert(i != this->knownLoops.end());

		this->knownLoops.erase(i);
	}

	/** lookup the corresponding iterate instance to a loop statement.
	 *  @param node AST loop node for which the corresponding entry should
	 *         get looked up.
	 *  @return corresponding entry.
	 */
	WhileIterate *lookup(LoopStat *node) const {
		std::map<LoopStat *, WhileIterate*>::const_iterator i = 
			this->knownLoops.find(node);
		assert(i != this->knownLoops.end());
		return i->second;
	}

private:
	//! mapping between AST loop statements and iterate instances.
	std::map<LoopStat *, WhileIterate *> knownLoops;
};

}; /* namespace ast */

#endif /* __GC_LOOPS_HPP_INCLUDED */
