@specs-feup/clava
Version:
A C/C++ source-to-source compiler written in Typescript
166 lines (140 loc) • 3.99 kB
text/typescript
import cytoscape from "cytoscape";
import {
Break,
Case,
Continue,
GotoStmt,
If,
LabelStmt,
Loop,
ReturnStmt,
Scope,
Statement,
Switch,
} from "../../../Joinpoints.js";
import CfgEdge from "./CfgEdge.js";
import CfgEdgeType from "./CfgEdgeType.js";
import CfgNodeType from "./CfgNodeType.js";
export default class CfgUtils {
/**
* @param $stmt - The statement join point
* @returns True if the statement is considered a leader
*/
static isLeader($stmt: Statement): boolean {
const graphNodeType = CfgUtils.getNodeType($stmt);
return graphNodeType !== undefined;
}
/**
* Returns the type of graph node based on the type of the leader statement. If this statement is not a leader, returns undefined
* @param $stmt - The statement join point
*/
static getNodeType($stmt: Statement): CfgNodeType | undefined {
if ($stmt instanceof If) {
return CfgNodeType.IF;
}
// Loop stmt
if ($stmt instanceof Loop) {
return CfgNodeType.LOOP;
}
// Break stmt
if ($stmt instanceof Break) {
return CfgNodeType.BREAK;
}
// Continue stmt
if ($stmt instanceof Continue) {
return CfgNodeType.CONTINUE;
}
// Switch stmt
if ($stmt instanceof Switch) {
return CfgNodeType.SWITCH;
}
//Case stmt
if ($stmt instanceof Case) {
return CfgNodeType.CASE;
}
// Goto stmt
if ($stmt instanceof GotoStmt) {
return CfgNodeType.GOTO;
}
// Label stmt
if ($stmt instanceof LabelStmt) {
return CfgNodeType.LABEL;
}
// Return stmt
if ($stmt instanceof ReturnStmt) {
return CfgNodeType.RETURN;
}
// Stmt is part of loop header
if ($stmt.isInsideLoopHeader) {
const $loop = $stmt.parent;
if (!($loop instanceof Loop)) {
throw new Error(
"Statement is inside loop header but parent is not a loop: " +
$stmt.code
);
}
if ($stmt.equals($loop.init)) {
return CfgNodeType.INIT;
} else if ($stmt.equals($loop.cond)) {
return CfgNodeType.COND;
} else if ($stmt.equals($loop.step)) {
return CfgNodeType.STEP;
} else {
throw new Error(
"Statement is in the header of loop at " +
$loop.location +
" but could not identify what part of the header: " +
$stmt.code
);
}
}
// Scope stmt
if ($stmt instanceof Scope) {
const parent = $stmt.parent;
if (parent instanceof If) {
if ($stmt.equals(parent.then)) {
return CfgNodeType.THEN;
} else if ($stmt.equals(parent.else)) {
return CfgNodeType.ELSE;
}
}
return CfgNodeType.SCOPE;
}
// If is the first statement of a scope and is not any of the other type of statements,
// consider the beginning of an INST_LIST
const $stmtParent = $stmt.parent;
if ($stmtParent instanceof Scope && $stmt.equals($stmtParent.firstStmt)) {
return CfgNodeType.INST_LIST;
}
const left = $stmt.siblingsLeft as Statement[];
if (left.length > 0) {
const lastLeft = left[left.length - 1];
const leftNodeType = CfgUtils.getNodeType(lastLeft);
if (
leftNodeType !== undefined &&
leftNodeType !== CfgNodeType.INST_LIST
) {
return CfgNodeType.INST_LIST;
}
}
return undefined;
}
static getTarget(node: cytoscape.NodeSingular, edgeType: CfgEdgeType) {
let target = undefined;
for (const edge of node.connectedEdges()) {
// Only targets of this node
if (edge.source() !== node) {
continue;
}
if ((edge.data() as CfgEdge).type === edgeType) {
if (target !== undefined) {
throw new Error(
`Found duplicated edge of type '${edgeType.toString()}' in node ${node.data()}`
);
}
target = edge.target();
}
}
return target;
}
}