public void Convert()
        {
            MethodRoot.Start = ConvertNode(MethodRoot.Start);

            var graphNodes = MethodRoot.Start.IterateGraphNodesRecursive(false).ToArray();

            foreach (var graphNode in graphNodes)
            {
                ConvertNode(graphNode);
            }

            GraphNode ConvertNode(GraphNode graphNode)
            {
                return(graphNode switch
                {
                    null => throw new ArgumentOutOfRangeException(nameof(graphNode)),
                    GraphDataFlowBlockNode _ => graphNode,
                    GraphDataFlowExpressionNode _ => graphNode,
                    GraphControlFlowBlockNode blockNode => ConvertControlFlowNode(blockNode),
                    GraphControlFlowConditionalNode conditionalNode => ConvertControlFlowNode(conditionalNode),
                    GraphControlFlowReturnNode returnNode => ConvertControlFlowNode(returnNode),
                    GraphDataFlowConditionalNode _ => graphNode,
                    GraphDataFlowReturnNode _ => graphNode,
                    _ => throw new ArgumentOutOfRangeException(nameof(graphNode))
                });
            }
        private bool SimplifyGraph(GraphMethodRoot methodNode)
        {
            var oldStart = methodNode.Start;

            var res = SimplifyNode(oldStart);

            if (res)
            {
                if (oldStart is GraphControlFlowBlockNode oldStartBlockNode)
                {
                    methodNode.Start = oldStartBlockNode.Outgoing;
                    Log.Verbose(
                        "CFG: {MethodName}: simplified away start point {Node}, new start point is {NewNode}",
                        methodNode.Name,
                        oldStart,
                        methodNode.Start
                        );
                }
                else
                {
                    Log.Error(
                        "CFG: {MethodName}: simplified away start point {Node}, but it wasn't {TypeName}",
                        methodNode.Name,
                        oldStart,
                        nameof(GraphControlFlowBlockNode)
                        );
                }
            }

            var graphNodes = methodNode.Start.IterateGraphNodesRecursive(false).ToArray();

            foreach (var graphNode in graphNodes)
            {
                res = SimplifyNode(graphNode) || res;
            }

            return(res);

            bool SimplifyNode(GraphNode graphNode)
            {
                return(graphNode switch
                {
                    null => throw new ArgumentOutOfRangeException(nameof(graphNode)),
                    GraphControlFlowBlockNode blockNode => SimplifyGraph(blockNode),
                    GraphControlFlowConditionalNode _ => false,
                    GraphControlFlowReturnNode _ => false,
                    _ => throw new ArgumentOutOfRangeException(nameof(graphNode))
                });
            }
Esempio n. 3
0
        AddStatementToGraphNode(StatementBase statement,
                                GraphMethodRoot methodRoot,
                                GraphControlFlowBlockNode target,
                                GraphNode continueTarget,
                                GraphNode breakTarget)
        {
            switch (statement)
            {
            case ContinueStatement _:
                target.Outgoing = continueTarget;
                return(Array.Empty <GraphNode>(), null);

            case ForIterationStatement forStatement:
            {
                var processConditional = ProcessConditional(forStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(conditionalStartNode, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block inside FOR that contains incrementors and stuff
                var iterationExpressionBlock = new GraphControlFlowBlockNode(methodRoot);

                // block after FOR
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    foreach (var expression in forStatement.IterationExpression)
                    {
                        iterationExpressionBlock.Body.Add(
                            new GraphControlFlowExpressionNode(methodRoot, expression)
                            );
                    }

                    iterationExpressionBlock.Outgoing = conditionalStartNode;
                }

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(forStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 iterationExpressionBlock,
                                                                                 nextBlock);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = iterationExpressionBlock;
                    }
                }

                conditionalNode.FalseOutgoing = nextBlock;

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case IfStatement ifStatement:
            {
                var processConditional = ProcessConditional(ifStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(_, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block after IF
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(ifStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 continueTarget,
                                                                                 breakTarget);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = nextBlock;
                    }
                }

                if (ifStatement.ElseBlock != null)
                {
                    var falseBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.FalseOutgoing = falseBlock;

                    var(falsePreemptiveExits, falseNext) = AddStatementToGraphNode(ifStatement.ElseBlock,
                                                                                   methodRoot,
                                                                                   falseBlock,
                                                                                   continueTarget,
                                                                                   breakTarget);

                    preemptiveExits.AddRange(falsePreemptiveExits);

                    if (falseNext != null)
                    {
                        falseNext.Outgoing = nextBlock;
                    }
                }
                else
                {
                    conditionalNode.FalseOutgoing = nextBlock;
                }

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case ReturnStatement returnStatement:
            {
                var graphReturnNode = new GraphControlFlowReturnNode(
                    methodRoot,
                    (ExpressionBase)returnStatement.What,
                    false
                    );
                target.Outgoing = graphReturnNode;
                return(new GraphNode[] { graphReturnNode }, null);
            }

            case SimpleCompoundStatement simpleCompoundStatement:
            {
                var preemptiveExits = new List <GraphNode>();
                var currentTarget   = target;

                foreach (var statementBase in simpleCompoundStatement.Body)
                {
                    var(newPreemptiveExits, newNext) = AddStatementToGraphNode(statementBase,
                                                                               methodRoot,
                                                                               currentTarget,
                                                                               continueTarget,
                                                                               breakTarget);

                    preemptiveExits.AddRange(newPreemptiveExits);

                    currentTarget = newNext;
                }

                if (currentTarget != null)
                {
                    var newBlockNode = new GraphControlFlowBlockNode(methodRoot);
                    currentTarget.Outgoing = newBlockNode;
                    currentTarget          = newBlockNode;
                }

                return(preemptiveExits.ToArray(), currentTarget);
            }

            case SimpleDeclarationStatement _:
                return(Array.Empty <GraphNode>(), target);

            case SimpleExpressionStatement simpleExpressionStatement:
            {
                var node = new GraphControlFlowExpressionNode(methodRoot, simpleExpressionStatement.Expression);
                target.Body.Add(node);
                return(Array.Empty <GraphNode>(), target);
            }

            case WhileIterationStatement whileStatement:
            {
                var processConditional = ProcessConditional(whileStatement);
                if (!processConditional.HasValue)
                {
                    return(Array.Empty <GraphNode>(), target);
                }

                var(conditionalStartNode, conditionalNode) = processConditional.Value;

                var preemptiveExits = new List <GraphNode>();

                // block after WHILE
                var nextBlock = new GraphControlFlowBlockNode(methodRoot);

                {
                    var trueBlock = new GraphControlFlowBlockNode(methodRoot);
                    conditionalNode.TrueOutgoing = trueBlock;

                    var(truePreemptiveExits, trueNext) = AddStatementToGraphNode(whileStatement.Block,
                                                                                 methodRoot,
                                                                                 trueBlock,
                                                                                 conditionalStartNode,
                                                                                 nextBlock);

                    preemptiveExits.AddRange(truePreemptiveExits);

                    if (trueNext != null)
                    {
                        trueNext.Outgoing = conditionalStartNode;
                    }
                }

                conditionalNode.FalseOutgoing = nextBlock;

                return(preemptiveExits.ToArray(), nextBlock);
            }

            case SimpleSelectionStatement _:
                goto default;

            default:
                throw new ArgumentOutOfRangeException(nameof(statement));
            }

            (GraphNode conditionalStartNode, GraphControlFlowConditionalNode conditionalNode)?
            ProcessConditional(SimpleSelectionStatement statement)
            {
                GraphControlFlowConditionalNode conditionalNode;

                if (statement.Condition.Count >= 1)
                {
                    conditionalNode = new GraphControlFlowConditionalNode(methodRoot, statement.Condition[^ 1]);