@eagleoutice/flowr 2.9.7 → 2.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +21 -21
  2. package/abstract-interpretation/absint-visitor.d.ts +5 -4
  3. package/abstract-interpretation/absint-visitor.js +12 -11
  4. package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
  5. package/control-flow/basic-cfg-guided-visitor.js +7 -6
  6. package/control-flow/cfg-dead-code.js +12 -9
  7. package/control-flow/cfg-properties.d.ts +2 -2
  8. package/control-flow/cfg-properties.js +3 -2
  9. package/control-flow/cfg-to-basic-blocks.js +9 -12
  10. package/control-flow/control-flow-graph.d.ts +382 -78
  11. package/control-flow/control-flow-graph.js +591 -106
  12. package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
  13. package/control-flow/dfg-cfg-guided-visitor.js +3 -3
  14. package/control-flow/diff-cfg.js +35 -29
  15. package/control-flow/extract-cfg.d.ts +3 -3
  16. package/control-flow/extract-cfg.js +145 -125
  17. package/control-flow/happens-before.js +2 -1
  18. package/control-flow/semantic-cfg-guided-visitor.js +2 -1
  19. package/control-flow/simple-visitor.js +8 -6
  20. package/control-flow/syntax-cfg-guided-visitor.js +2 -1
  21. package/control-flow/useless-loop.js +2 -1
  22. package/documentation/wiki-cfg.js +21 -9
  23. package/documentation/wiki-mk/doc-maker.js +1 -1
  24. package/package.json +1 -1
  25. package/project/context/flowr-file.d.ts +5 -0
  26. package/project/context/flowr-file.js +7 -0
  27. package/project/plugins/file-plugins/files/flowr-description-file.d.ts +1 -0
  28. package/project/plugins/file-plugins/files/flowr-description-file.js +5 -0
  29. package/project/plugins/file-plugins/files/flowr-namespace-file.d.ts +4 -0
  30. package/project/plugins/file-plugins/files/flowr-namespace-file.js +8 -0
  31. package/project/plugins/file-plugins/files/flowr-news-file.d.ts +4 -0
  32. package/project/plugins/file-plugins/files/flowr-news-file.js +8 -0
  33. package/queries/catalog/control-flow-query/control-flow-query-format.js +1 -1
  34. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.d.ts +2 -1
  35. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +19 -19
  36. package/search/search-executor/search-generators.js +2 -2
  37. package/util/assert.d.ts +3 -3
  38. package/util/mermaid/cfg.d.ts +1 -7
  39. package/util/mermaid/cfg.js +37 -44
  40. package/util/version.js +1 -1
@@ -1,67 +1,544 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ControlFlowGraph = exports.CfgVertexType = void 0;
4
- exports.edgeTypeToString = edgeTypeToString;
5
- exports.equalVertex = equalVertex;
6
- exports.isMarkerVertex = isMarkerVertex;
7
- exports.getVertexRootId = getVertexRootId;
3
+ exports.ControlFlowGraph = exports.CfgEdge = exports.CfgVertex = exports.CfgVertexType = void 0;
8
4
  exports.emptyControlFlowInformation = emptyControlFlowInformation;
5
+ const node_id_1 = require("../r-bridge/lang-4.x/ast/model/processing/node-id");
6
+ const convert_values_1 = require("../r-bridge/lang-4.x/convert-values");
9
7
  const assert_1 = require("../util/assert");
8
+ /**
9
+ * The type of a vertex in the {@link ControlFlowGraph}.
10
+ * Please use the helper object (e.g. {@link CfgVertex#getType|getType()}) to work with vertices instead of directly accessing the properties.
11
+ */
10
12
  var CfgVertexType;
11
13
  (function (CfgVertexType) {
12
- /** The explicit exit-nodes to ensure the hammock property */
13
- CfgVertexType["EndMarker"] = "end";
14
- /** something like an if, assignment, ... even though in the classical sense of R they are still expressions */
15
- CfgVertexType["Statement"] = "stm";
16
- /** something like an addition, ... */
17
- CfgVertexType["Expression"] = "expr";
18
- /** a (as far as R allows this) 'basic' block */
19
- CfgVertexType["Block"] = "blk";
14
+ /**
15
+ * The explicit exit-nodes to ensure the hammock property.
16
+ * @see {@link CfgVertex.makeMarker|CfgVertex.makeMarker()} - for a helper function to create end marker vertices
17
+ */
18
+ CfgVertexType[CfgVertexType["Marker"] = 0] = "Marker";
19
+ /**
20
+ * something like an if, assignment, ... even though in the classical sense of R they are still expressions
21
+ * @see {@link CfgVertex.makeStatement|CfgVertex.makeStatement()} - for a helper function to create statement vertices
22
+ */
23
+ CfgVertexType[CfgVertexType["Statement"] = 1] = "Statement";
24
+ /**
25
+ * something like an addition, ...
26
+ * @see {@link CfgVertex.makeExpression|CfgVertex.makeExpression()} - for a helper function to create expression vertices
27
+ */
28
+ CfgVertexType[CfgVertexType["Expression"] = 2] = "Expression";
29
+ /**
30
+ * a (as far as R allows this) 'basic' block
31
+ * @see {@link CfgVertex.makeBlock|CfgVertex.makeBlock()} - for a helper function to create basic block vertices
32
+ */
33
+ CfgVertexType[CfgVertexType["Block"] = 3] = "Block";
20
34
  })(CfgVertexType || (exports.CfgVertexType = CfgVertexType = {}));
