@eagleoutice/flowr 2.9.6 → 2.9.8

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 (62) hide show
  1. package/README.md +28 -26
  2. package/abstract-interpretation/absint-visitor.d.ts +5 -4
  3. package/abstract-interpretation/absint-visitor.js +12 -11
  4. package/abstract-interpretation/data-frame/dataframe-domain.js +1 -2
  5. package/benchmark/slicer.d.ts +0 -1
  6. package/benchmark/slicer.js +3 -9
  7. package/benchmark/stats/print.js +1 -0
  8. package/benchmark/summarizer/data.d.ts +2 -0
  9. package/benchmark/summarizer/first-phase/process.js +3 -1
  10. package/benchmark/summarizer/second-phase/process.js +4 -0
  11. package/cli/repl/commands/repl-commands.d.ts +1 -0
  12. package/cli/repl/commands/repl-commands.js +1 -0
  13. package/cli/repl/commands/repl-normalize.d.ts +1 -0
  14. package/cli/repl/commands/repl-normalize.js +28 -1
  15. package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
  16. package/control-flow/basic-cfg-guided-visitor.js +8 -9
  17. package/control-flow/cfg-dead-code.js +16 -15
  18. package/control-flow/cfg-properties.d.ts +2 -2
  19. package/control-flow/cfg-properties.js +3 -2
  20. package/control-flow/cfg-to-basic-blocks.js +9 -12
  21. package/control-flow/control-flow-graph.d.ts +384 -78
  22. package/control-flow/control-flow-graph.js +607 -115
  23. package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
  24. package/control-flow/dfg-cfg-guided-visitor.js +3 -3
  25. package/control-flow/diff-cfg.js +35 -29
  26. package/control-flow/extract-cfg.d.ts +5 -4
  27. package/control-flow/extract-cfg.js +156 -127
  28. package/control-flow/happens-before.js +2 -1
  29. package/control-flow/semantic-cfg-guided-visitor.js +2 -1
  30. package/control-flow/simple-visitor.d.ts +1 -2
  31. package/control-flow/simple-visitor.js +20 -15
  32. package/control-flow/syntax-cfg-guided-visitor.js +2 -1
  33. package/control-flow/useless-loop.js +2 -1
  34. package/documentation/doc-readme.js +11 -9
  35. package/documentation/wiki-absint.js +4 -3
  36. package/documentation/wiki-cfg.js +21 -9
  37. package/documentation/wiki-mk/doc-context.d.ts +3 -0
  38. package/documentation/wiki-mk/doc-context.js +4 -1
  39. package/documentation/wiki-mk/doc-maker.js +1 -1
  40. package/linter/linter-rules.d.ts +2 -2
  41. package/linter/rules/dataframe-access-validation.d.ts +2 -2
  42. package/linter/rules/dataframe-access-validation.js +3 -3
  43. package/package.json +1 -1
  44. package/project/cache/flowr-analyzer-controlflow-cache.js +3 -0
  45. package/project/cfg-kind.d.ts +5 -1
  46. package/project/cfg-kind.js +5 -1
  47. package/project/plugins/file-plugins/files/flowr-namespace-file.js +3 -2
  48. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +10 -2
  49. package/queries/catalog/control-flow-query/control-flow-query-format.js +1 -1
  50. package/queries/catalog/df-shape-query/df-shape-query-executor.js +12 -5
  51. package/r-bridge/lang-4.x/convert-values.js +1 -1
  52. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.d.ts +2 -1
  53. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +83 -53
  54. package/search/search-executor/search-generators.js +2 -2
  55. package/util/assert.d.ts +3 -3
  56. package/util/mermaid/cfg.d.ts +1 -7
  57. package/util/mermaid/cfg.js +37 -44
  58. package/util/r-regex.d.ts +4 -0
  59. package/util/r-regex.js +35 -3
  60. package/util/version.js +1 -1
  61. package/control-flow/invert-cfg.d.ts +0 -5
  62. package/control-flow/invert-cfg.js +0 -20
@@ -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,33 +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();
557
+ /** reverse edges for bidirectional mapping */
558
+ revEdgeInfos = new Map();
80
559
  /** used as an optimization to avoid unnecessary lookups */
81
- _mayHaveBasicBlocks = false;
560
+ _mayBB = false;
82
561
  /**
83
562
  * Add a new vertex to the control flow graph.
84
563
  * @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge
85
564
  */
