//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// DeclarationNode.cc -- 
//
// Author           : Rodolfo G. Esteves
// Created On       : Sat May 16 12:34:05 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Tue Jul 14 14:46:32 2015
// Update Count     : 126
//

#include <string>
#include <list>
#include <iterator>
#include <algorithm>
#include <cassert>

#include "TypeData.h"

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

#include "Parser.h"
#include "TypedefTable.h"
extern TypedefTable typedefTable;

using namespace std;

// These must remain in the same order as the corresponding DeclarationNode enumerations.
const char *DeclarationNode::storageName[] = { "extern", "static", "auto", "register", "inline", "fortran", "_Noreturn", "_Thread_local", "" };
const char *DeclarationNode::qualifierName[] = { "const", "restrict", "volatile", "lvalue", "_Atomic" };
const char *DeclarationNode::basicTypeName[] = { "char", "int", "float", "double", "void", "_Bool", "_Complex", "_Imaginary" };
const char *DeclarationNode::modifierName[]  = { "signed", "unsigned", "short", "long" };
const char *DeclarationNode::aggregateName[] = { "struct", "union", "context" };
const char *DeclarationNode::typeClassName[] = { "type", "dtype", "ftype" };

UniqueName DeclarationNode::anonymous( "__anonymous" );

extern LinkageSpec::Type linkage;		/* defined in cfa.y */

DeclarationNode *DeclarationNode::clone() const {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = maybeClone( type );
	newnode->name = name;
	newnode->storageClasses = storageClasses;
	newnode->bitfieldWidth = maybeClone( bitfieldWidth );
	newnode->hasEllipsis = hasEllipsis;
	newnode->initializer = initializer;
	newnode->next = maybeClone( next );
	newnode->linkage = linkage;
	return newnode;
}

DeclarationNode::DeclarationNode() : type( 0 ), bitfieldWidth( 0 ), initializer( 0 ), hasEllipsis( false ), linkage( ::linkage ) {
}

DeclarationNode::~DeclarationNode() {
	delete type;
	delete bitfieldWidth;
	delete initializer;
}

bool DeclarationNode::get_hasEllipsis() const {
	return hasEllipsis;
}

void DeclarationNode::print( std::ostream &os, int indent ) const {
	os << string( indent, ' ' );
	if ( name == "" ) {
		os << "unnamed: ";
	} else {
		os << name << ": ";
	} // if

	if ( linkage != LinkageSpec::Cforall ) {
		os << LinkageSpec::toString( linkage ) << " ";
	} // if

	printEnums( storageClasses.begin(), storageClasses.end(), DeclarationNode::storageName, os );
	if ( type ) {
		type->print( os, indent );
	} else {
		os << "untyped entity ";
	} // if

	if ( bitfieldWidth ) {
		os << endl << string( indent + 2, ' ' ) << "with bitfield width ";
		bitfieldWidth->printOneLine( os );
	} // if

	if ( initializer != 0 ) {
		os << endl << string( indent + 2, ' ' ) << "with initializer ";
		initializer->printOneLine( os );
	} // if

	os << endl;
}

void DeclarationNode::printList( std::ostream &os, int indent ) const {
	ParseNode::printList( os, indent );
	if ( hasEllipsis ) {
		os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
	} // if
}

DeclarationNode *DeclarationNode::newFunction( std::string *name, DeclarationNode *ret, DeclarationNode *param, StatementNode *body, bool newStyle ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );

	newnode->type = new TypeData( TypeData::Function );
	newnode->type->function->params = param;
	newnode->type->function->newStyle = newStyle;
	newnode->type->function->body = body;

	if ( body ) {
		newnode->type->function->hasBody = true;
	} // if

	if ( ret ) {
		newnode->type->base = ret->type;
		ret->type = 0;
		delete ret;
	} // if

	return newnode;
}

DeclarationNode *DeclarationNode::newQualifier( Qualifier q ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData();
	newnode->type->qualifiers.push_back( q );
	return newnode;
}

DeclarationNode *DeclarationNode::newStorageClass( DeclarationNode::StorageClass sc ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->storageClasses.push_back( sc );
	return newnode;
}

DeclarationNode *DeclarationNode::newBasicType( BasicType bt ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Basic );
	newnode->type->basic->typeSpec.push_back( bt );
	return newnode;
}

