Any() публичный статический Метод

public static Any ( ICode root ) : bool
root ICode
Результат bool
        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);
            }
        }
Пример #2
0
        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 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));
        }