UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

79 lines 3.56 kB
"use strict"; 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