protected override ICode VisitDoLoop(StmtDoLoop s) {
            var ctx = s.Ctx;
            var body = (Stmt)this.Visit(s.Body);
            var @while = (Expr)this.Visit(s.While);

            var conditionVars = VisitorFindVars.V(@while);
            var needAssigning = conditionVars.Except(this.stack.SelectMany(x => x), (IEqualityComparer<ExprVar>)this.phiComparer).ToArray();
            if (needAssigning.Any()) {
                var replacements = needAssigning.Select(x => {
                    var newExpr = ctx.Local(x.Type);
                    var phi = new ExprVarPhi(ctx) { Exprs = new[] { x, newExpr } };
                    return new { orgExpr = x, newExpr, phi };
                }).ToArray();
                foreach (var replace in replacements) {
                    this.stack.Peek().Add(replace.newExpr);
                    this.stack.Peek().Add(replace.phi);
                    @while = (Expr)VisitorReplace.V(@while, replace.orgExpr, replace.phi);
                }
                var assignmentStmts = replacements
                    .Select(x=>new StmtAssignment(ctx, x.newExpr, new ExprDefaultValue(ctx, x.newExpr.Type)))
                    .ToArray();
                body = new StmtBlock(ctx, assignmentStmts.Concat(body));
            }

            if (body != s.Body || @while != s.While) {
                return new StmtDoLoop(ctx, body, @while);
            } else {
                return s;
            }
        }
 protected override ICode VisitContinuation(StmtContinuation s) {
     // TODO: Why is this de-recursing blocks in continuations? Why doesn't it just derecurse itself (if possible)???
     if (s.To.StmtType != Stmt.NodeType.Block) {
         return base.VisitContinuation(s);
     }
     if (!this.seen.Add(s.To)) {
         return base.VisitContinuation(s);
     }
     var block = (StmtBlock)s.To;
     foreach (var stmt in block.Statements) {
         if (stmt.StmtType == Stmt.NodeType.Continuation) {
             // Continuation not inside 'if'
             var sCont = (StmtContinuation)stmt;
             if (sCont.To == block) {
                 // Recursive, so derecurse with no condition on loop
                 var body = new StmtBlock(s.Ctx, block.Statements.TakeWhile(x => x != stmt).ToArray());
                 var replaceWith = new StmtDoLoop(s.Ctx, body, new ExprLiteral(s.Ctx, true, s.Ctx.Boolean));
                 this.replaces.Add(s.To, replaceWith);
                 return base.VisitContinuation(s);
             }
         }
         if (stmt.StmtType == Stmt.NodeType.If) {
             // Continuation only statement within 'if' with only a 'then' clause
             var sIf = (StmtIf)stmt;
             if (sIf.Else == null && sIf.Then.StmtType == Stmt.NodeType.Continuation) {
                 var sThen = (StmtContinuation)sIf.Then;
                 if (sThen.To == block) {
                     // Recursive, so derecurse
                     var condition = sIf.Condition;
                     var bodyStmts = block.Statements.TakeWhile(x => x != stmt).ToArray();
                     var bodyLast = bodyStmts.LastOrDefault();
                     var body = new StmtBlock(s.Ctx, bodyStmts);
                     var loop = new StmtDoLoop(s.Ctx, body, condition);
                     var afterLoop = block.Statements.SkipWhile(x => x != stmt).Skip(1).ToArray();
                     if (VisitorFindContinuations.Get(new StmtBlock(s.Ctx, afterLoop)).Any(x => x.To == block)) {
                         // Cannot de-recurse yet, must wait for continuations to be merged
                         return base.VisitContinuation(s);
                     }
                     Stmt replaceWith;
                     if (afterLoop.Any()) {
                         var loopAndAfter = new[] { loop }.Concat(afterLoop).ToArray();
                         replaceWith = new StmtBlock(s.Ctx, loopAndAfter);
                     } else {
                         replaceWith = loop;
                     }
                     this.replaces.Add(s.To, replaceWith);
                     return base.VisitContinuation(s);
                 }
             }
         }
         if (VisitorFindContinuations.Any(stmt)) {
             // Another continuation present, cannot derecurse
             break;
         }
     }
     return base.VisitContinuation(s);
 }
 protected override ICode VisitDoLoop(StmtDoLoop s) {
     var body = (Stmt)this.Visit(s.Body);
     if (body == null) {
         // Loop has no body
         return null;
     }
     if (s.While.IsLiteralBoolean(false)) {
         // Will never loop
         return body;
     }
     if (body != s.Body) {
         return new StmtDoLoop(s.Ctx, body, s.While);
     } else {
         return s;
     }
 }
 protected override ICode VisitDoLoop(StmtDoLoop s) {
     var body = (Stmt)this.Visit(s.Body);
     StmtIf lastIf = null;
     IEnumerable<Stmt> preIf = null;
     if (body.StmtType == Stmt.NodeType.Block) {
         var sBlock = (StmtBlock)body;
         if (sBlock.Statements.Any()) {
             var sLast = sBlock.Statements.Last();
             if (sLast.StmtType == Stmt.NodeType.If) {
                 lastIf = (StmtIf)sLast;
                 preIf = sBlock.Statements.Take(sBlock.Statements.Count() - 1).ToArray();
             }
         }
     } else if (body.StmtType == Stmt.NodeType.If) {
         lastIf = (StmtIf)body;
         preIf = Enumerable.Empty<Stmt>();
     }
     if (lastIf != null) {
         Stmt afterLoop = null;
         StmtIf newIf = null;
         // See if final 'if' condition is same as the 'do' condition.
         // TODO: This may lead to a non-terminating situation...
         if (lastIf.Condition.DoesEqual(s.While)) {
             afterLoop = lastIf.Else;
             newIf = new StmtIf(s.Ctx, lastIf.Condition, lastIf.Then, null);
         } else if (lastIf.Condition.DoesEqualNot(s.While)) {
             afterLoop = lastIf.Then;
             newIf = new StmtIf(s.Ctx, lastIf.Condition, null, lastIf.Else);
         }
         if (afterLoop != null) {
             var loopBody = new StmtBlock(s.Ctx, preIf.Concat(newIf));
             var loop = new StmtDoLoop(s.Ctx, loopBody, s.While);
             var ret = new StmtBlock(s.Ctx, loop, afterLoop);
             return ret;
         }
     }
     if (body != s.Body) {
         return new StmtDoLoop(s.Ctx, body, s.While);
     } else {
         return s;
     }
 }
 protected override ICode VisitDoLoop(StmtDoLoop s) {
     this.NewLine();
     this.js.Append("do {");
     this.indent++;
     this.Visit(s.Body);
     this.indent--;
     this.NewLine();
     this.js.Append("} while (");
     this.Visit(s.While);
     this.js.Append(");");
     return s;
 }
 protected override ICode VisitDoLoop(StmtDoLoop s) {
     return this.Isolate(() => base.VisitDoLoop(s));
 }