/* $Id$ 
 * ConstantPropagation: propagate results of constant expressions.
 *
 * 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 __CONSTANT_PROPAGATION_HPP_INCLUDED
#define __CONSTANT_PROPAGATION_HPP_INCLUDED

#include <list>
#include "frontend/visitor/TopDownVisitor.hpp"
#include "frontend/ast/Types.hpp"

namespace ast {

//! evaluate constant expressions and propagate constant values.
/** @todo * set nodes for
 *          - index expressions
 *          - slices
 *          - ranges
 *          - initializer expressions
 *          - if conditions
 *          - assign statements
 *          - etc.
 *        * propagate constants in a process/function
 *        * what else?
 */
class ConstantPropagation : public TopDownVisitor {
public:
	ConstantPropagation();

private:
	/** visit a ConstInteger
         *  @param node node that get's visited.
         */
	virtual void visit(ConstInteger &node);

	/** visit a ConstReal
         *  @param node node that get's visited.
         */
	virtual void visit(ConstReal &node);

	/** visit a FunctionCall
         *  @param node node that get's visited.
         */
	virtual void visit(FunctionCall &node);

	/** Visit a VarAssignStat
	 *  @param node VarAssignStat node that get's visited.
	 */
	virtual void visit(VarAssignStat &node);

	/** Visit a SigAssignStat
	 *  @param node SigAssignStat node that get's visited.
	 */
	virtual void visit(SigAssignStat &node);

	/** visit a WaveFormElem
         *  @param node node that get's visited.
         */
	virtual void visit(WaveFormElem &node);

	/** Visit a WhileLoopStat
	 *  @param node WhileLoopStat node that get's visited.
	 */
	virtual void visit(WhileLoopStat &node);

	/** Visit a Subscript node.
	 *  @param node Subscript node that get's visited.
	 */
	virtual void visit(Subscript &node);

	/** Visit a Slice node.
	 *  @param node Slice node that get's visited.
	 */
	virtual void visit(Slice &node);

	/** Visit a TypeConversion node.
	 *  @param node TypeConversion node that get's visited.
	 */
	virtual void visit(TypeConversion &node);

	/** Visit a SimpleName node.
	 *  @param node SimpleName node that get's visited.
	 */
	virtual void visit(SimpleName &node);

	/** Visit a SelectedName node.
	 *  @param node SelectedName node that get's visited.
	 */
	virtual void visit(SelectedName &node);

	/** Visit an AttributeName node.
	 *  @param node AttributeName node that get's visited.
	 */
	virtual void visit(AttributeName &node);

	/** visit a TemporaryName
         *  @param node node that get's visited.
         */
	virtual void visit(TemporaryName &node);

	/** Visit a WaitStat
	 *  @param node WaitStat node that get's visited.
	 */
	virtual void visit(WaitStat &node);

	/** Visit a ReturnStat
	 *  @param node ReturnStat node that get's visited.
	 */
	virtual void visit(ReturnStat &node);

	/** Visit a AssertStat
	 *  @param node AssertStat node that get's visited.
	 */
	virtual void visit(AssertStat &node);

	/** Visit a DiscreteRange
	 *  @param node DiscreteRange node that get's visited.
	 */
	virtual void visit(DiscreteRange &node);

	/** Visit a CaseStat
	 *  @param node CaseStat node that get's visited.
	 */
	virtual void visit(CaseStat &node);

	/** Visit a CaseAlternative
	 *  @param node CaseAlternative node that get's visited.
	 */
	virtual void visit(CaseAlternative& node);

	/** Visit an Aggregate
	 *  @param node Aggregate node that get's visited.
	 */
	virtual void visit(Aggregate &node);

	/** Visit an AttributeSpecification node.
	 *  @param node AttributeSpecification node that gets visited.
	 */
	virtual void visit(AttributeSpecification &node);

	/** Visit a AssociationElement node.
	 *  @param node AssociationElement node that get's visited.
	 */
	virtual void visit(AssociationElement &node);

	//! Process a generic AstNode.
        /** This function will get called for each AstNode
         *  that get's visited.
         *
         *  @param node AstNode
         */
	virtual void process(AstNode &node);

	//! Process a generic ValDeclaration.
        /** This function will get called for each ValDeclaration (or class 
         *  derived from ValDeclaration) that get's visited.
         *
         *  @param node ValDeclaration instance.
         */
	virtual void process(ValDeclaration &node);

	//! Process a generic ConditionedStat.
        /** This function will get called for each ConditionedStat (or class
         *  derived from ConditionedStat) that get's visited.
         *
         *  @param node ConditionedStat instance.
         */
	virtual void process(ConditionedStat &node);

	//! try to reduce a builtin function call to a constant node.
	/** @param node FunctionCall with a builtin definition.
	 *  @param args constant positional parameter list.
	 */
	void 
	optimizeBuiltin(FunctionCall &node, std::list<Expression*> args);

	//! set node to the replacement in ConstValue
	/** @param node: reference to pointer to node, that should get 
	 * 		replaced.
	 *  @return true: if node is afterwards const (or was const before).
	 */
	bool setNode(Expression *&node) const;

	/** reset constValue */
	void reset(void);

	/** traverse (and optimize) a list of expressions
	 *  @param l list of Expressions to optimize. Will do nothing, if 
	 *         l is NULL.
	 *  @return true if all of the list were constants, false otherwise
	 *          (also false if the list is NULL).
	 */
	bool listOptimize(std::list<Expression*> *l);

	/** determine the corresponding ElementAssociation for an index
	 *  position. RangeSet's (via ResolveAggregates) must have been
	 *  set before.
	 *  @param index index position.
	 *  @param node corresponding aggregate
	 *  @return corresponding ElementAssociation, or NULL if not
	 *          found/error.
	 */
	ElementAssociation *
	findAggregateAssoc(universal_integer index, Aggregate &node) const;

	/** generate a constraint array type for a ConstArray.
	 *  @param haveType needed base type (may be constraint already)
	 *  @param numElems number of array elements
	 *  @return if haveType is already constraint, returns haveType.
	 *          Otherwise, a new constraint type is created, which
	 *          is constraint from 0 to elements - 1. The former
	 *          implicitely creates a subtype conversion.
	 */
	static TypeDeclaration *
	makeCAType(TypeDeclaration *haveType, size_t numElems);

	/** either the picked up constant, or NULL */
	Expression *constValue;
};

}; /* namespace ast */

#endif /* __CONSTANT_PROPAGATION_HPP_INCLUDED */
