protected override ICode VisitIf(StmtIf s) {
     var then = (Stmt)this.Visit(s.Then);
     var @else = (Stmt)this.Visit(s.Else);
     if (then == null && @else == null) {
         return null;
     }
     // Remove 'if' if condition is just true or false
     if (s.Condition.ExprType == Expr.NodeType.Literal) {
         if (s.Condition.IsLiteralBoolean(true)) {
             return then;
         }
         if (s.Condition.IsLiteralBoolean(false)) {
             return @else;
         }
     }
     // If 'then' and 'else' are identical, then remove 'if'
     if (then.DoesEqual(@else)) {
         return then;
     }
     // If 'if' only has an 'else' case, not a 'then' case, then swap
     if (then == null) {
         return new StmtIf(s.Ctx, s.Ctx.ExprGen.NotAutoSimplify(s.Condition), @else, null);
     }
     // If both 'if' parts only contain an assignment to the same (with phi clustering) target, then turn into ternary assignment
     if (then != null && @else != null && then.StmtType == Stmt.NodeType.Assignment && @else.StmtType == Stmt.NodeType.Assignment) {
         var thenAssign = (StmtAssignment)then;
         var elseAssign = (StmtAssignment)@else;
         if (this.AreClustered(thenAssign.Target, elseAssign.Target)) {
             this.replaceVars.Add(Tuple.Create(elseAssign.Target, thenAssign.Target));
             var ternary = new ExprTernary(s.Ctx, s.Condition, thenAssign.Expr, elseAssign.Expr);
             return new StmtAssignment(s.Ctx, thenAssign.Target, ternary);
         }
     }
     // If 'if' contains only 'if' then combine condition with 'and'
     if (@else == null && then.StmtType == Stmt.NodeType.If) {
         var thenIf = (StmtIf)then;
         if (thenIf.Else == null) {
             return new StmtIf(s.Ctx, s.Ctx.ExprGen.And(s.Condition, thenIf.Condition), thenIf.Then, null);
         }
     }
     if (then != s.Then || @else != s.Else) {
         return new StmtIf(s.Ctx, s.Condition, then, @else);
     } else {
         return s;
     }
 }
 protected override ICode VisitIf(StmtIf s) {
     if (!VisitorFindContinuations.Any(s)) {
         // 'If' contains no continuations, so no distribution can be done
         return s;
     }
     if (VisitorOnlyStatements.Only(s, Stmt.NodeType.If, Stmt.NodeType.Continuation) && this.ifInfo == null) {
         // 'If' only contains continuations, so no distribution can be done
         // Must visit base method to find contained continuations
         return base.VisitIf(s);
     }
     bool finalise = false;
     if (this.ifInfo == null) {
         finalise = true;
         this.ifInfo = new IfInfo();
     }
     this.ifInfo.Conditions.Push(s.Condition);
     var then = this.Visit(s.Then);
     this.ifInfo.Conditions.Pop();
     this.ifInfo.Conditions.Push(this.ctx.ExprGen.NotAutoSimplify(s.Condition));
     var @else = this.Visit(s.Else);
     this.ifInfo.Conditions.Pop();
     if (then != s.Then || @else != s.Else) {
         var @if = new StmtIf(s.Ctx, s.Condition, (Stmt)then, (Stmt)@else);
         if (finalise && this.ifInfo.AddToIf.Any()) {
             var ifStmts = this.ifInfo.AddToIf.GroupBy(x => x.Item1.To, x => x.Item2).Select(x =>
                 new StmtIf(s.Ctx, x.Aggregate((a, b) => this.ctx.ExprGen.Or(a, b)),
                     this.ifInfo.AddToIf.First(y => y.Item1.To == x.Key).Item1, null)
                 );
             var stmts = new Stmt[] { @if }.Concat(ifStmts).ToArray();
             this.ifInfo = null;
             return new StmtBlock(s.Ctx, stmts);
         } else {
             if (finalise) {
                 this.ifInfo = null;
             }
             return @if;
         }
     } else {
         // In this case, no continuations will have been found, so there cannot be any conditions to add
         if (finalise) {
             this.ifInfo = null;
         }
         return s;
     }
 }
 protected override ICode VisitIf(StmtIf s) {
     this.NewLine();
     this.code.Append("if (");
     this.Visit(s.Condition);
     this.code.Append(") {");
     this.indent++;
     this.Visit(s.Then);
     this.indent--;
     if (s.Else != null) {
         this.NewLine();
         this.code.Append("} else {");
         this.indent++;
         this.Visit(s.Else);
         this.indent--;
     }
     this.NewLine();
     this.code.Append("}");
     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 VisitIf(StmtIf s) {
            var ctx = s.Ctx;
            var condition = (Expr)this.Visit(s.Condition);

            this.stack.Push(new List<ExprVar>());
            var then = (Stmt)this.Visit(s.Then);
            var thenDA = this.stack.Pop();

            this.stack.Push(new List<ExprVar>());
            var @else = (Stmt)this.Visit(s.Else);
            var elseDA = this.stack.Pop();

            var intersection = thenDA.Intersect(elseDA, (IEqualityComparer<ExprVar>)this.phiComparer).ToArray();
            this.stack.Peek().AddRange(intersection);

            var conditionVars = VisitorFindVars.V(condition);
            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);
                    condition = (Expr)VisitorReplace.V(condition, replace.orgExpr, replace.phi);
                }
                this.ensureAssigned.Add(s, replacements.Select(x => x.newExpr).ToArray());
            }

            if (condition != s.Condition || then != s.Then || @else != s.Else) {
                var newS = new StmtIf(ctx, condition, then, @else);
                this.stmtMap.Add(newS,s);
                return newS;
            } else {
                return s;
            }
        }
        protected override ICode VisitBlock(StmtBlock s) {
            var ctx = s.Ctx;
            var statements = s.Statements
                .Select(x => (Stmt)this.Visit(x))
                .Where(x => x != null)
                .ToArray();
            var stNew = statements.Combine((a, b) => {
                // If two 'if' statements are both continuations, then bring a recursive continuation forwards if possible
                if (a.StmtType == Stmt.NodeType.If && b.StmtType == Stmt.NodeType.If) {
                    var aIf = (StmtIf)a;
                    var bIf = (StmtIf)b;
                    if (aIf.Then != null && bIf.Then != null
                        && aIf.Then.StmtType == Stmt.NodeType.Continuation && bIf.Then.StmtType == Stmt.NodeType.Continuation
                        && aIf.Else == null && bIf.Else == null) {
                        var aCont = (StmtContinuation)aIf.Then;
                        var bCont = (StmtContinuation)bIf.Then;
                        if (aCont.To != this.block && bCont.To == this.block) {
                            return new StmtBlock(ctx, b, a);
                        }
                    }
                }
                return null;
            })
            .ToArray();
            if (!statements.SequenceEqual(stNew)) {
                return new StmtBlock(ctx, stNew);
            }
            // If an 'if' statement containing only a continuation is followed by any other kind of statement then swap them
            // (with suitable 'if' guard). Look ahead and encase as much as possible in the 'if' guard
            for (int i = 0; i < statements.Length - 1; i++) {
                var stmt = statements[i];
                if (stmt.StmtType == Stmt.NodeType.If) {
                    var sIf = (StmtIf)stmt;
                    if (sIf.Then != null && sIf.Then.StmtType == Stmt.NodeType.Continuation && sIf.Else == null) {
                        var moveCount = 0;
                        for (int j = i + 1; j < statements.Length; j++) {
                            var b = statements[j];
                            bool move;
                            if (b.StmtType == Stmt.NodeType.Continuation) {
                                move = false;
                            } else if (b.StmtType != Stmt.NodeType.If) {
                                move = true;
                            } else {
                                var bIf = (StmtIf)b;
                                move = bIf.Then == null || bIf.Then.StmtType != Stmt.NodeType.Continuation || bIf.Else != null;
                            }
                            if (move) {
                                moveCount++;
                            } else {
                                break;
                            }
                        }
                        if (moveCount > 0) {
                            var moveBlock = new StmtBlock(ctx, statements.Skip(i + 1).Take(moveCount));
                            var ifBlock = new StmtIf(ctx, ctx.ExprGen.Not(sIf.Condition), moveBlock, null);
                            var allStmts =
                                statements.Take(i)
                                .Concat(ifBlock)
                                .Concat(statements[i])
                                .Concat(statements.Skip(i + 1 + moveCount))
                                .ToArray();
                            return new StmtBlock(ctx, allStmts);
                        }
                    }
                }
            }

            // Reorder if/continuations at end of block to group by continuation target
            var finalContsRev = statements.Reverse().TakeWhile(x => {
                if (x.StmtType == Stmt.NodeType.Continuation) {
                    return true;
                }
                if (x.StmtType == Stmt.NodeType.If) {
                    var xIf = (StmtIf)x;
                    if (xIf.Else == null && xIf.Then.StmtType == Stmt.NodeType.Continuation) {
                        return true;
                    }
                }
                return false;
            })
            .Select(x => {
                Stmt to;
                if (x.StmtType == Stmt.NodeType.Continuation) {
                    to = ((StmtContinuation)x).To;
                } else {
                    to = ((StmtContinuation)((StmtIf)x).Then).To;
                }
                return new { stmt = x, to };
            }).ToArray();
            var lookForMidCont = finalContsRev.Reverse().TakeWhile(x => x.stmt.StmtType != Stmt.NodeType.Continuation).ToArray();
            if (lookForMidCont.Length < finalContsRev.Length - 1) {
                // Look for non-if continuation in middle of final continuations
                // I suspect that this cannot ever occur
                var stmts = statements.Take(statements.Length - finalContsRev.Length)
                    .Concat(lookForMidCont.Select(x => x.stmt))
                    .Concat(finalContsRev.Select(x => x.stmt).Reverse().ElementAt(lookForMidCont.Length)).ToArray();
                return new StmtBlock(s.Ctx, stmts);
            }
            if (finalContsRev.Count() >= 2) {
                var newFinal = finalContsRev.Combine((a, b) => {
                    if (a.stmt.StmtType == Stmt.NodeType.Continuation && a.to == b.to) {
                        return a;
                    }
                    return null;
                });
                if (!finalContsRev.SequenceEqual(newFinal)) {
                    var stmts = statements.Take(statements.Length - finalContsRev.Length).Concat(newFinal.Reverse().Select(x => x.stmt));
                    return new StmtBlock(s.Ctx, stmts);
                }
                var dups = finalContsRev.GroupBy(x => x.to).Select(x => new { to = x.Key, count = x.Count() }).Where(x => x.count >= 2).ToArray();
                if (dups.Any()) {
                    var finalStmts = finalContsRev.Reverse().ToArray();
                    foreach (var dup in dups) {
                        var movingBack = new List<Stmt>();
                        var addIfs = new Dictionary<Stmt, IEnumerable<Expr>>();
                        foreach (var stmt in finalStmts) {
                            if (stmt.to == dup.to) {
                                movingBack.Add(stmt.stmt);
                            } else {
                                addIfs.Add(stmt.stmt, movingBack.Select(x => s.Ctx.ExprGen.Not(((StmtIf)x).Condition)).ToArray());
                            }
                            if (movingBack.Count == dup.count) {
                                finalStmts = finalStmts.SelectMany(x => {
                                    if (movingBack.Contains(x.stmt)) {
                                        if (x.stmt == movingBack.Last()) {
                                            return movingBack.Select(y => new { stmt = (Stmt)y, to = x.to });
                                        } else {
                                            return finalStmts.EmptyOf();
                                        }
                                    } else {
                                        var addIf = addIfs.ValueOrDefault(x.stmt);
                                        if (addIf != null && addIf.Any()) {
                                            var @if = addIf.Aggregate((a, b) => s.Ctx.ExprGen.And(a, b));
                                            var newIf = new StmtIf(s.Ctx, @if, x.stmt, null);
                                            return new[] { new { stmt = (Stmt)newIf, to = x.to } };
                                        } else {
                                            return new[] { x };
                                        }
                                    }
                                }).ToArray();

                                break;
                            }
                        }
                    }
                    var stmts = statements.Take(statements.Length - finalContsRev.Length).Concat(finalStmts.Select(x => x.stmt));
                    return new StmtBlock(s.Ctx, stmts);
                }
            }
            if (!statements.SequenceEqual(s.Statements)) {
                return new StmtBlock(ctx, statements);
            } else {
                return s;
            }
        }
        public static ICode V(ICode ast) {
            var ctx = ast.Ctx;
            var blockInfo = FindSuitableBlocks.GetInfo(ast);
            var bestBlock = blockInfo
                .Where(x => !x.Value.containsLeaveProtectedRegion && x.Value.numConts <= 1)
                .OrderBy(x => x.Value.numConts == 0 ? 1000 : x.Value.numConts)
                .ThenBy(x => x.Value.numICodes)
                .FirstOrDefault();
            if (bestBlock.Key == null) {
                return ast;
            }
            if (bestBlock.Value.numConts > 1) {
                // Best block must have just one continuation
                return ast;
            }
            Stmt addContTo = null;
            if (bestBlock.Value.numConts == 0) {
                addContTo = (Stmt)blockInfo.FirstOrDefault(x => x.Value.numConts == 0 && x.Key != bestBlock.Key).Key;
                if (addContTo == null) {
                    return ast;
                }
            }
            var blockAst = (Stmt)bestBlock.Key;
            if (blockAst.StmtType != Stmt.NodeType.Block) {
                // Best block must be StmtBlock
                return ast;
            }
            var stmtBlock = (StmtBlock)blockAst;
            var stmts = stmtBlock.Statements.ToArray();
            var cont = bestBlock.Value.numConts == 0 ? new StmtContinuation(ctx, addContTo, false) : (StmtContinuation)stmts.Last();

            var ifSkipContentPhi = new ExprVarPhi(ctx);
            var ifSkipInitialVar = ctx.Local(ctx.Boolean);
            var ifSkipContentVar = ctx.Local(ctx.Boolean);
            var ifSkipContentPhiExprs = new List<Expr> { ifSkipInitialVar, ifSkipContentVar };
            var ifSkipReset = new StmtAssignment(ctx, ifSkipContentVar, ctx.Literal(false));

            var inIfBlock = new StmtBlock(ctx, stmts.Take(stmts.Length - (bestBlock.Value.numConts == 0 ? 0 : 1)));
            var ifBlock = new StmtIf(ctx, ctx.ExprGen.Not(ifSkipContentPhi), inIfBlock, null);
            var newBlock = new StmtBlock(ctx, ifBlock, ifSkipReset, cont);
            ast = VisitorReplace.V(ast, blockAst, newBlock);

            var allConts = VisitorFindContinuationsRecursive.Get(ast);
            var contsNeedChanging = allConts.Where(x => x != cont && x.To == cont.To).ToArray();
            var contsReplaceInfo = contsNeedChanging
                .Select(x => {
                    var ifVar = ctx.Local(ctx.Boolean);
                    var newCont = new StmtBlock(ctx,
                        new StmtAssignment(ctx, ifVar, ctx.Literal(true)),
                        new StmtContinuation(ctx, newBlock, x.LeaveProtectedRegion));
                    return new { oldCont = x, ifVar, newCont };
                })
                .ToArray();

            foreach (var contReplace in contsReplaceInfo) {
                ifSkipContentPhiExprs.Add(contReplace.ifVar);
                ast = VisitorReplace.V(ast, contReplace.oldCont, contReplace.newCont);
            }
            ifSkipContentPhi.Exprs = ifSkipContentPhiExprs;

            // TODO: Shouldn't be required, but definite-assignment doesn't quite work properly, so is required
            var initalSkipVarAssignment = new StmtAssignment(ctx, ifSkipInitialVar, ctx.Literal(false));
            var newAst = new StmtBlock(ctx, initalSkipVarAssignment, (Stmt)ast);

            return newAst;
        }
        protected override ICode VisitSwitch(StmtSwitch s) {
            // If switch statement contains no continuations then it doesn't need processing
            if (!VisitorFindContinuations.Any(s)) {
                return base.VisitSwitch(s);
            }
            var ctx = s.Ctx;
            // If any cases go to the same continuation as the default case, remove them
            if (s.Default != null && s.Default.StmtType == Stmt.NodeType.Continuation) {
                var defaultCont = (StmtContinuation)s.Default;
                var sameAsDefault = s.Cases
                    .Where(x => x.Stmt != null && x.Stmt.StmtType == Stmt.NodeType.Continuation && ((StmtContinuation)x.Stmt).To == defaultCont.To)
                    .ToArray();
                if (sameAsDefault.Any()) {
                    var cases = s.Cases.Except(sameAsDefault);
                    return new StmtSwitch(ctx, s.Expr, cases, s.Default);
                }
            }
            // If multiple case statements all go the same continuation, then put them consecutively
            var groupedByTo = s.Cases
                .Where(x => x.Stmt != null && x.Stmt.StmtType == Stmt.NodeType.Continuation)
                .GroupBy(x => ((StmtContinuation)x.Stmt).To)
                .Where(x => x.Count() >= 2)
                .ToArray();
            if (groupedByTo.Any()) {
                var cases = s.Cases.Except(groupedByTo.SelectMany(x => x));
                var combinedCases = groupedByTo.SelectMany(x => {
                    var same = x.ToArray();
                    var last = same.Last();
                    var sameCases = same.Take(same.Length - 1).Select(y => new StmtSwitch.Case(y.Value, null))
                        .Concat(new StmtSwitch.Case(last.Value, last.Stmt));
                    return sameCases;
                });
                var allCases = cases.Concat(combinedCases).ToArray();
                return new StmtSwitch(ctx, s.Expr, allCases, s.Default);
            }
            Func<Stmt, IEnumerable<StmtContinuation>> getSingleFinalContinuation = stmt => {
                if (stmt == null) {
                    return Enumerable.Empty<StmtContinuation>();
                }
                var contCount = VisitorFindContinuations.Get(stmt).Count();
                if (contCount == 0) {
                    // Case contains return or throw
                    return Enumerable.Empty<StmtContinuation>();
                }
                if (contCount == 1) {
                    if (stmt.StmtType == Stmt.NodeType.Continuation) {
                        return new[] { (StmtContinuation)stmt };
                    }
                    if (stmt.StmtType == Stmt.NodeType.Block) {
                        var stmtBlock = (StmtBlock)stmt;
                        var last = stmtBlock.Statements.LastOrDefault();
                        if (last != null && last.StmtType == Stmt.NodeType.Continuation) {
                            return new[] { (StmtContinuation)last };
                        }
                    }
                }
                return new StmtContinuation[] { null };
            };
            var conts = s.Cases.Select(x => x.Stmt).Concat(s.Default).SelectMany(x => getSingleFinalContinuation(x)).ToArray();
            if (conts.All(x => x != null)) {
                // If all cases end with a continuation to the same stmt, then put that stmt after the switch and remove all continuations
                if (conts.AllSame(x => x.To)) {
                    Func<Stmt, Stmt> removeCont = stmt => {
                        if (stmt == null) {
                            return null;
                        }
                        switch (stmt.StmtType) {
                        case Stmt.NodeType.Continuation:
                            return new StmtBreak(ctx);
                        case Stmt.NodeType.Block:
                            var sBlock = (StmtBlock)stmt;
                            var stmts = sBlock.Statements.ToArray();
                            if (stmts.Last().StmtType == Stmt.NodeType.Continuation) {
                                stmts = stmts.Take(stmts.Length - 1).Concat(new StmtBreak(ctx)).ToArray();
                                return new StmtBlock(ctx, stmts);
                            } else {
                                return stmt;
                            }
                        default:
                            return stmt;
                        }
                    };
                    var cases = s.Cases.Select(x => new StmtSwitch.Case(x.Value, removeCont(x.Stmt))).ToArray();
                    var @switch = new StmtSwitch(ctx, s.Expr, cases, removeCont(s.Default));
                    return new StmtBlock(ctx, @switch, conts[0]);
                } else if (this.lastChance) {
                    // HACK: Change it into multiple if statements
                    var multiValues = new List<int>();
                    var converted = s.Cases.Aggregate(s.Default, (@else, @case) => {
                        multiValues.Add(@case.Value);
                        if (@case.Stmt == null) {
                            return @else;
                        } else {
                            var cond = multiValues.Aggregate((Expr)ctx.Literal(false), (expr, caseValue) => {
                                return ctx.ExprGen.Or(expr, ctx.ExprGen.Equal(s.Expr, ctx.Literal(caseValue)));
                            });
                            multiValues.Clear();
                            var @if = new StmtIf(ctx, cond, @case.Stmt, @else);
                            return @if;
                        }
                    });
                    return converted;
                }
                // If some cases end in a continuation that itself ends in a continuation that other cases end with
                // then use an extra variable to store whether to execute the intermediate code
                // TODO: This is too specific, need a more general-purpose solution to the problem where cases
                // don't all end by going to the same place
                //var contTos = conts.Select(x => x.To).Distinct().ToArray();
                //var finalContTos = contTos.Select(x => getSingleFinalContinuation(x).Select(y => y.NullThru(z => z.To))).SelectMany(x => x).ToArray();
                //if (!finalContTos.Any(x => x == null)) {
                //    // All continuations are fully substituted
                //    var distinctFinalContTos = finalContTos.Distinct().ToArray();
                //    if (distinctFinalContTos.Length == 1) {
                //        var selector = ctx.Local(ctx.Int32);
                //        var inIfCont = contTos.Single(x => x != distinctFinalContTos[0]);
                //        var inIf = new StmtContinuation(ctx, inIfCont, false);
                //        var afterIf = new StmtContinuation(ctx, distinctFinalContTos[0], false);
                //        var allCasesTo = new StmtBlock(ctx,
                //            new StmtIf(ctx, ctx.ExprGen.Equal(selector, ctx.Literal(1)), inIf, null),
                //            afterIf);
                //        Func<Stmt, Stmt> adjustCont = stmt => {
                //            var cont = VisitorFindContinuations.Get(stmt).Single();
                //            var newCont = new StmtContinuation(ctx, allCasesTo, false);
                //            var contChanged = (Stmt)VisitorReplace.V(stmt, cont, newCont);
                //            var sValue = cont.To == inIf.To ? 1 : 0;
                //            var withSelectorSet = new StmtBlock(ctx,
                //                new StmtAssignment(ctx, selector, ctx.Literal(sValue)),
                //                contChanged);
                //            return withSelectorSet;
                //        };
                //        var cases = s.Cases.Select(x => new StmtSwitch.Case(x.Value, adjustCont(x.Stmt))).ToArray();
                //        var @switch = new StmtSwitch(ctx, s.Expr, cases, adjustCont(s.Default));
                //        return @switch;
                //    } else {
                //        throw new NotImplementedException();
                //    }
                //}
            }

            return base.VisitSwitch(s);
        }