DeclarationNode *DeclarationNode::newModifier( Modifier mod ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Basic );
	newnode->type->basic->modifiers.push_back( mod );
	return newnode;
}

DeclarationNode *DeclarationNode::newForall( DeclarationNode *forall ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Unknown );
	newnode->type->forall = forall;
	return newnode;
}

DeclarationNode *DeclarationNode::newFromTypedef( std::string *name ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::SymbolicInst );
	newnode->type->symbolic->name = assign_strptr( name );
	newnode->type->symbolic->isTypedef = true;
	newnode->type->symbolic->params = 0;
	return newnode;
}

DeclarationNode *DeclarationNode::newAggregate( Aggregate kind, const std::string *name, ExpressionNode *actuals, DeclarationNode *fields ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Aggregate );
	newnode->type->aggregate->kind = kind;
	newnode->type->aggregate->name = assign_strptr( name );
	if ( newnode->type->aggregate->name == "" ) {		// anonymous aggregate ?
		newnode->type->aggregate->name = DeclarationNode::anonymous.newName();
	} else {
		// SKULLDUGGERY: generate a typedef for the aggregate name so that the aggregate does not have to be qualified
		// by "struct"
		typedefTable.addToEnclosingScope( newnode->type->aggregate->name, TypedefTable::TD );
		DeclarationNode *typedf = new DeclarationNode;
		typedf->name = newnode->type->aggregate->name;
		newnode->appendList( typedf->addType( newnode->clone() )->addTypedef() );
	} // if
	newnode->type->aggregate->actuals = actuals;
	newnode->type->aggregate->fields = fields;
	return newnode;
}

DeclarationNode *DeclarationNode::newEnum( std::string *name, DeclarationNode *constants ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );
	newnode->type = new TypeData( TypeData::Enum );
	newnode->type->enumeration->name = newnode->name;
	if ( newnode->type->enumeration->name == "" ) {		// anonymous enumeration ?
		newnode->type->enumeration->name = DeclarationNode::anonymous.newName();
	} else {
		// SKULLDUGGERY: generate a typedef for the enumeration name so that the enumeration does not have to be
		// qualified by "enum"
		typedefTable.addToEnclosingScope( newnode->type->enumeration->name, TypedefTable::TD );
		DeclarationNode *typedf = new DeclarationNode;
		typedf->name = newnode->type->enumeration->name;
		newnode->appendList( typedf->addType( newnode->clone() )->addTypedef() );
	} // if
	newnode->type->enumeration->constants = constants;
	return newnode;
}

DeclarationNode *DeclarationNode::newEnumConstant( std::string *name, ExpressionNode *constant ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );
	// do something with the constant
	return newnode;
}

DeclarationNode *DeclarationNode::newName( std::string *name ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );
	return newnode;
}

DeclarationNode *DeclarationNode::newFromTypeGen( std::string *name, ExpressionNode *params ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::SymbolicInst );
	newnode->type->symbolic->name = assign_strptr( name );
	newnode->type->symbolic->isTypedef = false;
	newnode->type->symbolic->actuals = params;
	return newnode;
}

DeclarationNode *DeclarationNode::newTypeParam( TypeClass tc, std::string *name ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );
	newnode->type = new TypeData( TypeData::Variable );
	newnode->type->variable->tyClass = tc;
	newnode->type->variable->name = newnode->name;
	return newnode;
}

DeclarationNode *DeclarationNode::newContext( std::string *name, DeclarationNode *params, DeclarationNode *asserts ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Aggregate );
	newnode->type->aggregate->kind = Context;
	newnode->type->aggregate->params = params;
	newnode->type->aggregate->fields = asserts;
	newnode->type->aggregate->name = assign_strptr( name );
	return newnode;
}

DeclarationNode *DeclarationNode::newContextUse( std::string *name, ExpressionNode *params ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::AggregateInst );
	newnode->type->aggInst->aggregate = new TypeData( TypeData::Aggregate );
	newnode->type->aggInst->aggregate->aggregate->kind = Context;
	newnode->type->aggInst->aggregate->aggregate->name = assign_strptr( name );
	newnode->type->aggInst->params = params;
	return newnode;
}

DeclarationNode *DeclarationNode::newTypeDecl( std::string *name, DeclarationNode *typeParams ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->name = assign_strptr( name );
	newnode->type = new TypeData( TypeData::Symbolic );
	newnode->type->symbolic->isTypedef = false;
	newnode->type->symbolic->params = typeParams;
	newnode->type->symbolic->name = newnode->name;
	return newnode;
}

