@syntest/cfg
Version:
A Control Flow Graph package
142 lines • 5.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ControlFlowGraph = void 0;
/*
* Copyright 2020-2023 Delft University of Technology and SynTest contributors
*
* This file is part of SynTest Framework - SynTest Core.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const cloneDeep = require("lodash.clonedeep");
/**
* Represents a control flow graph.
*/
class ControlFlowGraph {
constructor(entry, successExit, errorExit, nodes, edges) {
this._entry = entry;
this._successExit = successExit;
this._errorExit = errorExit;
this._nodes = cloneDeep(nodes);
this._edges = cloneDeep(edges);
this._incomingEdges = this.getIncomingEdgesMap();
this._outgoingEdges = this.getOutgoingEdgesMap();
}
get entry() {
return this._entry;
}
get successExit() {
return this._successExit;
}
get errorExit() {
return this._errorExit;
}
get nodes() {
return this._nodes;
}
get edges() {
return this._edges;
}
// Returns list of nodes that have an outgoing edge to the target node
getParents(targetNodeId) {
const parentEdges = this.getIncomingEdges(targetNodeId);
return parentEdges.map((edge) => this.getNodeById(edge.source));
}
// Returns list of nodes that have an outgoing edge from the target node
getChildren(targetNodeId) {
const childEdges = this.getOutgoingEdges(targetNodeId);
return childEdges.map((edge) => this.getNodeById(edge.target));
}
getIncomingEdges(nodeId) {
if (!this._incomingEdges.has(nodeId)) {
return [];
}
return [...this._incomingEdges.get(nodeId)];
}
getOutgoingEdges(nodeId) {
if (!this._outgoingEdges.has(nodeId)) {
return [];
}
return [...this._outgoingEdges.get(nodeId)];
}
/**
* Builds the incoming edges map of the graph
* @returns
*/
getIncomingEdgesMap() {
const map = new Map();
for (const edge of this._edges) {
if (!map.has(edge.target)) {
map.set(edge.target, []);
}
map.get(edge.target).push(edge);
}
return map;
}
/**
* Builds the outgoing edges map of the graph
* @returns
*/
getOutgoingEdgesMap() {
const map = new Map();
for (const edge of this._edges) {
if (!map.has(edge.source)) {
map.set(edge.source, []);
}
map.get(edge.source).push(edge);
}
return map;
}
// Successively applies a filter method on initial list of nodes with specified predicates
getNodesByPredicates(...predicates) {
let filteredList = [...this._nodes.values()];
for (const predicate of predicates) {
filteredList = filteredList.filter((element) => predicate(element));
}
return filteredList;
}
// Applies a find method on list of nodes with a given predicate
getNodeByPredicate(predicate) {
return [...this._nodes.values()].find((element) => predicate(element));
}
// Retrieves Node object based on its id
getNodeById(nodeId) {
return this._nodes.get(nodeId);
}
getNodesByIds(nodeIds) {
return nodeIds.map((id) => this.getNodeById(id));
}
// Filters list of nodes, returning only nodes of a given type
getNodesByType(type) {
return [...this._nodes.values()].filter((n) => n.type === type);
}
// Filters list of nodes by specified line numbers,
// returning only nodes that contain AT LEAST ONE OF the given line numbers
getNodesByLineNumbers(lineNumbers) {
return [...this._nodes.values()].filter((node) =>
// maybe should check in between
node.statements.some((statement) => lineNumbers.has(statement.location.start.line) ||
lineNumbers.has(statement.location.end.line)));
}
// Returns Node that contains specified line number and is of a given type
getNodeOfTypeByLine(lineNumber, type) {
return [...this._nodes.values()].find((n) => {
// TODO maybe should check in between?
return (n.type === type &&
n.statements.some((statement) => statement.location.start.line === lineNumber ||
statement.location.end.line === lineNumber));
});
}
}
exports.ControlFlowGraph = ControlFlowGraph;
//# sourceMappingURL=ControlFlowGraph.js.map