#include <cassert>
#include <algorithm>
#include <iterator>
#include "utility.h"
#include "TypeData.h"
#include "SynTree/Type.h"
#include "SynTree/Declaration.h"
#include "SynTree/Expression.h"
#include "SynTree/Statement.h"


TypeData::TypeData( Kind k ) : kind( k ), base( 0 ), forall( 0 ) {
    switch ( kind ) {
      case Unknown:
      case Pointer:
      case EnumConstant:
	// nothing else to initialize
	break;
      case Basic:
	basic = new Basic_t;
	break;
      case Array:
	array = new Array_t;
	array->dimension = 0;
	array->isVarLen = false;
	array->isStatic = false;
	break;
      case Function:
	function = new Function_t;
	function->params = 0;
	function->idList = 0;
	function->oldDeclList = 0;
	function->body = 0;
	function->hasBody = false;
	break;
      case Aggregate:
	aggregate = new Aggregate_t;
	aggregate->params = 0;
	aggregate->actuals = 0;
	aggregate->members = 0;
	break;
      case AggregateInst:
	aggInst = new AggInst_t;
	aggInst->aggregate = 0;
	aggInst->params = 0;
	break;
      case Enum:
	enumeration = new Enumeration_t;
	enumeration->constants = 0;
	break;
      case Symbolic:
      case SymbolicInst:
	symbolic = new Symbolic_t;
	symbolic->params = 0;
	symbolic->actuals = 0;
	symbolic->assertions = 0;
	break;
      case Variable:
	variable = new Variable_t;
	variable->tyClass = DeclarationNode::Type;
	variable->assertions = 0;
	break;
      case Tuple:
	tuple = new Tuple_t;
	tuple->members = 0;
	break;
  
      case Typeof:
	typeexpr = new Typeof_t;
	typeexpr->expr = 0;
	break;
  
      case Attr:
	attr = new Attr_t;
	attr->expr = 0;
	attr->type = 0;
	break;
    }
}

TypeData::~TypeData() {
    delete base;
    delete forall;

    switch ( kind ) {
      case Unknown:
      case Pointer:
      case EnumConstant:
	// nothing to destroy
	break;
      case Basic:
	delete basic;
	break;
      case Array:
	delete array->dimension;
	delete array;
	break;
      case Function:
	delete function->params;
	delete function->idList;
	delete function->oldDeclList;
	delete function->body;
	delete function;
	break;
      case Aggregate:
	delete aggregate->params;
	delete aggregate->actuals;
	delete aggregate->members;
	delete aggregate;
	break;
      case AggregateInst:
	delete aggInst->aggregate;
	delete aggInst->params;
	delete aggInst;
	break;
      case Enum:
	delete enumeration->constants;
	delete enumeration;
	break;
      case Symbolic:
      case SymbolicInst:
	delete symbolic->params;
	delete symbolic->actuals;
	delete symbolic->assertions;
	delete symbolic;
	break;
      case Variable:
	delete variable->assertions;
	delete variable;
	break;
      case Tuple:
	delete tuple->members;
	delete tuple;
	break;
  
      case Typeof:
	delete typeexpr->expr;
	delete typeexpr;
	break;
  
      case Attr:
	delete attr->expr;
	delete attr->type;
	delete attr;
	break;
    }
}

