[NotNull] private static IReadOnlyDictionary <IBasicBlock, IMutableBasicBlock> CloneVertices(
            [NotNull] this IControlFlowGraph input,
            IMutableControlFlowGraph output,
            [NotNull] Func <IBasicBlock, bool> keep,
            [CanBeNull] Action <IBasicBlock, IMutableBasicBlock> copy = null
            )
        {
            // Clone vertices (without edges)
            var replacements = new Dictionary <IBasicBlock, IMutableBasicBlock>();

            foreach (var vertex in input.Vertices.Where(keep))
            {
                var r = output.CreateNewBlock(vertex.Type, vertex.LineNumber, vertex.ID);
                replacements.Add(vertex, r);

                if (copy != null)
                {
                    copy(vertex, r);
                }
                else
                {
                    foreach (var stmt in vertex.Statements)
                    {
                        r.Add(stmt);
                    }
                }
            }

            return(replacements);
        }
Exemple #2
0
        private void HandleGoto(IMutableControlFlowGraph cfg, Goto @goto, IMutableBasicBlock block, int lineNumber)
        {
            block.Add(@goto);

            if (@goto.Destination.IsConstant)
            {
                var dest = @goto.Destination.StaticEvaluate();
                if (dest.Type == Execution.Type.Number)
                {
                    // We know exactly where this is going, jump to that line
                    var line      = Math.Clamp((int)dest.Number, 1, _maxLines);
                    var destBlock = GetLineEntryBlock(cfg, line);
                    cfg.CreateEdge(block, destBlock, EdgeType.GotoConstNum);
                }
                else if (dest.Type == Execution.Type.String)
                {
                    // We tried to statically jump to a string (which is always an error), fallthrough to the next line
                    AddFallthrough(cfg, block, lineNumber, EdgeType.GotoConstStr);
                }
            }
            else
            {
                // We don't know where this is going, so goto every line
                for (var j = 1; j <= _maxLines; j++)
                {
                    cfg.CreateEdge(block, GetLineEntryBlock(cfg, j), EdgeType.GotoExpression);
                }
            }
        }
Exemple #3
0
        private IMutableBasicBlock GetLineEntryBlock(IMutableControlFlowGraph cfg, int lineNumber)
        {
            if (!_lineStartBlocks.TryGetValue(lineNumber, out var block))
            {
                block = cfg.CreateNewBlock(BasicBlockType.LineStart, lineNumber);
                _lineStartBlocks.Add(lineNumber, block);
            }

            return(block);
        }
        private static IReadOnlyDictionary <IEdge, IEdge> CloneEdges(
            [NotNull] this IControlFlowGraph input,
            IMutableControlFlowGraph output,
            IReadOnlyDictionary <IBasicBlock, IMutableBasicBlock> vertexReplacements,
            [NotNull] Func <IEdge, bool> keep)
        {
            var replacements = new Dictionary <IEdge, IEdge>();

            foreach (var edge in input.Edges)
            {
                if (!keep(edge))
                {
                    continue;
                }

                replacements.Add(
                    edge,
                    output.CreateEdge(vertexReplacements[edge.Start], vertexReplacements[edge.End], edge.Type)
                    );
            }

            return(replacements);
        }
Exemple #5
0
        /// <summary>
        /// Convert a statement list into basic blocks. Return the final block that was created if it needs to be connected to the next block
        /// </summary>
        /// <param name="cfg"></param>
        /// <param name="statements"></param>
        /// <param name="lineNumber"></param>
        /// <param name="entry"></param>
        /// <returns>(entry_block!, exit_block?)</returns>
        private (IMutableBasicBlock, IMutableBasicBlock) HandleStatementList(IMutableControlFlowGraph cfg, StatementList statements, int lineNumber, IMutableBasicBlock entry)
        {
            var block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);

            cfg.CreateEdge(entry, block, EdgeType.Continue);

            foreach (var stmt in statements.Statements)
            {
                if (stmt is Goto @goto)
                {
                    HandleGoto(cfg, @goto, block, lineNumber);

                    // Create a new block which is _not_ linked to the previous (because we just unconditionally jumped away)
                    block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);
                }
                else if (stmt is If @if)
                {
                    block.Add(new Conditional(@if.Condition));

                    // Convert true and false branches into blocks
                    var(enTrue, exTrue) = HandleStatementList(cfg, @if.TrueBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber));
                    var(enFals, exFals) = HandleStatementList(cfg, @if.FalseBranch, lineNumber, cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber));

                    // Create edges from conditional to two branches
                    cfg.CreateEdge(block, enTrue, EdgeType.ConditionalTrue);
                    cfg.CreateEdge(block, enFals, EdgeType.ConditionalFalse);

                    // Link the exit blocks (if they're not null) to the next block
                    block = cfg.CreateNewBlock(BasicBlockType.Basic, lineNumber);
                    if (exTrue != null)
                    {
                        cfg.CreateEdge(exTrue, block, EdgeType.Continue);
                    }
                    if (exFals != null)
                    {
                        cfg.CreateEdge(exFals, block, EdgeType.Continue);
                    }
                }
                else if (stmt is EmptyStatement)
                {
                    // ignore empty statements, they (obviously) don't do anything
                    // ReSharper disable once RedundantJumpStatement
                    continue;
                }
                else
                {
                    // Add to block with fallthrough to next line if it can error
                    block.Add(stmt);
                    if (stmt.CanRuntimeError)
                    {
                        AddFallthrough(cfg, block, lineNumber, EdgeType.RuntimeError);

                        var b2 = cfg.CreateNewBlock(BasicBlockType.Basic, block.LineNumber);
                        cfg.CreateEdge(block, b2, EdgeType.Continue);
                        block = b2;
                    }
                }
            }

            return(entry, block);
        }
Exemple #6
0
 private void AddFallthrough(IMutableControlFlowGraph cfg, IBasicBlock source, int currentLineNumber, EdgeType type = EdgeType.Continue)
 {
     cfg.CreateEdge(source, GetLineEntryBlock(cfg, currentLineNumber == _maxLines ? 1 : currentLineNumber + 1), type);
 }