#pragma once

#define VISIT_START( node )                     \
	__attribute__((unused))                   \
	const auto & guard = init_guard();        \
	call_previsit( node );                    \
	if( visit_children() ) {                  \
		reset_visit();                      \

#define VISIT_END( node )                       \
	}                                         \
	call_postvisit( node );                   \

#define MUTATE_START( node )                    \
	__attribute__((unused))                   \
	const auto & guard = init_guard();        \
	call_premutate( node );                   \
	if( visit_children() ) {                  \
		reset_visit();                      \

#define MUTATE_END( type, node )                \
	}                                         \
	return call_postmutate< type * >( node ); \


#define VISIT_BODY( node )        \
	VISIT_START( node );        \
	Visitor::visit( node );     \
	VISIT_END( node );          \


#define MUTATE_BODY( type, node ) \
	MUTATE_START( node );       \
	Mutator::mutate( node );    \
	MUTATE_END( type, node );   \



template<typename T>
static inline bool empty( T * ptr ) {
	return !ptr || ptr->empty();
}

typedef std::list< Statement * > StmtList_t;

template< typename pass_type >
void PassVisitor< pass_type >::visitStatementList( std::list< Statement * > & statements ) {
	SemanticError errors;

	StmtList_t* beforeStmts = get_beforeStmts();
	StmtList_t* afterStmts  = get_afterStmts();

	for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
		if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); }
		try {
			(*i)->accept( *this );
		} catch ( SemanticError &e ) {
			errors.append( e );
		}
		if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
	}

	if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); }
	if ( !errors.isEmpty() ) { throw errors; }
}

template< typename pass_type >
void PassVisitor< pass_type >::mutateStatementList( std::list< Statement * > & statements ) {
	SemanticError errors;

	StmtList_t* beforeStmts = get_beforeStmts();
	StmtList_t* afterStmts  = get_afterStmts();

	for ( std::list< Statement* >::iterator i = statements.begin(); i != statements.end(); ++i ) {
		if ( !empty( afterStmts ) ) { statements.splice( i, *afterStmts ); }
		try {
			*i = (*i)->acceptMutator( *this );
		} catch ( SemanticError &e ) {
			errors.append( e );
		}
		if ( !empty( beforeStmts ) ) { statements.splice( i, *beforeStmts ); }
	}

	if ( !empty( afterStmts ) ) { statements.splice( statements.end(), *afterStmts ); }
	if ( !errors.isEmpty() ) { throw errors; }
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::visitStatement( Statement * stmt ) {
	// don't want statements from outer CompoundStmts to be added to this CompoundStmt
	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );

	maybeAccept( stmt, *this );

	StmtList_t* beforeStmts = get_beforeStmts();
	StmtList_t* afterStmts  = get_afterStmts();

	if( empty(beforeStmts) && empty(afterStmts) ) { return stmt; }

	CompoundStmt *compound = new CompoundStmt( noLabels );
	if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); }
	compound->get_kids().push_back( stmt );
	if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); }
	return compound;
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutateStatement( Statement * stmt ) {
	// don't want statements from outer CompoundStmts to be added to this CompoundStmt
	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );

	Statement *newStmt = maybeMutate( stmt, *this );

	StmtList_t* beforeStmts = get_beforeStmts();
	StmtList_t* afterStmts  = get_afterStmts();

	if( empty(beforeStmts) && empty(afterStmts) ) { return newStmt; }

	CompoundStmt *compound = new CompoundStmt( noLabels );
	if( !empty(beforeStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *beforeStmts ); }
	compound->get_kids().push_back( newStmt );
	if( !empty(afterStmts) ) { compound->get_kids().splice( compound->get_kids().end(), *afterStmts ); }
	return compound;
}