TypeData *TypeData::clone() const {
    TypeData *newtype = new TypeData( kind );
    newtype->qualifiers = qualifiers;
    newtype->base = maybeClone( base );
    newtype->forall = maybeClone( forall );

    switch ( kind ) {
      case Unknown:
      case EnumConstant:
      case Pointer:
	// nothing else to copy
	break;
      case Basic:
	newtype->basic->typeSpec = basic->typeSpec;
	newtype->basic->modifiers = basic->modifiers;
	break;
      case Array:
	newtype->array->dimension = maybeClone( array->dimension );
	newtype->array->isVarLen = array->isVarLen;
	newtype->array->isStatic = array->isStatic;
	break;
      case Function:
	newtype->function->params = maybeClone( function->params );
	newtype->function->idList = maybeClone( function->idList );
	newtype->function->oldDeclList = maybeClone( function->oldDeclList );
	newtype->function->body = maybeClone( function->body );
	newtype->function->hasBody = function->hasBody;
	newtype->function->newStyle = function->newStyle;
	break;
      case Aggregate:
	newtype->aggregate->params = maybeClone( aggregate->params );
	newtype->aggregate->actuals = maybeClone( aggregate->actuals );
	newtype->aggregate->members = maybeClone( aggregate->members );
	newtype->aggregate->name = aggregate->name;
	newtype->aggregate->kind = aggregate->kind;
	break;
      case AggregateInst:
	newtype->aggInst->aggregate = maybeClone( aggInst->aggregate );
	newtype->aggInst->params = maybeClone( aggInst->params );
	break;
      case Enum:
	newtype->enumeration->name = enumeration->name;
	newtype->enumeration->constants = maybeClone( enumeration->constants );
	break;
      case Symbolic:
      case SymbolicInst:
	newtype->symbolic->params = maybeClone( symbolic->params );
	newtype->symbolic->actuals = maybeClone( symbolic->actuals );
	newtype->symbolic->assertions = maybeClone( symbolic->assertions );
	newtype->symbolic->isTypedef = symbolic->isTypedef;
	newtype->symbolic->name = symbolic->name;
	break;
      case Variable:
	newtype->variable->assertions = maybeClone( variable->assertions );
	newtype->variable->name = variable->name;
	newtype->variable->tyClass = variable->tyClass;
	break;
      case Tuple:
	newtype->tuple->members = maybeClone( tuple->members );
	break;
    
      case Typeof:
	newtype->typeexpr->expr = maybeClone( typeexpr->expr );
	break;
  
      case Attr:
	newtype->attr->expr = maybeClone( attr->expr );
	newtype->attr->type = maybeClone( attr->type );
	break;
    }
    return newtype;
}

