UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

114 lines 3.85 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 g = this.config.controlFlow.graph; const n = this.config.defaultVisitingOrder === 'forward' ? (n) => g.ingoingEdges(n) : (n) => g.outgoingEdges(n); const stack = [...start]; while (stack.length > 0) { const current = stack.shift(); if (!this.visitNode(current)) { continue; } const outgoing = n(current) ?? []; for (const [to] of outgoing) { stack.unshift(to); } } } /** * 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 = vertex.type; 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.MidMarker: this.onMidMarkerNode(vertex); break; case control_flow_graph_1.CfgVertexType.EndMarker: this.onEndMarkerNode(vertex); break; case control_flow_graph_1.CfgVertexType.Block: this.onBasicBlockNode(vertex); break; default: (0, assert_1.assertUnreachable)(type); } } onBasicBlockNode(node) { if (this.config.defaultVisitingOrder === 'forward') { for (const elem of node.elems.toReversed()) { this.visitNode(elem.id); } } else { for (const elem of node.elems) { this.visitNode(elem.id); } } } onStatementNode(_node) { /* does nothing by default */ } onExpressionNode(_node) { /* does nothing by default */ } onMidMarkerNode(_node) { /* does nothing by default */ } onEndMarkerNode(_node) { /* does nothing by default */ } } exports.BasicCfgGuidedVisitor = BasicCfgGuidedVisitor; //# sourceMappingURL=basic-cfg-guided-visitor.js.map