/*
 * This file is part of the Cforall project
 *
 * $Id: Mutator.cc,v 1.30 2005/08/29 20:59:25 rcbilson Exp $
 *
 */

#include <cassert>
#include "Mutator.h"
#include "Initializer.h"
#include "Statement.h"
#include "Type.h"
#include "Declaration.h"
#include "Expression.h"
#include "Constant.h"
#include "utility.h"

Mutator::Mutator()
{
}

Mutator::~Mutator()
{
}

ObjectDecl*
Mutator::mutate(ObjectDecl *objectDecl)
{
    objectDecl->set_type( maybeMutate( objectDecl->get_type(), *this ) );
    objectDecl->set_init( maybeMutate( objectDecl->get_init(), *this ) );
    objectDecl->set_bitfieldWidth( maybeMutate( objectDecl->get_bitfieldWidth(), *this ) );
    return objectDecl;
}

DeclarationWithType*
Mutator::mutate(FunctionDecl *functionDecl)
{
    functionDecl->set_functionType( maybeMutate( functionDecl->get_functionType(), *this ) );
    mutateAll( functionDecl->get_oldDecls(), *this );
    functionDecl->set_statements( maybeMutate( functionDecl->get_statements(), *this ) );
    return functionDecl;
}

Declaration*
Mutator::handleAggregateDecl(AggregateDecl *aggregateDecl)
{
    mutateAll( aggregateDecl->get_parameters(), *this );
    mutateAll( aggregateDecl->get_members(), *this );
    return aggregateDecl;
}

Declaration* 
Mutator::mutate(StructDecl *aggregateDecl)
{
    handleAggregateDecl( aggregateDecl );
    return aggregateDecl;
}

Declaration* 
Mutator::mutate(UnionDecl *aggregateDecl)
{
    handleAggregateDecl( aggregateDecl );
    return aggregateDecl;
}

Declaration* 
Mutator::mutate(EnumDecl *aggregateDecl)
{
    handleAggregateDecl( aggregateDecl );
    return aggregateDecl;
}

Declaration* 
Mutator::mutate(ContextDecl *aggregateDecl)
{
    handleAggregateDecl( aggregateDecl );
    return aggregateDecl;
}

Declaration*
Mutator::handleNamedTypeDecl(NamedTypeDecl *typeDecl)
{
    mutateAll( typeDecl->get_parameters(), *this );
    mutateAll( typeDecl->get_assertions(), *this );
    typeDecl->set_base( maybeMutate( typeDecl->get_base(), *this ) );
    return typeDecl;
}

TypeDecl* 
Mutator::mutate(TypeDecl *typeDecl)
{
    handleNamedTypeDecl( typeDecl );
    return typeDecl;
}

Declaration* 
Mutator::mutate(TypedefDecl *typeDecl)
{
    handleNamedTypeDecl( typeDecl );
    return typeDecl;
}

CompoundStmt*
Mutator::mutate(CompoundStmt *compoundStmt)
{
    mutateAll( compoundStmt->get_kids(), *this );
    return compoundStmt;
}

Statement*
Mutator::mutate(ExprStmt *exprStmt)
{
    exprStmt->set_expr( maybeMutate( exprStmt->get_expr(), *this ) );
    return exprStmt;
}

Statement*
Mutator::mutate(IfStmt *ifStmt)
{
    ifStmt->set_condition(  maybeMutate( ifStmt->get_condition(), *this ) );
    ifStmt->set_thenPart(  maybeMutate( ifStmt->get_thenPart(), *this ) );
    ifStmt->set_elsePart(  maybeMutate( ifStmt->get_elsePart(), *this ) );
    return ifStmt;
}

Statement*
Mutator::mutate(WhileStmt *whileStmt)
{
    whileStmt->set_condition(  maybeMutate( whileStmt->get_condition(), *this ) );
    whileStmt->set_body(    maybeMutate( whileStmt->get_body(), *this ) );
    return whileStmt;
}

