/* $Id$
 *
 * DiscreteRange: AST node for a discrete range.
 *
 * Copyright (C) 2007-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 __DISCRETE_RANGE_HPP_INCLUDED
#define __DISCRETE_RANGE_HPP_INCLUDED

#include "frontend/ast/Name.hpp"
#include <stdexcept>

namespace ast {

//! a VHDL discrete range.
class DiscreteRange : public Expression {
public:
	/** This is a VHDL direction, either up or down.
	 */
	enum Direction {
		/** downwards (downto) */
		DIRECTION_DOWN		= -1,
		/** upwards (to) */
		DIRECTION_UP		= 1,
	};

	//! c'tor
	/** @param first first argument to DiscreteRange.
	 *  @param second second argument to DiscreteRange.
	 *  @param direct direction of the range.
	 *  @param loc location of the DiscreteRange.
	 */
	DiscreteRange(
		Expression *first,
		Expression *second,
		enum Direction direct,
		Location loc
		) :	Expression(loc),
			from(first),
			to(second),
			direction(direct),
			rangeName(NULL) {}

	//! alternate c'tor for range by subytpe indication
	/** @param si SubtypeIndication referring to a range constraint type.
	 *  @param loc location of the DiscreteRange.
	 */
	DiscreteRange(
		SubtypeIndication *si,
		Location loc);
			
	//! Accept a Visitor.
	/** All leaf AST nodes need to implement this method.
         *
         *  @param visitor the Visitor that can visit this node.
         */
	virtual void accept(Visitor& visitor) {
		visitor.visit(*this);
	}

	/** Put a textual representation of the AstNode on the stream.
	 *  @param stream stream to put the textual representation to.
	 */
	virtual void put(std::ostream &stream) const;

	/** determine the size of the array.
	 *  @return size of the array
	 */
	universal_integer getArraySize(void) const;

	/** determine the lower bound of the array.
	 *  @return lower bound of the array.
	 */
	universal_integer getLowerBound(void) const;

	/** determine the upper bound of the array.
	 *  @return upper bound of the array.
	 */
	universal_integer getUpperBound(void) const;

	/** determine the left bound of the array.
	 *  @return left bound of the array.
	 */
	universal_integer getLeftBound(void) const;

	/** determine the right bound of the array.
	 *  @return right bound of the array.
	 */
	universal_integer getRightBound(void) const;

	/** determine the direction of the array. Mainly for convenience, 
	 *  direction holds the same information.
	 *  @return direction of the array (-1 for downto, 1 for to).
	 */
	universal_integer getDirection(void) const {
		return this->direction;
	}

	/** from bound of the DiscreteRange */
	Expression *from;
	/** to bound of the DiscreteRange */
	Expression *to;
	/** direction of the range */
	enum Direction direction;

	/** optional range by range_attribute_name or
	 *  Other members should get set when
	 *  evaluating the name */
	Name *rangeName;

protected:
	/** Destructor */
	virtual ~DiscreteRange() {
		util::MiscUtil::terminate(from);
		util::MiscUtil::terminate(to);
		util::MiscUtil::terminate(rangeName);
	}

private:
	/** set from and to via range by SubtypeIndication 
	 *  @param si SubtypeIndication referring to a constraint type. */
	void 
	setFromAndTo(const SubtypeIndication *si)
		/* throw(std::runtime_error) */;
};

}; /* namespace ast */

#endif /* __DISCRETE_RANGE_HPP_INCLUDED */
