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