21
35
  /**
22
- * Provide a string representation of the given edge type.
36
+ * Helper object for {@link CfgVertex} - a vertex in the {@link ControlFlowGraph} that may have markers attached to it (e.g., for function calls).
23
37
  */
24
- function edgeTypeToString(type) {
25
- switch (type) {
26
- case 0 /* CfgEdgeType.Fd */:
27
- return 'FD';
28
- case 1 /* CfgEdgeType.Cd */:
29
- return 'CD';
30
- default:
31
- throw new Error(`Unknown edge type ${JSON.stringify(type)}`);
38
+ exports.CfgVertex = {
39
+ /**
40
+ * Create a new expression vertex with the given id, children, call targets, and markers.
41
+ * @param id - the id of the vertex, which should directly relate to the AST node
42
+ * @param children - child nodes attached to this one
43
+ * @param callTargets - if the vertex calls a function, this links all targets of this call
44
+ * @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
45
+ * @param end - the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers
46
+ * @see {@link CfgVertex#isExpression|isExpression()} - for a way to check whether a vertex is an expression vertex
47
+ */
48
+ makeExpression(id, { children, mid, end, callTargets } = {}) {
49
+ if (children === undefined && callTargets === undefined) {
50
+ if (mid === undefined && end === undefined) {
51
+ return [CfgVertexType.Expression, id];
52
+ }
53
+ else {
54
+ return [CfgVertexType.Expression, id, mid, end];
55
+ }
56
+ }
57
+ return [CfgVertexType.Expression, id, mid, end, children, callTargets];
58
+ },
59
+ /**
60
+ * A convenience function to create a new expression vertex with a canonical end marker ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id for the end marker.
61
+ * @param id - the id of the vertex, which should directly relate to the AST node
62
+ * @param children - child nodes attached to this one
63
+ * @param callTargets - if the vertex calls a function, this links all targets of this call
64
+ * @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
65
+ * @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices with a custom end marker
66
+ * @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id#
67
+ * @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker id
68
+ */
69
+ makeExpressionWithEnd(id, { children, mid, callTargets } = {}) {
70
+ return exports.CfgVertex.makeExpression(id, { children, mid, end: [exports.CfgVertex.toExitId(id)], callTargets });
71
+ },
72
+ /**
73
+ * A convenience function to create a new statement vertex with a canonical end marker ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id for the end marker.
74
+ * @param id - the id of the vertex, which should directly relate to the AST node
75
+ * @param children - child nodes attached to this one
76
+ * @param callTargets - if the vertex calls a function, this links all targets of this call
77
+ * @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
78
+ * @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices with a custom end marker
79
+ * @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id#
80
+ * @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker id
81
+ */
82
+ makeStatementWithEnd(id, { children, mid, callTargets } = {}) {
83
+ return exports.CfgVertex.makeStatement(id, { children, mid, end: [exports.CfgVertex.toExitId(id)], callTargets });
84
+ },
85
+ /**
86
+ * Create a new statement vertex with the given id, children, call targets, and markers.
87
+ * @param id - the id of the vertex, which should directly relate to the AST node
88
+ * @param children - child nodes attached to this one
89
+ * @param callTargets - if the vertex calls a function, this links all targets of this call
90
+ * @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
91
+ * @param end - the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers
92
+ * @see {@link CfgVertex#isStatement|isStatement()} - for a way to check whether a vertex is a statement vertex
93
+ */
94
+ makeStatement(id, { children, mid, end, callTargets } = {}) {
95
+ if (children === undefined && callTargets === undefined) {
96
+ if (mid === undefined && end === undefined) {
97
+ return [CfgVertexType.Statement, id];
98
+ }
99
+ else {
100
+ return [CfgVertexType.Statement, id, mid, end];
101
+ }
102
+ }
103
+ return [CfgVertexType.Statement, id, mid, end, children, callTargets];
104
+ },
105
+ /**
106
+ * A convenience function to create a new vertex which is either a statement or an expression.
107
+ */
108
+ makeExprOrStm(id, type, { children, mid, end, callTargets } = {}) {
109
+ if (children === undefined && callTargets === undefined) {
110
+ if (mid === undefined && end === undefined) {
111
+ return [type, id];
112
+ }
113
+ else {
114
+ return [type, id, mid, end];
115
+ }
116
+ }
117
+ return [type, id, mid, end, children, callTargets];
118
+ },
119
+ /**
120
+ * Create a new marker vertex with the given id, root id, children, and call targets.
121
+ * @param id - the id of the vertex, which should directly relate to the AST node
122
+ * @param rootId - the id of the AST node this end marker corresponds to
123
+ * @see {@link CfgVertex#isMarker|isMarker()} - for a way to check whether a vertex is an end marker vertex
124
+ * @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of an end marker vertex
125
+ * @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id
126
+ */
127
+ makeMarker(id, rootId) {
128
+ if (exports.CfgVertex.fromExitId(id) === rootId) {
129
+ return id;
130
+ }
131
+ else {
132
+ return [CfgVertexType.Marker, id, rootId];
133
+ }
134
+ },
135
+ /**
136
+ * A convenience function to create a new marker vertex with a canonical id ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id.
137
+ * @see {@link CfgVertex#makeMarker|makeMarker()} - for a way to create end marker vertices with a custom id
138
+ */
139
+ makeExitMarker(id) {
140
+ return exports.CfgVertex.toExitId(id);
141
+ },
142
+ /**
143
+ * Create a new basic block vertex with the given id, elements, children, and call targets.
144
+ * @param id - the id of the vertex, which should directly relate to the AST node
145
+ * @param elems - the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs
146
+ * @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex
147
+ */
148
+ makeBlock(id, elems) {
149
+ return [CfgVertexType.Block, id, elems];
150
+ },
151
+ /**
152
+ * Check whether the given vertex is an expression vertex.
153
+ * @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices
154
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
155
+ */
156
+ isExpression(vertex) {
157
+ return Array.isArray(vertex) && vertex[0] === CfgVertexType.Expression;
158
+ },
159
+ /**
160
+ * Check whether the given vertex is a statement vertex.
161
+ * @see {@link CfgVertex#makeStatement|makeStatement()} - for a way to create statement vertices
162
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
163
+ */
164
+ isStatement(vertex) {
165
+ return Array.isArray(vertex) && vertex[0] === CfgVertexType.Statement;
166
+ },
167
+ /**
168
+ * Check whether the given vertex is an end marker vertex.
169
+ * @see {@link CfgVertex#makeMarker|makeMarker()} - for a way to create end marker vertices
170
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
171
+ */
172
+ isMarker(vertex) {
173
+ return vertex !== undefined && (!Array.isArray(vertex) || vertex[0] === CfgVertexType.Marker);
174
+ },
175
+ /**
176
+ * Check whether the given vertex is a basic block vertex.
177
+ * @see {@link CfgVertex#makeBlock|makeBlock()} - for a way to create basic block vertices
178
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
179
+ */
180
+ isBlock(vertex) {
181
+ return Array.isArray(vertex) && vertex[0] === CfgVertexType.Block;
182
+ },
183
+ /**
184
+ * Get the type of the given vertex.
185
+ * @example
186
+ * ```ts
187
+ * const vertex: CfgVertex = CfgVertex.makeExpr('node-1')
188
+ * console.log(CfgVertex.getType(vertex)); // Output: CfgVertexType.Expression
189
+ * ```
190
+ * @see {@link CfgVertex#isExpression|isExpression()}, {@link CfgVertex#isStatement|isStatement()}, {@link CfgVertex#isMarker|isMarker()}, {@link CfgVertex#isBlock|isBlock()} - for ways to check the type of a vertex against a specific type instead of getting the type and checking it against a specific type
191
+ * @see {@link CfgVertex#getId|getId()} - for a way to get the id of a vertex
192
+ * @see {@link CfgVertex#typeToString|typeToString()} - for a way to convert the type of a vertex to a string for easier debugging and visualization
193
+ */
194
+ getType(vertex) {
195
+ return Array.isArray(vertex) ? vertex[0] : CfgVertexType.Marker;
196
+ },
197
+ /**
198
+ * Convert the given vertex type to a string for easier debugging and visualization.
199
+ * @see {@link CfgVertexType} - for the possible vertex types
200
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex and convert it to a string
201
+ */
202
+ typeToString(type) {
203
+ switch (type) {
204
+ case CfgVertexType.Marker:
205
+ return 'marker';
206
+ case CfgVertexType.Statement:
207
+ return 'statement';
208
+ case CfgVertexType.Expression:
209
+ return 'expression';
210
+ case CfgVertexType.Block:
211
+ return 'block';
212
+ default:
213
+ (0, assert_1.assertUnreachable)(type);
214
+ }
215
+ },
216
+ /**
217
+ * Get the id of the given vertex, which should directly relate to the AST node.
218
+ * @example
219
+ * ```ts
220
+ * const vertex: CfgVertex = CfgVertex.makeExpr('node-1')
221
+ * console.log(CfgVertex.getId(vertex)); // Output: 'node-1'
222
+ * ```
223
+ * @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex
224
+ * @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of a vertex
225
+ */
226
+ getId(vertex) {
227
+ return vertex === undefined ? undefined : (Array.isArray(vertex) ? vertex[1] : vertex);
228
+ },
229
+ /**
230
+ * Check whether two vertices are equal, i.e., they have the same type, id, and if they are basic block vertices, they also have the same elements in the same order.
231
+ */
232
+ equal(a, b) {
233
+ if (!Array.isArray(a) || !Array.isArray(b)) {
234
+ return a === b;
235
+ }
236
+ else if (a === b) {
237
+ return true;
238
+ }
239
+ else if (a[0] !== b[0] || a[1] !== b[1]) {
240
+ return false;
241
+ }
242
+ else if (a[0] === CfgVertexType.Block && b[0] === CfgVertexType.Block) {
243
+ return a[2].length === b[2].length && a[2].every((e, i) => exports.CfgVertex.equal(e, b[2][i]));
244
+ }
245
+ else if (a[0] === CfgVertexType.Marker && b[0] === CfgVertexType.Marker) {
246
+ return a[2] === b[2];
247
+ }
248
+ return true;
249
+ },
250
+ /**
251
+ * Get the root id of a vertex, i.e., the id of the AST node it corresponds to.
252
+ * For normal vertices, this is the same as the id of the vertex itself, for end marker vertices, this is the root id stored in the vertex.
253
+ * @see {@link CfgVertex#unpackRoot|unpackRoot()} - for a way to unpack the root id of a marker vertex
254
+ */
255
+ getRootId(vertex) {
256
+ return exports.CfgVertex.isMarker(vertex) ? exports.CfgVertex.unpackRootId(vertex) : vertex[1];
257
+ },
258
+ /**
259
+ * Unpack the root id of a marker vertex, i.e., get the root id stored in the vertex or derive it from the canonical id if it is not explicitly stored.
260
+ * @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of a vertex, which uses this function for marker vertices
261
+ */
262
+ unpackRootId(vertex) {
263
+ return Array.isArray(vertex) ? vertex[2] ?? exports.CfgVertex.fromExitId(vertex[1]) : exports.CfgVertex.fromExitId(vertex);
264
+ },
265
+ /**
266
+ * Get the elements of a basic block vertex, i.e., the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs.
267
+ * @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex before trying to get the elements
268
+ * @see {@link CfgVertex#setBasicBlockElements|setBasicBlockElements()} - for a way to set the elements of a basic block vertex
269
+ */
270
+ getBasicBlockElements(vertex) {
271
+ return vertex[2];
272
+ },
273
+ /**
274
+ * **Sets in-place**
275
+ * Set the elements of a basic block vertex, i.e., the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs.
276
+ * @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex before trying to set the elements
277
+ * @see {@link CfgVertex#getBasicBlockElements|getBasicBlockElements()} - for a way to get the elements of a basic block vertex
278
+ */
279
+ setBasicBlockElements(vertex, elems) {
280
+ vertex[2] = elems;
281
+ },
282
+ /**
283
+ * Get the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
284
+ * @see {@link CfgVertex#getMid|getMid()} - for a way to get the ids of the mid-markers attached to this vertex
285
+ * @see {@link CfgVertex#setEnd|setEnd()} - for a way to set the ids of the end-markers attached to this vertex
286
+ */
287
+ getEnd(vertex) {
288
+ if (vertex === undefined) {
289
+ return undefined;
290
+ }
291
+ const type = exports.CfgVertex.getType(vertex);
292
+ if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
293
+ return vertex[3];
294
+ }
295
+ return undefined;
296
+ },
297
+ /**
298
+ * **Sets in-place**
299
+ * Set the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers.
300
+ * @see {@link CfgVertex#getEnd|getEnd()} - for a way to get the ids of the end-markers attached to this vertex
301
+ */
302
+ setEnd(vertex, endMarkers) {
303
+ vertex[3] = endMarkers;
304
+ },
305
+ /**
306
+ * Get the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
307
+ */
308
+ getMid(vertex) {
309
+ if (vertex === undefined) {
310
+ return undefined;
311
+ }
312
+ const type = exports.CfgVertex.getType(vertex);
313
+ if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
314
+ return vertex[2];
315
+ }
316
+ return undefined;
317
+ },
318
+ /**
319
+ * **Sets in-place**
320
+ * Set the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
321
+ * @see {@link CfgVertex#getMid|getMid()} - for a way to get the ids of the mid-markers attached to this vertex
322
+ * @see {@link CfgVertex#setEnd|setEnd()} - for a way to set the ids of the end-markers attached to this vertex
323
+ */
324
+ setMid(vertex, midMarkers) {
325
+ vertex[2] = midMarkers;
326
+ },
327
+ /**
328
+ * Converts the given id to a, canonical, basic block lift (i.e., it adds 'bb-' as a prefix).
329
+ */
330
+ toBasicBlockId(id) {
331
+ return `bb-${id}`;
332
+ },
333
+ /**
334
+ * Converts the given id to a canonical, end marker lift (i.e., it adds '-end' as a suffix).
335
+ * @see {@link CfgVertex#fromExitId|fromExitId()} - for a way to convert the given id from a canonical end marker lift to the original id (i.e., it removes '-end' as a suffix if it is present)
336
+ */
337
+ toExitId(id) {
338
+ return `${id}-e`;
339
+ },
340
+ /**
341
+ * Converts the given id from a canonical end marker lift to the original id (i.e., it removes '-end' as a suffix if it is present).
342
+ * @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker lift (i.e., it adds '-end' as a suffix)
343
+ */
344
+ fromExitId(exitId) {
345
+ if (typeof exitId === 'string' && exitId.endsWith('-e')) {
346
+ return (0, node_id_1.normalizeIdToNumberIfPossible)(exitId.slice(0, -2));
347
+ }
348
+ else {
349
+ return exitId;
350
+ }
351
+ },
352
+ /**
353
+ * Get the call targets of a statement or expression vertex, which links all targets of this call.
354
+ */
355
+ getCallTargets(vertex) {
356
+ if (vertex === undefined) {
357
+ return undefined;
358
+ }
359
+ const type = exports.CfgVertex.getType(vertex);
360
+ if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
361
+ return vertex[5];
362
+ }
363
+ return undefined;
364
+ },
365
+ /**
366
+ * **Sets in-place**
367
+ * Set the call targets of a statement or expression vertex, which links all targets of this call.
368
+ * @see {@link CfgVertex#getCallTargets|getCallTargets()} - for a way to get the call targets of a statement or expression vertex
369
+ * @see {@link CfgVertex#mapCallTargets|mapCallTargets()} - for a way to map the call targets of a statement or expression vertex to new call targets
370
+ */
371
+ setCallTargets(vertex, callTargets) {
372
+ vertex[5] = callTargets;
373
+ },
374
+ /**
375
+ * Map the call targets of a statement or expression vertex, which links all targets of this call, to new call targets using the given mapping function.
376
+ * @see {@link CfgVertex#getCallTargets|getCallTargets()} - for a way to get the call targets of a statement or expression vertex
377
+ * @see {@link CfgVertex#setCallTargets|setCallTargets()} - for a way to set the call targets of a statement or expression vertex to new call targets
378
+ */
379
+ mapCallTargets(vertex, mapFn) {
380
+ const currentTargets = exports.CfgVertex.getCallTargets(vertex);
381
+ const newTargets = mapFn(currentTargets);
382
+ exports.CfgVertex.setCallTargets(vertex, newTargets);
383
+ },
384
+ /**
385
+ * Get the children of a statement or expression vertex, i.e., the child nodes attached to this one.
386
+ */
387
+ getChildren(vertex) {
388
+ if (vertex === undefined) {
389
+ return undefined;
390
+ }
391
+ const type = exports.CfgVertex.getType(vertex);
392
+ if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
393
+ return vertex[4];
394
+ }
395
+ return undefined;
32
396
  }
