UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

94 lines 3.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.visitCfgInReverseOrder = visitCfgInReverseOrder; exports.visitCfgInOrder = visitCfgInOrder; exports.canReach = canReach; const control_flow_graph_1 = require("./control-flow-graph"); /** * Visit all nodes reachable from the start node in the control flow graph, traversing the dependencies but ignoring cycles. * @param graph - The control flow graph. * @param startNodes - The nodes to start the traversal from. * @param visitor - The visitor function to call for each node, if you return true the traversal from this node will be stopped. * * This function is of type {@link SimpleCfgVisitor}. * * @see {@link visitCfgInOrder} for a traversal in order */ function visitCfgInReverseOrder(graph, startNodes, // eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- void is used to indicate that the return value is ignored/we never stop visitor) { const visited = new Set(); let queue = [...startNodes]; const hasBb = graph.mayHaveBasicBlocks(); while (queue.length > 0) { const current = queue.pop(); if (visited.has(current)) { continue; } visited.add(current); if (visitor(current)) { continue; } else if (hasBb) { const get = graph.getVertex(current); if (get?.type === control_flow_graph_1.CfgVertexType.Block) { queue = queue.concat(get.elems.toReversed().map(e => e.id)); } } const incoming = graph.outgoingEdges(current); if (incoming) { queue.push(...incoming.keys()); } } } /** * Visit all nodes reachable from the start node in the control flow graph, traversing the dependencies in execution order but ignoring cycles. * @param graph - The control flow graph. * @param startNodes - The nodes to start the traversal from. * @param visitor - The visitor function to call for each node, if you return true the traversal from this node will be stopped. * * This function is of type {@link SimpleCfgVisitor}. * * @see {@link visitCfgInReverseOrder} for a traversal in reversed order */ function visitCfgInOrder(graph, startNodes, // eslint-disable-next-line @typescript-eslint/no-invalid-void-type -- void is used to indicate that the return value is ignored/we never stop visitor) { const visited = new Set(); let queue = startNodes.slice(); const hasBb = graph.mayHaveBasicBlocks(); while (queue.length > 0) { const current = queue.shift(); if (visited.has(current)) { continue; } visited.add(current); if (visitor(current)) { continue; } else if (hasBb) { const get = graph.getVertex(current); if (get?.type === control_flow_graph_1.CfgVertexType.Block) { queue = queue.concat(get.elems.map(e => e.id)); } } const outgoing = graph.ingoingEdges(current) ?? []; for (const [to] of outgoing) { queue.push(to); } } } /** * Check if a node can reach another node in the control flow graph. */ function canReach(graph, from, to) { let reached = false; visitCfgInOrder(graph, from, node => { if (node === to) { reached = true; return true; } }); return reached; } //# sourceMappingURL=simple-visitor.js.map