Mercurial > projects > ddmd
diff dmd/CaseStatement.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | a8b50ff7f201 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/CaseStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,177 @@ +module dmd.CaseStatement; + +import dmd.Statement; +import dmd.Expression; +import dmd.Statement; +import dmd.Scope; +import dmd.Loc; +import dmd.IRState; +import dmd.InlineScanState; +import dmd.HdrGenState; +import dmd.OutBuffer; +import dmd.InterState; +import dmd.BE; +import dmd.SwitchStatement; +import dmd.WANT; +import dmd.TOK; +import dmd.VarExp; +import dmd.VarDeclaration; +import dmd.Type; +import dmd.TY; +import dmd.IntegerExp; +import dmd.GotoCaseStatement; + +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.Util; +import dmd.backend.BC; + +class CaseStatement : Statement +{ + Expression exp; + Statement statement; + + int index = 0; // which case it is (since we sort this) + block* cblock = null; // back end: label for the block + + this(Loc loc, Expression exp, Statement s) + { + super(loc); + + this.exp = exp; + this.statement = s; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + SwitchStatement sw = sc.sw; + + //printf("CaseStatement.semantic() %s\n", toChars()); + exp = exp.semantic(sc); + if (sw) + { + exp = exp.implicitCastTo(sc, sw.condition.type); + exp = exp.optimize(WANTvalue | WANTinterpret); + + /* This is where variables are allowed as case expressions. + */ + if (exp.op == TOKvar) + { VarExp ve = cast(VarExp)exp; + VarDeclaration v = ve.var.isVarDeclaration(); + Type t = exp.type.toBasetype(); + if (v && (t.isintegral() || t.ty == Tclass)) + { + /* Flag that we need to do special code generation + * 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; + } + } + + if (exp.op != TOKstring && exp.op != TOKint64) + { + error("case must be a string or an integral constant, not %s", exp.toChars()); + exp = new IntegerExp(0); + } + + L1: + for (int i = 0; i < sw.cases.dim; i++) + { + CaseStatement cs = cast(CaseStatement)sw.cases.data[i]; + + //printf("comparing '%s' with '%s'\n", exp.toChars(), cs.exp.toChars()); + if (cs.exp.equals(exp)) + { + error("duplicate case %s in switch statement", exp.toChars()); + break; + } + } + + sw.cases.push(cast(void*)this); + + // Resolve any goto case's with no exp to this case statement + for (int i = 0; i < sw.gotoCases.dim; i++) + { + GotoCaseStatement gcs = cast(GotoCaseStatement)sw.gotoCases.data[i]; + + if (!gcs.exp) + { + gcs.cs = this; + sw.gotoCases.remove(i); // remove from array + } + } + + if (sc.sw.tf !is sc.tf) + error("switch and case are in different finally blocks"); + } + else + error("case not in switch statement"); + statement = statement.semantic(sc); + return this; + } + + int compare(Object obj) + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + return statement.blockExit(); + } + + bool comeFrom() + { + return true; + } + + Expression interpret(InterState *istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + Statement inlineScan(InlineScanState* iss) + { + //printf("CaseStatement.inlineScan()\n"); + exp = exp.inlineScan(iss); + if (statement) + statement = statement.inlineScan(iss); + return this; + } + + void toIR(IRState *irs) + { + Blockx* blx = irs.blx; + block* bcase = blx.curblock; + if (!cblock) + cblock = block_calloc(blx); + block_next(blx,BCgoto,cblock); + block* bsw = irs.getSwitchBlock(); + if (bsw.BC == BCswitch) + list_append(&bsw.Bsucc,cblock); // second entry in pair + list_append(&bcase.Bsucc,cblock); + if (blx.tryblock != bsw.Btry) + error("case cannot be in different try block level from switch"); + incUsage(irs, loc); + if (statement) + statement.toIR(irs); + } +} \ No newline at end of file