Beispiel #9
0
 public DebugView(StmtIf s)
 {
     this.Condition = s.Condition;
     this.Then      = s.Then;
     this.Else      = s.Else;
 }
Beispiel #10
0
 public DebugView(StmtIf s) {
     this.Condition = s.Condition;
     this.Then = s.Then;
     this.Else = s.Else;
 }
 private void BuildBlock(IEnumerable<Instruction> insts, Instruction startOfNextPart) {
     var inst0 = insts.First();
     var instN = insts.Last();
     // Any instruction in the method could target this block
     var blockStarts = this.methodBlockStarts
         .Where(x => x.Offset >= inst0.Offset && x.Offset <= instN.Offset)
         .ToArray();
     // For each block create a StmtCil, with the correct ending.
     // Endings that require a expression have them set to null; they will be filled in during CIL decoding
     for (int i = 0; i < blockStarts.Length; i++) {
         var start = blockStarts[i];
         var end = i == blockStarts.Length - 1 ? insts.Last() : blockStarts[i + 1].Previous;
         var blockInsts = start.GetRange(end);
         Stmt blockEndStmt;
         var code = end.OpCode.Code;
         switch (end.OpCode.FlowControl) {
         case FlowControl.Cond_Branch:
             if (code == Code.Switch) {
                 var cases = ((Instruction[])end.Operand).Select(x => new StmtContinuation(this.ctx, x, false)).ToArray();
                 foreach (var @case in cases) {
                     this.mappable.Add(@case);
                 }
                 var @default = new StmtContinuation(this.ctx, end.Next, false);
                 this.mappable.Add(@default);
                 blockEndStmt = new StmtSwitch(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Int32),
                     cases.Select((x, value) => new StmtSwitch.Case(value, x)).ToArray(),
                     @default);
             } else {
                 var ifTrue = new StmtContinuation(this.ctx, (Instruction)end.Operand, false);
                 var ifFalse = new StmtContinuation(this.ctx, end.Next, false);
                 this.mappable.Add(ifTrue);
                 this.mappable.Add(ifFalse);
                 blockEndStmt = new StmtIf(this.ctx, new ExprVarInstResult(this.ctx, end, this.ctx.Boolean), ifTrue, ifFalse);
             }
             break;
         case FlowControl.Branch:
             var leaveProtectedRegion = code == Code.Leave || code == Code.Leave_S;
             blockEndStmt = new StmtContinuation(this.ctx, (Instruction)end.Operand, leaveProtectedRegion);
             this.mappable.Add((StmtContinuation)blockEndStmt);
             break;
         case FlowControl.Next:
         case FlowControl.Call:
             blockEndStmt = new StmtContinuation(this.ctx, end.Next, false);
             this.mappable.Add((StmtContinuation)blockEndStmt);
             break;
         case FlowControl.Return:
             switch (code) {
             case Code.Endfinally:
                 blockEndStmt = new StmtContinuation(this.ctx, startOfNextPart, true);
                 this.mappable.Add((StmtContinuation)blockEndStmt);
                 break;
             case Code.Ret:
                 blockEndStmt = new StmtContinuation(this.ctx, this.endBlock, false);
                 blockInsts = start == end ? Enumerable.Empty<Instruction>() : start.GetRange(end.Previous); // Remove 'ret' from statements
                 break;
             default:
                 blockEndStmt = null;
                 break;
             }
             break;
         case FlowControl.Throw:
             blockEndStmt = null;
             break;
         default:
             throw new NotImplementedException("Cannot handle: " + end.OpCode.FlowControl);
         }
         var block = new StmtCil(this.ctx, blockInsts, blockEndStmt);
         this.blockMap.Add(start, new List<Stmt> { block });
     }
 }