void TypeData::print( std::ostream &os, int indent ) const {
    using std::endl;
    using std::string;

    printEnums( qualifiers.begin(), qualifiers.end(), DeclarationNode::qualifierName, os );

    if ( forall ) {
	os << "forall " << endl;
	forall->printList( os, indent+4 );
    }

    switch ( kind ) {
      case Unknown:
	os << "entity of unknown type ";
	break;
      case Pointer:
	os << "pointer ";
	if ( base ) {
	    os << "to ";
	    base->print( os, indent );
	}
	break;
      case EnumConstant:
	os << "enumeration constant ";
	break;
      case Basic:
	printEnums( basic->modifiers.begin(), basic->modifiers.end(), DeclarationNode::modifierName, os );
	printEnums( basic->typeSpec.begin(), basic->typeSpec.end(), DeclarationNode::basicTypeName, os );
	break;
      case Array:
	if ( array->isStatic ) {
	    os << "static ";
	}
	if ( array->dimension ) {
	    os << "array of ";
	    array->dimension->printOneLine( os, indent );
	} else if ( array->isVarLen ) {
	    os << "variable-length array of ";
	} else {
	    os << "open array of ";
	}
	if ( base ) {
	    base->print( os, indent );
	}
	break;
      case Function:
	os << "function" << endl;
	if ( function->params ) {
	    os << string( indent+2, ' ' ) << "with parameters " << endl;
	    function->params->printList( os, indent+4 );
	} else {
	    os << string( indent+2, ' ' ) << "with no parameters " << endl;
	}
	if ( function->idList ) {
	    os << string( indent+2, ' ' ) << "with old-style identifier list " << endl;
	    function->idList->printList( os, indent+4 );
	}
	if ( function->oldDeclList ) {
	    os << string( indent+2, ' ' ) << "with old-style declaration list " << endl;
	    function->oldDeclList->printList( os, indent+4 );
	}
	os << string( indent+2, ' ' ) << "returning ";
	if ( base ) {
	    base->print( os, indent+4 );
	} else {
	    os << "nothing ";
	}
	os << endl;
	if ( function->hasBody ) {
	    os << string( indent+2, ' ' ) << "with body " << endl;
	}
	if ( function->body ) {
	    function->body->printList( os, indent+2 );
	}
	break;
      case Aggregate:
	os << DeclarationNode::tyConName[ aggregate->kind ] << ' ' << aggregate->name << endl;
	if ( aggregate->params ) {
	    os << string( indent+2, ' ' ) << "with type parameters " << endl;
	    aggregate->params->printList( os, indent+4 );
	}
	if ( aggregate->actuals ) {
	    os << string( indent+2, ' ' ) << "instantiated with actual parameters " << endl;
	    aggregate->actuals->printList( os, indent+4 );
	}
	if ( aggregate->members ) {
	    os << string( indent+2, ' ' ) << "with members " << endl;
	    aggregate->members->printList( os, indent+4 );
///     } else {
///       os << string( indent+2, ' ' ) << "with no members " << endl;
	}
	break;
      case AggregateInst:
	if ( aggInst->aggregate ) {
	    os << "instance of " ;
	    aggInst->aggregate->print( os, indent );
	} else {
	    os << "instance of an unspecified aggregate ";
	}
	if ( aggInst->params ) {
	    os << string( indent+2, ' ' ) << "with parameters " << endl;
	    aggInst->params->printList( os, indent+2 );
	}
	break;
      case Enum:
	os << "enumeration ";
	if ( enumeration->constants ) {
	    os << "with constants" << endl;
	    enumeration->constants->printList( os, indent+2 );
	}
	break;
      case SymbolicInst:
	os << "instance of type " << symbolic->name;
	if ( symbolic->actuals ) {
	    os << " with parameters" << endl;
	    symbolic->actuals->printList( os, indent + 2 );
	}
	break;
      case Symbolic:
	if ( symbolic->isTypedef ) {
	    os << "typedef definition ";
	} else {
	    os << "type definition ";
	}
	if ( symbolic->params ) {
	    os << endl << string( indent+2, ' ' ) << "with parameters" << endl;
	    symbolic->params->printList( os, indent + 2 );
	}
	if ( symbolic->assertions ) {
	    os << endl << string( indent+2, ' ' ) << "with assertions" << endl;
	    symbolic->assertions->printList( os, indent + 4 );
	    os << string( indent+2, ' ' );
	}
	if ( base ) {
	    os << "for ";
	    base->print( os, indent + 2 );
	}
	break;
      case Variable:
	os << DeclarationNode::typeClassName[ variable->tyClass ] << " variable ";
	if ( variable->assertions ) {
	    os << endl << string( indent+2, ' ' ) << "with assertions" << endl;
	    variable->assertions->printList( os, indent + 4 );
	    os << string( indent+2, ' ' );
	}
	break;
      case Tuple:
	os << "tuple ";
	if ( tuple->members ) {
	    os << "with members " << endl;
	    tuple->members->printList( os, indent + 2 );
	}
	break;
    
      case Typeof:
	os << "type-of expression ";
	if ( typeexpr->expr ) {
	    typeexpr->expr->print( os, indent + 2 );
	}
	break;
    
      case Attr:
	os << "attribute type decl " << attr->name << " applied to ";
	if ( attr->expr ) {
	    attr->expr->print( os, indent + 2 );
	}
	if ( attr->type ) {
	    attr->type->print( os, indent + 2 );
	}
	break;
    }
}

TypeData *TypeData::extractAggregate( bool toplevel ) const {
    TypeData *ret = 0;

    switch ( kind ) {
      case Aggregate:
	if ( !toplevel && aggregate->members ) {
	    ret = clone();
	    ret->qualifiers.clear();
	}
	break;
      case Enum:
	if ( !toplevel && enumeration->constants ) {
	    ret = clone();
	    ret->qualifiers.clear();
	}
	break;
      case AggregateInst:
	if ( aggInst->aggregate ) {
	    ret = aggInst->aggregate->extractAggregate( false );
	}
	break;
      default:
	if ( base ) {
	    ret = base->extractAggregate( false );
	}
    }
    return ret;
}