DeclarationNode *DeclarationNode::newPointer( DeclarationNode *qualifiers ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Pointer );
	return newnode->addQualifiers( qualifiers );
}

DeclarationNode *DeclarationNode::newArray( ExpressionNode *size, DeclarationNode *qualifiers, bool isStatic ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Array );
	newnode->type->array->dimension = size;
	newnode->type->array->isStatic = isStatic;
	if ( newnode->type->array->dimension == 0 || dynamic_cast<ConstantNode *>( newnode->type->array->dimension ) ) {
		newnode->type->array->isVarLen = false;
	} else {
		newnode->type->array->isVarLen = true;
	} // if
	return newnode->addQualifiers( qualifiers );
}

DeclarationNode *DeclarationNode::newVarArray( DeclarationNode *qualifiers ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Array );
	newnode->type->array->dimension = 0;
	newnode->type->array->isStatic = false;
	newnode->type->array->isVarLen = true;
	return newnode->addQualifiers( qualifiers );
}

DeclarationNode *DeclarationNode::newBitfield( ExpressionNode *size ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->bitfieldWidth = size;
	return newnode;
}

DeclarationNode *DeclarationNode::newTuple( DeclarationNode *members ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Tuple );
	newnode->type->tuple->members = members;
	return newnode;
}

DeclarationNode *DeclarationNode::newTypeof( ExpressionNode *expr ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Typeof );
	newnode->type->typeexpr->expr = expr;
	return newnode;
}

DeclarationNode *DeclarationNode::newAttr( std::string *name, ExpressionNode *expr ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Attr );
	newnode->type->attr->name = assign_strptr( name );
	newnode->type->attr->expr = expr;
	return newnode;
}

DeclarationNode *DeclarationNode::newAttr( std::string *name, DeclarationNode *type ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = new TypeData( TypeData::Attr );
	newnode->type->attr->name = assign_strptr( name );
	newnode->type->attr->type = type;
	return newnode;
}

static void addQualifiersToType( TypeData *&src, TypeData *dst ) {
	if ( src && dst ) {
		if ( src->forall && dst->kind == TypeData::Function ) {
			if ( dst->forall ) {
				dst->forall->appendList( src->forall );
			} else {
				dst->forall = src->forall;
			} // if
			src->forall = 0;
		} // if
		if ( dst->base ) {
			addQualifiersToType( src, dst->base );
		} else if ( dst->kind == TypeData::Function ) {
			dst->base = src;
			src = 0;
		} else {
			dst->qualifiers.splice( dst->qualifiers.end(), src->qualifiers );
		} // if
	} // if
}
	  
DeclarationNode *DeclarationNode::addQualifiers( DeclarationNode *q ) {
	if ( q ) {
		storageClasses.splice( storageClasses.end(), q->storageClasses );
		if ( q->type ) {
			if ( ! type ) {
				type = new TypeData;
			} // if
			addQualifiersToType( q->type, type );
			if ( q->type && q->type->forall ) {
				if ( type->forall ) {
					type->forall->appendList( q->type->forall );
				} else {
					if ( type->kind == TypeData::Aggregate ) {
						type->aggregate->params = q->type->forall;
						// change implicit typedef from TYPEDEFname to TYPEGENname
						typedefTable.changeKind( type->aggregate->name, TypedefTable::TG );
					} else {
						type->forall = q->type->forall;
					} // if
				} // if
				q->type->forall = 0;
			} // if
		} // if
	} // if
	delete q;
	return this;
}

DeclarationNode *DeclarationNode::copyStorageClasses( DeclarationNode *q ) {
	storageClasses = q->storageClasses;
	return this;
}

