public static void CopyTo([NotNull] this IBasicBlock a, [NotNull] IMutableBasicBlock b) { foreach (var stmt in a.Statements) { b.Add(stmt); } }
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); } } }
/// <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); }