void buildForall( const DeclarationNode *firstNode, std::list< TypeDecl* > &outputList ) {
  
    buildList( firstNode, outputList );
    for ( std::list< TypeDecl* >::iterator i = outputList.begin(); i != outputList.end(); ++i ) {
	if ( (*i)->get_kind() == TypeDecl::Any ) {
	    FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
	    assignType->get_parameters().push_back( new ObjectDecl( "", Declaration::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ) ), 0 ) );
	    assignType->get_parameters().push_back( new ObjectDecl( "", Declaration::NoStorageClass, LinkageSpec::Cforall, 0, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), 0 ) );
	    assignType->get_returnVals().push_back( new ObjectDecl( "", Declaration::NoStorageClass, LinkageSpec::Cforall, 0, new TypeInstType( Type::Qualifiers(), (*i)->get_name(), *i ), 0 ) );
	    (*i)->get_assertions().push_front( new FunctionDecl( "?=?", Declaration::NoStorageClass, LinkageSpec::Cforall,  assignType, 0, false ) );
	}
    }
}

Declaration *TypeData::buildDecl( std::string name, Declaration::StorageClass sc, Expression *bitfieldWidth, bool isInline, LinkageSpec::Type linkage, Initializer *init ) const {
    if ( kind == TypeData::Function ) {
	FunctionDecl *decl;
	if ( function->hasBody ) {
	    if ( function->body ) {
		Statement *stmt = function->body->build();
		CompoundStmt *body = dynamic_cast< CompoundStmt* >( stmt );
		assert( body );
		decl = new FunctionDecl( name, sc, linkage, buildFunction(), body, isInline );
	    } else {
		// std::list<Label> ls;
		decl = new FunctionDecl( name, sc, linkage, buildFunction(), new CompoundStmt( std::list<Label>() ), isInline );
	    }
	} else {
	    decl = new FunctionDecl( name, sc, linkage, buildFunction(), 0, isInline );
	}
	for ( DeclarationNode *cur = function->idList; cur != 0; cur = dynamic_cast< DeclarationNode* >( cur->get_link() ) ) {
	    if ( cur->get_name() != "" ) {
		decl->get_oldIdents().insert( decl->get_oldIdents().end(), cur->get_name() );
	    }
	}
	buildList( function->oldDeclList, decl->get_oldDecls() );
	return decl;
    } else if ( kind == TypeData::Aggregate ) {
	return buildAggregate();
    } else if ( kind == TypeData::Enum ) {
	return buildEnum();
    } else if ( kind == TypeData::Symbolic ) {
	return buildSymbolic( name, sc );
    } else if ( kind == TypeData::Variable ) {
	return buildVariable();
    } else {
	if ( isInline ) {
	    throw SemanticError( "invalid inline specification in declaration of ", this );
	} else {
	    return new ObjectDecl( name, sc, linkage, bitfieldWidth, build(), init );
	}
    }
    return 0;
}

Type *TypeData::build() const {

    switch ( kind ) {
      case Unknown:
	// fill in implicit int
	return new BasicType( buildQualifiers(), BasicType::SignedInt );

      case Basic:
	return buildBasicType();

      case Pointer:
	return buildPointer();

      case Array:
	return buildArray();

      case Function:
	return buildFunction();

      case AggregateInst:
	return buildAggInst();

      case EnumConstant:
	// the name gets filled in later -- by SymTab::Validate
	return new EnumInstType( buildQualifiers(), "" );

      case SymbolicInst:
	return buildSymbolicInst();;

      case Tuple:
	return buildTuple();
  
      case Typeof:
	return buildTypeof();

      case Attr:
	return buildAttr();

      case Symbolic:
      case Enum:
      case Aggregate:
      case Variable:
	assert( false );
    }

    return 0;
}

Type::Qualifiers TypeData::buildQualifiers() const {
    Type::Qualifiers q;
    for ( std::list< DeclarationNode::Qualifier >::const_iterator i = qualifiers.begin(); i != qualifiers.end(); ++i ) {
	switch ( *i ) {
	  case DeclarationNode::Const:
	    q.isConst = true;
	    break;
	  case DeclarationNode::Volatile:
	    q.isVolatile = true;
	    break;
	  case DeclarationNode::Restrict:
	    q.isRestrict = true;
	    break;
	  case DeclarationNode::Lvalue:
	    q.isLvalue = true;
	    break;
	}
    }
    return q;
}

