/* $Id$ 
 * TopDownVisitor: Base class of Visitors that need a standard (top-down)
 * traversal.
 *
 * 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.
 */


#include <iostream>

#include "frontend/visitor/TopDownVisitor.hpp"
#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/ConstReal.hpp"
#include "frontend/ast/ConstArray.hpp"
#include "frontend/ast/Entity.hpp"
#include "frontend/ast/SymbolDeclaration.hpp"
#include "frontend/ast/ValDeclaration.hpp"
#include "frontend/ast/SignalDeclaration.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/ast/Expression.hpp"
#include "frontend/ast/IfStat.hpp"
#include "frontend/ast/NullStat.hpp"
#include "frontend/ast/ForLoopStat.hpp"
#include "frontend/ast/WhileLoopStat.hpp"
#include "frontend/ast/NextStat.hpp"
#include "frontend/ast/VarAssignStat.hpp"
#include "frontend/ast/WaitStat.hpp"
#include "frontend/ast/ExitStat.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/WaveFormElem.hpp"
#include "frontend/ast/ReturnStat.hpp"
#include "frontend/ast/ProcCallStat.hpp"
#include "frontend/ast/AssertStat.hpp"
#include "frontend/ast/VarDeclaration.hpp"
#include "frontend/ast/DiscreteRange.hpp"
#include "frontend/ast/CaseStat.hpp"
#include "frontend/ast/CaseAlternative.hpp"
#include "frontend/ast/Others.hpp"
#include "frontend/ast/Architecture.hpp"
#include "frontend/ast/AssociationElement.hpp"
#include "frontend/ast/FunctionDeclaration.hpp"
#include "frontend/ast/ProcedureDeclaration.hpp"
#include "frontend/ast/CompInstStat.hpp"
#include "frontend/ast/Package.hpp"
#include "frontend/ast/PackageBody.hpp"
#include "frontend/ast/Process.hpp"
#include "frontend/ast/SubprogBody.hpp"
#include "frontend/ast/CondalSigAssign.hpp"
#include "frontend/ast/EnumerationType.hpp"
#include "frontend/ast/PhysicalType.hpp"
#include "frontend/ast/PhysicalTypeUnit.hpp"
#include "frontend/ast/RangeConstraintType.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"
#include "frontend/ast/RecordType.hpp"
#include "frontend/ast/Aggregate.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/ElementAssociation.hpp"
#include "frontend/ast/SubtypeIndication.hpp"
#include "frontend/ast/Library.hpp"
#include "frontend/ast/LibraryList.hpp"
#include "frontend/ast/Subscript.hpp"
#include "frontend/ast/Slice.hpp"
#include "frontend/ast/TypeConversion.hpp"
#include "frontend/ast/SimpleName.hpp"
#include "frontend/ast/TemporaryName.hpp"
#include "frontend/ast/SelectedName.hpp"
#include "frontend/ast/AttributeName.hpp"
#include "frontend/ast/AttributeDeclaration.hpp"
#include "frontend/ast/AttributeSpecification.hpp"

