Mercurial > projects > ldc
diff dmd2/enum.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 638d16625da2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/enum.c Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,392 @@ + +// 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"; +} + +