Ejemplo n.º 1
0
    static ControlFlowGraph ReduceBreak(ControlFlowGraph graph, CfgLoop loop, LoopPart part)
    {
        // Func<string> vis = () => graph.ToVis().AddPointer("part", part.Index).ToString(); // For VS Code debug visualisation

        // Break = needs to exit the loop to be a break
        if (!part.Break)
        {
            return(graph);
        }

        // Outside entry = non-structured code, so give up
        if (part.OutsideEntry)
        {
            return(graph);
        }

        var children = graph.Children(part.Index);

        if (children.Length != 2)
        {
            throw new ControlFlowGraphException($"Break at {part.Index} has unexpected child count ({children.Length})", graph);
        }

        bool isfirstChildInLoop = loop.Body.Any(x => x.Index == children[0]) || children[0] == loop.Header.Index;
        var  exitTarget         = isfirstChildInLoop ? children[1] : children[0];

        // Add LoopSuccessor edge if this is the last link to the MainExit.
        var remainingLoopChildren = loop.Body
                                    .Where(x => x.Index != part.Index)
                                    .Aggregate(
            (IEnumerable <int>)graph.Children(loop.Header.Index),
            (current, x) => current.Union(graph.Children(x.Index)));

        if (loop.MainExit.HasValue && !remainingLoopChildren.Contains(loop.MainExit.Value))
        {
            graph = graph.AddEdge(loop.Header.Index, loop.MainExit.Value, CfgEdge.LoopSuccessor);
        }

        if (exitTarget != loop.MainExit)
        {
            var targetChildren = graph.Children(exitTarget);
            if (targetChildren.Length != 1 || targetChildren[0] != loop.MainExit)
            {
                return(graph);
            }

            var condition = graph.Nodes[part.Index];
            if (graph.GetEdgeLabel(part.Index, exitTarget) == CfgEdge.False)
            {
                condition = Emit.Negation(condition);
            }

            var ifNode = Emit.If(condition, Emit.Seq(graph.Nodes[exitTarget], Emit.Break()));
            return(graph
                   .RemoveNode(exitTarget)
                   .ReplaceNode(part.Index, ifNode));
        }

        return(ReplaceLoopBranch(graph, part.Index, exitTarget, Emit.Break()));
    }
Ejemplo n.º 2
0
 [Fact] public void BreakTest() =>
 TestRoundTrip("while (a) { if (b) { break }, c }",
               Emit.While(Emit.Name("a"),
                          Emit.Seq(
                              Emit.If(Emit.Name("b"), Emit.Break()),
                              S(Emit.Name("c")))),
               ScriptParser.TopLevel);