namespace ast {

int TopDownVisitor::visits = 0;

TopDownVisitor::TopDownVisitor() 
{
	TopDownVisitor::visits += 1;
}

void
TopDownVisitor::visit(ElementAssociation &node)
{
	this->process(node);
	if (node.choices != NULL) {
		this->listTraverse(*node.choices);
	}

	if (node.actual != NULL) {
		node.actual->accept(*this);
	}
}

void
TopDownVisitor::visit(ConstInteger &node)
{
	//FIXME
	this->process(node);
}

void
TopDownVisitor::visit(ConstReal &node)
{
	this->process(node);
}

void
TopDownVisitor::visit(ConstArray &node)
{
	this->process(node);
	for (std::vector<ConstInteger*>::iterator i = node.elements->begin();
		i != node.elements->end(); i++) {

		(*i)->accept(*this);
	}
}

void
TopDownVisitor::visit(SimpleName &node)
{
	this->process(node);
}

void
TopDownVisitor::visit(SelectedName &node)
{
	this->process(node);
}

void
TopDownVisitor::visit(AttributeName &node)
{
	this->process(node);
}

void
TopDownVisitor::visit(TemporaryName &node)
{
	this->process(node);
}


void
TopDownVisitor::visit(Entity& node)
{
	this->process(node);

	/* traverse generics */
	if (node.generics != NULL) {
		this->listTraverse(*node.generics);
	}

	/* traverse ports */
	if (node.ports != NULL) {
		this->listTraverse(*node.ports);
	}
}

void
TopDownVisitor::visit(SignalDeclaration& node)
{
	this->process(node);
}

void
TopDownVisitor::visit(ConstantDeclaration& node)
{
	this->process(node);
}

void
TopDownVisitor::visit(FunctionCall& node)
{
	this->process(node);

	if (node.subprog) {
		node.subprog->accept(*this);
	}

	if (node.arguments) {
		this->listTraverse(*node.arguments);
	}

}

void
TopDownVisitor::visit(IfStat &node)
{
	this->process(node);

	if (node.thenStats) {
		this->listTraverse(*node.thenStats);
	}

	if (node.elseStats) {
		this->listTraverse(*node.elseStats);
	}
}

void
TopDownVisitor::visit(NullStat& node)
{
	this->process(node);
}

void
TopDownVisitor::visit(ForLoopStat &node)
{
	this->process(node);

	if (node.loopVariable != NULL) {
		node.loopVariable->accept(*this);
	}
	
	/* traverse to discrete range */
	if (node.range != NULL) {
		node.range->accept(*this);
	}
}

void
TopDownVisitor::visit(WhileLoopStat &node)
{
	this->process(node);

	/* traverse condition */
	if (node.condition) {
		node.condition->accept(*this);
	}
}

void 
TopDownVisitor::visit(NextStat &node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(VarAssignStat& node) 
{
	this->process(node);

	/* traverse to target */
	if (node.target) {
		node.target->accept(*this);
	}
	
	/* traverse to source */
	if (node.source) {
		node.source->accept(*this);
	}
}

void 
TopDownVisitor::visit(WaitStat& node) 
{
	this->process(node);

	/* traverse to Sensitivity list */
	if (node.sensitivities) {
		this->listTraverse(*node.sensitivities);
	}
	
	/* traverse to timeout */
	if (node.timeout) {
		node.timeout->accept(*this);
	}
}

void 
TopDownVisitor::visit(ExitStat& node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(SigAssignStat& node) 
{
	this->process(node);

	/* traverse to target */
	if (node.target != NULL) {
		node.target->accept(*this);
	}
	
	/* traverse to waveForm */
	if (node.waveForm != NULL) {
		this->listTraverse(*node.waveForm);
	}
}

void 
TopDownVisitor::visit(WaveFormElem& node) 
{
	this->process(node);

	/* traverse to value */
	if (node.value != NULL) {
		node.value->accept(*this);
	}
	
	/* traverse to delay */
	if (node.delay != NULL) {
		node.delay->accept(*this);
	}
}

void 
TopDownVisitor::visit(ReturnStat& node) 
{
	this->process(node);

	/* traverse to result */
	if (node.result != NULL) {
		node.result->accept(*this);
	}
}

void 
TopDownVisitor::visit(ProcCallStat& node) 
{
	this->process(node);

	/* traverse to arguments */
	if (node.arguments != NULL) {
		this->listTraverse(*node.arguments);
	}

	/* traverse to referring symbol */
	if (node.subprog != NULL) {
		node.subprog->accept(*this);
	}
}

void 
TopDownVisitor::visit(AssertStat& node) 
{
	this->process(node);

	/* traverse to report expression */
	if (node.report != NULL) {
		node.report->accept(*this);
	}

	/* traverse to severity expression */
	if (node.severity != NULL) {
		node.severity->accept(*this);
	}
}

void 
TopDownVisitor::visit(VarDeclaration& node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(DiscreteRange& node) 
{
	this->process(node);

	/* traverse to from */
	if (node.from != NULL) {
		node.from->accept(*this);
	}

	/* traverse to */
	if (node.to != NULL) {
		node.to->accept(*this);
	}
}


void 
TopDownVisitor::visit(CaseStat& node) 
{
	this->process(node);

	/* traverse to select */
	if (node.select != NULL) {
		node.select->accept(*this);
	}

	/* traverse to alternatives */
	if (node.alternatives != NULL) {
		this->listTraverse(*node.alternatives);
	}
}

void 
TopDownVisitor::visit(CaseAlternative& node) 
{
	this->process(node);

	/* traverse to isVals */
	if (node.isVals != NULL) {
		this->listTraverse(*node.isVals);
	}

	/* traverse to thenStats */
	if (node.thenStats != NULL) {
		this->listTraverse(*node.thenStats);
	}
}

void 
TopDownVisitor::visit(Others &node)
{
	this->process(node);
}

void 
TopDownVisitor::visit(Architecture &node) 
{
	this->process(node);

	/* traverse to concurrentStats */
	if (node.concurrentStats != NULL) {
		this->listTraverse(*node.concurrentStats);
	}
}

void 
TopDownVisitor::visit(AssociationElement& node) 
{
	this->process(node);

	/* traverse to formalPart */
	if (node.formal != NULL) {
		node.formal->accept(*this);
	}

	/* traverse to actual */
	if (node.actual != NULL) {
		node.actual->accept(*this);
	}
}

void 
TopDownVisitor::visit(FunctionDeclaration& node) 
{
	this->process(node);

	if (node.returnType != NULL) {
		node.returnType->accept(*this);
	}
}

void 
TopDownVisitor::visit(ProcedureDeclaration& node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(CompInstStat& node) 
{
	this->process(node);

	/* traverse to entityName */
	if (node.entityName != NULL) {
		node.entityName->accept(*this);
	}

	/* traverse to genericMap */
	if (node.genericMap != NULL) {
		this->listTraverse(*node.genericMap);
	}

	/* traverse to portMap */
	if (node.portMap != NULL) {
		this->listTraverse(*node.portMap);
	}
}

void 
TopDownVisitor::visit(Package& node) 
{
	this->process(node);

	if (node.body != NULL) {
		node.body->accept(*this);
	}
}

void 
TopDownVisitor::visit(PackageBody& node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(Process &node)
{
	this->process(node);

	if (node.sensitivityList != NULL) {
		this->listTraverse(*node.sensitivityList);
	}

	if (node.declarations != NULL) {
		this->listTraverse(*node.declarations);
	}

	if (node.seqStats != NULL) {
		this->listTraverse(*node.seqStats);
	}
}

void 
TopDownVisitor::visit(SubprogBody& node) 
{
	this->process(node);

	if (node.declarations != NULL) {
		this->listTraverse(*node.declarations);
	}

	if (node.seqStats != NULL) {
		this->listTraverse(*node.seqStats);
	}

}

void 
TopDownVisitor::visit(CondalSigAssign& node) 
{
	this->process(node);

	if (node.target != NULL) {
		node.target->accept(*this);
	}

	if (node.assignStat != NULL) {
		node.assignStat->accept(*this);
	}
}

void 
TopDownVisitor::visit(EnumerationType& node) 
{
	this->process(node);
}

void 
TopDownVisitor::visit(PhysicalType& node) 
{
	this->process(node);

	if (node.constraint != NULL) {
		node.constraint->accept(*this);
	}

	if (node.units != NULL) {
		this->listTraverse(*node.units);
	}
}

void 
TopDownVisitor::visit(PhysicalTypeUnit& node) 
{
	this->process(node);

	if (node.physUnit != NULL) {
		node.physUnit->accept(*this);
	}
}

void 
TopDownVisitor::visit(RangeConstraintType& node) 
{
	this->process(node);

	if (node.constraint != NULL) {
		node.constraint->accept(*this);
	}
}

void 
TopDownVisitor::visit(UnconstrainedArrayType& node) 
{
	this->process(node);

	if (node.indexTypes != NULL) {
		this->listTraverse(*node.indexTypes);
	}

	if (node.elementType != NULL) {
		node.elementType->accept(*this);
	}
}

void 
TopDownVisitor::visit(RecordType& node) 
{
	this->process(node);

	if (node.elements != NULL) {
		this->listTraverse(*(node.elements));
	}

}

void
TopDownVisitor::visit(RecordTypeElement& node)
{
	this->process(node);

	if (node.subtype) {
		node.subtype->accept(*this);
	}
}

void
TopDownVisitor::visit(Aggregate& node)
{
	this->process(node);

	if (node.associations) {
		this->listTraverse(*node.associations);
	}
}

void
TopDownVisitor::visit(SubtypeIndication& node)
{
	this->process(node);

	if (node.typeName) {
		node.typeName->accept(*this);
	}

	if (node.constraint) {
		node.constraint->accept(*this);
	}

	if (node.indexConstraint != NULL) {
		this->listTraverse(*node.indexConstraint);
	}
}

void
TopDownVisitor::visit(Library& node)
{
	this->process(node);
	this->listTraverse(node.units);
}

void
TopDownVisitor::visit(LibraryList& node)
{
	this->process(node);
	this->listTraverse(node.libraries);
}

void
TopDownVisitor::visit(Subscript& node)
{
	this->process(node);

	if (node.source) {
		node.source->accept(*this);
	}
}

void
TopDownVisitor::visit(Slice &node)
{
	this->process(node);

	if (node.source) {
		node.source->accept(*this);
	}

	if (node.range) {
		node.range->accept(*this);
	}
}

void
TopDownVisitor::visit(TypeConversion &node) 
{
	this->process(node);

	if (node.source) {
		node.source->accept(*this);
	}
}

void
TopDownVisitor::visit(AttributeDeclaration &node)
{
	this->process(node);
}

void
TopDownVisitor::visit(AttributeSpecification &node)
{
	this->process(node);

	assert(node.init != NULL);
	node.init->accept(*this);
}


void
TopDownVisitor::process(AstNode &node)
{
}

void
TopDownVisitor::process(ValDeclaration& node)
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	SymbolDeclaration& sNode = static_cast<SymbolDeclaration&>(node);
	this->process(sNode);

	/* traverse to initializer */
	if (node.init != NULL) {
		node.init->accept(*this);
	}

	/* traverse to subtype indic */
	if (node.subtypeIndic != NULL) {
		node.subtypeIndic->accept(*this);
	}
}

void
TopDownVisitor::process(SymbolDeclaration& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	AstNode& aNode = static_cast<AstNode&>(node);
	
	this->process(aNode);
}

void
TopDownVisitor::process(Expression& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	AstNode& aNode = static_cast<AstNode&>(node);
	
	this->process(aNode);
}

void
TopDownVisitor::process(SeqStat& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	AstNode& anode = static_cast<AstNode&>(node);
	
	this->process(anode);
}

void
TopDownVisitor::process(LoopStat& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	SeqStat& snode = static_cast<SeqStat&>(node);
	
	this->process(snode);

	/* taverse to loopStats */
	if (node.loopStats != NULL) {
		this->listTraverse(*node.loopStats);
	}
}

void
TopDownVisitor::process(ConditionedStat& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	SeqStat& snode = static_cast<SeqStat&>(node);
	
	this->process(snode);

	/* taverse to condition */
	if (node.condition != NULL) {
		node.condition->accept(*this);
	}
}

void
TopDownVisitor::process(Callable &node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	SymbolDeclaration& snode = static_cast<SymbolDeclaration&>(node);
	
	this->process(snode);

	/* taverse to arguments */
	if (node.arguments != NULL) {
		this->listTraverse(*node.arguments);
	}

	/* traverse to definition */
	if (node.definition != NULL) {
		node.definition->accept(*this);
	}
}

void
TopDownVisitor::process(LibUnit &node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	AttributableDeclaration& snode = 
		static_cast<AttributableDeclaration&>(node);
	
	this->process(snode);

	/* taverse to useClauses */
	if (node.useClauses != NULL) {
		this->listTraverse(*node.useClauses);
	}
	
	if (node.declarations != NULL) {
		this->listTraverse(*node.declarations);
	}
}

void
TopDownVisitor::process(TypeDeclaration& node) 
{
	/* up one class in hierarchy... this cast must never fail, or the 
	 * class hierarchy is wrong. */
	SymbolDeclaration& snode = static_cast<SymbolDeclaration&>(node);
	
	this->process(snode);
}

void
TopDownVisitor::process(Name &node)
{
	Expression &e = static_cast<Expression&>(node);
	this->process(e);
}

void
TopDownVisitor::process(PrefixedName &node)
{
	Name &n = static_cast<Name&>(node);
	this->process(n);

	if (node.prefix) {
		node.prefix->accept(*this);
	}
}

void
TopDownVisitor::process(AttributableDeclaration &node)
{
	SymbolDeclaration &snode = static_cast<SymbolDeclaration &>(node);
	this->process(snode);
}



}; /* namespace ast */
