UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

111 lines 3.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BasicCfgGuidedVisitor = void 0; const control_flow_graph_1 = require("./control-flow-graph"); const assert_1 = require("../util/assert"); /** * In contrast to {@link visitCfgInOrder} and {@link visitCfgInReverseOrder}, this visitor is not a simple visitor * and serves as the basis for a variety of more complicated visiting orders of the control flow graph. * It includes features to provide additional information using the {@link NormalizedAst} and the {@link DataflowGraph}. * * Use {@link BasicCfgGuidedVisitor#start} to start the traversal. */ class BasicCfgGuidedVisitor { config; visited; constructor(config) { this.config = { ...config }; this.visited = new Map(); } /** * call this function to indicate that a node is to be considered visited. * @returns `true` if the node was not visited before, `false` otherwise */ visitNode(node) { if (this.visited.has(node)) { return false; } this.visited.set(node, 1); this.onVisitNode(node); return true; } startVisitor(start) { const graph = this.config.controlFlow.graph; let getNext; if (this.config.defaultVisitingOrder === 'forward') { getNext = (node) => graph.ingoingEdges(node)?.keys().toArray().reverse(); } else { getNext = (node) => graph.outgoingEdges(node)?.keys(); } const stack = Array.from(start); while (stack.length > 0) { const current = stack.pop(); if (!this.visitNode(current)) { continue; } for (const next of getNext(current) ?? []) { stack.push(next); } } } /** * Start the visiting process. */ start() { this.startVisitor(this.config.defaultVisitingOrder === 'forward' ? this.config.controlFlow.entryPoints : this.config.controlFlow.exitPoints); } /** * Get the control flow vertex for the given node id or fail if it does not exist. */ getCfgVertex(id) { return this.config.controlFlow.graph.getVertex(id); } onVisitNode(node) { const vertex = this.getCfgVertex(node); if (vertex === undefined) { return; } const type = control_flow_graph_1.CfgVertex.getType(vertex); switch (type) { case control_flow_graph_1.CfgVertexType.Statement: this.onStatementNode(vertex); break; case control_flow_graph_1.CfgVertexType.Expression: this.onExpressionNode(vertex); break; case control_flow_graph_1.CfgVertexType.Marker: this.onEndMarkerNode(vertex); break; case control_flow_graph_1.CfgVertexType.Block: this.onBasicBlockNode(vertex); break; default: (0, assert_1.assertUnreachable)(type); } } onBasicBlockNode(node) { const elems = control_flow_graph_1.CfgVertex.getBasicBlockElements(node); if (this.config.defaultVisitingOrder === 'forward') { for (const elem of elems.toReversed()) { this.visitNode(control_flow_graph_1.CfgVertex.getId(elem)); } } else { for (const elem of elems) { this.visitNode(control_flow_graph_1.CfgVertex.getId(elem)); } } } onStatementNode(_node) { /* does nothing by default */ } onExpressionNode(_node) { /* does nothing by default */ } onEndMarkerNode(_node) { /* does nothing by default */ } } exports.BasicCfgGuidedVisitor = BasicCfgGuidedVisitor; //# sourceMappingURL=basic-cfg-guided-visitor.js.map