diff dmd2/statement.c @ 1526:54b3c1394d62

Merged dmdfe 2.031.
author Robert Clipsham <robert@octarineparrot.com>
date Tue, 07 Jul 2009 02:26:11 +0100
parents 638d16625da2
children e4f7b5d9c68a
line wrap: on
line diff
--- a/dmd2/statement.c	Mon Jul 06 23:57:27 2009 +0100
+++ b/dmd2/statement.c	Tue Jul 07 02:26:11 2009 +0100
@@ -144,6 +144,13 @@
     return FALSE;
 }
 
+// Return TRUE if statement has no code in it
+int Statement::isEmpty()
+{
+    //printf("Statement::isEmpty()\n");
+    return FALSE;
+}
+
 /****************************************
  * If this statement has code that needs to run in a finally clause
  * at the end of the current scope, return that code in the form of
@@ -580,6 +587,16 @@
     return comefrom;
 }
 
+int CompoundStatement::isEmpty()
+{
+    for (int i = 0; i < statements->dim; i++)
+    {	Statement *s = (Statement *) statements->data[i];
+	if (s && !s->isEmpty())
+	    return FALSE;
+    }
+    return TRUE;
+}
+
 
 /******************************** CompoundDeclarationStatement ***************************/
 
@@ -856,6 +873,12 @@
     return statement ? statement->comeFrom() : FALSE;
 }
 
+int ScopeStatement::isEmpty()
+{
+    //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE);
+    return statement ? statement->isEmpty() : TRUE;
+}
+
 void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     buf->writeByte('{');
@@ -1536,7 +1559,6 @@
 	    /* Generate a temporary __r and initialize it with the aggregate.
 	     */
 	    Identifier *id = Identifier::generateId("__r");
-	    aggr = aggr->semantic(sc);
 	    Expression *rinit = new SliceExp(loc, aggr, NULL, NULL);
 	    rinit = rinit->trySemantic(sc);
 	    if (!rinit)			// if application of [] failed
@@ -1870,7 +1892,7 @@
 		}
 
 		s = new CompoundStatement(loc, a);
-		s = new SwitchStatement(loc, e, s);
+		s = new SwitchStatement(loc, e, s, FALSE);
 		s = s->semantic(sc);
 	    }
 	    break;
@@ -2546,23 +2568,25 @@
 
 /******************************** SwitchStatement ***************************/
 
-SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b)
+SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal)
     : Statement(loc)
 {
-    condition = c;
-    body = b;
+    this->condition = c;
+    this->body = b;
+    this->isFinal = isFinal;
     sdefault = NULL;
     cases = NULL;
     hasNoDefault = 0;
     hasVars = 0;
-    // LDC
+#if IN_LLVM
     enclosingScopeExit = NULL;
+#endif
 }
 
 Statement *SwitchStatement::syntaxCopy()
 {
     SwitchStatement *s = new SwitchStatement(loc,
-	condition->syntaxCopy(), body->syntaxCopy());
+	condition->syntaxCopy(), body->syntaxCopy(), isFinal);
     return s;
 }
 
@@ -2571,8 +2595,9 @@
     //printf("SwitchStatement::semantic(%p)\n", this);
     assert(!cases);		// ensure semantic() is only run once
 
-    // LDC
+#if IN_LLVM
     enclosingScopeExit = sc->enclosingScopeExit;
+#endif
 
     condition = condition->semantic(sc);
     condition = resolveProperties(sc, condition);
@@ -2663,6 +2688,37 @@
 	body = cs;
     }
 
+#if DMDV2
+    if (isFinal)
+    {	Type *t = condition->type;
+	while (t->ty == Ttypedef)
+	{   // Don't use toBasetype() because that will skip past enums
+	    t = ((TypeTypedef *)t)->sym->basetype;
+	}
+	if (condition->type->ty == Tenum)
+	{   TypeEnum *te = (TypeEnum *)condition->type;
+	    EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration();
+	    assert(ed);
+	    size_t dim = ed->members->dim;
+	    for (size_t i = 0; i < dim; i++)
+	    {
+		EnumMember *em = ((Dsymbol *)ed->members->data[i])->isEnumMember();
+		if (em)
+		{
+		    for (size_t j = 0; j < cases->dim; j++)
+		    {   CaseStatement *cs = (CaseStatement *)cases->data[j];
+			if (cs->exp->equals(em->value))
+			    goto L1;
+		    }
+		    error("enum member %s not represented in final switch", em->toChars());
+		}
+	      L1:
+		;
+	    }
+	}
+    }
+#endif
+
     sc->pop();
     return this;
 }