static void addTypeToType( TypeData *&src, TypeData *&dst ) {
	if ( src && dst ) {
		if ( src->forall && dst->kind == TypeData::Function ) {
			if ( dst->forall ) {
				dst->forall->appendList( src->forall );
			} else {
				dst->forall = src->forall;
			} // if
			src->forall = 0;
		} // if
		if ( dst->base ) {
			addTypeToType( src, dst->base );
		} else {
			switch ( dst->kind ) {
			  case TypeData::Unknown:
				src->qualifiers.splice( src->qualifiers.end(), dst->qualifiers );
				dst = src;
				src = 0;
				break;
			  case TypeData::Basic:
				dst->qualifiers.splice( dst->qualifiers.end(), src->qualifiers );
				if ( src->kind != TypeData::Unknown ) {
					assert( src->kind == TypeData::Basic );
					dst->basic->modifiers.splice( dst->basic->modifiers.end(), src->basic->modifiers );
					dst->basic->typeSpec.splice( dst->basic->typeSpec.end(), src->basic->typeSpec );
				} // if
				break;
			  default:
				switch ( src->kind ) {
				  case TypeData::Aggregate:
				  case TypeData::Enum:
					dst->base = new TypeData( TypeData::AggregateInst );
					dst->base->aggInst->aggregate = src;
					if ( src->kind == TypeData::Aggregate ) {
						dst->base->aggInst->params = maybeClone( src->aggregate->actuals );
					} // if
					dst->base->qualifiers.splice( dst->base->qualifiers.end(), src->qualifiers );
					src = 0;
					break;
				  default:
					if ( dst->forall ) {
						dst->forall->appendList( src->forall );
					} else {
						dst->forall = src->forall;
					} // if
					src->forall = 0;
					dst->base = src;
					src = 0;
				} // switch
			} // switch
		} // if
	} // if
}

DeclarationNode *DeclarationNode::addType( DeclarationNode *o ) {
	if ( o ) {
		storageClasses.splice( storageClasses.end(), o->storageClasses );
		if ( o->type ) {
			if ( ! type ) {
				if ( o->type->kind == TypeData::Aggregate || o->type->kind == TypeData::Enum ) {
					type = new TypeData( TypeData::AggregateInst );
					type->aggInst->aggregate = o->type;
					if ( o->type->kind == TypeData::Aggregate ) {
						type->aggInst->params = maybeClone( o->type->aggregate->actuals );
					} // if
					type->qualifiers.splice( type->qualifiers.end(), o->type->qualifiers );
				} else {
					type = o->type;
				} // if
				o->type = 0;
			} else {
				addTypeToType( o->type, type );
			} // if
		} // if
		if ( o->bitfieldWidth ) {
			bitfieldWidth = o->bitfieldWidth;
		} // if

		// there may be typedefs chained onto the type
		if ( o->get_link() ) {
			set_link( o->get_link()->clone() );
		} // if
	} // if
	delete o;
	return this;
}

DeclarationNode *DeclarationNode::addTypedef() {
	TypeData *newtype = new TypeData( TypeData::Symbolic );
	newtype->symbolic->params = 0;
	newtype->symbolic->isTypedef = true;
	newtype->symbolic->name = name;
	newtype->base = type;
	type = newtype;
	return this;
}

DeclarationNode *DeclarationNode::addAssertions( DeclarationNode *assertions ) {
	assert( type );
	switch ( type->kind ) {
	  case TypeData::Symbolic:
		if ( type->symbolic->assertions ) {
			type->symbolic->assertions->appendList( assertions );
		} else {
			type->symbolic->assertions = assertions;
		} // if
		break;
	  case TypeData::Variable:
		if ( type->variable->assertions ) {
			type->variable->assertions->appendList( assertions );
		} else {
			type->variable->assertions = assertions;
		} // if
		break;
	  default:
		assert( false );
	} // switch
	
	return this;
}

DeclarationNode *DeclarationNode::addName( std::string *newname ) {
	name = assign_strptr( newname );
	return this;
}

DeclarationNode *DeclarationNode::addBitfield( ExpressionNode *size ) {
	bitfieldWidth = size;
	return this;
}

DeclarationNode *DeclarationNode::addVarArgs() {
	assert( type );
	hasEllipsis = true;
	return this;
}

DeclarationNode *DeclarationNode::addFunctionBody( StatementNode *body ) {
	assert( type );
	assert( type->kind == TypeData::Function );
	assert( type->function->body == 0 );
	type->function->body = body;
	type->function->hasBody = true;
	return this;
}

DeclarationNode *DeclarationNode::addOldDeclList( DeclarationNode *list ) {
	assert( type );
	assert( type->kind == TypeData::Function );
	assert( type->function->oldDeclList == 0 );
	type->function->oldDeclList = list;
	return this;
}

static void setBase( TypeData *&type, TypeData *newType ) {
	if ( type ) {
		TypeData *prevBase = type;
		TypeData *curBase = type->base;
		while ( curBase != 0 ) {
			prevBase = curBase;
			curBase = curBase->base;
		} // while
		prevBase->base = newType;
	} else {
		type = newType;
	} // if
}