Statement*
Mutator::mutate(ForStmt *forStmt)
{
    forStmt->set_initialization(    maybeMutate( forStmt->get_initialization(), *this ) );
    forStmt->set_condition(  maybeMutate( forStmt->get_condition(), *this ) );
    forStmt->set_increment(  maybeMutate( forStmt->get_increment(), *this ) );
    forStmt->set_body(	maybeMutate( forStmt->get_body(), *this ) );
    return forStmt;
}

Statement*
Mutator::mutate(SwitchStmt *switchStmt)
{
    switchStmt->set_condition( maybeMutate( switchStmt->get_condition(), *this ) );
    mutateAll( switchStmt->get_branches(), *this );
    return switchStmt;
}

Statement*
Mutator::mutate(ChooseStmt *switchStmt)
{
    switchStmt->set_condition(	maybeMutate( switchStmt->get_condition(), *this ) );
    mutateAll( switchStmt->get_branches(), *this );
    return switchStmt;
}

Statement*
Mutator::mutate(FallthruStmt *fallthruStmt)
{
    return fallthruStmt;
}

Statement*
Mutator::mutate(CaseStmt *caseStmt)
{
    caseStmt->set_condition(	maybeMutate( caseStmt->get_condition(), *this ) );
    mutateAll (caseStmt->get_statements(), *this );

    return caseStmt;
}

Statement*
Mutator::mutate(BranchStmt *branchStmt)
{
    return branchStmt;
}

Statement*
Mutator::mutate(ReturnStmt *returnStmt)
{
    returnStmt->set_expr(  maybeMutate( returnStmt->get_expr(), *this ) );
    return returnStmt;
}

Statement*
Mutator::mutate(TryStmt *tryStmt)
{
    tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) );
    mutateAll( tryStmt->get_catchers(), *this );
    return tryStmt;
}

Statement*
Mutator::mutate(CatchStmt *catchStmt)
{
    catchStmt->set_decl( maybeMutate( catchStmt->get_decl(), *this ) );
    catchStmt->set_body( maybeMutate( catchStmt->get_body(), *this ) );
    return catchStmt;
}

Statement*
Mutator::mutate(FinallyStmt *finalStmt)
{
    finalStmt->set_block( maybeMutate( finalStmt->get_block(), *this ) );
    return finalStmt;
}

NullStmt*
Mutator::mutate(NullStmt *nullStmt)
{
    return nullStmt;
}

Statement*
Mutator::mutate(DeclStmt *declStmt)
{
    declStmt->set_decl( maybeMutate( declStmt->get_decl(), *this ) );
    return declStmt;
}

Expression*
Mutator::mutate(ApplicationExpr *applicationExpr)
{
    mutateAll( applicationExpr->get_results(), *this );
    applicationExpr->set_function(  maybeMutate( applicationExpr->get_function(), *this ) );
    mutateAll( applicationExpr->get_args(), *this );
    return applicationExpr;
}

Expression*
Mutator::mutate(UntypedExpr *untypedExpr)
{
    mutateAll( untypedExpr->get_results(), *this );
    mutateAll( untypedExpr->get_args(), *this );
    return untypedExpr;
}

Expression*
Mutator::mutate(NameExpr *nameExpr)
{
    mutateAll( nameExpr->get_results(), *this );
    return nameExpr;
}

Expression*
Mutator::mutate(AddressExpr *addressExpr)
{
    mutateAll( addressExpr->get_results(), *this );
    addressExpr->set_arg(  maybeMutate( addressExpr->get_arg(), *this ) );
    return addressExpr;
}

Expression*
Mutator::mutate(LabelAddressExpr *labelAddressExpr)
{
    mutateAll( labelAddressExpr->get_results(), *this );
    labelAddressExpr->set_arg(	maybeMutate( labelAddressExpr->get_arg(), *this ) );
    return labelAddressExpr;
}

Expression*
Mutator::mutate(CastExpr *castExpr)
{
    mutateAll( castExpr->get_results(), *this );
    castExpr->set_arg(	maybeMutate( castExpr->get_arg(), *this ) );
    return castExpr;
}

