Mercurial > projects > ddmd
diff dmd/EnumDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 427f8aa74d28 1628b221808d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/EnumDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,416 @@ +module dmd.EnumDeclaration; + +import dmd.ScopeDsymbol; +import dmd.AddExp; +import dmd.Type; +import dmd.CmpExp; +import dmd.IntegerExp; +import dmd.EqualExp; +import dmd.TOK; +import dmd.Id; +import dmd.TY; +import dmd.DsymbolTable; +import dmd.STC; +import dmd.Expression; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Scope; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.Global; +import dmd.Loc; +import dmd.TypeEnum; +import dmd.EnumMember; +import dmd.DYNCAST; +import dmd.WANT; +import dmd.Id; +import dmd.Lexer; + +import dmd.backend.SC; +import dmd.backend.FL; +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.Classsym; +import dmd.backend.SFL; +import dmd.backend.LIST; +import dmd.codegen.Util; + +import std.stdio : writef; + +class EnumDeclaration : ScopeDsymbol +{ /* enum ident : memtype { ... } + */ + Type type; // the TypeEnum + Type memtype; // type of the members + +version (DMDV1) { + ulong maxval; + ulong minval; + ulong defaultval; // default initializer +} else { + Expression maxval; + Expression minval; + Expression defaultval; // default initializer +} + bool isdeprecated; + + this(Loc loc, Identifier id, Type memtype) + { + super(id); + this.loc = loc; + type = new TypeEnum(this); + this.memtype = memtype; + } + + Dsymbol syntaxCopy(Dsymbol s) + { + assert(false); + } + + void semantic(Scope sc) + { + Type t; + Scope sce; + + //writef("EnumDeclaration.semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), toChars()); + //writef("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 & STC.STCdeprecated) + isdeprecated = true; + + 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 == TY.Tenum) + { EnumDeclaration sym = cast(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); + writef("\tdeferring %s\n", toChars()); + return; + } + } +static if (false) { + // 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; + } +} + } + + 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 = (cast(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.DYNCAST_EXPRESSION); + e = e.semantic(sce); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (memtype) + { + e = e.implicitCastTo(sce, memtype); + e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (!isAnonymous()) + e = e.castTo(sce, type); + t = memtype; + } + else if (em.type) + { + e = e.implicitCastTo(sce, em.type); + e = e.optimize(WANT.WANTvalue | WANT.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(WANT.WANTvalue | WANT.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(TOK.TOKequal, em.loc, elast, t.getProperty(Loc(0), Id.max)); + e = e.semantic(sce); + e = e.optimize(WANT.WANTvalue | WANT.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(WANT.WANTvalue | WANT.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 scxx = sce; scxx; scxx = scxx.enclosing) + { + if (scxx.scopesym) + { + if (!scxx.scopesym.symtab) + scxx.scopesym.symtab = new DsymbolTable(); + em.addMember(sce, scxx.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(TOK.TOKlt, em.loc, e, minval); + ec = ec.semantic(sce); + ec = ec.optimize(WANT.WANTvalue | WANT.WANTinterpret); + if (ec.toInteger()) + minval = e; + + ec = new CmpExp(TOK.TOKgt, em.loc, e, maxval); + ec = ec.semantic(sce); + ec = ec.optimize(WANT.WANTvalue | WANT.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(); + } + + bool oneMember(Dsymbol* ps) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Type getType() + { + return type; + } + + string kind() + { + return "enum"; + } + +version (DMDV2) { + Dsymbol search(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; + } + + return ScopeDsymbol.search(loc, ident, flags); + } +} + bool isDeprecated() // is Dsymbol deprecated? + { + return isdeprecated; + } + + void emitComment(Scope sc) + { + assert(false); + } + + void toDocBuffer(OutBuffer buf) + { + assert(false); + } + + EnumDeclaration isEnumDeclaration() { return this; } + + void toObjFile(int multiobj) // compile to .obj file + { + //printf("EnumDeclaration::toObjFile('%s')\n", toChars()); + version (DMDV2) { + if (isAnonymous()) + return; + } + + if (global.params.symdebug) + toDebug(); + + type.getTypeInfo(null); // generate TypeInfo + + TypeEnum tc = cast(TypeEnum)type; + if (!tc.sym.defaultval || type.isZeroInit(Loc(0))) { + ; + } else { + SC scclass = SCglobal; + if (inTemplateInstance()) + scclass = SCcomdat; + + // Generate static initializer + toInitializer(); + sinit.Sclass = scclass; + sinit.Sfl = FLdata; + version (ELFOBJ) { // Burton + sinit.Sseg = Segment.CDATA; + } + version (MACHOBJ) { + sinit.Sseg = Segment.DATA; + } + version (DMDV1) { + dtnbytes(&sinit.Sdt, tc.size(0), cast(char*)&tc.sym.defaultval); + //sinit->Sdt = tc->sym->init->toDt(); + } + version (DMDV2) { + tc.sym.defaultval.toDt(&sinit.Sdt); + } + outdata(sinit); + } + } + + void toDebug() + { + assert(false); + } + + int cvMember(ubyte* p) + { + assert(false); + } + + Symbol* sinit; + + Symbol* toInitializer() + { + Symbol* s; + Classsym* stag; + + if (!sinit) + { + stag = fake_classsym(Id.ClassInfo); + Identifier ident_save = ident; + if (!ident) + ident = Lexer.uniqueId("__enum"); + s = toSymbolX("__init", SCextern, stag.Stype, "Z"); + ident = ident_save; + s.Sfl = FLextern; + s.Sflags |= SFLnodebug; + slist_add(s); + sinit = s; + } + + return sinit; + } +}; \ No newline at end of file