DeclarationNode *DeclarationNode::addPointer( DeclarationNode *p ) {
	if ( p ) {
		assert( p->type->kind == TypeData::Pointer );
		setBase( type, p->type );
		p->type = 0;
		delete p;
	} // if
	return this;
}

DeclarationNode *DeclarationNode::addArray( DeclarationNode *a ) {
	if ( a ) {
		assert( a->type->kind == TypeData::Array );
		setBase( type, a->type );
		a->type = 0;
		delete a;
	} // if
	return this;
}

DeclarationNode *DeclarationNode::addNewPointer( DeclarationNode *p ) {
	if ( p ) {
		assert( p->type->kind == TypeData::Pointer );
		if ( type ) {
			switch ( type->kind ) {
			  case TypeData::Aggregate:
			  case TypeData::Enum:
				p->type->base = new TypeData( TypeData::AggregateInst );
				p->type->base->aggInst->aggregate = type;
				if ( type->kind == TypeData::Aggregate ) {
					p->type->base->aggInst->params = maybeClone( type->aggregate->actuals );
				} // if
				p->type->base->qualifiers.splice( p->type->base->qualifiers.end(), type->qualifiers );
				break;

			  default:
				p->type->base = type;
			} // switch
			type = 0;
		} // if
		delete this;
		return p;
	} else {
		return this;
	} // if
}

static TypeData *findLast( TypeData *a ) {
	assert( a );
	TypeData *cur = a;
	while ( cur->base ) {
		cur = cur->base;
	} // while
	return cur;
}

DeclarationNode *DeclarationNode::addNewArray( DeclarationNode *a ) {
	if ( a ) {
		assert( a->type->kind == TypeData::Array );
		TypeData *lastArray = findLast( a->type );
		if ( type ) {  
			switch ( type->kind ) {
			  case TypeData::Aggregate:
			  case TypeData::Enum:
				lastArray->base = new TypeData( TypeData::AggregateInst );
				lastArray->base->aggInst->aggregate = type;
				if ( type->kind == TypeData::Aggregate ) {
					lastArray->base->aggInst->params = maybeClone( type->aggregate->actuals );
				} // if
				lastArray->base->qualifiers.splice( lastArray->base->qualifiers.end(), type->qualifiers );
				break;
			  default:
				lastArray->base = type;
			} // switch
			type = 0;
		} // if
		delete this;
		return a;
	} else {
		return this;
	} // if
}

DeclarationNode *DeclarationNode::addParamList( DeclarationNode *params ) {
	TypeData *ftype = new TypeData( TypeData::Function );
	ftype->function->params = params;
	setBase( type, ftype );
	return this;
}

static TypeData *addIdListToType( TypeData *type, DeclarationNode *ids ) {
	if ( type ) {
		if ( type->kind != TypeData::Function ) {
			type->base = addIdListToType( type->base, ids );
		} else {
			type->function->idList = ids;
		} // if
		return type;
	} else {
		TypeData *newtype = new TypeData( TypeData::Function );
		newtype->function->idList = ids;
		return newtype;
	} // if
}
	
DeclarationNode *DeclarationNode::addIdList( DeclarationNode *ids ) {
	type = addIdListToType( type, ids );
	return this;
}

DeclarationNode *DeclarationNode::addInitializer( InitializerNode *init ) {
	//assert
	initializer = init;
	return this;
}

DeclarationNode *DeclarationNode::cloneBaseType( string *newName ) {
	DeclarationNode *newnode = new DeclarationNode;
	TypeData *srcType = type;
	while ( srcType->base ) {
		srcType = srcType->base;
	} // while
	newnode->type = maybeClone( srcType );
	if ( newnode->type->kind == TypeData::AggregateInst ) {
		// don't duplicate members
		if ( newnode->type->aggInst->aggregate->kind == TypeData::Enum ) {
			delete newnode->type->aggInst->aggregate->enumeration->constants;
			newnode->type->aggInst->aggregate->enumeration->constants = 0;
		} else {
			assert( newnode->type->aggInst->aggregate->kind == TypeData::Aggregate );
			delete newnode->type->aggInst->aggregate->aggregate->fields;
			newnode->type->aggInst->aggregate->aggregate->fields = 0;
		} // if
	} // if
	newnode->type->forall = maybeClone( type->forall );
	newnode->storageClasses = storageClasses;
	newnode->name = assign_strptr( newName );
	return newnode;
}