template< typename pass_type >
void PassVisitor< pass_type >::visitExpression( Expression * expr ) {
	if( !expr ) return;

	auto env_ptr = get_env_ptr();
	if ( env_ptr && expr->get_env() ) {
		*env_ptr = expr->get_env();
	}
	// xxx - should env be cloned (or moved) onto the result of the mutate?
	expr->accept( *this );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutateExpression( Expression * expr ) {
	if( !expr ) return nullptr;

	auto env_ptr = get_env_ptr();
	if ( env_ptr && expr->get_env() ) {
		*env_ptr = expr->get_env();
	}
	// xxx - should env be cloned (or moved) onto the result of the mutate?
	return expr->acceptMutator( *this );
}


//------------------------------------------------------------------------------------------------------------------------------------------------------------------------

template< typename pass_type >
void PassVisitor< pass_type >::visit( ObjectDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( FunctionDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( StructDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UnionDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( EnumDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TraitDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TypeDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TypedefDecl * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AsmDecl * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// CompoundStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( CompoundStmt * node ) {
	VISIT_START( node );
	call_beginScope();

	visitStatementList( node->get_kids() );

	call_endScope();
	VISIT_END( node );
}

template< typename pass_type >
CompoundStmt * PassVisitor< pass_type >::mutate( CompoundStmt * node ) {
	MUTATE_START( node );
	call_beginScope();

	mutateStatementList( node->get_kids() );

	call_endScope();
	MUTATE_END( CompoundStmt, node );
}

//--------------------------------------------------------------------------
// ExprStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( ExprStmt * node ) {
	VISIT_START( node );
	call_beginScope();

	visitExpression( node->get_expr() );

	call_endScope();
	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( ExprStmt * node ) {
	MUTATE_START( node );

	node->set_expr( mutateExpression( node->get_expr() ) );

	MUTATE_END( Statement, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AsmStmt * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// IfStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( IfStmt * node ) {
	VISIT_START( node ); 

	visitExpression( node->get_condition() );
	node->set_thenPart ( visitStatement( node->get_thenPart() ) );
	node->set_elsePart ( visitStatement( node->get_elsePart() ) );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( IfStmt * node ) {
	MUTATE_START( node ); 

	node->set_condition( mutateExpression( node->get_condition() ) );
	node->set_thenPart ( mutateStatement ( node->get_thenPart()  ) );
	node->set_elsePart ( mutateStatement ( node->get_elsePart()  ) );

	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// WhileStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( WhileStmt * node ) {
	VISIT_START( node ); 

	visitExpression( node->get_condition() );
	node->set_body( visitStatement( node->get_body() ) );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( WhileStmt * node ) {
	MUTATE_START( node ); 

	node->set_condition( mutateExpression( node->get_condition() ) );
	node->set_body( mutateStatement( node->get_body() ) );

	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// WhileStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( ForStmt * node ) {
	VISIT_START( node ); 

	acceptAll( node->get_initialization(), *this );
	visitExpression( node->get_condition() );
	visitExpression( node->get_increment() );
	node->set_body( visitStatement( node->get_body() ) );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( ForStmt * node ) {
	MUTATE_START( node ); 

	mutateAll( node->get_initialization(), *this );
	node->set_condition( mutateExpression( node->get_condition() ) );
	node->set_increment( mutateExpression( node->get_increment() ) );
	node->set_body( mutateStatement( node->get_body() ) );

	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// SwitchStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( SwitchStmt * node ) {
	VISIT_START( node ); 

	visitExpression( node->get_condition() );
	visitStatementList( node->get_statements() );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( SwitchStmt * node ) {
	MUTATE_START( node ); 
	
	node->set_condition( mutateExpression( node->get_condition() ) );
	mutateStatementList( node->get_statements() );
	
	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// SwitchStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( CaseStmt * node ) {
	VISIT_START( node ); 
	
	visitExpression( node->get_condition() );
	visitStatementList( node->get_statements() );
	
	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( CaseStmt * node ) {
	MUTATE_START( node ); 
	
	node->set_condition(  mutateExpression( node->get_condition() ) );
	mutateStatementList( node->get_statements() );
	
	MUTATE_END( Statement, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( BranchStmt * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// ReturnStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( ReturnStmt * node ) {
	VISIT_START( node );

	visitExpression( node->get_expr() );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( ReturnStmt * node ) {
	MUTATE_START( node );

	node->set_expr( mutateExpression( node->get_expr() ) );

	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// ThrowStmt

template< typename pass_type >
void PassVisitor< pass_type >::visit( ThrowStmt * node ) {
	VISIT_BODY( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( ThrowStmt * node ) {
	MUTATE_BODY( Statement, node );
}

//--------------------------------------------------------------------------
// TryStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( TryStmt * node ) {
	VISIT_START( node );

	maybeAccept( node->get_block(), *this );
	acceptAll( node->get_catchers(), *this );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( TryStmt * node ) {
	MUTATE_START( node );

	node->set_block(  maybeMutate( node->get_block(), *this ) );
	mutateAll( node->get_catchers(), *this );
	
	MUTATE_END( Statement, node );
}

//--------------------------------------------------------------------------
// CatchStmt
template< typename pass_type >
void PassVisitor< pass_type >::visit( CatchStmt * node ) {
	VISIT_START( node );

	node->set_body( visitStatement( node->get_body() ) );
	maybeAccept( node->get_decl(), *this );

	VISIT_END( node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( CatchStmt * node ) {
	MUTATE_START( node );
	
	node->set_body(  mutateStatement( node->get_body() ) );
	node->set_decl(  maybeMutate( node->get_decl(), *this ) );
	
	MUTATE_END( Statement, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( FinallyStmt * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( NullStmt * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( DeclStmt * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ImplicitCtorDtorStmt * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ApplicationExpr * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// UntypedExpr
template< typename pass_type >
void PassVisitor< pass_type >::visit( UntypedExpr * node ) {
	VISIT_START( node );

	for ( auto expr : node->get_args() ) {
		visitExpression( expr );
	}

	VISIT_END( node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UntypedExpr * node ) {
	MUTATE_START( node );

	for ( auto& expr : node->get_args() ) {
		expr = mutateExpression( expr );
	}

	MUTATE_END( Expression, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( NameExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( CastExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AddressExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( LabelAddressExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UntypedMemberExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( MemberExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( VariableExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ConstantExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( SizeofExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AlignofExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UntypedOffsetofExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( OffsetofExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( OffsetPackExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AttrExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( LogicalExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ConditionalExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( CommaExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TypeExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AsmExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ImplicitCopyCtorExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ConstructorExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( CompoundLiteralExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UntypedValofExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( RangeExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UntypedTupleExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TupleExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TupleIndexExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TupleAssignExpr * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// UntypedExpr
template< typename pass_type >
void PassVisitor< pass_type >::visit( StmtExpr * node ) {
	VISIT_START( node );

	// don't want statements from outer CompoundStmts to be added to this StmtExpr
	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );

	Visitor::visit( node );

	VISIT_END( node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( StmtExpr * node ) {
	MUTATE_START( node );
	
	// don't want statements from outer CompoundStmts to be added to this StmtExpr
	ValueGuardPtr< TypeSubstitution * >      oldEnv        ( get_env_ptr() );
	ValueGuardPtr< std::list< Statement* > > oldBeforeStmts( get_beforeStmts() );
	ValueGuardPtr< std::list< Statement* > > oldAfterStmts ( get_afterStmts () );

	Mutator::mutate( node );

	MUTATE_END( Expression, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UniqueExpr * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( VoidType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( BasicType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( PointerType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ArrayType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( FunctionType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( StructInstType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( UnionInstType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( EnumInstType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TraitInstType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TypeInstType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TupleType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( TypeofType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( AttrType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( VarArgsType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ZeroType * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( OneType * node ) {
	VISIT_BODY( node ); 
}

//--------------------------------------------------------------------------
// UntypedExpr
template< typename pass_type >
void PassVisitor< pass_type >::visit( SingleInit * node ) {
	VISIT_START( node );

	visitExpression( node->get_value() );

	VISIT_END( node );
}

template< typename pass_type >
Initializer * PassVisitor< pass_type >::mutate( SingleInit * node ) {
	MUTATE_START( node );

	node->set_value( mutateExpression( node->get_value() ) );

	MUTATE_END( Initializer, node );
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ListInit * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( ConstructorInit * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( Subrange * node ) {
	VISIT_BODY( node ); 
}

template< typename pass_type >
void PassVisitor< pass_type >::visit( Constant * node ) {
	VISIT_BODY( node ); 
}

//---------------------------------------------------------------------------------------------------------------

template< typename pass_type >
DeclarationWithType * PassVisitor< pass_type >::mutate( ObjectDecl * node ) {
	MUTATE_BODY( DeclarationWithType, node );
}

template< typename pass_type >
DeclarationWithType * PassVisitor< pass_type >::mutate( FunctionDecl * node ) {
	MUTATE_BODY( DeclarationWithType, node );
}

template< typename pass_type >
Declaration * PassVisitor< pass_type >::mutate( StructDecl * node ) {
	MUTATE_BODY( Declaration, node );
}

template< typename pass_type >
Declaration * PassVisitor< pass_type >::mutate( UnionDecl * node ) {
	MUTATE_BODY( Declaration, node );
}

template< typename pass_type >
Declaration * PassVisitor< pass_type >::mutate( EnumDecl * node ) {
	MUTATE_BODY( Declaration, node );
}

template< typename pass_type >
Declaration * PassVisitor< pass_type >::mutate( TraitDecl * node ) {
	MUTATE_BODY( Declaration, node );
}

template< typename pass_type >
TypeDecl * PassVisitor< pass_type >::mutate( TypeDecl * node ) {
	MUTATE_BODY( TypeDecl, node );
}

template< typename pass_type >
Declaration * PassVisitor< pass_type >::mutate( TypedefDecl * node ) {
	MUTATE_BODY( Declaration, node );
}

template< typename pass_type >
AsmDecl * PassVisitor< pass_type >::mutate( AsmDecl * node ) {
	MUTATE_BODY( AsmDecl, node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( AsmStmt * node ) {
	MUTATE_BODY( Statement, node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( BranchStmt * node ) {
	MUTATE_BODY( Statement, node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( FinallyStmt * node ) {
	MUTATE_BODY( Statement, node );
}

template< typename pass_type >
NullStmt * PassVisitor< pass_type >::mutate( NullStmt * node ) {
	MUTATE_BODY( NullStmt, node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( DeclStmt * node ) {
	MUTATE_BODY( Statement, node );
}

template< typename pass_type >
Statement * PassVisitor< pass_type >::mutate( ImplicitCtorDtorStmt * node ) {
	MUTATE_BODY( Statement, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( ApplicationExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( NameExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( AddressExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( LabelAddressExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( CastExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UntypedMemberExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( MemberExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( VariableExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( ConstantExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( SizeofExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( AlignofExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UntypedOffsetofExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( OffsetofExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( OffsetPackExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( AttrExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( LogicalExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( ConditionalExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( CommaExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( TypeExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( AsmExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( ImplicitCopyCtorExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( ConstructorExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( CompoundLiteralExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UntypedValofExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( RangeExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UntypedTupleExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( TupleExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( TupleIndexExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( TupleAssignExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Expression * PassVisitor< pass_type >::mutate( UniqueExpr * node ) {
	MUTATE_BODY( Expression, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( VoidType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( BasicType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( PointerType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( ArrayType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( FunctionType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( StructInstType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( UnionInstType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( EnumInstType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( TraitInstType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( TypeInstType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( TupleType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( TypeofType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( AttrType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( VarArgsType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( ZeroType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Type * PassVisitor< pass_type >::mutate( OneType * node ) {
	MUTATE_BODY( Type, node );
}

template< typename pass_type >
Initializer * PassVisitor< pass_type >::mutate( ListInit * node ) {
	MUTATE_BODY( Initializer, node );
}

template< typename pass_type >
Initializer * PassVisitor< pass_type >::mutate( ConstructorInit * node ) {
	MUTATE_BODY( Initializer, node );
}

template< typename pass_type >
Subrange * PassVisitor< pass_type >::mutate( Subrange * node  )  {
	MUTATE_BODY( Subrange, node );
}

template< typename pass_type >
Constant * PassVisitor< pass_type >::mutate( Constant * node  )  {
	MUTATE_BODY( Constant, node );
}