#include <sys/types.h>
#include "ansi.h"
#include "config.h"
#include "host.h"
#include "files.h"
#include "hash.h"
#include "il.h"
#include "type_util.h"

#undef NULL
#define NULL			0

int
is_typedef(sym)
	symbol_t *sym;
{
	return sym->sym_kind == type_symbol;
}

int
is_enum_literal(sym)
	symbol_t *sym;
{
	return sym->sym_kind == enum_literal;
}

int
is_array(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);
	return typ->type_kind == array_of;
}

int
is_access(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);
	return typ->type_kind == pointer_to;
}

int
is_aggregate(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);

	switch (typ->type_kind) {
	  case array_of:
	  case struct_of:
	  case union_of:
		return 1;
	}

	return 0;
}

int
is_access_to_record(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);

	if (is_access(typ)) {
		typ = typ->type_next;
		assert(typ != NULL);

		switch (typ->type_kind) {
		  case struct_of:
		  case union_of:
			return 1;
		}
	}

	return 0;
}

int
is_static_function(typ)
	typeinfo_t *typ;
{
  top:
	assert(typ != NULL);

	if (typ->_static) {
		return 1;
	}

	switch (typ->type_kind) {
	  case function_type:
	  case pointer_to:
		typ = typ->type_next;
		goto top;
	}

	return 0;
}

int
is_function_pointer(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);

	if (typ->type_kind == pointer_to) {
		assert(typ->type_next != NULL);
		return typ->type_next->type_kind == function_type;
	}

	return 0;
}

int
alignto(val, align)
	int val, align;
{
	if (align <= 2) {
		return val;
	}
	align--;
	return (val + align) & ~align;
}

/*
 * Type allocator.
 */
typeinfo_t*
new_type(kind)
	typekind_t kind;
{
	typeinfo_t *typ;

	typ = (typeinfo_t*) allocate(sizeof(typeinfo_t));
	typ->type_kind = kind;
	set_hash_for_type(typ);
	return typ;
}

typeinfo_t*
copy_type(typ)
	typeinfo_t *typ;
{
	typeinfo_t *t;

	if (typ == NULL) {
		return NULL;
	}

	t = (typeinfo_t*) allocate(sizeof(typeinfo_t));
	*t = *typ;
	t->type_next = copy_type(typ->type_next);
	return t;
}

typeinfo_t*
concat_types(t1,t2)
	typeinfo_t *t1, *t2;
{
	typeinfo_t* t;

	if (t1 == NULL)		return t2;
	if (t2 == NULL)		return t1;

	for (t = t1; t->type_next; t = t->type_next);

	t->type_next = t2;
	return t1;
}

int
type_alignof(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);
	return typ->_alignof;
}

int
type_sizeof(typ)
	typeinfo_t *typ;
{
	assert(typ != NULL);
	return typ->_sizeof;
}

typeinfo_t*
set_signed_type(typ)
	typeinfo_t *typ;
{
	typ->_unsigned = 0;
	typ->_signed = 1;
	set_hash_for_type(typ);
	return typ;
}

typeinfo_t*
set_unsigned_type(typ)
	typeinfo_t *typ;
{
	typ->_unsigned = 1;
	typ->_signed = 0;
	set_hash_for_type(typ);
	return typ;
}

typeinfo_t*
add_pointer_type(typ)
	typeinfo_t *typ;
{
	typeinfo_t *ptr_type;

	assert(typ != NULL);
	ptr_type = new_type(pointer_to);
	ptr_type->type_next = typ;
	ptr_type->_typedef = typ->_typedef;
	ptr_type->_sizeof = SIZEOF_ADDRESS;
	ptr_type->_alignof = ALIGNOF_ADDRESS;
	set_hash_for_type(ptr_type);
	return ptr_type;
}

typeinfo_t*
add_function_type(typ)
	typeinfo_t *typ;
{
	typeinfo_t *ftype;

	assert(typ != NULL);
	ftype = new_type(function_type);
	ftype->type_next = typ;
	ftype->_typedef = typ->_typedef;
	set_hash_for_type(ftype);
	return ftype;
}

typeinfo_t*
add_array_type(typ, nelem)
	typeinfo_t *typ;
	host_int_t nelem;
{
	typeinfo_t *array_type;
	unsigned long bsize;

	array_type = new_type(array_of);
	array_type->type_info.array_elements = nelem;
	array_type->type_next = typ;
	array_type->_typedef = typ->_typedef;

	switch (nelem) {
	  case -1:
		array_type->_sizeof = SIZEOF_ADDRESS;
		array_type->_alignof = ALIGNOF_ADDRESS;
		break;
	  case 0:
		array_type->_sizeof = 0;
		array_type->_alignof = 0;
		break;
	  default:
		array_type->_alignof = type_alignof(typ);
		bsize = alignto(type_sizeof(typ), array_type->_alignof);
		array_type->_sizeof = bsize * nelem;
		break;
	}

	set_hash_for_type(array_type);
	return array_type;
}

/*
 * All types get hashed to make type comparisons faster and
 * to maintain the anonymous type tables.  Anonymous types
 * must be generated for things like: extern int foo[];
 * The integer array type must be defined for Ada.
 */
unsigned int
set_hash_for_type(typ)
	typeinfo_t *typ;
{
	unsigned int hash = 0;

	assert(typ != NULL);

	hash += 7 * typ->type_kind;

	if (typ->type_kind != array_of) {
		hash += typ->_sizeof;
	}

	hash += typ->_alignof;

	if (typ->_unsigned) hash += 3;
	if (typ->_signed) hash += 5;

	if (typ->type_next != NULL) {
		hash += set_hash_for_type(typ->type_next);
	}

	typ->type_hash = hash;
	return hash;
}

/*
 * Tags can be function parameters, fields of
 * unions and structs, or enumeration literals.
 */
static int
equal_tags(t1, t2)
	typeinfo_t *t1, *t2;
{
	symbol_t *bt1, *bt2;
	symbol_t *tags1, *tags2;

	if (t1 == t2) return 1;

	bt1 = t1->type_base;
	bt2 = t2->type_base;

	if (bt1 == bt2) return 1;

	if (bt1 == NULL || bt2 == NULL) return 0;

	return bt1->sym_tags == bt2->sym_tags;
}

/*
 * Type comparison routine.
 */
int
equal_types(t1, t2)
	typeinfo_t *t1, *t2;
{
	if (t1 == t2) return 1;

	for (; t1 && t2; t1 = t1->type_next, t2 = t2->type_next) {
		if (t1->type_hash != t2->type_hash) return 0;
		if (t1->type_kind != t2->type_kind) return 0;
		if (t1->_unsigned != t2->_unsigned) return 0;
		if (t1->_signed != t2->_signed) return 0;
		if (t1->type_base != NULL && t2->type_base != NULL) {
			if (t1->type_base != t2->type_base) return 0;
		}
		if (t1->type_kind != array_of) {
			if (t1->_sizeof != t2->_sizeof) return 0;
		}
		if (t1->_alignof != t2->_alignof) return 0;
		switch (t1->type_kind) {
		  case array_of:
#if 0
			if (t1->type_info.array_elements != t2->type_info.array_elements) {
				return 0;
			}
#endif
			break;
		  case struct_of:
		  case union_of:
			if (! equal_tags(t1, t2)) {
				return 0;
			}
		  default:
			break;
		}
	}

	return (t1 == NULL && t2 == NULL);
}


syntax highlighted by Code2HTML, v. 0.9.1