/*ident	"@(#)cls4:src/typ2.c	1.1" */
/*******************************************************************************
 
C++ source for the C++ Language System, Release 3.0.  This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.

Copyright (c) 1991 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T.  All Rights Reserved.

THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

*******************************************************************************/
 
#include "cfront.h"
#include "size.h"
#include "template.h"

extern int chars_in_largest;
int largest_int;

void typ_init()
{	
	chars_in_largest = strlen(LARGEST_INT);
	largest_int = int(str_to_long(LARGEST_INT));

	defa_type = new basetype(INT,0);	// note defa_type!=int_type
	int_type = new basetype(INT,0);		// but they both represent `int'

	PERM(int_type); int_type->defined = DEFINED ;
	PERM(defa_type); defa_type->defined = DEFINED ;

	moe_type = new basetype(INT,0);
	PERM(moe_type); moe_type->defined = DEFINED ;
	moe_type->b_const = 1;
	moe_type->check(0);

	uint_type = new basetype(INT,0);
	PERM(uint_type); uint_type->defined = DEFINED ;
	uint_type->type_adj(UNSIGNED);
	uint_type->check(0);

	long_type = new basetype(LONG,0);
	PERM(long_type); long_type->defined = DEFINED ;
	long_type->check(0);

	ulong_type = new basetype(LONG,0);
	PERM(ulong_type); ulong_type->defined = DEFINED ;
	ulong_type->type_adj(UNSIGNED);
	ulong_type->check(0);

	short_type = new basetype(SHORT,0);
	PERM(short_type); short_type->defined = DEFINED ;
	short_type->check(0);

	ushort_type = new basetype(SHORT,0);
	PERM(ushort_type); ushort_type->defined = DEFINED ;
	ushort_type->type_adj(UNSIGNED);
	ushort_type->check(0);

	float_type = new basetype(FLOAT,0);
	PERM(float_type); float_type->defined = DEFINED ;

	double_type = new basetype(DOUBLE,0);
	PERM(double_type); double_type->defined = DEFINED ;

	ldouble_type = new basetype(LDOUBLE,0);
	PERM(ldouble_type); ldouble_type->defined = DEFINED ;

	zero_type = new basetype(ZTYPE,0);
	PERM(zero_type); zero_type->defined = DEFINED ;
	zero->tp = zero_type;

	void_type = new basetype(VOID,0);
	PERM(void_type); void_type->defined = DEFINED ;

	char_type = new basetype(CHAR,0);
	PERM(char_type); char_type->defined = DEFINED ;

	uchar_type = new basetype(CHAR,0);
	PERM(uchar_type); uchar_type->defined = DEFINED ;
	uchar_type->type_adj(UNSIGNED);
	uchar_type->check(0);

	Pchar_type = char_type->addrof();
	PERM(Pchar_type); Pchar_type->defined = DEFINED ;

	Pint_type = int_type->addrof();
	PERM(Pint_type); Pint_type->defined = DEFINED ;

	Pvoid_type = void_type->addrof();
	PERM(Pvoid_type); Pvoid_type->defined = DEFINED ;

	Pfctvec_type = new fct(int_type,0,0);	// must be last, see basetype::normalize()
	Pfctvec_type = Pfctvec_type->addrof();
	Pfctvec_type = Pfctvec_type->addrof();
	PERM(Pfctvec_type); Pfctvec_type->defined = DEFINED ;

	gtbl = new table(GTBLSIZE,0,0);
	gtbl->t_name = new name("global");
	ptbl = new table(CTBLSIZE,0,0);
	ptbl->t_name = new name("ptbl");
	tmp_tbl = new table(CTBLSIZE,0,0);
	templ_compilation::templates = new table(128,0,0);
	bound_expr_tbl = new table(12,0,0);
}

Pbase basetype::arit_conv(Pbase t)
/*
	perform the "usual arithmetic conversions" C ref Manual 6.6
	on "this" op "t"
	"this" and "t" are integral or floating
	"t" may be 0
*/
{
// error('d', "arit_conv: this: %k %d %t %d", base, base, this, this );

	bit l;
	bit u;
	bit f;
	bit l1 = (base == LONG);
	bit u1 = b_unsigned;
	bit f1 = (base==FLOAT || base==DOUBLE || base==LDOUBLE);
	if (t) {
		t = (Pbase)t->skiptypedefs();
// error('d', "arit_conv: t: %k %d %t %d", t->base, t->base, t, t );

		bit l2 = (t->base == LONG);
		bit u2 = t->b_unsigned;
		bit f2 = (t->base==FLOAT || t->base==DOUBLE || t->base==LDOUBLE);
		l = l1 || l2;
		u = u1 || u2;
		f = f1 || f2;
	}
	else {
		l = l1;
		u = u1;
		f = f1;
	}

	if (f) {
		if (base==LDOUBLE || (t && t->base==LDOUBLE)) return ldouble_type;
		if (base==DOUBLE || (t && t->base==DOUBLE)) return double_type;
		return float_type;
	}
	if (l & u) return ulong_type;
	if (l & !u) return long_type;
	if (u) {
		if (base==INT || (t && t->base==INT)) return uint_type;
		if (SZ_SHORT==SZ_INT) // ANSIism
			if (base==SHORT || (t && t->base==SHORT)) return uint_type;
		return int_type;
	}

	return int_type;
}

