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))
                });
            }
示例#3
0
        private void BuildGraphForBlock([NotNull] SimpleCompoundStatement compoundStatement,
                                        [NotNull] GraphMethodRoot methodRoot)
        {
            var graphNode = new GraphControlFlowBlockNode(methodRoot);

            methodRoot.Start           = graphNode;
            var(preemptiveExits, next) = AddStatementToGraphNode(compoundStatement,
                                                                 methodRoot,
                                                                 graphNode,
                                                                 null,
                                                                 null);

            if (next != null)
            {
                next.Outgoing = new GraphControlFlowReturnNode(methodRoot, null, true);
            }
        }
        private bool SimplifyGraph(GraphControlFlowBlockNode blockNode)
        {
            if (blockNode.Body.Count != 0)
            {
                return(false);
            }

            var child = blockNode.Outgoing;

            child.ReplaceIncomingNode(blockNode, blockNode.Incoming, true);

            foreach (var parentNode in blockNode.Incoming)
            {
                parentNode.ReplaceOutgoingNode(blockNode, child);
            }

            blockNode.Incoming.Clear();

            return(true);
        }
        private void SplitBlocksAtMethodJumps(GraphMethodRoot methodRoot)
        {
            var graphNodes = methodRoot.Start.IterateGraphNodesRecursive(true).ToArray();

            foreach (var graphNode in graphNodes)
            {
                switch (graphNode)
                {
                case null:
                    throw new ArgumentNullException(nameof(graphNode));

                case GraphControlFlowBlockNode graphBlockNode:
                {
                    var currentBlockNode = graphBlockNode;
                    while (currentBlockNode != null)
                    {
                        var index = 0;
                        for (; index < currentBlockNode.Body.Count; index++)
                        {
                            var expressionBase = currentBlockNode.Body[index];
                            var functionCall   = ScanExpressionForFunctionCalls(expressionBase.Expression);
                            if (functionCall == null)
                            {
                                continue;
                            }

                            if (index == currentBlockNode.Body.Count - 1)
                            {
                                continue;
                            }

                            // split
                            var node = new GraphControlFlowBlockNode(methodRoot)
                            {
                                Outgoing = currentBlockNode.Outgoing
                            };

                            var moveStart = index + 1;
                            var moveCount = currentBlockNode.Body.Count - moveStart;

                            foreach (var expressionNode in currentBlockNode.Body.ToArray()[moveStart..(moveStart + moveCount)])
示例#6
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]);