@eagleoutice/flowr 2.1.8 → 2.1.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.
- package/benchmark/summarizer/first-phase/process.js +6 -5
- package/cli/repl/commands/repl-dataflow.js +5 -2
- package/cli/repl/commands/repl-normalize.js +5 -2
- package/cli/repl/commands/repl-query.js +2 -2
- package/cli/repl/server/messages/message-query.js +1 -1
- package/dataflow/environments/default-builtin-config.js +45 -6
- package/dataflow/environments/environment.d.ts +46 -8
- package/dataflow/environments/environment.js +24 -1
- package/dataflow/environments/identifier.d.ts +49 -7
- package/dataflow/environments/identifier.js +11 -2
- package/dataflow/extractor.js +5 -4
- package/dataflow/graph/dataflowgraph-builder.d.ts +6 -0
- package/dataflow/graph/dataflowgraph-builder.js +8 -0
- package/dataflow/graph/edge.d.ts +10 -4
- package/dataflow/graph/edge.js +12 -5
- package/dataflow/graph/graph.d.ts +41 -3
- package/dataflow/graph/graph.js +39 -34
- package/dataflow/graph/vertex.d.ts +66 -7
- package/dataflow/graph/vertex.js +15 -0
- package/dataflow/info.d.ts +79 -11
- package/dataflow/info.js +20 -0
- package/dataflow/internal/linker.d.ts +4 -2
- package/dataflow/internal/linker.js +12 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +16 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +83 -6
- package/dataflow/internal/process/functions/call/common.js +1 -1
- package/documentation/doc-util/doc-dfg.d.ts +0 -1
- package/documentation/doc-util/doc-dfg.js +1 -14
- package/documentation/print-capabilities-markdown.js +1 -1
- package/documentation/print-dataflow-graph-wiki.js +26 -7
- package/documentation/print-linting-and-testing-wiki.js +60 -26
- package/documentation/print-query-wiki.js +1 -1
- package/package.json +17 -3
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +13 -0
- package/queries/catalog/call-context-query/call-context-query-format.js +3 -1
- package/queries/catalog/call-context-query/cascade-action.d.ts +8 -0
- package/queries/catalog/call-context-query/cascade-action.js +13 -0
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +41 -4
- package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -0
- package/queries/query.d.ts +4 -4
- package/queries/query.js +17 -5
- package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +5 -1
- package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +6 -1
- package/r-bridge/lang-4.x/ast/model/processing/node-id.js +6 -1
- package/slicing/static/slice-call.d.ts +7 -2
- package/slicing/static/slice-call.js +33 -44
- package/slicing/static/static-slicer.d.ts +5 -1
- package/slicing/static/static-slicer.js +22 -8
- package/slicing/static/visiting-queue.d.ts +4 -4
- package/slicing/static/visiting-queue.js +5 -3
- package/statistics/output/print-stats.js +2 -1
- package/statistics/summarizer/post-process/histogram.js +2 -1
- package/statistics/summarizer/post-process/post-process-output.js +2 -1
- package/statistics/summarizer/second-phase/process.js +3 -3
- package/util/arrays.d.ts +1 -1
- package/util/arrays.js +3 -3
- package/util/cfg/cfg.js +4 -2
- package/util/mermaid/cfg.js +1 -1
- package/util/summarizer.js +2 -2
- package/util/version.js +1 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { DataflowGraphEdge } from './edge';
|
|
2
|
-
import { EdgeType } from './edge';
|
|
1
|
+
import type { DataflowGraphEdge, EdgeType } from './edge';
|
|
3
2
|
import type { DataflowInformation } from '../info';
|
|
4
3
|
import type { DataflowGraphVertexArgument, DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from './vertex';
|
|
5
4
|
import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
@@ -7,30 +6,56 @@ import type { IdentifierDefinition, IdentifierReference } from '../environments/
|
|
|
7
6
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
7
|
import type { AstIdMap } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
9
8
|
import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
|
|
9
|
+
/**
|
|
10
|
+
* Describes the information we store per function body.
|
|
11
|
+
* The {@link DataflowFunctionFlowInformation#exitPoints} are stored within the enclosing {@link DataflowGraphVertexFunctionDefinition} vertex.
|
|
12
|
+
*/
|
|
10
13
|
export type DataflowFunctionFlowInformation = Omit<DataflowInformation, 'graph' | 'exitPoints'> & {
|
|
11
14
|
graph: Set<NodeId>;
|
|
12
15
|
};
|
|
13
16
|
/**
|
|
17
|
+
* A reference with a name, e.g. `a` and `b` in the following function call:
|
|
18
|
+
*
|
|
14
19
|
* ```r
|
|
15
20
|
* foo(a = 3, b = 2)
|
|
16
21
|
* ```
|
|
22
|
+
*
|
|
23
|
+
* @see #isNamedArgument
|
|
24
|
+
* @see PositionalFunctionArgument
|
|
17
25
|
*/
|
|
18
26
|
export interface NamedFunctionArgument extends IdentifierReference {
|
|
19
27
|
readonly name: string;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
30
|
+
* A reference which does not have a name, like the references to the arguments `3` and `2` in the following:
|
|
31
|
+
*
|
|
22
32
|
* ```r
|
|
23
33
|
* foo(3, 2)
|
|
24
34
|
* ```
|
|
35
|
+
*
|
|
36
|
+
* @see #isPositionalArgument
|
|
37
|
+
* @see NamedFunctionArgument
|
|
25
38
|
*/
|
|
26
39
|
export interface PositionalFunctionArgument extends Omit<IdentifierReference, 'name'> {
|
|
27
40
|
readonly name?: undefined;
|
|
28
41
|
}
|
|
29
42
|
/** Summarizes either named (`foo(a = 3, b = 2)`), unnamed (`foo(3, 2)`), or empty (`foo(,)`) arguments within a function. */
|
|
30
43
|
export type FunctionArgument = NamedFunctionArgument | PositionalFunctionArgument | typeof EmptyArgument;
|
|
44
|
+
/**
|
|
45
|
+
* Check if the given argument is a {@link PositionalFunctionArgument}.
|
|
46
|
+
*/
|
|
31
47
|
export declare function isPositionalArgument(arg: FunctionArgument): arg is PositionalFunctionArgument;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the given argument is a {@link NamedFunctionArgument}.
|
|
50
|
+
*/
|
|
32
51
|
export declare function isNamedArgument(arg: FunctionArgument): arg is NamedFunctionArgument;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the reference of a non-empty argument.
|
|
54
|
+
*/
|
|
33
55
|
export declare function getReferenceOfArgument(arg: FunctionArgument): NodeId | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* A reference that is enough to indicate start and end points of an edge within the dataflow graph.
|
|
58
|
+
*/
|
|
34
59
|
type ReferenceForEdge = Pick<IdentifierReference, 'nodeId' | 'controlDependencies'> | IdentifierDefinition;
|
|
35
60
|
/**
|
|
36
61
|
* Maps the edges target to the edge information
|
|
@@ -41,11 +66,20 @@ export type OutgoingEdges<Edge extends DataflowGraphEdge = DataflowGraphEdge> =
|
|
|
41
66
|
* In other words, it maps the source to the edge information.
|
|
42
67
|
*/
|
|
43
68
|
export type IngoingEdges<Edge extends DataflowGraphEdge = DataflowGraphEdge> = Map<NodeId, Edge>;
|
|
69
|
+
/**
|
|
70
|
+
* The structure of the serialized {@link DataflowGraph}.
|
|
71
|
+
*/
|
|
44
72
|
export interface DataflowGraphJson {
|
|
45
73
|
readonly rootVertices: NodeId[];
|
|
46
74
|
readonly vertexInformation: [NodeId, DataflowGraphVertexInfo][];
|
|
47
75
|
readonly edgeInformation: [NodeId, [NodeId, DataflowGraphEdge][]][];
|
|
48
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* An unknown side effect describes something that we cannot handle correctly (in all cases).
|
|
79
|
+
* For example, `eval` will be marked as an unknown side effect as we have no idea of how it will affect the program.
|
|
80
|
+
* Linked side effects are used whenever we know that a call may be affected by another one in a way that we cannot
|
|
81
|
+
* grasp from the dataflow perspective (e.g., an indirect dependency based on the currently active graphic device).
|
|
82
|
+
*/
|
|
49
83
|
export type UnknownSidEffect = NodeId | {
|
|
50
84
|
id: NodeId;
|
|
51
85
|
linkTo: LinkTo<RegExp>;
|
|
@@ -60,6 +94,11 @@ export type UnknownSidEffect = NodeId | {
|
|
|
60
94
|
* However, this does not have to hold during the construction as edges may point from or to vertices which are yet to be constructed.
|
|
61
95
|
*
|
|
62
96
|
* All methods return the modified graph to allow for chaining.
|
|
97
|
+
*
|
|
98
|
+
* @see {@link DataflowGraph#addEdge|`addEdge`} - to add an edge to the graph
|
|
99
|
+
* @see {@link DataflowGraph#addVertex|`addVertex`} - to add a vertex to the graph
|
|
100
|
+
* @see {@link DataflowGraph#fromJson|`fromJson`} - to construct a dataflow graph object from a deserialized JSON object.
|
|
101
|
+
* @see {@link emptyGraph} - to create an empty graph (useful in tests)
|
|
63
102
|
*/
|
|
64
103
|
export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo, Edge extends DataflowGraphEdge = DataflowGraphEdge> {
|
|
65
104
|
private static DEFAULT_ENVIRONMENT;
|
|
@@ -144,7 +183,6 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
144
183
|
addEdge(from: ReferenceForEdge, to: ReferenceForEdge, type: EdgeType): this;
|
|
145
184
|
/** {@inheritDoc} */
|
|
146
185
|
addEdge(from: NodeId | ReferenceForEdge, to: NodeId | ReferenceForEdge, type: EdgeType): this;
|
|
147
|
-
private installEdge;
|
|
148
186
|
/**
|
|
149
187
|
* Merges the other graph into *this* one (in-place). The return value is only for convenience.
|
|
150
188
|
*
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -5,7 +5,6 @@ exports.isPositionalArgument = isPositionalArgument;
|
|
|
5
5
|
exports.isNamedArgument = isNamedArgument;
|
|
6
6
|
exports.getReferenceOfArgument = getReferenceOfArgument;
|
|
7
7
|
const assert_1 = require("../../util/assert");
|
|
8
|
-
const edge_1 = require("./edge");
|
|
9
8
|
const diff_1 = require("./diff");
|
|
10
9
|
const vertex_1 = require("./vertex");
|
|
11
10
|
const arrays_1 = require("../../util/arrays");
|
|
@@ -16,23 +15,27 @@ const clone_1 = require("../environments/clone");
|
|
|
16
15
|
const json_1 = require("../../util/json");
|
|
17
16
|
const built_in_1 = require("../environments/built-in");
|
|
18
17
|
const logger_1 = require("../logger");
|
|
18
|
+
/**
|
|
19
|
+
* Check if the given argument is a {@link PositionalFunctionArgument}.
|
|
20
|
+
*/
|
|
19
21
|
function isPositionalArgument(arg) {
|
|
20
22
|
return arg !== r_function_call_1.EmptyArgument && arg.name === undefined;
|
|
21
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if the given argument is a {@link NamedFunctionArgument}.
|
|
26
|
+
*/
|
|
22
27
|
function isNamedArgument(arg) {
|
|
23
28
|
return arg !== r_function_call_1.EmptyArgument && arg.name !== undefined;
|
|
24
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the reference of a non-empty argument.
|
|
32
|
+
*/
|
|
25
33
|
function getReferenceOfArgument(arg) {
|
|
26
34
|
if (arg !== r_function_call_1.EmptyArgument) {
|
|
27
|
-
return arg
|
|
35
|
+
return arg?.nodeId;
|
|
28
36
|
}
|
|
29
37
|
return undefined;
|
|
30
38
|
}
|
|
31
|
-
function extractEdgeIds(from, to) {
|
|
32
|
-
const fromId = typeof from === 'object' ? from.nodeId : from;
|
|
33
|
-
const toId = typeof to === 'object' ? to.nodeId : to;
|
|
34
|
-
return { fromId, toId };
|
|
35
|
-
}
|
|
36
39
|
/**
|
|
37
40
|
* The dataflow graph holds the dataflow information found within the given AST.
|
|
38
41
|
* We differentiate the directed edges in {@link EdgeType} and the vertices indicated by {@link DataflowGraphVertexArgument}
|
|
@@ -43,6 +46,11 @@ function extractEdgeIds(from, to) {
|
|
|
43
46
|
* However, this does not have to hold during the construction as edges may point from or to vertices which are yet to be constructed.
|
|
44
47
|
*
|
|
45
48
|
* All methods return the modified graph to allow for chaining.
|
|
49
|
+
*
|
|
50
|
+
* @see {@link DataflowGraph#addEdge|`addEdge`} - to add an edge to the graph
|
|
51
|
+
* @see {@link DataflowGraph#addVertex|`addVertex`} - to add a vertex to the graph
|
|
52
|
+
* @see {@link DataflowGraph#fromJson|`fromJson`} - to construct a dataflow graph object from a deserialized JSON object.
|
|
53
|
+
* @see {@link emptyGraph} - to create an empty graph (useful in tests)
|
|
46
54
|
*/
|
|
47
55
|
class DataflowGraph {
|
|
48
56
|
static DEFAULT_ENVIRONMENT = undefined;
|
|
@@ -185,13 +193,10 @@ class DataflowGraph {
|
|
|
185
193
|
return this;
|
|
186
194
|
}
|
|
187
195
|
/**
|
|
188
|
-
* Will insert a new edge into the graph,
|
|
189
|
-
* if the direction of the edge is of no importance (`same-read-read` or `same-def-def`), source
|
|
190
|
-
* and target will be sorted so that `from` has the lower, and `to` the higher id (default ordering).
|
|
191
196
|
* Please note that this will never make edges to {@link BuiltIn} as they are not part of the graph.
|
|
192
197
|
*/
|
|
193
198
|
addEdge(from, to, type) {
|
|
194
|
-
const
|
|
199
|
+
const [fromId, toId] = extractEdgeIds(from, to);
|
|
195
200
|
if (fromId === toId || toId === built_in_1.BuiltIn) {
|
|
196
201
|
return this;
|
|
197
202
|
}
|
|
@@ -206,7 +211,6 @@ class DataflowGraph {
|
|
|
206
211
|
else {
|
|
207
212
|
existingFrom.set(toId, edge);
|
|
208
213
|
}
|
|
209
|
-
this.installEdge(type, toId, fromId, edge);
|
|
210
214
|
}
|
|
211
215
|
else {
|
|
212
216
|
// adding the type
|
|
@@ -214,21 +218,6 @@ class DataflowGraph {
|
|
|
214
218
|
}
|
|
215
219
|
return this;
|
|
216
220
|
}
|
|
217
|
-
installEdge(type, toId, fromId, edge) {
|
|
218
|
-
if (type === edge_1.EdgeType.DefinesOnCall) {
|
|
219
|
-
const otherEdge = {
|
|
220
|
-
...edge,
|
|
221
|
-
types: edge_1.EdgeType.DefinedByOnCall
|
|
222
|
-
};
|
|
223
|
-
const existingTo = this.edgeInformation.get(toId);
|
|
224
|
-
if (existingTo === undefined) {
|
|
225
|
-
this.edgeInformation.set(toId, new Map([[fromId, otherEdge]]));
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
existingTo.set(fromId, otherEdge);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
221
|
/**
|
|
233
222
|
* Merges the other graph into *this* one (in-place). The return value is only for convenience.
|
|
234
223
|
*
|
|
@@ -269,7 +258,7 @@ class DataflowGraph {
|
|
|
269
258
|
existing.set(target, edge);
|
|
270
259
|
}
|
|
271
260
|
else {
|
|
272
|
-
get.types
|
|
261
|
+
get.types |= edge.types;
|
|
273
262
|
}
|
|
274
263
|
}
|
|
275
264
|
}
|
|
@@ -304,8 +293,17 @@ class DataflowGraph {
|
|
|
304
293
|
const vertex = this.getVertex(from, true);
|
|
305
294
|
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${from} to add control dependency`);
|
|
306
295
|
vertex.controlDependencies ??= [];
|
|
307
|
-
if (to
|
|
308
|
-
|
|
296
|
+
if (to) {
|
|
297
|
+
let hasControlDependency = false;
|
|
298
|
+
for (const { id, when: cond } of vertex.controlDependencies) {
|
|
299
|
+
if (id === to && when !== cond) {
|
|
300
|
+
hasControlDependency = true;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (!hasControlDependency) {
|
|
305
|
+
vertex.controlDependencies.push({ id: to, when });
|
|
306
|
+
}
|
|
309
307
|
}
|
|
310
308
|
return this;
|
|
311
309
|
}
|
|
@@ -334,8 +332,8 @@ class DataflowGraph {
|
|
|
334
332
|
exports.DataflowGraph = DataflowGraph;
|
|
335
333
|
function mergeNodeInfos(current, next) {
|
|
336
334
|
if (current.tag !== next.tag) {
|
|
337
|
-
logger_1.dataflowLogger.warn(`nodes to be joined for the same id should have the same tag, but ${JSON.stringify(current, json_1.jsonReplacer)} vs. ${JSON.stringify(next, json_1.jsonReplacer)} -- we are currently not handling cases in which vertices may be either! Keeping current.`);
|
|
338
|
-
return
|
|
335
|
+
logger_1.dataflowLogger.warn(() => `nodes to be joined for the same id should have the same tag, but ${JSON.stringify(current, json_1.jsonReplacer)} vs. ${JSON.stringify(next, json_1.jsonReplacer)} -- we are currently not handling cases in which vertices may be either! Keeping current.`);
|
|
336
|
+
return current;
|
|
339
337
|
}
|
|
340
338
|
if (current.tag === vertex_1.VertexType.VariableDefinition) {
|
|
341
339
|
(0, assert_1.guard)(current.scope === next.scope, 'nodes to be joined for the same id must have the same scope');
|
|
@@ -347,7 +345,14 @@ function mergeNodeInfos(current, next) {
|
|
|
347
345
|
(0, assert_1.guard)(current.scope === next.scope, 'nodes to be joined for the same id must have the same scope');
|
|
348
346
|
(0, assert_1.guard)((0, arrays_1.arrayEqual)(current.exitPoints, next.exitPoints), 'nodes to be joined must have same exist points');
|
|
349
347
|
}
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
return current;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Returns the ids of the dataflow vertices referenced by a {@link ReferenceForEdge}.
|
|
352
|
+
*/
|
|
353
|
+
function extractEdgeIds(from, to) {
|
|
354
|
+
const fromId = typeof from === 'object' ? from.nodeId : from;
|
|
355
|
+
const toId = typeof to === 'object' ? to.nodeId : to;
|
|
356
|
+
return [fromId, toId];
|
|
352
357
|
}
|
|
353
358
|
//# sourceMappingURL=graph.js.map
|
|
@@ -3,7 +3,6 @@ import type { DataflowFunctionFlowInformation, FunctionArgument } from './graph'
|
|
|
3
3
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
4
|
import type { REnvironmentInformation } from '../environments/environment';
|
|
5
5
|
import type { ControlDependency } from '../info';
|
|
6
|
-
export type DataflowGraphVertices<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo> = Map<NodeId, Vertex>;
|
|
7
6
|
export declare enum VertexType {
|
|
8
7
|
Value = "value",
|
|
9
8
|
Use = "use",
|
|
@@ -12,7 +11,7 @@ export declare enum VertexType {
|
|
|
12
11
|
FunctionDefinition = "function-definition"
|
|
13
12
|
}
|
|
14
13
|
/**
|
|
15
|
-
* Arguments required to construct a vertex in the dataflow graph.
|
|
14
|
+
* Arguments required to construct a vertex in the {@link DataflowGraph|dataflow graph}.
|
|
16
15
|
*
|
|
17
16
|
* @see DataflowGraphVertexUse
|
|
18
17
|
* @see DataflowGraphVertexVariableDefinition
|
|
@@ -24,7 +23,9 @@ interface DataflowGraphVertexBase extends MergeableRecord {
|
|
|
24
23
|
*/
|
|
25
24
|
readonly tag: VertexType;
|
|
26
25
|
/**
|
|
27
|
-
* The id of the node (the id assigned by the {@link ParentInformation} decoration)
|
|
26
|
+
* The id of the node (the id assigned by the {@link ParentInformation} decoration).
|
|
27
|
+
* This unanimously identifies the vertex in the {@link DataflowGraph|dataflow graph}
|
|
28
|
+
* as well as the corresponding {@link NormalizedAst|normalized AST}.
|
|
28
29
|
*/
|
|
29
30
|
id: NodeId;
|
|
30
31
|
/**
|
|
@@ -32,19 +33,40 @@ interface DataflowGraphVertexBase extends MergeableRecord {
|
|
|
32
33
|
*/
|
|
33
34
|
environment?: REnvironmentInformation | undefined;
|
|
34
35
|
/**
|
|
35
|
-
*
|
|
36
|
+
* @see {@link ControlDependency} - the collection of control dependencies which have an influence on whether the vertex is executed.
|
|
36
37
|
*/
|
|
37
38
|
controlDependencies: ControlDependency[] | undefined;
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* Marker vertex for a value in the dataflow of the program.
|
|
42
|
+
* This does not contain the _value_ of the referenced constant
|
|
43
|
+
* as this is available with the {@link DataflowGraphVertexBase#id|id} in the {@link NormalizedAst|normalized AST}
|
|
44
|
+
* (or more specifically the {@link AstIdMap}).
|
|
45
|
+
*
|
|
46
|
+
* If you have a {@link DataflowGraph|dataflow graph} named `graph`
|
|
47
|
+
* with an {@link AstIdMap} and a value vertex object with name `value` the following Code should work:
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const node = graph.idMap.get(value.id)
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* This then returns the corresponding node in the {@link NormalizedAst|normalized AST}, for example,
|
|
55
|
+
* an {@link RNumber} or {@link RString}.
|
|
56
|
+
*
|
|
57
|
+
* This works similarly for {@link IdentifierReference|identifier references}
|
|
58
|
+
* for which you can use the {@link IdentifierReference#nodeId|`nodeId`}.
|
|
59
|
+
*
|
|
60
|
+
* @see {@link isValueVertex} - to check if a vertex is a value vertex
|
|
41
61
|
*/
|
|
42
62
|
export interface DataflowGraphVertexValue extends DataflowGraphVertexBase {
|
|
43
63
|
readonly tag: VertexType.Value;
|
|
44
64
|
readonly environment?: undefined;
|
|
45
65
|
}
|
|
46
66
|
/**
|
|
47
|
-
* Arguments required to construct a vertex which represents the usage of a variable in the dataflow graph.
|
|
67
|
+
* Arguments required to construct a vertex which represents the usage of a variable in the {@link DataflowGraph|dataflow graph}.
|
|
68
|
+
*
|
|
69
|
+
* @see {@link isUseVertex} - to check if a vertex is a use vertex
|
|
48
70
|
*/
|
|
49
71
|
export interface DataflowGraphVertexUse extends DataflowGraphVertexBase {
|
|
50
72
|
readonly tag: VertexType.Use;
|
|
@@ -52,7 +74,9 @@ export interface DataflowGraphVertexUse extends DataflowGraphVertexBase {
|
|
|
52
74
|
readonly environment?: undefined;
|
|
53
75
|
}
|
|
54
76
|
/**
|
|
55
|
-
* Arguments required to construct a vertex which represents the usage of a variable in the dataflow graph.
|
|
77
|
+
* Arguments required to construct a vertex which represents the usage of a variable in the {@link DataflowGraph|dataflow graph}.
|
|
78
|
+
*
|
|
79
|
+
* @see {@link isFunctionCallVertex} - to check if a vertex is a function call vertex
|
|
56
80
|
*/
|
|
57
81
|
export interface DataflowGraphVertexFunctionCall extends DataflowGraphVertexBase {
|
|
58
82
|
readonly tag: VertexType.FunctionCall;
|
|
@@ -71,13 +95,20 @@ export interface DataflowGraphVertexFunctionCall extends DataflowGraphVertexBase
|
|
|
71
95
|
environment: REnvironmentInformation | undefined;
|
|
72
96
|
}
|
|
73
97
|
/**
|
|
74
|
-
* Arguments required to construct a vertex which represents the definition of a variable in the dataflow graph.
|
|
98
|
+
* Arguments required to construct a vertex which represents the definition of a variable in the {@link DataflowGraph|dataflow graph}.
|
|
99
|
+
*
|
|
100
|
+
* @see {@link isVariableDefinitionVertex} - to check if a vertex is a variable definition vertex
|
|
75
101
|
*/
|
|
76
102
|
export interface DataflowGraphVertexVariableDefinition extends DataflowGraphVertexBase {
|
|
77
103
|
readonly tag: VertexType.VariableDefinition;
|
|
78
104
|
/** Does not require an environment, those are attached to the call */
|
|
79
105
|
readonly environment?: undefined;
|
|
80
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Arguments required to construct a vertex which represents the definition of a function in the {@link DataflowGraph|dataflow graph}.
|
|
109
|
+
*
|
|
110
|
+
* @see {@link isFunctionDefinitionVertex} - to check if a vertex is a function definition vertex
|
|
111
|
+
*/
|
|
81
112
|
export interface DataflowGraphVertexFunctionDefinition extends DataflowGraphVertexBase {
|
|
82
113
|
readonly tag: VertexType.FunctionDefinition;
|
|
83
114
|
/**
|
|
@@ -93,11 +124,39 @@ export interface DataflowGraphVertexFunctionDefinition extends DataflowGraphVert
|
|
|
93
124
|
exitPoints: readonly NodeId[];
|
|
94
125
|
environment?: REnvironmentInformation;
|
|
95
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* What is to be passed to construct a vertex in the {@link DataflowGraph|dataflow graph}
|
|
129
|
+
*/
|
|
96
130
|
export type DataflowGraphVertexArgument = DataflowGraphVertexUse | DataflowGraphVertexVariableDefinition | DataflowGraphVertexFunctionDefinition | DataflowGraphVertexFunctionCall | DataflowGraphVertexValue;
|
|
131
|
+
/**
|
|
132
|
+
* This is the union type of all possible vertices that appear within a {@link DataflowGraph|dataflow graph},
|
|
133
|
+
* they can be constructed passing a {@link DataflowGraphVertexArgument} to the graph.
|
|
134
|
+
*
|
|
135
|
+
* See {@link DataflowGraphVertices} for an id-based mapping.
|
|
136
|
+
*/
|
|
97
137
|
export type DataflowGraphVertexInfo = Required<DataflowGraphVertexArgument>;
|
|
138
|
+
/**
|
|
139
|
+
* A mapping of {@link NodeId}s to {@link DataflowGraphVertexInfo|vertices}.
|
|
140
|
+
*/
|
|
141
|
+
export type DataflowGraphVertices<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo> = Map<NodeId, Vertex>;
|
|
142
|
+
/**
|
|
143
|
+
* Check if the given vertex is a {@link DataflowGraphVertexValue|value vertex}.
|
|
144
|
+
*/
|
|
98
145
|
export declare function isValueVertex(vertex: DataflowGraphVertexBase): vertex is DataflowGraphVertexValue;
|
|
146
|
+
/**
|
|
147
|
+
* Check if the given vertex is a {@link DataflowGraphVertexUse|use vertex}.
|
|
148
|
+
*/
|
|
99
149
|
export declare function isUseVertex(vertex: DataflowGraphVertexBase): vertex is DataflowGraphVertexUse;
|
|
150
|
+
/**
|
|
151
|
+
* Check if the given vertex is a {@link DataflowGraphVertexFunctionCall|function call vertex}.
|
|
152
|
+
*/
|
|
100
153
|
export declare function isFunctionCallVertex(vertex: DataflowGraphVertexBase): vertex is DataflowGraphVertexFunctionCall;
|
|
154
|
+
/**
|
|
155
|
+
* Check if the given vertex is a {@link DataflowGraphVertexVariableDefinition|variable definition vertex}.
|
|
156
|
+
*/
|
|
101
157
|
export declare function isVariableDefinitionVertex(vertex: DataflowGraphVertexBase): vertex is DataflowGraphVertexVariableDefinition;
|
|
158
|
+
/**
|
|
159
|
+
* Check if the given vertex is a {@link DataflowGraphVertexFunctionDefinition|function definition vertex}.
|
|
160
|
+
*/
|
|
102
161
|
export declare function isFunctionDefinitionVertex(vertex: DataflowGraphVertexBase): vertex is DataflowGraphVertexFunctionDefinition;
|
|
103
162
|
export {};
|
package/dataflow/graph/vertex.js
CHANGED
|
@@ -14,18 +14,33 @@ var VertexType;
|
|
|
14
14
|
VertexType["VariableDefinition"] = "variable-definition";
|
|
15
15
|
VertexType["FunctionDefinition"] = "function-definition";
|
|
16
16
|
})(VertexType || (exports.VertexType = VertexType = {}));
|
|
17
|
+
/**
|
|
18
|
+
* Check if the given vertex is a {@link DataflowGraphVertexValue|value vertex}.
|
|
19
|
+
*/
|
|
17
20
|
function isValueVertex(vertex) {
|
|
18
21
|
return vertex.tag === VertexType.Value;
|
|
19
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if the given vertex is a {@link DataflowGraphVertexUse|use vertex}.
|
|
25
|
+
*/
|
|
20
26
|
function isUseVertex(vertex) {
|
|
21
27
|
return vertex.tag === VertexType.Use;
|
|
22
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if the given vertex is a {@link DataflowGraphVertexFunctionCall|function call vertex}.
|
|
31
|
+
*/
|
|
23
32
|
function isFunctionCallVertex(vertex) {
|
|
24
33
|
return vertex.tag === VertexType.FunctionCall;
|
|
25
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if the given vertex is a {@link DataflowGraphVertexVariableDefinition|variable definition vertex}.
|
|
37
|
+
*/
|
|
26
38
|
function isVariableDefinitionVertex(vertex) {
|
|
27
39
|
return vertex.tag === VertexType.VariableDefinition;
|
|
28
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if the given vertex is a {@link DataflowGraphVertexFunctionDefinition|function definition vertex}.
|
|
43
|
+
*/
|
|
29
44
|
function isFunctionDefinitionVertex(vertex) {
|
|
30
45
|
return vertex.tag === VertexType.FunctionDefinition;
|
|
31
46
|
}
|
package/dataflow/info.d.ts
CHANGED
|
@@ -4,6 +4,24 @@ import type { IdentifierReference } from './environments/identifier';
|
|
|
4
4
|
import type { REnvironmentInformation } from './environments/environment';
|
|
5
5
|
import { DataflowGraph } from './graph/graph';
|
|
6
6
|
import type { GenericDifferenceInformation, WriteableDifferenceReport } from '../util/diff';
|
|
7
|
+
/**
|
|
8
|
+
* A control dependency links a vertex to the control flow element which
|
|
9
|
+
* may have an influence on its execution.
|
|
10
|
+
* Within `if(p) a else b`, `a` and `b` have a control dependency on the `if` (which in turn decides based on `p`).
|
|
11
|
+
*
|
|
12
|
+
* @see {@link happensInEveryBranch} - to check whether a list of control dependencies is exhaustive
|
|
13
|
+
*/
|
|
14
|
+
export interface ControlDependency {
|
|
15
|
+
/** The id of the node that causes the control dependency to be active (e.g., the condition of an if) */
|
|
16
|
+
readonly id: NodeId;
|
|
17
|
+
/** when does this control dependency trigger (if the condition is true or false)? */
|
|
18
|
+
readonly when?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Classifies the type of exit point encountered.
|
|
22
|
+
*
|
|
23
|
+
* @see {@link ExitPoint}
|
|
24
|
+
*/
|
|
7
25
|
export declare const enum ExitPointType {
|
|
8
26
|
/** The exit point is the implicit (last executed expression of a function/block) */
|
|
9
27
|
Default = 0,
|
|
@@ -14,20 +32,31 @@ export declare const enum ExitPointType {
|
|
|
14
32
|
/** The exit point is an explicit `next` call (or an alias of it) */
|
|
15
33
|
Next = 3
|
|
16
34
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
35
|
+
/**
|
|
36
|
+
* An exit point describes the position which ends the current control flow structure.
|
|
37
|
+
* This may be as innocent as the last expression or explicit with a `return`/`break`/`next`.
|
|
38
|
+
*
|
|
39
|
+
* @see {@link ExitPointType} - for the different types of exit points
|
|
40
|
+
* @see {@link addNonDefaultExitPoints} - to easily modify lists of exit points
|
|
41
|
+
* @see {@link alwaysExits} - to check whether a list of control dependencies always triggers an exit
|
|
42
|
+
* @see {@link filterOutLoopExitPoints} - to remove loop exit points from a list
|
|
43
|
+
*/
|
|
23
44
|
export interface ExitPoint {
|
|
24
45
|
/** What kind of exit point is this one? May be used to filter for exit points of specific causes. */
|
|
25
46
|
readonly type: ExitPointType;
|
|
26
47
|
/** The id of the node which causes the exit point! */
|
|
27
48
|
readonly nodeId: NodeId;
|
|
28
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Control dependencies which influence if the exit point triggers
|
|
51
|
+
* (e.g., if the `return` is contained within an `if` statement).
|
|
52
|
+
*
|
|
53
|
+
* @see {@link happensInEveryBranch} - to check whether control dependencies are exhaustive
|
|
54
|
+
*/
|
|
29
55
|
readonly controlDependencies: ControlDependency[] | undefined;
|
|
30
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds all non-default exit points to the existing list.
|
|
59
|
+
*/
|
|
31
60
|
export declare function addNonDefaultExitPoints(existing: ExitPoint[], add: readonly ExitPoint[]): void;
|
|
32
61
|
/** The control flow information for the current DataflowInformation. */
|
|
33
62
|
export interface DataflowCfgInformation {
|
|
@@ -37,24 +66,63 @@ export interface DataflowCfgInformation {
|
|
|
37
66
|
exitPoints: readonly ExitPoint[];
|
|
38
67
|
}
|
|
39
68
|
/**
|
|
40
|
-
* The dataflow information is
|
|
69
|
+
* The dataflow information is one of the fundamental structures we have in the dataflow analysis.
|
|
70
|
+
* It is continuously updated during the dataflow analysis
|
|
41
71
|
* and holds its current state for the respective subtree processed.
|
|
72
|
+
* Each processor during the dataflow analysis may use the information from its children
|
|
73
|
+
* to produce a new state of the dataflow information.
|
|
74
|
+
*
|
|
75
|
+
* You may initialize a new dataflow information with {@link initializeCleanDataflowInformation}.
|
|
76
|
+
*
|
|
77
|
+
* @see {@link DataflowCfgInformation} - the control flow aspects
|
|
42
78
|
*/
|
|
43
79
|
export interface DataflowInformation extends DataflowCfgInformation {
|
|
44
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* References that have not been identified as read or write and will be so on higher processors.
|
|
82
|
+
*
|
|
83
|
+
* For example, when we analyze the `x` vertex in `x <- 3`, we will first create an unknown reference for `x`
|
|
84
|
+
* as we have not yet seen the assignment!
|
|
85
|
+
*
|
|
86
|
+
* @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
|
|
87
|
+
*/
|
|
45
88
|
unknownReferences: readonly IdentifierReference[];
|
|
46
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* References which are read within the current subtree.
|
|
91
|
+
*
|
|
92
|
+
* @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
|
|
93
|
+
* */
|
|
47
94
|
in: readonly IdentifierReference[];
|
|
48
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* References which are written to within the current subtree
|
|
97
|
+
*
|
|
98
|
+
* @see {@link IdentifierReference} - a reference on a variable, parameter, function call, ...
|
|
99
|
+
*/
|
|
49
100
|
out: readonly IdentifierReference[];
|
|
50
101
|
/** Current environments used for name resolution, probably updated on the next expression-list processing */
|
|
51
102
|
environment: REnvironmentInformation;
|
|
52
103
|
/** The current constructed dataflow graph */
|
|
53
104
|
graph: DataflowGraph;
|
|
54
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Initializes an empty {@link DataflowInformation} object with the given entry point and data.
|
|
108
|
+
* This is to be used as a "starting point" when processing leaf nodes during the dataflow extraction.
|
|
109
|
+
*
|
|
110
|
+
* @see {@link DataflowInformation}
|
|
111
|
+
*/
|
|
55
112
|
export declare function initializeCleanDataflowInformation<T>(entryPoint: NodeId, data: Pick<DataflowProcessorInformation<T>, 'environment' | 'completeAst'>): DataflowInformation;
|
|
113
|
+
/**
|
|
114
|
+
* Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean,
|
|
115
|
+
* the list contains a dependency on the `true` and on the `false` case).
|
|
116
|
+
*/
|
|
56
117
|
export declare function happensInEveryBranch(controlDependencies: readonly ControlDependency[] | undefined): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Checks whether the given dataflow information always exits (i.e., if there is a non-default exit point in every branch).
|
|
120
|
+
* @see {@link ExitPoint} - for the different types of exit points
|
|
121
|
+
*/
|
|
57
122
|
export declare function alwaysExits(data: DataflowInformation): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Filters out exit points which end their cascade within a loop.
|
|
125
|
+
*/
|
|
58
126
|
export declare function filterOutLoopExitPoints(exitPoints: readonly ExitPoint[]): readonly ExitPoint[];
|
|
59
127
|
export declare function diffControlDependency<Report extends WriteableDifferenceReport>(a: ControlDependency | undefined, b: ControlDependency | undefined, info: GenericDifferenceInformation<Report>): void;
|
|
60
128
|
export declare function diffControlDependencies<Report extends WriteableDifferenceReport>(a: ControlDependency[] | undefined, b: ControlDependency[] | undefined, info: GenericDifferenceInformation<Report>): void;
|
package/dataflow/info.js
CHANGED
|
@@ -8,9 +8,18 @@ exports.filterOutLoopExitPoints = filterOutLoopExitPoints;
|
|
|
8
8
|
exports.diffControlDependency = diffControlDependency;
|
|
9
9
|
exports.diffControlDependencies = diffControlDependencies;
|
|
10
10
|
const graph_1 = require("./graph/graph");
|
|
11
|
+
/**
|
|
12
|
+
* Adds all non-default exit points to the existing list.
|
|
13
|
+
*/
|
|
11
14
|
function addNonDefaultExitPoints(existing, add) {
|
|
12
15
|
existing.push(...add.filter(({ type }) => type !== 0 /* ExitPointType.Default */));
|
|
13
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Initializes an empty {@link DataflowInformation} object with the given entry point and data.
|
|
19
|
+
* This is to be used as a "starting point" when processing leaf nodes during the dataflow extraction.
|
|
20
|
+
*
|
|
21
|
+
* @see {@link DataflowInformation}
|
|
22
|
+
*/
|
|
14
23
|
function initializeCleanDataflowInformation(entryPoint, data) {
|
|
15
24
|
return {
|
|
16
25
|
unknownReferences: [],
|
|
@@ -22,6 +31,10 @@ function initializeCleanDataflowInformation(entryPoint, data) {
|
|
|
22
31
|
exitPoints: [{ nodeId: entryPoint, type: 0 /* ExitPointType.Default */, controlDependencies: undefined }]
|
|
23
32
|
};
|
|
24
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean,
|
|
36
|
+
* the list contains a dependency on the `true` and on the `false` case).
|
|
37
|
+
*/
|
|
25
38
|
function happensInEveryBranch(controlDependencies) {
|
|
26
39
|
if (controlDependencies === undefined) {
|
|
27
40
|
/* the cds are unconstrained */
|
|
@@ -43,9 +56,16 @@ function happensInEveryBranch(controlDependencies) {
|
|
|
43
56
|
}
|
|
44
57
|
return trues.every(id => falseSet.has(id));
|
|
45
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Checks whether the given dataflow information always exits (i.e., if there is a non-default exit point in every branch).
|
|
61
|
+
* @see {@link ExitPoint} - for the different types of exit points
|
|
62
|
+
*/
|
|
46
63
|
function alwaysExits(data) {
|
|
47
64
|
return data.exitPoints?.some(e => e.type !== 0 /* ExitPointType.Default */ && happensInEveryBranch(e.controlDependencies)) ?? false;
|
|
48
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Filters out exit points which end their cascade within a loop.
|
|
68
|
+
*/
|
|
49
69
|
function filterOutLoopExitPoints(exitPoints) {
|
|
50
70
|
return exitPoints.filter(({ type }) => type === 1 /* ExitPointType.Return */ || type === 0 /* ExitPointType.Default */);
|
|
51
71
|
}
|
|
@@ -23,8 +23,10 @@ export declare function linkFunctionCalls(graph: DataflowGraph, idMap: AstIdMap,
|
|
|
23
23
|
functionCall: NodeId;
|
|
24
24
|
called: readonly DataflowGraphVertexInfo[];
|
|
25
25
|
}[];
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* convenience function returning all known call targets, as well as the name source which defines them
|
|
28
|
+
*/
|
|
29
|
+
export declare function getAllFunctionCallTargets(call: NodeId, graph: DataflowGraph, environment?: REnvironmentInformation): NodeId[];
|
|
28
30
|
export declare function getAllLinkedFunctionDefinitions(functionDefinitionReadIds: ReadonlySet<NodeId>, dataflowGraph: DataflowGraph): Set<DataflowGraphVertexInfo>;
|
|
29
31
|
/**
|
|
30
32
|
* This method links a set of read variables to definitions in an environment.
|