bit vec_const = 0;
bit fct_const = 0;

bit type::tconst()
/*
	is this type a constant
*/
{
	Ptype t = this;
	vec_const = 0;
	fct_const = 0;
//error('d',"tconst %t",t);
xxx:
	switch (t->base) {
	case TYPE:
		if (Pbase(t)->b_const) return 1;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case VEC:
		vec_const = 1;
		return 1;
	case PTR:
	case RPTR:
		return Pptr(t)->b_const;
	case FCT:
	case OVERLOAD:
		fct_const = 1;
		return 1;
	default:
		return Pbase(t)->b_const;
	}
}

bit
type::is_const_object()
{
	int cc = this->tconst();
	Ptype tt = this->skiptypedefs();
	while ( cc && tt->base == VEC ) {
		tt = Pvec(tt)->typ;
		cc = tt->tconst();
		tt = tt->skiptypedefs();
	}
	return cc;
}

TOK type::set_const(bit mode)
/*
	make someting a constant or variable, return old status
*/
{
	Ptype t = this;
	int m;
xxx:
	switch (t->base) {
	case TYPE:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		t = Pbase(t)->b_name->tp;
		goto xxx;
	case ANY:
	case RPTR:
	case VEC:
		return t->base;		// constant by definition
	case PTR:
		m = Pptr(t)->b_const;
		Pptr(t)->b_const = mode;
		return m;
	default:
		m = Pbase(t)->b_const;
		Pbase(t)->b_const = mode;
		return m;
	}
}

Pptr type::is_ref()
{
	Ptype t = skiptypedefs();

	switch (t->base) {
	case RPTR:	return Pptr(t);
	default:	return 0;
	}
}

Pclass Mptr;

