/* $Id$
 *
 * Perform a standard traversal on the intermediate code.
 *
 * Copyright (C) 2010 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 "intermediate/visitor/StandardTraversal.hpp"
#include "intermediate/opcodes/Connect.hpp"
#include "intermediate/opcodes/Je.hpp"
#include "intermediate/opcodes/Jne.hpp"
#include "intermediate/opcodes/Jb.hpp"
#include "intermediate/opcodes/Jbe.hpp"
#include "intermediate/opcodes/Jmp.hpp"
#include "intermediate/opcodes/Mov.hpp"
#include "intermediate/opcodes/Abort.hpp"
#include "intermediate/opcodes/Add.hpp"
#include "intermediate/opcodes/Sub.hpp"
#include "intermediate/opcodes/IMul.hpp"
#include "intermediate/opcodes/Div.hpp"
#include "intermediate/opcodes/Call.hpp"
#include "intermediate/opcodes/Return.hpp"
#include "intermediate/opcodes/Proc.hpp"
#include "intermediate/opcodes/Update.hpp"
#include "intermediate/opcodes/GetSig.hpp"
#include "intermediate/opcodes/GetSimTime.hpp"
#include "intermediate/opcodes/ROffset.hpp"
#include "intermediate/opcodes/AOffset.hpp"
#include "intermediate/opcodes/Suspend.hpp"
#include "intermediate/opcodes/WakeOn.hpp"
#include "intermediate/opcodes/WakeAt.hpp"
#include "intermediate/opcodes/Log.hpp"
#include "intermediate/opcodes/BeginTransfer.hpp"
#include "intermediate/opcodes/EndTransfer.hpp"
#include "intermediate/opcodes/SetParam.hpp"
#include "intermediate/opcodes/GetParam.hpp"
#include "intermediate/operands/ImmediateOperand.hpp"
#include "intermediate/operands/IndirectOperand.hpp"
#include "intermediate/operands/Reference.hpp"
#include "intermediate/operands/Register.hpp"
#include "intermediate/container/CodeContainer.hpp"
#include "intermediate/container/Label.hpp"
#include "intermediate/container/Data.hpp"
#include "intermediate/container/TypeElement.hpp"
#include "intermediate/container/Type.hpp"

namespace intermediate {

StandardTraversal::StandardTraversal() 
{
}

void
StandardTraversal::visit(CodeContainer &node)
{
	this->listTraverse(node.typeDefinitions);
	this->listTraverse(node.transferData);
	this->listTraverse(node.stackData);
	this->listTraverse(node.children);
	this->listTraverse(node.code);
}

void
StandardTraversal::visit(ImmediateOperand &node)
{
	// leaf node
}

void
StandardTraversal::visit(BeginTransfer &node)
{
	node.src->accept(*this);
	node.comp->accept(*this);
}

void
StandardTraversal::visit(EndTransfer &node)
{
	node.src->accept(*this);
	node.cleanupStack->accept(*this);
}

void
StandardTraversal::visit(SetParam &node)
{
	node.src->accept(*this);
	node.container->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(GetParam &node)
{
	node.src->accept(*this);
	node.container->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(Connect &node)
{
	node.driver->accept(*this);
	node.signal->accept(*this);
}

void
StandardTraversal::visit(Mov &node)
{
	node.dst->accept(*this);
	node.src->accept(*this);
}


void
StandardTraversal::visit(Je &node)
{
	this->traverseCondJmp(node);
}

void
StandardTraversal::visit(Jbe &node)
{
	this->traverseCondJmp(node);
}

void
StandardTraversal::visit(Jne &node)
{
	this->traverseCondJmp(node);
}

void
StandardTraversal::visit(Jb &node)
{
	this->traverseCondJmp(node);
}

void
StandardTraversal::visit(Jmp &node)
{
	node.trg->accept(*this);
}

void
StandardTraversal::visit(Label &node)
{
	// leaf node
}

void
StandardTraversal::visit(Add &node)
{
	this->traverseBinOp(node);
}


void
StandardTraversal::visit(Abort &node)
{
	// leaf node
}

void
StandardTraversal::visit(Sub &node)
{
	this->traverseBinOp(node);
}

void
StandardTraversal::visit(Call &node)
{
	node.dst->accept(*this);
}

void
StandardTraversal::visit(Return &node)
{
	// leaf node
}

void
StandardTraversal::visit(Proc &node)
{
	node.dst->accept(*this);
}

void
StandardTraversal::visit(Update &node)
{
	node.src->accept(*this);
	node.delay->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(GetSig &node)
{
	node.src->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(GetSimTime &node)
{
	node.dst->accept(*this);
}


void
StandardTraversal::visit(IMul &node)
{
	this->traverseBinOp(node);
}

void
StandardTraversal::visit(Div &node)
{
	this->traverseBinOp(node);
}

void
StandardTraversal::visit(ROffset &node)
{
	node.base->accept(*this);
	node.offset->accept(*this);
	node.rtype->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(AOffset &node)
{
	node.base->accept(*this);
	node.offset->accept(*this);
	node.atype->accept(*this);
	node.dst->accept(*this);
}

void
StandardTraversal::visit(Suspend &node)
{
	// leaf node
}

void
StandardTraversal::visit(WakeOn &node)
{
	node.src->accept(*this);
}

void
StandardTraversal::visit(WakeAt &node)
{
	node.wakeTime->accept(*this);
}

void
StandardTraversal::visit(Log &node)
{
	node.lvl->accept(*this);
	node.c->accept(*this);
}

void
StandardTraversal::visit(IndirectOperand &node)
{
	node.src->accept(*this);
}

void
StandardTraversal::visit(Reference &node)
{
	// leaf node
}

void
StandardTraversal::visit(Register &node)
{
	// leaf node
}

void
StandardTraversal::visit(Data &node)
{
	node.dataType->accept(*this);
}

void
StandardTraversal::visit(Type &node)
{
	this->listTraverse(node.elements);
}

void
StandardTraversal::visit(TypeElement &node)
{
	this->listTraverse(node.init);
}

template <typename T>
void
StandardTraversal::traverseCondJmp(T &node)
{
	node.left->accept(*this);
	node.right->accept(*this);
	node.trg->accept(*this);
}

template <typename T>
void
StandardTraversal::traverseBinOp(T &node)
{
	node.left->accept(*this);
	node.right->accept(*this);
	node.dst->accept(*this);
}

}; /* namespace intermediate */