DeclarationNode *DeclarationNode::cloneBaseType( DeclarationNode *o ) {
	if ( o ) {
		o->storageClasses.insert( o->storageClasses.end(), storageClasses.begin(), storageClasses.end() );
		if ( type ) {
			TypeData *srcType = type;
			while ( srcType->base ) {
				srcType = srcType->base;
			} // while
			TypeData *newType = srcType->clone();
			if ( newType->kind == TypeData::AggregateInst ) {
				// don't duplicate members
				if ( newType->aggInst->aggregate->kind == TypeData::Enum ) {
					delete newType->aggInst->aggregate->enumeration->constants;
					newType->aggInst->aggregate->enumeration->constants = 0;
				} else {
					assert( newType->aggInst->aggregate->kind == TypeData::Aggregate );
					delete newType->aggInst->aggregate->aggregate->fields;
					newType->aggInst->aggregate->aggregate->fields = 0;
				} // if
			} // if
			newType->forall = maybeClone( type->forall );
			if ( ! o->type ) {
				o->type = newType;
			} else {
				addTypeToType( newType, o->type );
				delete newType;
			} // if
		} // if
	} // if
	return o;
}

DeclarationNode *DeclarationNode::cloneType( string *newName ) {
	DeclarationNode *newnode = new DeclarationNode;
	newnode->type = maybeClone( type );
	newnode->storageClasses = storageClasses;
	newnode->name = assign_strptr( newName );
	return newnode;
}

DeclarationNode *DeclarationNode::cloneType( DeclarationNode *o ) {
	if ( o ) {
		o->storageClasses.insert( o->storageClasses.end(), storageClasses.begin(), storageClasses.end() );
		if ( type ) {
			TypeData *newType = type->clone();
			if ( ! o->type ) {
				o->type = newType;
			} else {
				addTypeToType( newType, o->type );
				delete newType;
			} // if
		} // if
	} // if
	return o;
}

DeclarationNode *DeclarationNode::appendList( DeclarationNode *node ) {
	if ( node != 0 ) {
		set_link( node );
	} // if
	return this;
}

DeclarationNode *DeclarationNode::extractAggregate() const {
	if ( type ) {
		TypeData *ret = type->extractAggregate();
		if ( ret ) {
			DeclarationNode *newnode = new DeclarationNode;
			newnode->type = ret;
			return newnode;
		} // if
	} // if
	return 0;
}

void buildList( const DeclarationNode *firstNode, std::list< Declaration * > &outputList ) {
	SemanticError errors;
	std::back_insert_iterator< std::list< Declaration *> > out( outputList );
	const DeclarationNode *cur = firstNode;
	while ( cur ) {
		try {
			if ( DeclarationNode *extr = cur->extractAggregate() ) {
				// handle the case where a structure declaration is contained within an object or type declaration
				Declaration *decl = extr->build();
				if ( decl ) {
					*out++ = decl;
				} // if
			} // if
			Declaration *decl = cur->build();
			if ( decl ) {
				*out++ = decl;
			} // if
		} catch( SemanticError &e ) {
			errors.append( e );
		} // try
		cur = dynamic_cast< DeclarationNode *>( cur->get_link() );
	} // while
	if ( ! errors.isEmpty() ) {
		throw errors;
	} // if
}

void buildList( const DeclarationNode *firstNode, std::list< DeclarationWithType *> &outputList ) {
	SemanticError errors;
	std::back_insert_iterator< std::list< DeclarationWithType *> > out( outputList );
	const DeclarationNode *cur = firstNode;
	while ( cur ) {
		try {
///       if ( DeclarationNode *extr = cur->extractAggregate() ) {
/// 	// handle the case where a structure declaration is contained within an object or type
/// 	// declaration
/// 	Declaration *decl = extr->build();
/// 	if ( decl ) {
///          *out++ = decl;
/// 	}
///       }
			Declaration *decl = cur->build();
			if ( decl ) {
				if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType *>( decl ) ) {
					*out++ = dwt;
				} else if ( StructDecl *agg = dynamic_cast< StructDecl *>( decl ) ) {
					StructInstType *inst = new StructInstType( Type::Qualifiers(), agg->get_name() );
					*out++ = new ObjectDecl( "", DeclarationNode::NoStorageClass, linkage, 0, inst, 0 );
					delete agg;
				} else if ( UnionDecl *agg = dynamic_cast< UnionDecl *>( decl ) ) {
					UnionInstType *inst = new UnionInstType( Type::Qualifiers(), agg->get_name() );
					*out++ = new ObjectDecl( "", DeclarationNode::NoStorageClass, linkage, 0, inst, 0 );
				} // if
			} // if
		} catch( SemanticError &e ) {
			errors.append( e );
		} // try
		cur = dynamic_cast< DeclarationNode *>( cur->get_link() );
	} // while
	if ( ! errors.isEmpty() ) {
		throw errors;
	} // if
}

