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