@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
79 lines • 3.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CfgBuilder = void 0;
const control_flow_graph_1 = require("./control-flow-graph");
/**
* Records the vertices and edges of a control flow graph instead of building it, as the bottom-up fold would
* copy an eager graph once per nesting level. {@link CfgBuilder#mergeWith|mergeWith()} only references the other
* builder, {@link CfgBuilder#materialize|materialize()} replays everything once in recording order — the
* order an eager merge produced, which the vertex order of a function definition's children relies on.
*/
class CfgBuilder {
operations = [];
addVertex(vertex, rootVertex = true) {
this.operations.push({ kind: 0 /* BuilderOperationType.Vertex */, vertex, root: rootVertex });
return this;
}
addEdge(from, to, edge) {
this.operations.push({ kind: 1 /* BuilderOperationType.Edge */, from, to, edge });
return this;
}
/**
* Record that the other builder is part of this one, it must not be modified afterwards.
* @param other - the builder to include
* @param forceNested - should its vertices count as nested (e.g., within a function definition)
*/
mergeWith(other, forceNested = false) {
this.operations.push({ kind: 2 /* BuilderOperationType.Merge */, other, nested: forceNested });
return this;
}
/** The last vertex recorded for the given id, searching the merged builders only if we hold none. */
getVertex(id) {
for (let i = this.operations.length - 1; i >= 0; i--) {
const operation = this.operations[i];
if (operation.kind === 0 /* BuilderOperationType.Vertex */) {
if (control_flow_graph_1.CfgVertex.getId(operation.vertex) === id) {
return operation.vertex;
}
}
else if (operation.kind === 2 /* BuilderOperationType.Merge */) {
const found = operation.other.getVertex(id);
if (found !== undefined) {
return found;
}
}
}
return undefined;
}
/** The ids of all vertices that are not nested, in insertion order. */
rootIds(collected = new Set()) {
for (const operation of this.operations) {
if (operation.kind === 0 /* BuilderOperationType.Vertex */) {
if (operation.root) {
collected.add(control_flow_graph_1.CfgVertex.getId(operation.vertex));
}
}
else if (operation.kind === 2 /* BuilderOperationType.Merge */ && !operation.nested) {
operation.other.rootIds(collected);
}
}
return collected;
}
/** Replays all recorded operations into a {@link ControlFlowGraph}. */
materialize(graph = new control_flow_graph_1.ControlFlowGraph(), nested = false) {
for (const operation of this.operations) {
if (operation.kind === 0 /* BuilderOperationType.Vertex */) {
graph.addVertex(operation.vertex, operation.root && !nested);
}
else if (operation.kind === 1 /* BuilderOperationType.Edge */) {
graph.addEdge(operation.from, operation.to, operation.edge);
}
else {
operation.other.materialize(graph, nested || operation.nested);
}
}
return graph;
}
}
exports.CfgBuilder = CfgBuilder;
//# sourceMappingURL=cfg-builder.js.map