33
- }
397
+ };
34
398
  /**
35
- * Checks whether two vertices are equal.
399
+ * Helper object for {@link CfgEdge} - an edge in the {@link ControlFlowGraph}.
36
400
  */
37
- function equalVertex(a, b) {
38
- if (a.type !== b.type || a.id !== b.id) {
401
+ exports.CfgEdge = {
402
+ /**
403
+ * Check whether the given edge is a flow dependency edge.
404
+ */
405
+ isFlowDependency(edge) {
406
+ return edge === 0 /* CfgEdgeType.Fd */;
407
+ },
408
+ /**
409
+ * Check whether the given edge is a control dependency edge.
410
+ */
411
+ isControlDependency(edge) {
412
+ return Array.isArray(edge) && edge.length === 2;
413
+ },
414
+ /**
415
+ * Create a flow dependency edge.
416
+ */
417
+ makeFd() {
418
+ return 0 /* CfgEdgeType.Fd */;
419
+ },
420
+ /**
421
+ * Create a control dependency edge with the given cause and condition.
422
+ * @param controlId - the id of the vertex that causes the control dependency
423
+ * @param whenTrue - whether the control dependency is satisfied with a true condition or is it negated (e.g., else-branch)
424
+ * @see {@link CfgEdge#makeCdTrue|makeCdTrue()} - for a version of this function that assumes the control dependency is satisfied with a true condition
425
+ * @see {@link CfgEdge#makeCdFalse|makeCdFalse()} - for a version of this function that assumes the control dependency is negated (e.g., else-branch)
426
+ */
427
+ makeCd(controlId, whenTrue) {
428
+ return [controlId, whenTrue];
429
+ },
430
+ /**
431
+ * Create a control dependency edge with the given cause and a true condition.
432
+ * @param controlId - the id of the vertex that causes the control dependency
433
+ * @see {@link CfgEdge#makeCd|makeCd()} - for a version of this function that allows to specify the condition as well
434
+ */
435
+ makeCdTrue(controlId) {
436
+ return [controlId, convert_values_1.RTrue];
437
+ },
438
+ /**
439
+ * Create a control dependency edge with the given cause and a negated condition (e.g., else-branch).
440
+ * @param controlId - the id of the vertex that causes the control dependency
441
+ * @see {@link CfgEdge#makeCd|makeCd()} - for a version of this function that allows to specify the condition as well
442
+ */
443
+ makeCdFalse(controlId) {
444
+ return [controlId, convert_values_1.RFalse];
445
+ },
446
+ /**
447
+ * Get the cause of a control dependency edge, i.e., the id of the vertex that causes the control dependency.
448
+ * If the edge is not a control dependency edge, this returns undefined.
449
+ *
450
+ * This is the pendant of {@link CfgEdge#isControlDependency|isControlDependency()} on a {@link CfgEdge}.
451
+ * @see {@link CfgEdge#unpackCause|unpackCause()} - for a version of this function that assumes the edge is a control dependency edge and hence does not return undefined
452
+ */
453
+ getCause(edge) {
454
+ if (exports.CfgEdge.isControlDependency(edge)) {
455
+ return edge[0];
456
+ }
457
+ else {
458
+ return undefined;
459
+ }
460
+ },
461
+ /**
462
+ * Get the cause of a control dependency edge, i.e., the id of the vertex that causes the control dependency.
463
+ */
464
+ unpackCause(edge) {
465
+ return edge[0];
466
+ },
467
+ /**
468
+ * Get whether the control dependency edge is satisfied with a true condition or is it negated (e.g., else-branch).
469
+ * If the edge is not a control dependency edge, this returns undefined.
470
+ *
471
+ * This is the pendant of {@link CfgEdge#isControlDependency|isControlDependency()} on a {@link CfgEdge}.
472
+ * @see {@link CfgEdge#unpackWhen|unpackWhen()} - for a version of this function that assumes the edge is a control dependency edge and hence does not return undefined
473
+ */
474
+ getWhen(edge) {
475
+ if (exports.CfgEdge.isControlDependency(edge)) {
476
+ return edge[1];
477
+ }
478
+ else {
479
+ return undefined;
480
+ }
481
+ },
482
+ /**
483
+ * Get whether the control dependency edge is satisfied with a true condition or is it negated (e.g., else-branch).
484
+ */
485
+ unpackWhen(edge) {
486
+ return edge[1];
487
+ },
488
+ /**
489
+ * Check whether two edges are equal.
490
+ */
491
+ equals(a, b) {
492
+ if (exports.CfgEdge.isFlowDependency(a) && exports.CfgEdge.isFlowDependency(b)) {
493
+ return true;
494
+ }
495
+ else if (exports.CfgEdge.isControlDependency(a) && exports.CfgEdge.isControlDependency(b)) {
496
+ return a[0] === b[0] && a[1] === b[1];
497
+ }
39
498
  return false;
499
+ },
500
+ /**
501
+ * Check whether the given edge is of the given type.
502
+ * @see {@link CfgEdge#getType|getType()} - for a version of this function that returns the type of the edge instead of checking against a given type
503
+ */
504
+ isOfType(edge, type) {
505
+ return exports.CfgEdge.getType(edge) === type;
506
+ },
507
+ /**
508
+ * Get the type of the given edge.
509
+ * @see {@link CfgEdge#isOfType|isOfType()} - for a version of this function that checks whether the edge is of a given type
510
+ */
511
+ getType(edge) {
512
+ return exports.CfgEdge.isFlowDependency(edge) ? 0 /* CfgEdgeType.Fd */ : 1 /* CfgEdgeType.Cd */;
513
+ },
514
+ /**
515
+ * Provide a string representation of the given edge, e.g., for debugging or visualization purposes.
516
+ * @see {@link CfgEdge#toString|toString()} - for a version of this function that also includes the details of the edge (e.g., cause and condition for control dependency edges)
517
+ */
518
+ typeToString(edge) {
519
+ if (exports.CfgEdge.isFlowDependency(edge)) {
520
+ return 'FD';
521
+ }
522
+ else {
523
+ return 'CD';
524
+ }
525
+ },
526
+ /**
527
+ * Provide a string representation of the given edge, including its details (e.g., cause and condition for control dependency edges), e.g., for debugging or visualization purposes.
528
+ * @see {@link CfgEdge#typeToString|typeToString()} - for a version of this function that only includes the type of the edge
529
+ */
530
+ toString(edge) {
531
+ if (exports.CfgEdge.isFlowDependency(edge)) {
532
+ return 'FD';
533
+ }
534
+ else {
535
+ return `CD(${edge[0]}, ${edge[1] === convert_values_1.RTrue ? 'T' : 'F'})`;
536
+ }
40
537
  }
41
- else if (a.type === CfgVertexType.Block && b.type === CfgVertexType.Block) {
42
- return a.elems.length === b.elems.length && a.elems.every((e, i) => e.id === b.elems[i].id);
43
- }
44
- else if (a.type === CfgVertexType.EndMarker && b.type === CfgVertexType.EndMarker) {
45
- return a.root === b.root;
46
- }
47
- return true;
48
- }
49
- /**
50
- * Checks whether a vertex is a marker vertex (i.e., does not correspond to an actual AST node
51
- * but is a marker in the control flow graph).
52
- */
53
- function isMarkerVertex(vertex) {
54
- return vertex.type === CfgVertexType.EndMarker;
55
- }
56
- /**
57
- * Get the root id of a vertex, i.e., the id of the AST node it corresponds to.
58
- */
59
- function getVertexRootId(vertex) {
60
- return isMarkerVertex(vertex) ? vertex.root : vertex.id;
61
- }
538
+ };
62
539
  /**
63
540
  * This class represents the control flow graph of an R program.
64
- * The control flow may be hierarchical when confronted with function definitions (see {@link CfgSimpleVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
541
+ * The control flow may be hierarchical when confronted with function definitions (see {@link CfgVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
65
542
  *
66
543
  * There are two very simple visitors to traverse a CFG:
67
544
  * - {@link visitCfgInOrder} visits the graph in the order of the vertices
@@ -70,35 +547,40 @@ function getVertexRootId(vertex) {
70
547
  * If you want to prohibit modification, please refer to the {@link ReadOnlyControlFlowGraph} interface.
71
548
  */
72
549
  class ControlFlowGraph {
73
- rootVertices = new Set();
550
+ roots = new Set();
74
551
  /** Nesting-Independent vertex information, mapping the id to the vertex */
75
- vertexInformation = new Map();
552
+ vtxInfos = new Map();
76
553
  /** the basic block children map contains a mapping of ids to all vertices that are nested in basic blocks, mapping them to the Id of the block they appear in */
77
554
  bbChildren = new Map();
78
555
  /** basic block agnostic edges */
79
- edgeInformation = new Map();
556
+ edgeInfos = new Map();
80
557
  /** reverse edges for bidirectional mapping */
81
- reverseEdgeInfo = new Map();
558
+ revEdgeInfos = new Map();
82
559
  /** used as an optimization to avoid unnecessary lookups */
83
- _mayHaveBasicBlocks = false;
560
+ _mayBB = false;
84
561
  /**
85
562
  * Add a new vertex to the control flow graph.
86
563
  * @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge
87
564
  */
88
565
  addVertex(vertex, rootVertex = true) {
89
- (0, assert_1.guard)(!this.vertexInformation.has(vertex.id), `Node with id ${vertex.id} already exists`);
90
- if (vertex.type === CfgVertexType.Block) {
91
- this._mayHaveBasicBlocks = true;
92
- if (vertex.elems.some(e => this.bbChildren.has(e.id) || this.rootVertices.has(e.id))) {
93
- throw new Error(`Vertex ${vertex.id} contains vertices that are already part of the graph`);
566
+ const vid = exports.CfgVertex.getId(vertex);
567
+ (0, assert_1.guard)(!this.vtxInfos.has(vid), `Node with id ${vid} already exists`);
568
+ if (exports.CfgVertex.isBlock(vertex)) {
569
+ this._mayBB = true;
570
+ const elems = exports.CfgVertex.getBasicBlockElements(vertex);
571
+ if (elems.some(e => {
572
+ const eid = exports.CfgVertex.getId(e);
573
+ return this.bbChildren.has(eid) || this.roots.has(eid);
574
+ })) {
575
+ throw new Error(`Vertex ${vid} contains vertices that are already part of the graph`);
94
576
  }
95
- for (const elem of vertex.elems) {
96
- this.bbChildren.set(elem.id, vertex.id);
577
+ for (const elem of elems) {
578
+ this.bbChildren.set(exports.CfgVertex.getId(elem), vid);
97
579
  }
98
580
  }
99
- this.vertexInformation.set(vertex.id, vertex);
581
+ this.vtxInfos.set(vid, vertex);
100
582
  if (rootVertex) {
101
- this.rootVertices.add(vertex.id);
583
+ this.roots.add(vid);
102
584
  }
103
585
  return this;
104
586
  }
@@ -108,14 +590,14 @@ class ControlFlowGraph {
108
590
  * @see {@link ControlFlowGraph#addEdges|addEdges()} - to add multiple edges at once
109
591
  */
110
592
  addEdge(from, to, edge) {
111
- const edgesFrom = this.edgeInformation.get(from) ?? new Map();
112
- if (!this.edgeInformation.has(from)) {
113
- this.edgeInformation.set(from, edgesFrom);
593
+ const edgesFrom = this.edgeInfos.get(from) ?? new Map();
594
+ if (!this.edgeInfos.has(from)) {
595
+ this.edgeInfos.set(from, edgesFrom);
114
596
  }
115
597
  edgesFrom.set(to, edge);
116
- const edgesTo = this.reverseEdgeInfo.get(to) ?? new Map();
117
- if (!this.reverseEdgeInfo.has(to)) {
118
- this.reverseEdgeInfo.set(to, edgesTo);
598
+ const edgesTo = this.revEdgeInfos.get(to) ?? new Map();
599
+ if (!this.revEdgeInfos.has(to)) {
600
+ this.revEdgeInfos.set(to, edgesTo);
119
601
  }
120
602
  edgesTo.set(from, edge);
121
603
  return this;
@@ -130,23 +612,24 @@ class ControlFlowGraph {
130
612
  return this;
131
613
  }
132
614
  outgoingEdges(node) {
133
- return this.edgeInformation.get(node);
615
+ return this.edgeInfos.get(node);
134
616
  }
135
617
  ingoingEdges(node) {
136
- return this.reverseEdgeInfo.get(node);
618
+ return this.revEdgeInfos.get(node);
137
619
  }
138
620
  rootIds() {
139
- return this.rootVertices;
621
+ return this.roots;
140
622
  }
141
623
  vertices(includeBasicBlockElements = true) {
142
624
  if (includeBasicBlockElements) {
143
- const all = new Map(this.vertexInformation);
625
+ const all = new Map(this.vtxInfos);
144
626
  for (const [id, block] of this.bbChildren.entries()) {
145
627
  const blockVertex = all.get(block);
146
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
628
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
147
629
  continue;
148
630
  }
149
- const elem = blockVertex.elems.find(e => e.id === id);
631
+ const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
632
+ const elem = elems.find(e => exports.CfgVertex.getId(e) === id);
150
633
  if (elem !== undefined) {
151
634
  all.set(id, elem);
152
635
  }
@@ -154,7 +637,7 @@ class ControlFlowGraph {
154
637
  return all;
155
638
  }
156
639
  else {
157
- return this.vertexInformation;
640
+ return this.vtxInfos;
158
641
  }
159
642
  }
160
643
  getBasicBlock(elemId) {
@@ -162,20 +645,20 @@ class ControlFlowGraph {
162
645
  if (block === undefined) {
163
646
  return undefined;
164
647
  }
165
- const blockVertex = this.vertexInformation.get(block);
166
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
648
+ const blockVertex = this.vtxInfos.get(block);
649
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
167
650
  return undefined;
168
651
  }
169
652
  return blockVertex;
170
653
  }
171
654
  edges() {
172
- return this.edgeInformation;
655
+ return this.edgeInfos;
173
656
  }
174
657
  /**
175
658
  * Retrieve a vertex by its id.
176
659
  */
177
660
  getVertex(id, includeBlocks = true) {
178
- const res = this.vertexInformation.get(id);
661
+ const res = this.vtxInfos.get(id);
179
662
  if (res || !includeBlocks) {
180
663
  return res;
181
664
  }
@@ -183,17 +666,18 @@ class ControlFlowGraph {
183
666
  if (block === undefined) {
184
667
  return undefined;
185
668
  }
186
- const blockVertex = this.vertexInformation.get(block);
187
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
669
+ const blockVertex = this.vtxInfos.get(block);
670
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
188
671
  return undefined;
189
672
  }
190
- blockVertex.elems.find(e => e.id === id);
673
+ const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
674
+ return elems.find(e => exports.CfgVertex.getId(e) === id);
191
675
  }
192
676
  hasVertex(id, includeBlocks = true) {
193
- return this.vertexInformation.has(id) || (this._mayHaveBasicBlocks && includeBlocks && this.bbChildren.has(id));
677
+ return this.vtxInfos.has(id) || (this._mayBB && includeBlocks && this.bbChildren.has(id));
194
678
  }
195
679
  mayHaveBasicBlocks() {
196
- return this._mayHaveBasicBlocks;
680
+ return this._mayBB;
197
681
  }
198
682
  /**
199
683
  * This removes the vertex and all edges to and from it.
@@ -202,9 +686,9 @@ class ControlFlowGraph {
202
686
  * @see {@link ControlFlowGraph#removeEdge|removeEdge()} - to remove a specific edge
203
687
  */
204
688
  removeVertex(id) {
205
- this.vertexInformation.delete(id);
206
- this.edgeInformation.delete(id);
207
- this.reverseEdgeInfo.delete(id);
689
+ this.vtxInfos.delete(id);
690
+ this.edgeInfos.delete(id);
691
+ this.revEdgeInfos.delete(id);
208
692
  this.bbChildren.delete(id);
209
693
  // remove all bbChildren with id as target
210
694
  for (const [a, b] of this.bbChildren.entries()) {
@@ -212,13 +696,13 @@ class ControlFlowGraph {
212
696
  this.bbChildren.delete(a);
213
697
  }
214
698
  }
215
- for (const edges of this.edgeInformation.values()) {
699
+ for (const edges of this.edgeInfos.values()) {
216
700
  edges.delete(id);
217
701
  }
218
- for (const edges of this.reverseEdgeInfo.values()) {
702
+ for (const edges of this.revEdgeInfos.values()) {
219
703
  edges.delete(id);
220
704
  }
221
- this.rootVertices.delete(id);
705
+ this.roots.delete(id);
222
706
  return this;
223
707
  }
224
708
  /**
@@ -227,18 +711,18 @@ class ControlFlowGraph {
227
711
  * @see {@link ControlFlowGraph#removeVertex|removeVertex()} - to remove a vertex and all its edges
228
712
  */
229
713
  removeEdge(from, to) {
230
- const edgesFrom = this.edgeInformation.get(from);
714
+ const edgesFrom = this.edgeInfos.get(from);
231
715
  if (edgesFrom) {
232
716
  edgesFrom.delete(to);
233
717
  if (edgesFrom.size === 0) {
234
- this.edgeInformation.delete(from);
718
+ this.edgeInfos.delete(from);
235
719
  }
236
720
  }
237
- const edgesTo = this.reverseEdgeInfo.get(to);
721
+ const edgesTo = this.revEdgeInfos.get(to);
238
722
  if (edgesTo) {
239
723
  edgesTo.delete(from);
240
724
  if (edgesTo.size === 0) {
241
- this.reverseEdgeInfo.delete(to);
725
+ this.revEdgeInfos.delete(to);
242
726
  }
243
727
  }
244
728
  return this;
@@ -247,14 +731,14 @@ class ControlFlowGraph {
247
731
  mergeTwoBasicBlocks(a, b) {
248
732
  const aVertex = this.getVertex(a);
249
733
  const bVertex = this.getVertex(b);
250
- if (!aVertex || !bVertex || aVertex.type !== CfgVertexType.Block || bVertex.type !== CfgVertexType.Block) {
734
+ if (!aVertex || !bVertex || !exports.CfgVertex.isBlock(aVertex) || !exports.CfgVertex.isBlock(bVertex)) {
251
735
  return this;
252
736
  }
253
- const bElems = bVertex.elems;
254
- aVertex.elems = aVertex.elems.concat(bElems);
737
+ const bElems = exports.CfgVertex.getBasicBlockElements(bVertex);
738
+ exports.CfgVertex.setBasicBlockElements(aVertex, [...exports.CfgVertex.getBasicBlockElements(aVertex), ...bElems]);
255
739
  // update cache
256
740
  for (const elem of bElems) {
257
- this.bbChildren.set(elem.id, a);
741
+ this.bbChildren.set(exports.CfgVertex.getId(elem), a);
258
742
  }
259
743
  // drop all edges from a to b
260
744
  this.removeEdge(a, b);
@@ -267,6 +751,7 @@ class ControlFlowGraph {
267
751
  return this;
268
752
  }
269
753
  /**
754
+ * **This Operation is in-place and modifies the current graph.**
270
755
  * Merge another control flow graph into this one.
271
756
  * @param other - the other control flow graph to merge into this one
272
757
  * @param forceNested - should the other graph be assumed to be fully nested (e.g., within a function definition).
@@ -274,24 +759,24 @@ class ControlFlowGraph {
274
759
  * This is the pendant of {@link DataflowGraph#mergeWith|mergeWith()} on a {@link DataflowGraph}.
275
760
  */
276
761
  mergeWith(other, forceNested = false) {
277
- this._mayHaveBasicBlocks ||= other._mayHaveBasicBlocks;
278
- const roots = other.rootVertices;
279
- if (this._mayHaveBasicBlocks) {
280
- for (const [id, node] of other.vertexInformation) {
762
+ this._mayBB ||= other._mayBB;
763
+ const roots = other.roots;
764
+ if (this._mayBB) {
765
+ for (const [id, node] of other.vtxInfos) {
281
766
  this.addVertex(node, forceNested ? false : roots.has(id));
282
767
  }
283
768
  }
284
769
  else {
285
- for (const [id, node] of other.vertexInformation) {
286
- this.vertexInformation.set(id, node);
770
+ for (const [id, node] of other.vtxInfos) {
771
+ this.vtxInfos.set(id, node);
287
772
  }
288
773
  if (!forceNested) {
289
774
  for (const root of roots) {
290
- this.rootVertices.add(root);
775
+ this.roots.add(root);
291
776
  }
292
777
  }
293
778
  }
294
- for (const [from, edges] of other.edgeInformation) {
779
+ for (const [from, edges] of other.edgeInfos) {
295
780
  this.addEdges(from, edges);
296
781
  }
297
782
  return this;