view dmd/enum.c @ 270:d9d5d59873d8 trunk

[svn r291] Fixed a bunch of the old Phobos tests to work with Tango. Branch statements now emit a new block after it. Fixed the _adSort runtime function had a bad signature. Added a missing dot prefix on compiler generated string tables for string switch. Fixed, PTRSIZE seems like it was wrong on 64bit, now it definitely gets set properly.
author lindquist
date Mon, 16 Jun 2008 16:01:19 +0200
parents c53b6e3fe49a
children aaade6ded589
line wrap: on
line source


// Copyright (c) 1999-2006 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#include <stdio.h>
#include <assert.h>

#include "root.h"
#include "enum.h"
#include "mtype.h"
#include "scope.h"

/********************************* EnumDeclaration ****************************/

EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
    : ScopeDsymbol(id)
{
    this->loc = loc;
    type = new TypeEnum(this);
    this->memtype = memtype;
    maxval = 0;
    minval = 0;
    defaultval = 0;
    sinit = NULL;
}

Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
{
    Type *t = NULL;
    if (memtype)
	t = memtype->syntaxCopy();

    EnumDeclaration *ed;
    if (s)
    {	ed = (EnumDeclaration *)s;
	ed->memtype = t;
    }
    else
	ed = new EnumDeclaration(loc, ident, t);
    ScopeDsymbol::syntaxCopy(ed);
    return ed;
}

void EnumDeclaration::semantic(Scope *sc)
{   int i;
    uinteger_t number;
    Type *t;
    Scope *sce;

    //printf("EnumDeclaration::semantic(sd = %p, '%s')\n", sc->scopesym, sc->scopesym->toChars());
    if (symtab)			// if already done
	return;
    if (!memtype)
	memtype = Type::tint32;
    parent = sc->scopesym;
    memtype = memtype->semantic(loc, sc);

    /* Check to see if memtype is forward referenced
     */
    if (memtype->ty == Tenum)
    {	EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
	if (!sym->memtype)
	{
	    error("base enum %s is forward referenced", sym->toChars());
	    memtype = Type::tint32;
	}
    }

    if (!memtype->isintegral())
    {	error("base type must be of integral type, not %s", memtype->toChars());
	memtype = Type::tint32;
    }

    t = isAnonymous() ? memtype : type;
    symtab = new DsymbolTable();
    sce = sc->push(this);
    sce->parent = this;
    number = 0;
    if (!members)		// enum ident;
	return;
    if (members->dim == 0)
	error("enum %s must have at least one member", toChars());
    int first = 1;
    for (i = 0; i < members->dim; i++)
    {
	EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
	Expression *e;

	if (!em)
	    /* The e->semantic(sce) can insert other symbols, such as
	     * template instances and function literals.
	     */
	    continue;

	//printf("Enum member '%s'\n",em->toChars());
	e = em->value;
	if (e)
	{
	    assert(e->dyncast() == DYNCAST_EXPRESSION);
	    e = e->semantic(sce);
	    e = e->optimize(WANTvalue);
	    // Need to copy it because we're going to change the type
	    e = e->copy();
	    e = e->implicitCastTo(sc, memtype);
	    e = e->optimize(WANTvalue);
	    number = e->toInteger();
	    e->type = t;
	}
	else
	{   // Default is the previous number plus 1

	    // Check for overflow
	    if (!first)
	    {
		switch (t->toBasetype()->ty)
		{
		    case Tbool:
			if (number == 2)	goto Loverflow;
			break;

		    case Tint8:
			if (number == 128) goto Loverflow;
			break;

		    case Tchar:
		    case Tuns8:
			if (number == 256) goto Loverflow;
			break;

		    case Tint16:
			if (number == 0x8000) goto Loverflow;
			break;

		    case Twchar:
		    case Tuns16:
			if (number == 0x10000) goto Loverflow;
			break;

		    case Tint32:
			if (number == 0x80000000) goto Loverflow;
			break;

		    case Tdchar:
		    case Tuns32:
			if (number == 0x100000000LL) goto Loverflow;
			break;

		    case Tint64:
			if (number == 0x8000000000000000LL) goto Loverflow;
			break;

		    case Tuns64:
			if (number == 0) goto Loverflow;
			break;

		    Loverflow:
			error("overflow of enum value");
			break;

		    default:
			assert(0);
		}
	    }
	    e = new IntegerExp(em->loc, number, t);
	}
	em->value = e;

	// Add to symbol table only after evaluating 'value'
	if (isAnonymous())
	{
	    //sce->enclosing->insert(em);
	    for (Scope *scx = sce->enclosing; scx; scx = scx->enclosing)
	    {
		if (scx->scopesym)
		{
		    if (!scx->scopesym->symtab)
			scx->scopesym->symtab = new DsymbolTable();
		    em->addMember(sce, scx->scopesym, 1);
		    break;
		}
	    }
	}
	else
	    em->addMember(sc, this, 1);

	if (first)
	{   first = 0;
	    defaultval = number;
	    minval = number;
	    maxval = number;
	}
	else if (memtype->isunsigned())
	{
	    if (number < minval)
		minval = number;
	    if (number > maxval)
		maxval = number;
	}
	else
	{
	    if ((sinteger_t)number < (sinteger_t)minval)
		minval = number;
	    if ((sinteger_t)number > (sinteger_t)maxval)
		maxval = number;
	}

	number++;
    }
    //printf("defaultval = %lld\n", defaultval);

    sce->pop();
    //members->print();
}

int EnumDeclaration::oneMember(Dsymbol **ps)
{
    if (isAnonymous())
	return Dsymbol::oneMembers(members, ps);
    return Dsymbol::oneMember(ps);
}

void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{   int i;

    buf->writestring("enum ");
    if (ident)
    {	buf->writestring(ident->toChars());
	buf->writeByte(' ');
    }
    if (memtype)
    {
	buf->writestring(": ");
	memtype->toCBuffer(buf, NULL, hgs);
    }
    if (!members)
    {
	buf->writeByte(';');
	buf->writenl();
	return;
    }
    buf->writenl();
    buf->writeByte('{');
    buf->writenl();
    for (i = 0; i < members->dim; i++)
    {
	EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember();
	if (!em)
	    continue;
	//buf->writestring("    ");
	em->toCBuffer(buf, hgs);
	buf->writeByte(',');
	buf->writenl();
    }
    buf->writeByte('}');
    buf->writenl();
}

Type *EnumDeclaration::getType()
{
    return type;
}

char *EnumDeclaration::kind()
{
    return "enum";
}

/********************************* EnumMember ****************************/

EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value)
    : Dsymbol(id)
{
    this->value = value;
    this->loc = loc;
}

Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
{
    Expression *e = NULL;
    if (value)
	e = value->syntaxCopy();

    EnumMember *em;
    if (s)
    {	em = (EnumMember *)s;
	em->loc = loc;
	em->value = e;
    }
    else
	em = new EnumMember(loc, ident, e);
    return em;
}

void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring(ident->toChars());
    if (value)
    {
	buf->writestring(" = ");
	value->toCBuffer(buf, hgs);
    }
}

char *EnumMember::kind()
{
    return "enum member";
}