Expression*
Mutator::mutate(UntypedMemberExpr *memberExpr)
{
    mutateAll( memberExpr->get_results(), *this );
    memberExpr->set_aggregate(	maybeMutate( memberExpr->get_aggregate(), *this ) );
    return memberExpr;
}

Expression*
Mutator::mutate(MemberExpr *memberExpr)
{
    mutateAll( memberExpr->get_results(), *this );
    memberExpr->set_aggregate(	maybeMutate( memberExpr->get_aggregate(), *this ) );
    return memberExpr;
}

Expression*
Mutator::mutate(VariableExpr *variableExpr)
{
    mutateAll( variableExpr->get_results(), *this );
    return variableExpr;
}

Expression*
Mutator::mutate(ConstantExpr *constantExpr)
{
    mutateAll( constantExpr->get_results(), *this );
//  maybeMutate( constantExpr->get_constant(), *this )
    return constantExpr;
}

Expression*
Mutator::mutate(SizeofExpr *sizeofExpr)
{
    mutateAll( sizeofExpr->get_results(), *this );
    if( sizeofExpr->get_isType() ) {
	sizeofExpr->set_type(	 maybeMutate( sizeofExpr->get_type(), *this ) );
    } else {
	sizeofExpr->set_expr(	 maybeMutate( sizeofExpr->get_expr(), *this ) );
    }
    return sizeofExpr;
}

Expression*
Mutator::mutate(AttrExpr *attrExpr)
{
    mutateAll( attrExpr->get_results(), *this );
    if( attrExpr->get_isType() ) {
	attrExpr->set_type(	 maybeMutate( attrExpr->get_type(), *this ) );
    } else {
	attrExpr->set_expr(	 maybeMutate( attrExpr->get_expr(), *this ) );
    }
    return attrExpr;
}

Expression*
Mutator::mutate(LogicalExpr *logicalExpr)
{
    mutateAll( logicalExpr->get_results(), *this );
    logicalExpr->set_arg1(  maybeMutate( logicalExpr->get_arg1(), *this ) );
    logicalExpr->set_arg2(  maybeMutate( logicalExpr->get_arg2(), *this ) );
    return logicalExpr;
}

Expression*
Mutator::mutate(ConditionalExpr *conditionalExpr)
{
    mutateAll( conditionalExpr->get_results(), *this );
    conditionalExpr->set_arg1(	maybeMutate( conditionalExpr->get_arg1(), *this ) );
    conditionalExpr->set_arg2(	maybeMutate( conditionalExpr->get_arg2(), *this ) );
    conditionalExpr->set_arg3(	maybeMutate( conditionalExpr->get_arg3(), *this ) );
    return conditionalExpr;
}

Expression*
Mutator::mutate(CommaExpr *commaExpr)
{
    mutateAll( commaExpr->get_results(), *this );
    commaExpr->set_arg1(    maybeMutate( commaExpr->get_arg1(), *this ) );
    commaExpr->set_arg2(    maybeMutate( commaExpr->get_arg2(), *this ) );
    return commaExpr;
}

Expression*
Mutator::mutate(TupleExpr *tupleExpr)
{
    mutateAll( tupleExpr->get_results(), *this );
    mutateAll( tupleExpr->get_exprs(), *this );
    return tupleExpr;
}

Expression*
Mutator::mutate(SolvedTupleExpr *tupleExpr)
{
    mutateAll( tupleExpr->get_results(), *this );
    mutateAll( tupleExpr->get_exprs(), *this );
    return tupleExpr;
}

Expression*
Mutator::mutate(TypeExpr *typeExpr)
{
    mutateAll( typeExpr->get_results(), *this );
    typeExpr->set_type( maybeMutate( typeExpr->get_type(), *this ) );
    return typeExpr;
}

Expression*
Mutator::mutate(UntypedValofExpr *valofExpr)
{
    mutateAll( valofExpr->get_results(), *this );
    return valofExpr;
}