Type *TypeData::buildBasicType() const {
    static const BasicType::Kind kindMap[] = { BasicType::Char, BasicType::SignedInt, BasicType::Float, BasicType::Double,
					       BasicType::Char /* void */, BasicType::Bool, BasicType::DoubleComplex,
					       BasicType::DoubleImaginary };
    bool init = false;
    bool sawDouble = false;
    bool sawSigned = false;
    BasicType::Kind ret;

    for ( std::list< DeclarationNode::BasicType >::const_iterator i = basic->typeSpec.begin(); i != basic->typeSpec.end(); ++i ) {
	if ( !init ) {
	    init = true;
	    if ( *i == DeclarationNode::Void ) {
		if ( basic->typeSpec.size() != 1 || !basic->modifiers.empty() ) {
		    throw SemanticError( "invalid type specifier \"void\" in type ", this );
		} else {
		    return new VoidType( buildQualifiers() );
		}
	    } else {
		ret = kindMap[ *i ];
	    }
	} else {
	    switch ( *i ) {
	      case DeclarationNode::Float:
		if ( sawDouble ) {
		    throw SemanticError( "invalid type specifier \"float\" in type ", this );
		} else {
		    switch ( ret ) {
		      case BasicType::DoubleComplex:
			ret = BasicType::FloatComplex;
			break;
		      case BasicType::DoubleImaginary:
			ret = BasicType::FloatImaginary;
			break;
		      default:
			throw SemanticError( "invalid type specifier \"float\" in type ", this );
		    }
		}
		break;
	      case DeclarationNode::Double:
		if ( sawDouble ) {
		    throw SemanticError( "duplicate type specifier \"double\" in type ", this );
		} else {
		    switch ( ret ) {
		      case BasicType::DoubleComplex:
		      case BasicType::DoubleImaginary:
			break;
		      default:
			throw SemanticError( "invalid type specifier \"double\" in type ", this );
		    }
		}
		break;
	
	      case DeclarationNode::Complex:
		switch ( ret ) {
		  case BasicType::Float:
		    ret = BasicType::FloatComplex;
		    break;
          
		  case BasicType::Double:
		    ret = BasicType::DoubleComplex;
		    break;
		  default:
		    throw SemanticError( "invalid type specifier \"complex\" in type ", this );
		}
		break;
        
	      case DeclarationNode::Imaginary:
		switch ( ret ) {
		  case BasicType::Float:
		    ret = BasicType::FloatImaginary;
		    break;
          
		  case BasicType::Double:
		    ret = BasicType::DoubleImaginary;
		    break;
		  default:
		    throw SemanticError( "invalid type specifier \"imaginary\" in type ", this );
		}
		break;
        
	      default:
		throw SemanticError( std::string( "invalid type specifier \"" ) + DeclarationNode::basicTypeName[ *i ] + "\" in type ", this );
	    }
	}
	if ( *i == DeclarationNode::Double ) {
	    sawDouble = true;
	}
    }

    for ( std::list< DeclarationNode::Modifier >::const_iterator i = basic->modifiers.begin(); i != basic->modifiers.end(); ++i ) {
	switch ( *i ) {
	  case DeclarationNode::Long:
	    if ( !init ) {
		init = true;
		ret = BasicType::LongSignedInt;
	    } else {
		switch ( ret ) {
		  case BasicType::SignedInt:
		    ret = BasicType::LongSignedInt;
		    break;
		  case BasicType::UnsignedInt:
		    ret = BasicType::LongUnsignedInt;
		    break;
		  case BasicType::LongSignedInt:
		    ret = BasicType::LongLongSignedInt;
		    break;
		  case BasicType::LongUnsignedInt:
		    ret = BasicType::LongLongUnsignedInt;
		    break;
		  case BasicType::Double:
		    ret = BasicType::LongDouble;
		    break;
		  case BasicType::DoubleComplex:
		    ret = BasicType::LongDoubleComplex;
		    break;
		  case BasicType::DoubleImaginary:
		    ret = BasicType::LongDoubleImaginary;
		    break;
		  default:
		    throw SemanticError( "invalid type modifier \"long\" in type ", this );
		}
	    }
	    break;
	  case DeclarationNode::Short:
	    if ( !init ) {
		init = true;
		ret = BasicType::ShortSignedInt;
	    } else {
		switch ( ret ) {
		  case BasicType::SignedInt:
		    ret = BasicType::ShortSignedInt;
		    break;
		  case BasicType::UnsignedInt:
		    ret = BasicType::ShortUnsignedInt;
		    break;
		  default:
		    throw SemanticError( "invalid type modifier \"short\" in type ", this );
		}
	    }
	    break;
	  case DeclarationNode::Signed:
	    if ( !init ) {
		init = true;
		ret = BasicType::SignedInt;
	    } else if ( sawSigned ) {
		throw SemanticError( "duplicate type modifer \"signed\" in type ", this );
	    } else {
		switch ( ret ) {
		  case BasicType::SignedInt:
		  case BasicType::ShortSignedInt:
		    break;
		  case BasicType::Char:
		    ret = BasicType::SignedChar;
		    break;
		  default:
		    throw SemanticError( "invalid type modifer \"signed\" in type ", this );
		}
	    }
	    break;
	  case DeclarationNode::Unsigned:
	    if ( !init ) {
		init = true;
		ret = BasicType::UnsignedInt;
	    } else if ( sawSigned ) {
		throw SemanticError( "invalid type modifer \"unsigned\" in type ", this );
	    } else {
		switch ( ret ) {
		  case BasicType::LongSignedInt:
		    ret = BasicType::LongUnsignedInt;
		    break;
		  case BasicType::SignedInt:
		    ret = BasicType::UnsignedInt;
		    break;
		  case BasicType::ShortSignedInt:
		    ret = BasicType::ShortUnsignedInt;
		    break;
		  case BasicType::Char:
		    ret = BasicType::UnsignedChar;
		    break;
		  default:
		    throw SemanticError( "invalid type modifer \"unsigned\" in type ", this );
		}
	    }
	    break;
	}

	if ( *i == DeclarationNode::Signed ) {
	    sawSigned = true;
	}
    }

    BasicType *bt;
    if ( !init ) {
	bt = new BasicType( buildQualifiers(), BasicType::SignedInt );
    } else {
	bt = new BasicType( buildQualifiers(), ret );
    }
    buildForall( forall, bt->get_forall() );
    return bt;
}


