@specs-feup/alpakka
Version:
Alpakka is a [LARA Framework](https://github.com/specs-feup/lara-framework) source-to-source compiler for Android's [smali](https://github.com/google/smali) syntax. It enables the analysis and transformation of Android apps through APK files.
128 lines • 4.54 kB
JavaScript
import ControlFlowEdge from "../edge/ControlFlowEdge.js";
import BaseNode from "../../graph/BaseNode.js";
import { Joinpoint } from "../../../../../Joinpoints.js";
var FlowNode;
(function (FlowNode) {
class Class extends BaseNode.Class {
insertBefore(node) {
this.insertSubgraphBefore(node, [node]);
}
insertSubgraphBefore(head, tail) {
this.incomers.forEach((edge) => {
edge.target = head;
});
for (const tailNode of tail) {
tailNode.nextNode = this;
}
}
removeFromFlow() {
// TODO improve ergonomics with Collection class
const incomers = this.incomers.filter((edge) => edge.is(ControlFlowEdge.TypeGuard));
const outgoers = this.outgoers.filter((edge) => edge.is(ControlFlowEdge.TypeGuard));
if (incomers.length === 0 || outgoers.length === 0) {
for (const edge of incomers) {
edge.remove();
}
for (const edge of outgoers) {
edge.remove();
}
}
else if (outgoers.length === 1) {
for (const edge of incomers) {
edge.target = outgoers[0].target;
}
outgoers[0].remove();
}
else {
throw new Error("Cannot remove node with at least one incomer and multiple outgoers.");
}
}
get reachableNodes() {
const result = [];
for (const [node] of this.bfs((e) => e.is(ControlFlowEdge.TypeGuard))) {
if (node.is(FlowNode.TypeGuard)) {
result.push(node.as(FlowNode.Class));
}
}
return result;
}
get previousEdges() {
return this.incomers
.filter((edge) => edge.is(ControlFlowEdge.TypeGuard))
.map((edge) => edge)
.map((edge) => edge.as(ControlFlowEdge.Class));
}
get previousNodes() {
return this.previousEdges
.map((edge) => edge.source)
.filter((node) => node.is(FlowNode.TypeGuard))
.map((node) => node)
.map((node) => node.as(FlowNode.Class));
}
get nextEdges() {
return this.outgoers
.filter((edge) => edge.is(ControlFlowEdge.TypeGuard))
.map((edge) => edge)
.map((edge) => edge.as(ControlFlowEdge.Class));
}
get nextNodes() {
return this.nextEdges
.map((edge) => edge.target)
.filter((node) => node.is(FlowNode.TypeGuard))
.map((node) => node)
.map((node) => node.as(FlowNode.Class));
}
get jp() {
return this.scratchData.$jp;
}
}
FlowNode.Class = Class;
class Builder extends BaseNode.Builder {
#$jp;
#flowNodeType;
constructor(type, $jp) {
super();
this.#$jp = $jp;
this.#flowNodeType = type;
}
buildData(data) {
return {
...super.buildData(data),
flowNodeType: this.#flowNodeType,
};
}
buildScratchData(scratchData) {
return {
...super.buildScratchData(scratchData),
$jp: this.#$jp,
};
}
}
FlowNode.Builder = Builder;
FlowNode.TypeGuard = {
isDataCompatible(data) {
if (!BaseNode.TypeGuard.isDataCompatible(data))
return false;
const d = data;
if (!Object.values(Type).includes(d.flowNodeType))
return false;
return true;
},
isScratchDataCompatible(scratchData) {
if (!BaseNode.TypeGuard.isScratchDataCompatible(scratchData))
return false;
const s = scratchData;
if (s.$jp !== undefined && !(s.$jp instanceof Joinpoint))
return false;
return true;
},
};
// ------------------------------------------------------------
let Type;
(function (Type) {
Type["INSTRUCTION"] = "instruction";
Type["CONDITION"] = "condition";
})(Type = FlowNode.Type || (FlowNode.Type = {}));
})(FlowNode || (FlowNode = {}));
export default FlowNode;
//# sourceMappingURL=FlowNode.js.map