Mercurial > projects > ddmd
diff dmd/IfStatement.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | b7d29f613539 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/IfStatement.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,311 @@ +module dmd.IfStatement; + +import dmd.Statement; +import dmd.Argument; +import dmd.Loc; +import dmd.Expression; +import dmd.VarDeclaration; +import dmd.Scope; +import dmd.InterState; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.InlineCostState; +import dmd.InlineDoState; +import dmd.InlineScanState; +import dmd.IRState; +import dmd.BE; +import dmd.WANT; +import dmd.ScopeDsymbol; +import dmd.Type; +import dmd.CondExp; +import dmd.AndAndExp; +import dmd.OrOrExp; +import dmd.AssignExp; +import dmd.VarExp; + +import dmd.backend.elem; +import dmd.backend.Util; +import dmd.backend.block; +import dmd.backend.Blockx; +import dmd.backend.BC; + +class IfStatement : Statement +{ + Argument arg; + Expression condition; + Statement ifbody; + Statement elsebody; + + VarDeclaration match; // for MatchExpression results + + this(Loc loc, Argument arg, Expression condition, Statement ifbody, Statement elsebody) + { + super(loc); + this.arg = arg; + this.condition = condition; + this.ifbody = ifbody; + this.elsebody = elsebody; + } + + Statement syntaxCopy() + { + assert(false); + } + + Statement semantic(Scope sc) + { + condition = condition.semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition.checkToBoolean(); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + condition = condition.optimize(WANT.WANTflags); + + // Evaluate at runtime + uint cs0 = sc.callSuper; + uint cs1; + + Scope scd; + if (arg) + { + /* Declare arg, which we will set to be the + * result of condition. + */ + ScopeDsymbol sym = new ScopeDsymbol(); + sym.parent = sc.scopesym; + scd = sc.push(sym); + + Type t = arg.type ? arg.type : condition.type; + match = new VarDeclaration(loc, t, arg.ident, null); + match.noauto = true; + match.semantic(scd); + if (!scd.insert(match)) + assert(0); + + match.parent = sc.func; + + /* Generate: + * (arg = condition) + */ + VarExp v = new VarExp(Loc(0), match); + condition = new AssignExp(loc, v, condition); + condition = condition.semantic(scd); + } + else + scd = sc.push(); + + ifbody = ifbody.semantic(scd); + scd.pop(); + + cs1 = sc.callSuper; + sc.callSuper = cs0; + if (elsebody) + elsebody = elsebody.semanticScope(sc, null, null); + + sc.mergeCallSuper(loc, cs1); + + return this; + } + + Expression interpret(InterState* istate) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + bool usesEH() + { + assert(false); + } + + BE blockExit() + { + //printf("IfStatement::blockExit(%p)\n", this); + + BE result = BE.BEnone; + if (condition.canThrow()) + result |= BE.BEthrow; + if (condition.isBool(true)) + { + if (ifbody) + result |= ifbody.blockExit(); + else + result |= BE.BEfallthru; + } + else if (condition.isBool(false)) + { + if (elsebody) + result |= elsebody.blockExit(); + else + result |= BE.BEfallthru; + } + else + { + if (ifbody) + result |= ifbody.blockExit(); + else + result |= BE.BEfallthru; + + if (elsebody) + result |= elsebody.blockExit(); + else + result |= BE.BEfallthru; + } + + //printf("IfStatement::blockExit(%p) = x%x\n", this, result); + return result; + } + + IfStatement isIfStatement() { return this; } + + int inlineCost(InlineCostState* ics) + { + int cost; + + /* Can't declare variables inside ?: expressions, so + * we cannot inline if a variable is declared. + */ + if (arg) + return COST_MAX; + + cost = condition.inlineCost(ics); + + /* Specifically allow: + * if (condition) + * return exp1; + * else + * return exp2; + * Otherwise, we can't handle return statements nested in if's. + */ + + if (elsebody && ifbody && + ifbody.isReturnStatement() && + elsebody.isReturnStatement()) + { + cost += ifbody.inlineCost(ics); + cost += elsebody.inlineCost(ics); + //printf("cost = %d\n", cost); + } + else + { + ics.nested += 1; + if (ifbody) + cost += ifbody.inlineCost(ics); + if (elsebody) + cost += elsebody.inlineCost(ics); + ics.nested -= 1; + } + return cost; + } + + Expression doInline(InlineDoState ids) + { + Expression econd; + Expression e1; + Expression e2; + Expression e; + + assert(!arg); + econd = condition.doInline(ids); + assert(econd); + if (ifbody) + e1 = ifbody.doInline(ids); + else + e1 = null; + if (elsebody) + e2 = elsebody.doInline(ids); + else + e2 = null; + if (e1 && e2) + { + e = new CondExp(econd.loc, econd, e1, e2); + e.type = e1.type; + } + else if (e1) + { + e = new AndAndExp(econd.loc, econd, e1); + e.type = Type.tvoid; + } + else if (e2) + { + e = new OrOrExp(econd.loc, econd, e2); + e.type = Type.tvoid; + } + else + { + e = econd; + } + return e; + } + + Statement inlineScan(InlineScanState* iss) + { + condition = condition.inlineScan(iss); + if (ifbody) + ifbody = ifbody.inlineScan(iss); + if (elsebody) + elsebody = elsebody.inlineScan(iss); + return this; + } + + void toIR(IRState* irs) + { + elem* e; + Blockx* blx = irs.blx; + + //printf("IfStatement::toIR('%s')\n", condition.toChars()); + + IRState mystate = IRState(irs, this); + + // bexit is the block that gets control after this IfStatement is done + block* bexit = mystate.breakBlock ? mystate.breakBlock : block_calloc(); + + incUsage(irs, loc); +static if (false) { + if (match) + { + /* Generate: + * if (match = RTLSYM_IFMATCH(string, pattern)) ... + */ + assert(condition.op == TOK.TOKmatch); + e = matchexp_toelem(cast(MatchExp)condition, &mystate, RTLSYM.RTLSYM_IFMATCH); + Symbol *s = match.toSymbol(); + symbol_add(s); + e = el_bin(OPeq, TYnptr, el_var(s), e); + } + else + { + e = condition.toElem(&mystate); + } +} else { + e = condition.toElem(&mystate); +} + block_appendexp(blx.curblock, e); + block* bcond = blx.curblock; + block_next(blx, BC.BCiftrue, null); + + list_append(&bcond.Bsucc, blx.curblock); + if (ifbody) + ifbody.toIR(&mystate); + + list_append(&blx.curblock.Bsucc, bexit); + + if (elsebody) + { + block_next(blx, BC.BCgoto, null); + list_append(&bcond.Bsucc, blx.curblock); + elsebody.toIR(&mystate); + list_append(&blx.curblock.Bsucc, bexit); + } + else + list_append(&bcond.Bsucc, bexit); + + block_next(blx, BC.BCgoto, bexit); + } +} \ No newline at end of file