ldc/dmd2/enum.c

392 lines
9.2 KiB
C

// Copyright (c) 1999-2008 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"
#include "id.h"
#include "expression.h"
#include "module.h"
#include "declaration.h"
/********************************* EnumDeclaration ****************************/
EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
: ScopeDsymbol(id)
{
this->loc = loc;
type = new TypeEnum(this);
this->memtype = memtype;
maxval = NULL;
minval = NULL;
defaultval = NULL;
sinit = NULL;
scope = NULL;
isdeprecated = 0;
}
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)
{
Type *t;
Scope *sce;
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
//printf("EnumDeclaration::semantic() %s\n", toChars());
if (!members) // enum ident;
return;
if (!memtype && !isAnonymous())
{ // Set memtype if we can to reduce fwd reference errors
memtype = Type::tint32; // case 1) enum ident { ... }
}
if (symtab) // if already done
{ if (!scope)
return; // semantic() already completed
}
else
symtab = new DsymbolTable();
Scope *scx = NULL;
if (scope)
{ sc = scope;
scx = scope; // save so we don't make redundant copies
scope = NULL;
}
if (sc->stc & STCdeprecated)
isdeprecated = 1;
parent = sc->parent;
/* The separate, and distinct, cases are:
* 1. enum { ... }
* 2. enum : memtype { ... }
* 3. enum ident { ... }
* 4. enum ident : memtype { ... }
*/
if (memtype)
{
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 || !sym->members || !sym->symtab || sym->scope)
{ // memtype is forward referenced, so try again later
scope = scx ? scx : new Scope(*sc);
scope->setNoFree();
scope->module->addDeferredSemantic(this);
printf("\tdeferring %s\n", toChars());
return;
}
}
#if 0 // Decided to abandon this restriction for D 2.0
if (!memtype->isintegral())
{ error("base type must be of integral type, not %s", memtype->toChars());
memtype = Type::tint32;
}
#endif
}
type = type->semantic(loc, sc);
if (isAnonymous())
sce = sc;
else
{ sce = sc->push(this);
sce->parent = this;
}
if (members->dim == 0)
error("enum %s must have at least one member", toChars());
int first = 1;
Expression *elast = NULL;
for (int 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());
if (em->type)
em->type = em->type->semantic(em->loc, sce);
e = em->value;
if (e)
{
assert(e->dyncast() == DYNCAST_EXPRESSION);
e = e->semantic(sce);
e = e->optimize(WANTvalue | WANTinterpret);
if (memtype)
{
e = e->implicitCastTo(sce, memtype);
e = e->optimize(WANTvalue | WANTinterpret);
if (!isAnonymous())
e = e->castTo(sce, type);
t = memtype;
}
else if (em->type)
{
e = e->implicitCastTo(sce, em->type);
e = e->optimize(WANTvalue | WANTinterpret);
assert(isAnonymous());
t = e->type;
}
else
t = e->type;
}
else if (first)
{
if (memtype)
t = memtype;
else if (em->type)
t = em->type;
else
t = Type::tint32;
e = new IntegerExp(em->loc, 0, Type::tint32);
e = e->implicitCastTo(sce, t);
e = e->optimize(WANTvalue | WANTinterpret);
if (!isAnonymous())
e = e->castTo(sce, type);
}
else
{
// Set value to (elast + 1).
// But first check that (elast != t.max)
assert(elast);
e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max));
e = e->semantic(sce);
e = e->optimize(WANTvalue | WANTinterpret);
if (e->toInteger())
error("overflow of enum value %s", elast->toChars());
// Now set e to (elast + 1)
e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32));
e = e->semantic(sce);
e = e->castTo(sce, elast->type);
e = e->optimize(WANTvalue | WANTinterpret);
}
elast = e;
em->value = e;
// Add to symbol table only after evaluating 'value'
if (isAnonymous())
{
/* Anonymous enum members get added to enclosing scope.
*/
for (Scope *scx = sce; 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);
/* Compute .min, .max and .default values.
* If enum doesn't have a name, we can never identify the enum type,
* so there is no purpose for a .min, .max or .default
*/
if (!isAnonymous())
{
if (first)
{ defaultval = e;
minval = e;
maxval = e;
}
else
{ Expression *ec;
/* In order to work successfully with UDTs,
* build expressions to do the comparisons,
* and let the semantic analyzer and constant
* folder give us the result.
*/
// Compute if(e < minval)
ec = new CmpExp(TOKlt, em->loc, e, minval);
ec = ec->semantic(sce);
ec = ec->optimize(WANTvalue | WANTinterpret);
if (ec->toInteger())
minval = e;
ec = new CmpExp(TOKgt, em->loc, e, maxval);
ec = ec->semantic(sce);
ec = ec->optimize(WANTvalue | WANTinterpret);
if (ec->toInteger())
maxval = e;
}
}
first = 0;
}
//printf("defaultval = %lld\n", defaultval);
//if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
if (sc != sce)
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;
}
const char *EnumDeclaration::kind()
{
return "enum";
}
int EnumDeclaration::isDeprecated()
{
return isdeprecated;
}
Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags)
{
//printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
if (scope)
// Try one last time to resolve this enum
semantic(scope);
if (!members || !symtab || scope)
{ error("is forward referenced when looking for '%s'", ident->toChars());
//*(char*)0=0;
return NULL;
}
Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
return s;
}
/********************************* EnumMember ****************************/
EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type)
: Dsymbol(id)
{
this->value = value;
this->type = type;
this->loc = loc;
}
Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
{
Expression *e = NULL;
if (value)
e = value->syntaxCopy();
Type *t = NULL;
if (type)
t = type->syntaxCopy();
EnumMember *em;
if (s)
{ em = (EnumMember *)s;
em->loc = loc;
em->value = e;
em->type = t;
}
else
em = new EnumMember(loc, ident, e, t);
return em;
}
void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (type)
type->toCBuffer(buf, ident, hgs);
else
buf->writestring(ident->toChars());
if (value)
{
buf->writestring(" = ");
value->toCBuffer(buf, hgs);
}
}
const char *EnumMember::kind()
{
return "enum member";
}