@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
94 lines • 3.49 kB
JavaScript
;
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