Type*
Mutator::mutate(VoidType *voidType)
{
    mutateAll( voidType->get_forall(), *this );
    return voidType;
}

Type*
Mutator::mutate(BasicType *basicType)
{
    mutateAll( basicType->get_forall(), *this );
    return basicType;
}

Type*
Mutator::mutate(PointerType *pointerType)
{
    mutateAll( pointerType->get_forall(), *this );
    pointerType->set_base( maybeMutate( pointerType->get_base(), *this ) );
    return pointerType;
}

Type*
Mutator::mutate(ArrayType *arrayType)
{
    mutateAll( arrayType->get_forall(), *this );
    arrayType->set_dimension( maybeMutate( arrayType->get_dimension(), *this ) );
    arrayType->set_base( maybeMutate( arrayType->get_base(), *this ) );
    return arrayType;
}

Type*
Mutator::mutate(FunctionType *functionType)
{
    mutateAll( functionType->get_forall(), *this );
    mutateAll( functionType->get_returnVals(), *this );
    mutateAll( functionType->get_parameters(), *this );
    return functionType;
}

Type*
Mutator::handleReferenceToType(ReferenceToType *aggregateUseType)
{
    mutateAll( aggregateUseType->get_forall(), *this );
    mutateAll( aggregateUseType->get_parameters(), *this );
    return aggregateUseType;
}

Type* 
Mutator::mutate(StructInstType *aggregateUseType)
{
    handleReferenceToType( aggregateUseType );
    return aggregateUseType;
}

Type* 
Mutator::mutate(UnionInstType *aggregateUseType)
{
    handleReferenceToType( aggregateUseType );
    return aggregateUseType;
}

Type* 
Mutator::mutate(EnumInstType *aggregateUseType)
{
    handleReferenceToType( aggregateUseType );
    return aggregateUseType;
}

Type* 
Mutator::mutate(ContextInstType *aggregateUseType)
{
    handleReferenceToType( aggregateUseType );
    mutateAll( aggregateUseType->get_members(), *this );
    return aggregateUseType;
}

Type* 
Mutator::mutate(TypeInstType *aggregateUseType)
{
    handleReferenceToType( aggregateUseType );
    return aggregateUseType;
}

Type*
Mutator::mutate(TupleType *tupleType)
{
    mutateAll( tupleType->get_forall(), *this );
    mutateAll( tupleType->get_types(), *this );
    return tupleType;
}

Type*
Mutator::mutate(TypeofType *typeofType)
{
    assert( typeofType->get_expr() );
    typeofType->set_expr( typeofType->get_expr()->acceptMutator( *this ) );
    return typeofType;
}

Type*
Mutator::mutate(AttrType *attrType)
{
    if( attrType->get_isType() ) {
	assert( attrType->get_type() );
	attrType->set_type( attrType->get_type()->acceptMutator( *this ) );
    } else {
	assert( attrType->get_expr() );
	attrType->set_expr( attrType->get_expr()->acceptMutator( *this ) );
    }
    return attrType;
}

Initializer*
Mutator::mutate(MemberInit *memberInit)
{
    memberInit->set_value( memberInit->get_value()->acceptMutator( *this ) );
    return memberInit;
}

Initializer*
Mutator::mutate(ElementInit *elementInit)
{
    elementInit->set_value( elementInit->get_value()->acceptMutator( *this ) );
    return elementInit;
}

Initializer*
Mutator::mutate(SingleInit *singleInit)
{
    singleInit->set_value( singleInit->get_value()->acceptMutator( *this ) );
    return singleInit;
}

Initializer*
Mutator::mutate(ListInit *listInit)
{
    mutateAll( listInit->get_designators(), *this );
    mutateAll( listInit->get_initializers(), *this );
    return listInit;
}

Subrange *
Mutator::mutate(Subrange *subrange)
{
    return subrange;
}

Constant *
Mutator::mutate(Constant *constant)
{
    return constant;
}

