/* $Id$
 *
 * CodeContainer: can contain code and data and subcontainers.
 *
 * 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 __CODE_CONTAINER_HPP_INCLUDED
#define __CODE_CONTAINER_HPP_INCLUDED

#include <list>
#include "intermediate/Node.hpp"
#include "intermediate/container/Data.hpp"
#include "intermediate/container/Type.hpp"
#include "intermediate/operands/RegisterFactory.hpp"

namespace intermediate {

//! can contain arbitrary seqences of code.
/** The CodeContainer can contain various intermediate code, and can be
 *  nested in itself.
 *  The text segment of a code container resembles exactly one function,
 *  which has the same name as the code container itself. The 
 *  transfer segment denotes the parameters passed to the function.
 *  Subcontainers may denote other functions, which however may only
 *  be called from inside the container itself.
 *  The stack segment contains the locals of the funtion.
 */
class CodeContainer : public Node {
public:
	enum DataModeE {
		/** data should get added to the stack segment */
		DATA_STACK,
		/** data should get added to the transfer segment */
		DATA_TRANSFER
	};

	//! c'tor
	/** @param n name of the CodeContainer. The name of the code
	 *         container can be used in Call or Process statements.
	 *  @param parent parent CodeContainer, NULL for the outer most
	 *         CodeContainer.
	 */
	CodeContainer(std::string n, CodeContainer *parent) 
		: name(n),
		dataMode(DATA_STACK),
		regFab(RegisterFactory()),
		nestingLevel(parent == NULL ? 0 : parent->nestingLevel + 1),
		staticParent(parent) {

		if (parent != NULL) {
			parent->children.push_back(this);
		}
	}
	

	//! Accept a Visitor.
 	/** All intermediate code nodes need to implement this method.
         *
         *  @param v the Visitor that can visit this node.
         */
	virtual void accept(Visitor& v) {
		v.visit(*this);
	}

	//! add a piece of intermediate code to the container.
	/** @param n node to add to the container.
	 */
	void addCode(Node *n) {
		this->code.push_back(n);
	}

	//! add data to the container.
	/** @param n data to add to the container.
	 */
	void addData(Data *n) {
		switch (this->dataMode) {
		case DATA_STACK:
			this->stackData.push_back(n);
			break;

		case DATA_TRANSFER:	
			this->transferData.push_back(n);
			break;
		}
		n->nestingLevel = this->nestingLevel;
	}

	//! add a type defintion to the container
	/** @param t type definition to add.
	 */
	void addType(Type *t) {
		this->typeDefinitions.push_back(t);
	}

	//! create a virtual register
	/** @param type type of the virtual register operand
	 *  @return newly created virtual register.
	 */
	Register*
	createRegister(enum OpType type) {
		return this->regFab.getReg(type);
	}

	/** return the number of virtual registers that are used by this
	 *  CodeContainer.
	 *  @return number of used virtual registers.
	 */
	size_t getNumUsedRegs(void) const {
		return this->regFab.getNumUsedRegs();
	}

	/** child code containers. Will get evaluated *before* the current
	 *  container. */
	std::list<CodeContainer*> children;
	/** list of Type definitions covering stack and transfer data. */
	std::list<Type*> typeDefinitions;
	/** data that should be stored on the local stack */
	std::list<Data*> stackData;
	/** transfer data (parameters) */
	std::list<Data*> transferData;
	//! code contained in the container.
	std::list<Node*> code;
	//! name of the container
	std::string name;
	//! default data mode
	enum DataModeE dataMode;
	//! associated RegisterFactory instance.
	RegisterFactory regFab;
	//! nesting level (outmost=0)
	unsigned int nestingLevel;
	//! parent code container
	const CodeContainer *staticParent;

protected:
	virtual ~CodeContainer() {}
}; 

}; /* namespace intermediate */

#endif /* __CODE_CONTAINER_HPP_INCLUDED */