Pptr type::is_ptr()
{
	Ptype t = skiptypedefs();

	switch (t->base) {
	case PTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

Pptr type::is_ptr_or_ref()
{
	Ptype t = skiptypedefs();

	switch (t->base) {
	case PTR:
	case RPTR:
	case VEC:	Mptr = Pptr(t)->memof;
			return Pptr(t);
	default:	return 0;
	}
}

int type::align()
{
	Ptype t = skiptypedefs();

/*fprintf(stderr,"align %d %d\n",t,t->base);*/
	switch (t->base) {
	case COBJ:	return t->bname_type()->align();
	case VEC:	return Pvec(t)->typ->align();
	case ANY:	return 1;
	case CHAR:	return AL_CHAR;
	case SHORT:	return AL_SHORT;
	case INT:	return AL_INT;
	case LONG:	return AL_LONG;
	case FLOAT:	return AL_FLOAT;
	case DOUBLE:	return AL_DOUBLE;
	case LDOUBLE:	return AL_LDOUBLE;
	case PTR:
	case RPTR:	return AL_WPTR;
	case CLASS:	return Pclass(t)->obj_align;
	case ENUM:
	case EOBJ:	return AL_INT;
	case VOID:	error("illegal use of void"); return AL_INT;
	default:	error('i',"(%d,%k)->type::align",t,t->base);
	}
}

bit fake_sizeof;

int type::tsizeof(int ptmc)
/*
	the sizeof type operator
	return the size in bytes of the types representation
*/
{
	Ptype t = skiptypedefs();

//error('d',"zx %t %d",t,t->base);
	if (t == 0) error('i',"typ.tsizeof(t==0)");
	switch (t->base) {
	case COBJ:
		t = t->bname_type();
		if (t == 0) return 0;	// ``fake'' generated classes: _Sdd
		return t->tsizeof(ptmc);

	case ANY:	return 1;
	case VOID:	return 0;
	case ZTYPE:	return SZ_WPTR;	/* assume pointer */
	case CHAR:	return SZ_CHAR;
	case SHORT:	return SZ_SHORT;
	case INT:	return SZ_INT;
	case LONG:	return SZ_LONG;
	case FLOAT:	return SZ_FLOAT;
	case DOUBLE:	return SZ_DOUBLE;
	case LDOUBLE:	return SZ_LDOUBLE;

	case VEC:
		{	Pvec v = Pvec(t);
			if (v->size == 0) {
				if (fake_sizeof == 0) error("sizeof array with undeclared dimension");
				return SZ_WPTR;	// vector argument has sizeof ptr
			}
			return v->size * v->typ->tsizeof();
		}
	case RPTR:	
	case PTR:
	{	
		int k = (Pptr(t)->memof && !ptmc)?sizeof(short)+sizeof(short):0;
		t = Pptr(t)->typ->skiptypedefs();

		switch (t->base) {
		default:	return SZ_WPTR;
		case CHAR:	return SZ_BPTR;
		case FCT:	return SZ_WPTR+k;
		}
	}
	case FIELD:
		error("sizeof(field)");
		return Pbase(t)->b_bits/BI_IN_BYTE+1;
	case OVERLOAD:
	case FCT:
		error("sizeof(function)");
		return 0;

	case CLASS:	
	{
                Pclass cl = Pclass(t);
		if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
			if ( cl->class_base == CL_TEMPLATE || 
			     cl->class_base == UNINSTANTIATED )
				error("YC%t not yet instantiated; please add an explicit instantiation (Tdef%t<Ts>)",cl,cl);
			else error("%tU, size not known",cl);
			return SZ_INT;
		}
	 	if (cl->c_body == 1)	// detect first allocation or sizeof
	 		cl->dcl_print(0);
		return cl->obj_size;
	}

	case EOBJ:
		if ((t->enumtype()->defined&(DEFINED|SIMPLIFIED)) == 0)
			error("%tU, size not known",t->enumtype());
	case ENUM:	return SZ_INT;

	default:	return 0;	// deref can be called for any type
			//error('i',"sizeof(%d)",t->base);
	}
}

bit type::vec_type()
{
	Ptype t = skiptypedefs();

	switch (t->base) {
	case ANY:
	case VEC:
	case PTR:
	case RPTR:	return 1;
	default:	return 0;
	}
}

int ref_initializer;

Ptype type::deref()
/*	index==1:	*p
	index==0:	p[expr]
*/
{
//error('d',"%t -> deref() refd %d",this,ref_initializer);
	Ptype t = skiptypedefs();

	switch (t->base) {
	case PTR:
	case RPTR:
	case VEC:
	{
		if (t == Pvoid_type)
			error("void* dereferenced");
		t = Pvec(t)->typ;
		if (ref_initializer == 0) {
			Ptype tt = t->skiptypedefs();
			if (tt->base == COBJ) { 
                        	tt = tt->bname_type();
                        	if (tt && Pclass(tt)->defined&(DEFINED|SIMPLIFIED))
                                	(void) t->tsizeof();
                        }
		}
		// no break
	}
	case ANY:
		return t;
	default:
		error("nonP dereferenced");
		return any_type;
	}
}

Pfct type::memptr()
// is ``this'' a pointer to member function
{
	if (this == 0) return 0;
	Ptype t = skiptypedefs();
	if (t->base != PTR || Pptr(t)->memof==0) return 0;

	t = Pptr(t)->typ->skiptypedefs();
	return (t->base == FCT) ? Pfct(t) : 0;
}

Ptype type::skiptypedefs()
// starting from ``this'', return first non-typedef
{
	register Ptype t = this;
	if(t==0) return t;
	while (t->base == TYPE) {
		t = t->bname_type();
	}
	return t;
}

Ptype type::skiptypedefs(bit &isconst)
// starting from ``this'', return first non-typedef
{
	register Ptype t = this;
	isconst=0;
	if(t==0) return t;
	while (t->base == TYPE) {
		isconst |= Pbase(t)->b_const;
		t = t->bname_type();
	}
	isconst |= Pbase(t)->b_const;
	return t;
}

Ptype type::mkconst()
{
	Ptype r = this;

	switch(base) {
	case TYPE:
	{
		Ptype t = skiptypedefs();
		if(t->base == VEC)
			return t->mkconst();
	}
	case INT:
	case CHAR:
	case SHORT:
	case LONG:
	case FLOAT:
	case DOUBLE:
	case LDOUBLE:
	case FIELD:
	case ZTYPE:
	case COBJ:
	case EOBJ:
		if(b_const==0) {
//			r = new basetype(*(Pbase)this); // won't compile with 2.0
			r = new basetype(base,0);
			PERM(r);
			*(Pbase)r = *(Pbase)this;
			r->b_const=1;
		}
		break;
	case PTR:
	case RPTR:
		if(b_const==0) {
//			r = new ptr(*(Pptr)this); // won't compile with 2.0
			r = new ptr(base,0);
			PERM(r);
			*(Pptr)r = *(Pptr)this;
			r->b_const=1;
		}
		break;
	case VEC:
	{
		Ptype t = Pvec(this)->typ->mkconst();
		if(t != Pvec(this)->typ) {
//			r = new vec(*(Pvec)this); // won't compile with 2.0
			r = new vec(Pvec(this)->typ,0);
			PERM(r);
			*(Pvec)r = *(Pvec)this;
			Pvec(r)->typ=t;
		}
		break;
	}

	default:
		error('i',"mkconst for %t",this);
	}

	return r;
}
