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";
+}
+
+