86
565
  addVertex(vertex, rootVertex = true) {
87
- (0, assert_1.guard)(!this.vertexInformation.has(vertex.id), `Node with id ${vertex.id} already exists`);
88
- if (vertex.type === CfgVertexType.Block) {
89
- this._mayHaveBasicBlocks = true;
90
- if (vertex.elems.some(e => this.bbChildren.has(e.id) || this.rootVertices.has(e.id))) {
91
- 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`);
92
576
  }
93
- for (const elem of vertex.elems) {
94
- this.bbChildren.set(elem.id, vertex.id);
577
+ for (const elem of elems) {
578
+ this.bbChildren.set(exports.CfgVertex.getId(elem), vid);
95
579
  }
96
580
  }
97
- this.vertexInformation.set(vertex.id, vertex);
581
+ this.vtxInfos.set(vid, vertex);
98
582
  if (rootVertex) {
99
- this.rootVertices.add(vertex.id);
583
+ this.roots.add(vid);
100
584
  }
101
585
  return this;
102
586
  }
@@ -106,51 +590,46 @@ class ControlFlowGraph {
106
590
  * @see {@link ControlFlowGraph#addEdges|addEdges()} - to add multiple edges at once
107
591
  */
108
592
  addEdge(from, to, edge) {
109
- const edgesFrom = this.edgeInformation.get(from) ?? new Map();
110
- if (!this.edgeInformation.has(from)) {
111
- 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);
112
596
  }
113
597
  edgesFrom.set(to, edge);
598
+ const edgesTo = this.revEdgeInfos.get(to) ?? new Map();
599
+ if (!this.revEdgeInfos.has(to)) {
600
+ this.revEdgeInfos.set(to, edgesTo);
601
+ }
602
+ edgesTo.set(from, edge);
114
603
  return this;
115
604
  }
116
605
  /**
117
606
  * Add multiple edges from a given source vertex to the control flow graph.
118
607
  */
119
608
  addEdges(from, to) {
120
- const edgesFrom = this.edgeInformation.get(from) ?? new Map();
121
- if (!this.edgeInformation.has(from)) {
122
- this.edgeInformation.set(from, edgesFrom);
123
- }
124
- for (const [toId, edge] of to) {
125
- edgesFrom.set(toId, edge);
609
+ for (const [toNode, edge] of to) {
610
+ this.addEdge(from, toNode, edge);
126
611
  }
127
612
  return this;
128
613
  }
129
614
  outgoingEdges(node) {
130
- return this.edgeInformation.get(node);
615
+ return this.edgeInfos.get(node);
131
616
  }
132
- ingoingEdges(id) {
133
- const edges = new Map();
134
- for (const [source, outgoing] of this.edgeInformation.entries()) {
135
- const o = outgoing.get(id);
136
- if (o) {
137
- edges.set(source, o);
138
- }
139
- }
140
- return edges;
617
+ ingoingEdges(node) {
618
+ return this.revEdgeInfos.get(node);
141
619
  }
142
620
  rootIds() {
143
- return this.rootVertices;
621
+ return this.roots;
144
622
  }
145
623
  vertices(includeBasicBlockElements = true) {
146
624
  if (includeBasicBlockElements) {
147
- const all = new Map(this.vertexInformation);
625
+ const all = new Map(this.vtxInfos);
148
626
  for (const [id, block] of this.bbChildren.entries()) {
149
627
  const blockVertex = all.get(block);
150
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
628
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
151
629
  continue;
152
630
  }
153
- 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);
154
633
  if (elem !== undefined) {
155
634
  all.set(id, elem);
156
635
  }
@@ -158,7 +637,7 @@ class ControlFlowGraph {
158
637
  return all;
159
638
  }
160
639
  else {
161
- return this.vertexInformation;
640
+ return this.vtxInfos;
162
641
  }
163
642
  }
164
643
  getBasicBlock(elemId) {
@@ -166,20 +645,20 @@ class ControlFlowGraph {
166
645
  if (block === undefined) {
167
646
  return undefined;
168
647
  }
169
- const blockVertex = this.vertexInformation.get(block);
170
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
648
+ const blockVertex = this.vtxInfos.get(block);
649
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
171
650
  return undefined;
172
651
  }
173
652
  return blockVertex;
174
653
  }
175
654
  edges() {
176
- return this.edgeInformation;
655
+ return this.edgeInfos;
177
656
  }
178
657
  /**
179
658
  * Retrieve a vertex by its id.
180
659
  */
181
660
  getVertex(id, includeBlocks = true) {
182
- const res = this.vertexInformation.get(id);
661
+ const res = this.vtxInfos.get(id);
183
662
  if (res || !includeBlocks) {
184
663
  return res;
185
664
  }
@@ -187,17 +666,18 @@ class ControlFlowGraph {
187
666
  if (block === undefined) {
188
667
  return undefined;
189
668
  }
190
- const blockVertex = this.vertexInformation.get(block);
191
- if (blockVertex === undefined || blockVertex.type !== CfgVertexType.Block) {
669
+ const blockVertex = this.vtxInfos.get(block);
670
+ if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
192
671
  return undefined;
193
672
  }
194
- blockVertex.elems.find(e => e.id === id);
673
+ const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
674
+ return elems.find(e => exports.CfgVertex.getId(e) === id);
195
675
  }
196
676
  hasVertex(id, includeBlocks = true) {
197
- 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));
198
678
  }
199
679
  mayHaveBasicBlocks() {
200
- return this._mayHaveBasicBlocks;
680
+ return this._mayBB;
201
681
  }
202
682
  /**
203
683
  * This removes the vertex and all edges to and from it.
@@ -206,8 +686,9 @@ class ControlFlowGraph {
206
686
  * @see {@link ControlFlowGraph#removeEdge|removeEdge()} - to remove a specific edge
207
687
  */
208
688
  removeVertex(id) {
209
- this.vertexInformation.delete(id);
210
- this.edgeInformation.delete(id);
689
+ this.vtxInfos.delete(id);
690
+ this.edgeInfos.delete(id);
691
+ this.revEdgeInfos.delete(id);
211
692
  this.bbChildren.delete(id);
212
693
  // remove all bbChildren with id as target
213
694
  for (const [a, b] of this.bbChildren.entries()) {
@@ -215,10 +696,13 @@ class ControlFlowGraph {
215
696
  this.bbChildren.delete(a);
216
697
  }
217
698
  }
218
- for (const edges of this.edgeInformation.values()) {
699
+ for (const edges of this.edgeInfos.values()) {
700
+ edges.delete(id);
701
+ }
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,11 +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 edges = this.edgeInformation.get(from);
231
- if (edges) {
232
- edges.delete(to);
233
- if (edges.size === 0) {
234
- this.edgeInformation.delete(from);
714
+ const edgesFrom = this.edgeInfos.get(from);
715
+ if (edgesFrom) {
716
+ edgesFrom.delete(to);
717
+ if (edgesFrom.size === 0) {
718
+ this.edgeInfos.delete(from);
719
+ }
720
+ }
721
+ const edgesTo = this.revEdgeInfos.get(to);
722
+ if (edgesTo) {
723
+ edgesTo.delete(from);
724
+ if (edgesTo.size === 0) {
725
+ this.revEdgeInfos.delete(to);
235
726
  }
236
727
  }
237
728
  return this;
@@ -240,14 +731,14 @@ class ControlFlowGraph {
240
731
  mergeTwoBasicBlocks(a, b) {
241
732
  const aVertex = this.getVertex(a);
242
733
  const bVertex = this.getVertex(b);
243
- if (!aVertex || !bVertex || aVertex.type !== CfgVertexType.Block || bVertex.type !== CfgVertexType.Block) {
734
+ if (!aVertex || !bVertex || !exports.CfgVertex.isBlock(aVertex) || !exports.CfgVertex.isBlock(bVertex)) {
244
735
  return this;
245
736
  }
246
- const bElems = bVertex.elems;
247
- aVertex.elems = aVertex.elems.concat(bElems);
737
+ const bElems = exports.CfgVertex.getBasicBlockElements(bVertex);
738
+ exports.CfgVertex.setBasicBlockElements(aVertex, [...exports.CfgVertex.getBasicBlockElements(aVertex), ...bElems]);
248
739
  // update cache
249
740
  for (const elem of bElems) {
250
- this.bbChildren.set(elem.id, a);
741
+ this.bbChildren.set(exports.CfgVertex.getId(elem), a);
251
742
  }
252
743
  // drop all edges from a to b
253
744
  this.removeEdge(a, b);
@@ -260,6 +751,7 @@ class ControlFlowGraph {
260
751
  return this;
261
752
  }
262
753
  /**
754
+ * **This Operation is in-place and modifies the current graph.**
263
755
  * Merge another control flow graph into this one.
264
756
  * @param other - the other control flow graph to merge into this one
265
757
  * @param forceNested - should the other graph be assumed to be fully nested (e.g., within a function definition).
@@ -267,24 +759,24 @@ class ControlFlowGraph {
267
759
  * This is the pendant of {@link DataflowGraph#mergeWith|mergeWith()} on a {@link DataflowGraph}.
268
760
  */
269
761
  mergeWith(other, forceNested = false) {
270
- this._mayHaveBasicBlocks ||= other._mayHaveBasicBlocks;
271
- const roots = other.rootVertices;
272
- if (this._mayHaveBasicBlocks) {
273
- 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) {
274
766
  this.addVertex(node, forceNested ? false : roots.has(id));
275
767
  }
276
768
  }
277
769
  else {
278
- for (const [id, node] of other.vertexInformation) {
279
- this.vertexInformation.set(id, node);
770
+ for (const [id, node] of other.vtxInfos) {
771
+ this.vtxInfos.set(id, node);
280
772
  }
281
773
  if (!forceNested) {
282
774
  for (const root of roots) {
283
- this.rootVertices.add(root);
775
+ this.roots.add(root);
284
776
  }
285
777
  }
286
778
  }
287
- for (const [from, edges] of other.edgeInformation) {
779
+ for (const [from, edges] of other.edgeInfos) {
288
780
  this.addEdges(from, edges);
289
781
  }
290
782
  return this;