private IngoingEdgesOverlay ComputeIngoingEdges(BuildGraph graph) { var ingoing = new IngoingEdgesOverlay(() => new List <EdgeInfo>()); var visited = new OrdinalOverlay <BuildNodeId, BuildNode, bool>(); var stack = new Stack <BuildNode>(); stack.Push(graph.EnterNode); visited[graph.EnterNode] = true; while (stack.Count > 0) { var node = stack.Pop(); foreach (var edge in node.OutgoingEdges) { var edgeInfo = new EdgeInfo(edge, node); ingoing[edge.To].Add(edgeInfo); if (!visited[edge.To]) { stack.Push(edge.To); visited[edge.To] = true; } } } return(ingoing); }
// TODO: Consider splitting into multiple methods to increase readability public GeneratedGraphs Translate() { this.builder = new FlowGraphBuilder(this.flowGraphId); this.ingoingEdges = this.ComputeIngoingEdges(this.BuildGraph); this.expressionTranslator = new ExpressionTranslator(this); this.buildToFlowVariablesMap = new OrdinalOverlay <BuildVariableId, BuildVariable, FlowVariable>(); this.buildToFlowNodesMap = new OrdinalOverlay <BuildNodeId, BuildNode, FlowNodeMappedInfo>(); var nodeQueue = new Queue <BuildNode>(); var edgeQueue = new Queue <EdgeInfo>(); var visitedNodes = new OrdinalOverlay <BuildNodeId, BuildNode, bool>(); var buildParameters = this.BuildGraph.Variables .Where(v => v.Origin == VariableOrigin.Parameter || v.Origin == VariableOrigin.This); var flowParameters = new List <FlowVariable>(); foreach (var parameter in buildParameters) { flowParameters.Add(this.TranslateVariable(parameter)); } var flowEnterNode = this.builder.AddEnterNode(flowParameters); this.buildToFlowNodesMap[this.BuildGraph.EnterNode] = flowEnterNode; visitedNodes[this.BuildGraph.EnterNode] = true; Contract.Assert(this.BuildGraph.EnterNode.OutgoingEdges.Count == 1); var firstNonEnterNode = this.BuildGraph.EnterNode.OutgoingEdges.Single().To; nodeQueue.Enqueue(firstNonEnterNode); visitedNodes[firstNonEnterNode] = true; while (nodeQueue.Count > 0) { var buildNode = nodeQueue.Dequeue(); Contract.Assert(visitedNodes[buildNode]); Contract.Assert(this.buildToFlowNodesMap[buildNode].FlowNode == null); BuildNode firstBuildNode, lastBuildNode; var flowNode = this.TryTranslateBorderNode(buildNode); if (flowNode != null) { firstBuildNode = buildNode; lastBuildNode = buildNode; this.buildToFlowNodesMap[buildNode] = flowNode; } else { this.ProcessInnerNodesSequence(buildNode, out firstBuildNode, out lastBuildNode, out var operations); flowNode = this.builder.AddInnerNode(operations, lastBuildNode.Flags); // TODO: Handle flag merging when there are flag types that need it this.MapAssignmentsToFlowNode(firstBuildNode, lastBuildNode, flowNode); } // TODO: Try to get rid of the empty nodes (empty blocks etc.) Contract.Assert(flowNode != null); foreach (var edge in lastBuildNode.OutgoingEdges) { if (!visitedNodes[edge.To]) { nodeQueue.Enqueue(edge.To); visitedNodes[edge.To] = true; } } foreach (var edgeInfo in this.ingoingEdges[firstBuildNode]) { var flowFromNode = this.buildToFlowNodesMap[edgeInfo.From].FlowNode; if (flowFromNode == null) { edgeQueue.Enqueue(edgeInfo); } else { this.TranslateEdge(edgeInfo.Edge, edgeInfo.From, flowFromNode, flowNode); } } } while (edgeQueue.Count > 0) { var edgeInfo = edgeQueue.Dequeue(); FlowNode flowFrom = this.buildToFlowNodesMap[edgeInfo.From]; FlowNode flowTo = this.buildToFlowNodesMap[edgeInfo.Edge.To]; Contract.Assert(flowFrom != null); Contract.Assert(flowTo != null); this.TranslateEdge(edgeInfo.Edge, edgeInfo.From, flowFrom, flowTo); } this.FlowGraph = this.builder.FreezeAndReleaseGraph(); this.FinishDisplayGraph(); return(new GeneratedGraphs(this.FlowGraph, this.DisplayGraph)); }