#include <list>
#include <cassert>

#include "SynTree/Type.h"
#include "SynTree/Statement.h"
#include "SynTree/Expression.h"
#include "SynTree/Declaration.h"

#include "LabelTypeChecker.h"


namespace ControlStruct {
    void LabelTypeChecker::visit(UntypedExpr *untypedExpr){
	assert( untypedExpr != 0 );
	NameExpr *fname;
	if ( ((fname = dynamic_cast<NameExpr *>(untypedExpr->get_function())) != 0) 
	    && fname->get_name() == std::string("LabAddress") )
	    std::cerr << "Taking the label of an address." << std::endl;
	else {
	    acceptAll( untypedExpr->get_results(), *this );
	    acceptAll( untypedExpr->get_args(), *this );
	} // if
	return;
    }

    void LabelTypeChecker::visit(CompoundStmt *compoundStmt) {
	index.enterScope();
	acceptAll( compoundStmt->get_kids(), *this );
	index.leaveScope();
    }

    void LabelTypeChecker::visit(DeclStmt *declStmt){
	declStmt->accept( index );

	//ObjectDecl *odecl = 0;
	// if ( ( odecl = dynamic_cast<ObjectDecl *>(declStmt->get_decl()) ) != 0 ){
	return;
    }

    void LabelTypeChecker::visit(BranchStmt *branchStmt) {
	if ( branchStmt->get_type() != BranchStmt::Goto ) return;
	Expression *target;
	if ( (target = branchStmt->get_computedTarget()) == 0 ) return;

	NameExpr *name;
	if ( ((name = dynamic_cast<NameExpr *>(target)) == 0) )
	    return; // Not a name expression
    
	std::list< DeclarationWithType * > interps;
	index.lookupId(name->get_name(), interps);
	if ( interps.size() != 1)
	    // in case of multiple declarations
	    throw SemanticError("Illegal label expression: " + name->get_name() );

	PointerType *ptr;
	if ( (ptr = dynamic_cast<PointerType *>(interps.front()->get_type())) != 0 )
	    if ( dynamic_cast<VoidType *>(ptr->get_base()) != 0 )
		return;
	    else
		throw SemanticError("Wrong type of parameter for computed goto");
	else
	    throw SemanticError("Wrong type of parameter for computed goto");

	return;
    }
} // namespace ControlStruct