@@ -2746,13 +2802,13 @@
     exp = exp->semantic(sc);
     if (sw)
     {
-	// LDC
+#if IN_LLVM
 	enclosingScopeExit = sc->enclosingScopeExit;
 	if (enclosingScopeExit != sw->enclosingScopeExit)
 	{
 	    error("case must be inside the same try, synchronized or volatile level as switch");
 	}
-
+#endif
 	exp = exp->implicitCastTo(sc, sw->condition->type);
 	exp = exp->optimize(WANTvalue | WANTinterpret);
 
@@ -2767,6 +2823,8 @@
 		 * for this, i.e. generate a sequence of if-then-else
 		 */
 		sw->hasVars = 1;
+		if (sw->isFinal)
+		    error("case variables not allowed in final switch statements");
 		goto L1;
 	    }
 	}
@@ -2846,6 +2904,85 @@
     statement->toCBuffer(buf, hgs);
 }
 
+/******************************** CaseRangeStatement ***************************/
+
+#if DMDV2
+
+CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first,
+	Expression *last, Statement *s)
+    : Statement(loc)
+{
+    this->first = first;
+    this->last = last;
+    this->statement = s;
+}
+
+Statement *CaseRangeStatement::syntaxCopy()
+{
+    CaseRangeStatement *s = new CaseRangeStatement(loc,
+	first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy());
+    return s;
+}
+
+Statement *CaseRangeStatement::semantic(Scope *sc)
+{   SwitchStatement *sw = sc->sw;
+
+    //printf("CaseRangeStatement::semantic() %s\n", toChars());
+    if (sw->isFinal)
+	error("case ranges not allowed in final switch");
+
+    first = first->semantic(sc);
+    first = first->implicitCastTo(sc, sw->condition->type);
+    first = first->optimize(WANTvalue | WANTinterpret);
+    dinteger_t fval = first->toInteger();
+
+    last = last->semantic(sc);
+    last = last->implicitCastTo(sc, sw->condition->type);
+    last = last->optimize(WANTvalue | WANTinterpret);
+    dinteger_t lval = last->toInteger();
+
+    if (lval - fval > 256)
+    {	error("more than 256 cases in case range");
+	lval = fval + 256;
+    }
+
+    /* This works by replacing the CaseRange with an array of Case's.
+     *
+     * case a: .. case b: s;
+     *    =>
+     * case a:
+     *   [...]
+     * case b:
+     *   s;
+     */
+
+    Statements *statements = new Statements();
+    for (dinteger_t i = fval; i <= lval; i++)
+    {
+	Statement *s = statement;
+	if (i != lval)
+	    s = new ExpStatement(loc, NULL);
+	Expression *e = new IntegerExp(loc, i, first->type);
+	Statement *cs = new CaseStatement(loc, e, s);
+	statements->push(cs);
+    }
+    Statement *s = new CompoundStatement(loc, statements);
+    s = s->semantic(sc);
+    return s;
+}
+
+void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    buf->writestring("case ");
+    first->toCBuffer(buf, hgs);
+    buf->writestring(": .. case ");
+    last->toCBuffer(buf, hgs);
+    buf->writenl();
+    statement->toCBuffer(buf, hgs);
+}
+
+#endif
+
 /******************************** DefaultStatement ***************************/
 
 DefaultStatement::DefaultStatement(Loc loc, Statement *s)
@@ -2877,12 +3014,18 @@
 	}
 	sc->sw->sdefault = this;
 
-	// LDC
+#if IN_LLVM
 	enclosingScopeExit = sc->enclosingScopeExit;
 	if (enclosingScopeExit != sc->sw->enclosingScopeExit)
 	{
 	    error("default must be inside the same try, synchronized or volatile level as switch");
 	}
+
+    if (sc->sw->isFinal)
+    {
+        error("default statement not allowed in final switch statement");
+    }
+#endif
     }
     else
 	error("default not in switch statement");
@@ -3217,6 +3360,7 @@
 
 	    // Construct: { vresult = exp; return cases.dim + 1; }
 	    exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp);
+	    exp->op = TOKconstruct;
 	    exp = exp->semantic(sc);
 	    Statement *s1 = new ExpStatement(loc, exp);
 	    Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1));
@@ -3233,6 +3377,7 @@
 	    VarExp *v = new VarExp(0, fd->vresult);
 
 	    exp = new AssignExp(loc, v, exp);
+	    exp->op = TOKconstruct;
 	    exp = exp->semantic(sc);
 	}
 
@@ -3757,9 +3902,10 @@
 	}
     }
 
-    if (!body)
+    if (!body || body->isEmpty())
+    {
 	return NULL;
-
+    }
     return this;
 }