void buildTypeList( const DeclarationNode *firstNode, std::list< Type *> &outputList ) {
	SemanticError errors;
	std::back_insert_iterator< std::list< Type *> > out( outputList );
	const DeclarationNode *cur = firstNode;
	while ( cur ) {
		try {
			*out++ = cur->buildType();
		} catch( SemanticError &e ) {
			errors.append( e );
		} // try
		cur = dynamic_cast< DeclarationNode *>( cur->get_link() );
	} // while
	if ( ! errors.isEmpty() ) {
		throw errors;
	} // if
}

Declaration *DeclarationNode::build() const {
	if ( type ) {
		Declaration *newDecl = type->buildDecl( name, buildStorageClass(), maybeBuild< Expression >( bitfieldWidth ), buildFuncSpecifier( Inline ), buildFuncSpecifier( Noreturn ), linkage, maybeBuild< Initializer >(initializer) );
		return newDecl;
	} // if
	if ( ! buildFuncSpecifier( Inline ) && ! buildFuncSpecifier( Noreturn ) ) {
		return new ObjectDecl( name, buildStorageClass(), linkage, maybeBuild< Expression >( bitfieldWidth ), 0, maybeBuild< Initializer >( initializer ) );
	} // if
	throw SemanticError( "invalid function specifier in declaration of ", this );
}

Type *DeclarationNode::buildType() const {
	assert( type );
  
	switch ( type->kind ) {
	  case TypeData::Enum:
		return new EnumInstType( type->buildQualifiers(), type->enumeration->name );
	  case TypeData::Aggregate: {
		  ReferenceToType *ret;
		  switch ( type->aggregate->kind ) {
			case DeclarationNode::Struct:
			  ret = new StructInstType( type->buildQualifiers(), type->aggregate->name );
			  break;
			case DeclarationNode::Union:
			  ret = new UnionInstType( type->buildQualifiers(), type->aggregate->name );
			  break;
			case DeclarationNode::Context:
			  ret = new ContextInstType( type->buildQualifiers(), type->aggregate->name );
			  break;
			default:
			  assert( false );
		  } // switch
		  buildList( type->aggregate->actuals, ret->get_parameters() );
		  return ret;
	  }
	  case TypeData::Symbolic: {
		  TypeInstType *ret = new TypeInstType( type->buildQualifiers(), type->symbolic->name, false );
		  buildList( type->symbolic->actuals, ret->get_parameters() );
		  return ret;
	  }
	  default:
		return type->build();
	} // switch
}

DeclarationNode::StorageClass DeclarationNode::buildStorageClass() const {
	DeclarationNode::StorageClass ret = DeclarationNode::NoStorageClass;
	for ( std::list< DeclarationNode::StorageClass >::const_iterator i = storageClasses.begin(); i != storageClasses.end(); ++i ) {
	  if ( *i == DeclarationNode::Inline || *i == DeclarationNode::Noreturn ) continue; // ignore function specifiers
	  if ( ret != DeclarationNode::NoStorageClass ) {	// already have a valid storage class ?
			throw SemanticError( "invalid combination of storage classes in declaration of ", this );
		} // if
		ret = *i;
	} // for
	return ret;
}

bool DeclarationNode::buildFuncSpecifier( DeclarationNode::StorageClass key ) const {
	std::list< DeclarationNode::StorageClass >::const_iterator first = std::find( storageClasses.begin(), storageClasses.end(), key );
  if ( first == storageClasses.end() ) return false;	// not found
	first = std::find( ++first, storageClasses.end(), key ); // found
  if ( first == storageClasses.end() ) return true;		// not found again
	throw SemanticError( "duplicate function specifier in declaration of ", this );
}

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