PointerType *TypeData::buildPointer() const {
    PointerType *pt;
    if ( base ) {
	pt = new PointerType( buildQualifiers(), base->build() );
    } else {
	pt = new PointerType( buildQualifiers(), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    }
    buildForall( forall, pt->get_forall() );
    return pt;
}

ArrayType *TypeData::buildArray() const {
  
    ArrayType *at;
    if ( base ) {
	at = new ArrayType( buildQualifiers(), base->build(), maybeBuild< Expression >( array->dimension ),
			    array->isVarLen, array->isStatic );
    } else {
	at = new ArrayType( buildQualifiers(), new BasicType( Type::Qualifiers(), BasicType::SignedInt ),
			    maybeBuild< Expression >( array->dimension ), array->isVarLen, array->isStatic );
    }
    buildForall( forall, at->get_forall() );
    return at;
}

FunctionType *TypeData::buildFunction() const {
    assert( kind == Function );
    bool hasEllipsis = function->params ? function->params->get_hasEllipsis() : true;
    if ( !function->params ) hasEllipsis = !function->newStyle;
    FunctionType *ft = new FunctionType( buildQualifiers(), hasEllipsis );
    buildList( function->params, ft->get_parameters() );
    buildForall( forall, ft->get_forall() );
    if ( base ) {
	switch ( base->kind ) {
	  case Tuple:
	    buildList( base->tuple->members, ft->get_returnVals() );
	    break;
	  default:
	    ft->get_returnVals().push_back( dynamic_cast< DeclarationWithType* >( base->buildDecl( "", Declaration::NoStorageClass, 0, false, LinkageSpec::Cforall ) ) );
	}
    } else {
	ft->get_returnVals().push_back( new ObjectDecl( "", Declaration::NoStorageClass, LinkageSpec::Cforall, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), 0 ) );
    }
    return ft;
}

