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