AggregateDecl *TypeData::buildAggregate() const {
    assert( kind == Aggregate );
    AggregateDecl *at;
    switch ( aggregate->kind ) {
      case DeclarationNode::Struct:
	at = new StructDecl( aggregate->name );
	break;
    
      case DeclarationNode::Union:
	at = new UnionDecl( aggregate->name );
	break;
    
      case DeclarationNode::Context:
	at = new ContextDecl( aggregate->name );
	break;
    
      default:
	assert( false );
    }
  
    buildList( aggregate->params, at->get_parameters() );
    buildList( aggregate->members, at->get_members() );

    return at;
}

/// namespace {
/// Type*
/// makeType( Declaration* decl )
/// {
///   if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
///     return dwt->get_type()->clone();
///   } else {
///     return 0;
///   }
/// }
/// }

ReferenceToType *TypeData::buildAggInst() const {
    assert( kind == AggregateInst );
    std::string name;

    ReferenceToType *ret;
    if ( aggInst->aggregate->kind == Enum ) {
	ret = new EnumInstType( buildQualifiers(), aggInst->aggregate->enumeration->name );
    } else {
	assert( aggInst->aggregate->kind == Aggregate );
	switch ( aggInst->aggregate->aggregate->kind ) {
	  case DeclarationNode::Struct:
	    ret = new StructInstType( buildQualifiers(), aggInst->aggregate->aggregate->name );
	    break;
	  case DeclarationNode::Union:
	    ret = new UnionInstType( buildQualifiers(), aggInst->aggregate->aggregate->name );
	    break;
	  case DeclarationNode::Context:
	    ret = new ContextInstType( buildQualifiers(), aggInst->aggregate->aggregate->name );
	    break;
	  default:
	    assert( false );
	}
    }
    buildList( aggInst->params, ret->get_parameters() );
    buildForall( forall, ret->get_forall() );
    return ret;
}

NamedTypeDecl *TypeData::buildSymbolic( const std::string &name, Declaration::StorageClass sc ) const {
    assert( kind == Symbolic );
    NamedTypeDecl *ret;
    if ( symbolic->isTypedef ) {
	ret = new TypedefDecl( name, sc, maybeBuild< Type >( base ) );
    } else {
	ret = new TypeDecl( name, sc, maybeBuild< Type >( base ), TypeDecl::Any );
    }
    buildList( symbolic->params, ret->get_parameters() );
    buildList( symbolic->assertions, ret->get_assertions() );
    return ret;
}

TypeDecl *TypeData::buildVariable() const {
    assert( kind == Variable );
    static const TypeDecl::Kind kindMap[] = { TypeDecl::Any, TypeDecl::Ftype, TypeDecl::Dtype };

    TypeDecl *ret = new TypeDecl( variable->name, Declaration::NoStorageClass, 0, kindMap[ variable->tyClass ] );
    buildList( variable->assertions, ret->get_assertions() );
    
    return ret;
}

EnumDecl *TypeData::buildEnum() const {
    assert( kind == Enum );
    EnumDecl *ret = new EnumDecl( enumeration->name );
    buildList( enumeration->constants, ret->get_members() );

    return ret;
}

TypeInstType *TypeData::buildSymbolicInst() const {
    assert( kind == SymbolicInst );


    TypeInstType *ret = new TypeInstType( buildQualifiers(), symbolic->name, false );
    buildList( symbolic->actuals, ret->get_parameters() );
    buildForall( forall, ret->get_forall() );

    return ret;
}

TupleType *TypeData::buildTuple() const {
    assert( kind == Tuple );


    TupleType *ret = new TupleType( buildQualifiers() );
    buildTypeList( tuple->members, ret->get_types() );
    buildForall( forall, ret->get_forall() );

    return ret;
}

TypeofType *TypeData::buildTypeof() const {
    assert( kind == Typeof );
    assert( typeexpr );
    assert( typeexpr->expr );
    TypeofType *ret = new TypeofType( buildQualifiers(), typeexpr->expr->build() );

    return ret;
}

AttrType *TypeData::buildAttr() const {
    assert( kind == Attr );
    assert( attr );
    AttrType *ret;
    if ( attr->expr ) {
	ret = new AttrType( buildQualifiers(), attr->name, attr->expr->build() );
    } else {
	assert( attr->type );
	ret = new AttrType( buildQualifiers(), attr->name, attr->type->buildType() );
    }

    return ret;
}
