@eagleoutice/flowr 2.1.8 → 2.1.10
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/README.md +3 -0
- 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/config.d.ts +21 -0
- package/config.js +19 -2
- package/dataflow/environments/built-in.d.ts +2 -0
- package/dataflow/environments/built-in.js +2 -0
- package/dataflow/environments/default-builtin-config.js +48 -8
- package/dataflow/environments/define.js +78 -0
- package/dataflow/environments/environment.d.ts +46 -8
- package/dataflow/environments/environment.js +24 -1
- package/dataflow/environments/identifier.d.ts +60 -10
- package/dataflow/environments/identifier.js +11 -2
- package/dataflow/environments/resolve-by-name.d.ts +10 -5
- package/dataflow/environments/resolve-by-name.js +103 -5
- 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 +122 -8
- package/dataflow/graph/vertex.js +19 -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-access.d.ts +11 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +141 -49
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +8 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +40 -11
- 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/built-in/built-in-if-then-else.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +15 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +50 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +29 -1
- package/dataflow/internal/process/functions/call/common.js +16 -2
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +3 -2
- 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-interface-wiki.js +6 -1
- 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/list-access.d.ts +48 -0
- package/util/list-access.js +115 -0
- package/util/mermaid/cfg.js +1 -1
- package/util/summarizer.js +2 -2
- package/util/version.js +1 -1
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import type { BuiltInIdentifierConstant, BuiltInIdentifierDefinition } from './built-in';
|
|
2
2
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
3
|
import type { ControlDependency } from '../info';
|
|
4
|
+
import type { ContainerIndicesCollection } from '../graph/vertex';
|
|
4
5
|
export type Identifier = string & {
|
|
5
6
|
__brand?: 'identifier';
|
|
6
7
|
};
|
|
7
8
|
/**
|
|
8
|
-
* Each reference
|
|
9
|
-
* However, when checking we may want to allow for one of several types,
|
|
9
|
+
* Each reference has exactly one reference type, stored as the respective number.
|
|
10
|
+
* However, when checking, we may want to allow for one of several types,
|
|
10
11
|
* allowing the combination of the respective bitmasks.
|
|
12
|
+
*
|
|
13
|
+
* Having reference types is important as R separates a variable definition from
|
|
14
|
+
* a function when resolving an {@link Identifier|identifier}.
|
|
15
|
+
* In `c <- 3; print(c(1, 2))` the call to `c` works normally (as the vector constructor),
|
|
16
|
+
* while writing `c <- function(...) ..1` overshadows the built-in and causes `print` to only output the first element.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link isReferenceType} - for checking if a (potentially joint) reference type contains a certain type
|
|
19
|
+
* @see {@link ReferenceTypeReverseMapping} - for debugging
|
|
11
20
|
*/
|
|
12
21
|
export declare enum ReferenceType {
|
|
13
22
|
/** The identifier type is unknown */
|
|
@@ -27,19 +36,38 @@ export declare enum ReferenceType {
|
|
|
27
36
|
/** The identifier is defined by a built-in function */
|
|
28
37
|
BuiltInFunction = 128
|
|
29
38
|
}
|
|
39
|
+
/** Reverse mapping of the reference types so you can get the name from the bitmask (useful for debugging) */
|
|
30
40
|
export declare const ReferenceTypeReverseMapping: Map<ReferenceType, string>;
|
|
31
41
|
/**
|
|
32
42
|
* Check if the reference types have an overlapping type!
|
|
33
43
|
*/
|
|
34
44
|
export declare function isReferenceType(t: ReferenceType, target: ReferenceType): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Describes all types of reference (definitions) that can appear within a graph (i.e., that are not built-in like the
|
|
47
|
+
* default definition for the assignment operator `<-`).
|
|
48
|
+
*
|
|
49
|
+
* @see {@link InGraphIdentifierDefinition} - for the definition of an identifier within the graph
|
|
50
|
+
*/
|
|
35
51
|
export type InGraphReferenceType = Exclude<ReferenceType, ReferenceType.BuiltInConstant | ReferenceType.BuiltInFunction>;
|
|
36
52
|
/**
|
|
37
|
-
*
|
|
38
|
-
* Without any surrounding
|
|
39
|
-
* Similarly, `b` will create a reference
|
|
53
|
+
* An identifier reference points to a variable like `a` in `b <- a`.
|
|
54
|
+
* Without any surrounding code, `a` will produce the identifier reference `a`.
|
|
55
|
+
* Similarly, `b` will create a reference (although it will be an {@link IdentifierDefinition|identifier definition}
|
|
56
|
+
* which adds even more information).
|
|
57
|
+
*
|
|
58
|
+
* In general,
|
|
59
|
+
* references are merely pointers (with meta-information) to a vertex in the {@link DataflowGraph|dataflow graph}.
|
|
60
|
+
* In the context of the extractor, for example,
|
|
61
|
+
* they indicate the references that are currently (during the analysis at this given node)
|
|
62
|
+
* {@link DataflowInformation#in|read (`in`)}, {@link DataflowInformation#out|written (`out`)},
|
|
63
|
+
* or {@link DataflowInformation#unknownReferences|unknown (`unknownReferences`)}.
|
|
64
|
+
*
|
|
65
|
+
* @see {@link InGraphIdentifierDefinition}
|
|
40
66
|
*/
|
|
41
67
|
export interface IdentifierReference {
|
|
42
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* The id of the node which represents the reference in the {@link NormalizedAst|normalized AST} and the {@link DataflowGraph|dataflow graph}.
|
|
70
|
+
*/
|
|
43
71
|
readonly nodeId: NodeId;
|
|
44
72
|
/** Name the reference is identified by (e.g., the name of the variable), undefined if the reference is "artificial" (e.g., anonymous) */
|
|
45
73
|
readonly name: Identifier | undefined;
|
|
@@ -51,13 +79,35 @@ export interface IdentifierReference {
|
|
|
51
79
|
*/
|
|
52
80
|
controlDependencies: ControlDependency[] | undefined;
|
|
53
81
|
}
|
|
54
|
-
|
|
82
|
+
/**
|
|
83
|
+
* The definition of an {@link Identifier|identifier} within the {@link DataflowGraph|graph}.
|
|
84
|
+
* This extends on the {@link IdentifierReference}
|
|
85
|
+
* by adding the {@link NodeId} of the definition
|
|
86
|
+
* (and using `type` to mark the object type).
|
|
87
|
+
*
|
|
88
|
+
* Within a code snippet like `a <- 3`, the symbol processor will first create an
|
|
89
|
+
* {@link IdentifierReference|identifier reference} for `a` to reference the use
|
|
90
|
+
* and then promote it to an {@link InGraphIdentifierDefinition|identifier definition}.
|
|
91
|
+
*
|
|
92
|
+
* @see {@link IdentifierReference}
|
|
93
|
+
*/
|
|
94
|
+
export interface InGraphIdentifierDefinition extends IdentifierReference {
|
|
55
95
|
readonly type: InGraphReferenceType;
|
|
56
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* The assignment node which ultimately defined this identifier
|
|
98
|
+
* (the arrow operator for e.g. `x <- 3`, or `assign` call in `assign("x", 3)`)
|
|
99
|
+
*/
|
|
57
100
|
readonly definedAt: NodeId;
|
|
101
|
+
readonly value?: NodeId[];
|
|
102
|
+
/**
|
|
103
|
+
* this attribute links a definition to indices (pointer links) it may be affected by or related to
|
|
104
|
+
*/
|
|
105
|
+
indicesCollection?: ContainerIndicesCollection;
|
|
58
106
|
}
|
|
59
107
|
/**
|
|
60
|
-
* Stores the definition of an identifier within an {@link IEnvironment}
|
|
108
|
+
* Stores the definition of an identifier within an {@link IEnvironment}.
|
|
109
|
+
*
|
|
110
|
+
* {@link BuiltInIdentifierDefinition} and {@link BuiltInIdentifierConstant} are used for built-in functions and constants only,
|
|
111
|
+
* so the most important one for your day-to-day R script is the {@link InGraphIdentifierDefinition}.
|
|
61
112
|
*/
|
|
62
113
|
export type IdentifierDefinition = InGraphIdentifierDefinition | BuiltInIdentifierDefinition | BuiltInIdentifierConstant;
|
|
63
|
-
export {};
|
|
@@ -3,9 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ReferenceTypeReverseMapping = exports.ReferenceType = void 0;
|
|
4
4
|
exports.isReferenceType = isReferenceType;
|
|
5
5
|
/**
|
|
6
|
-
* Each reference
|
|
7
|
-
* However, when checking we may want to allow for one of several types,
|
|
6
|
+
* Each reference has exactly one reference type, stored as the respective number.
|
|
7
|
+
* However, when checking, we may want to allow for one of several types,
|
|
8
8
|
* allowing the combination of the respective bitmasks.
|
|
9
|
+
*
|
|
10
|
+
* Having reference types is important as R separates a variable definition from
|
|
11
|
+
* a function when resolving an {@link Identifier|identifier}.
|
|
12
|
+
* In `c <- 3; print(c(1, 2))` the call to `c` works normally (as the vector constructor),
|
|
13
|
+
* while writing `c <- function(...) ..1` overshadows the built-in and causes `print` to only output the first element.
|
|
14
|
+
*
|
|
15
|
+
* @see {@link isReferenceType} - for checking if a (potentially joint) reference type contains a certain type
|
|
16
|
+
* @see {@link ReferenceTypeReverseMapping} - for debugging
|
|
9
17
|
*/
|
|
10
18
|
var ReferenceType;
|
|
11
19
|
(function (ReferenceType) {
|
|
@@ -26,6 +34,7 @@ var ReferenceType;
|
|
|
26
34
|
/** The identifier is defined by a built-in function */
|
|
27
35
|
ReferenceType[ReferenceType["BuiltInFunction"] = 128] = "BuiltInFunction";
|
|
28
36
|
})(ReferenceType || (exports.ReferenceType = ReferenceType = {}));
|
|
37
|
+
/** Reverse mapping of the reference types so you can get the name from the bitmask (useful for debugging) */
|
|
29
38
|
exports.ReferenceTypeReverseMapping = new Map(Object.entries(ReferenceType).map(([k, v]) => [v, k]));
|
|
30
39
|
/**
|
|
31
40
|
* Check if the reference types have an overlapping type!
|
|
@@ -2,6 +2,8 @@ import type { REnvironmentInformation } from './environment';
|
|
|
2
2
|
import { Ternary } from '../../util/logic';
|
|
3
3
|
import type { Identifier, IdentifierDefinition } from './identifier';
|
|
4
4
|
import { ReferenceType } from './identifier';
|
|
5
|
+
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
|
+
import type { DataflowGraph } from '../graph/graph';
|
|
5
7
|
/**
|
|
6
8
|
* Resolves a given identifier name to a list of its possible definition location using R scoping and resolving rules.
|
|
7
9
|
*
|
|
@@ -13,8 +15,11 @@ import { ReferenceType } from './identifier';
|
|
|
13
15
|
*/
|
|
14
16
|
export declare function resolveByName(name: Identifier, environment: REnvironmentInformation, target?: ReferenceType): IdentifierDefinition[] | undefined;
|
|
15
17
|
export declare function resolvesToBuiltInConstant(name: Identifier | undefined, environment: REnvironmentInformation, wantedValue: unknown): Ternary;
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export declare function resolveToConstants(name: Identifier | undefined, environment: REnvironmentInformation): unknown[] | undefined;
|
|
19
|
+
export declare function getAliases(sourceIds: readonly NodeId[], dataflow: DataflowGraph, environment: REnvironmentInformation): NodeId[] | undefined;
|
|
20
|
+
export declare function resolveToValues(identifier: Identifier | undefined, environment: REnvironmentInformation, graph: DataflowGraph): unknown[] | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Convenience function using the variable resolver as specified within the configuration file
|
|
23
|
+
* In the future we may want to have this set once at the start of the analysis
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveValueOfVariable(identifier: Identifier | undefined, environment: REnvironmentInformation, graph: DataflowGraph): unknown[] | undefined;
|
|
@@ -3,9 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolveByName = resolveByName;
|
|
4
4
|
exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
|
|
5
5
|
exports.resolveToConstants = resolveToConstants;
|
|
6
|
+
exports.getAliases = getAliases;
|
|
7
|
+
exports.resolveToValues = resolveToValues;
|
|
8
|
+
exports.resolveValueOfVariable = resolveValueOfVariable;
|
|
6
9
|
const environment_1 = require("./environment");
|
|
7
10
|
const identifier_1 = require("./identifier");
|
|
8
11
|
const info_1 = require("../info");
|
|
12
|
+
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
13
|
+
const vertex_1 = require("../graph/vertex");
|
|
14
|
+
const config_1 = require("../../config");
|
|
15
|
+
const assert_1 = require("../../util/assert");
|
|
9
16
|
const FunctionTargetTypes = identifier_1.ReferenceType.Function | identifier_1.ReferenceType.BuiltInFunction | identifier_1.ReferenceType.Unknown | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Parameter;
|
|
10
17
|
const VariableTargetTypes = identifier_1.ReferenceType.Variable | identifier_1.ReferenceType.Parameter | identifier_1.ReferenceType.Argument | identifier_1.ReferenceType.Unknown;
|
|
11
18
|
const ConstantTargetTypes = identifier_1.ReferenceType.Constant | identifier_1.ReferenceType.BuiltInConstant | identifier_1.ReferenceType.Unknown;
|
|
@@ -86,12 +93,103 @@ function resolveToConstants(name, environment) {
|
|
|
86
93
|
return undefined;
|
|
87
94
|
}
|
|
88
95
|
const definitions = resolveByName(name, environment, identifier_1.ReferenceType.Constant);
|
|
89
|
-
|
|
96
|
+
return definitions?.map(def => def.value);
|
|
97
|
+
}
|
|
98
|
+
const AliasHandler = {
|
|
99
|
+
[vertex_1.VertexType.Value]: (sourceId) => [sourceId],
|
|
100
|
+
[vertex_1.VertexType.Use]: getUseAlias,
|
|
101
|
+
[vertex_1.VertexType.FunctionCall]: () => undefined,
|
|
102
|
+
[vertex_1.VertexType.FunctionDefinition]: () => undefined,
|
|
103
|
+
[vertex_1.VertexType.VariableDefinition]: () => undefined
|
|
104
|
+
};
|
|
105
|
+
function getUseAlias(sourceId, dataflow, environment) {
|
|
106
|
+
const definitions = [];
|
|
107
|
+
// Source is Symbol -> resolve definitions of symbol
|
|
108
|
+
const identifier = (0, node_id_1.recoverName)(sourceId, dataflow.idMap);
|
|
109
|
+
if (identifier === undefined) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const defs = resolveByName(identifier, environment);
|
|
113
|
+
if (defs === undefined) {
|
|
90
114
|
return undefined;
|
|
91
115
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
116
|
+
for (const def of defs) {
|
|
117
|
+
// If one definition is not constant (or a variable aliasing a constant)
|
|
118
|
+
// we can't say for sure what value the source has
|
|
119
|
+
if (def.type === identifier_1.ReferenceType.Variable) {
|
|
120
|
+
if (def.value === undefined) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
definitions.push(...def.value);
|
|
124
|
+
}
|
|
125
|
+
else if (def.type === identifier_1.ReferenceType.Constant || def.type === identifier_1.ReferenceType.BuiltInConstant) {
|
|
126
|
+
definitions.push(def.nodeId);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return definitions;
|
|
133
|
+
}
|
|
134
|
+
function getAliases(sourceIds, dataflow, environment) {
|
|
135
|
+
const definitions = new Set();
|
|
136
|
+
for (const sourceId of sourceIds) {
|
|
137
|
+
const info = dataflow.getVertex(sourceId);
|
|
138
|
+
if (info === undefined) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const defs = AliasHandler[info.tag](sourceId, dataflow, environment);
|
|
142
|
+
for (const def of defs ?? []) {
|
|
143
|
+
definitions.add(def);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return [...definitions];
|
|
147
|
+
}
|
|
148
|
+
function resolveToValues(identifier, environment, graph) {
|
|
149
|
+
if (identifier === undefined) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const defs = resolveByName(identifier, environment);
|
|
153
|
+
if (defs === undefined) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const values = [];
|
|
157
|
+
for (const def of defs) {
|
|
158
|
+
if (def.type === identifier_1.ReferenceType.BuiltInConstant) {
|
|
159
|
+
values.push(def.value);
|
|
160
|
+
}
|
|
161
|
+
else if (def.type === identifier_1.ReferenceType.BuiltInFunction) {
|
|
162
|
+
// Tracked in #1207
|
|
163
|
+
}
|
|
164
|
+
else if (def.value !== undefined) {
|
|
165
|
+
/* if there is at least one location for which we have no idea, we have to give up for now! */
|
|
166
|
+
if (def.value.length === 0) {
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
for (const id of def.value) {
|
|
170
|
+
const value = graph.idMap?.get(id)?.content;
|
|
171
|
+
if (value !== undefined) {
|
|
172
|
+
values.push(value);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (values.length == 0) {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
return values;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Convenience function using the variable resolver as specified within the configuration file
|
|
184
|
+
* In the future we may want to have this set once at the start of the analysis
|
|
185
|
+
*/
|
|
186
|
+
function resolveValueOfVariable(identifier, environment, graph) {
|
|
187
|
+
const resolve = (0, config_1.getConfig)().solver.variables;
|
|
188
|
+
switch (resolve) {
|
|
189
|
+
case config_1.VariableResolve.Alias: return resolveToValues(identifier, environment, graph);
|
|
190
|
+
case config_1.VariableResolve.Builtin: return resolveToConstants(identifier, environment);
|
|
191
|
+
case config_1.VariableResolve.Disabled: return [];
|
|
192
|
+
default: (0, assert_1.assertUnreachable)(resolve);
|
|
193
|
+
}
|
|
96
194
|
}
|
|
97
195
|
//# sourceMappingURL=resolve-by-name.js.map
|
package/dataflow/extractor.js
CHANGED
|
@@ -20,6 +20,7 @@ const built_in_source_1 = require("./internal/process/functions/call/built-in/bu
|
|
|
20
20
|
const cfg_1 = require("../util/cfg/cfg");
|
|
21
21
|
const edge_1 = require("./graph/edge");
|
|
22
22
|
const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
|
|
23
|
+
const built_in_function_definition_1 = require("./internal/process/functions/call/built-in/built-in-function-definition");
|
|
23
24
|
exports.processors = {
|
|
24
25
|
[type_1.RType.Number]: process_value_1.processValue,
|
|
25
26
|
[type_1.RType.String]: process_value_1.processValue,
|
|
@@ -56,11 +57,9 @@ function resolveLinkToSideEffects(ast, graph) {
|
|
|
56
57
|
if (typeof s !== 'object') {
|
|
57
58
|
continue;
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
-
cfg = (0, cfg_1.extractCFG)(ast).graph;
|
|
61
|
-
}
|
|
60
|
+
cfg ??= (0, cfg_1.extractCFG)(ast).graph;
|
|
62
61
|
/* this has to change whenever we add a new link to relations because we currently offer no abstraction for the type */
|
|
63
|
-
const potentials = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(s.id, cfg, graph, s.linkTo
|
|
62
|
+
const potentials = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(s.id, cfg, graph, s.linkTo);
|
|
64
63
|
for (const pot of potentials) {
|
|
65
64
|
graph.addEdge(s.id, pot, edge_1.EdgeType.Reads);
|
|
66
65
|
}
|
|
@@ -92,6 +91,8 @@ function produceDataFlowGraph(request, ast) {
|
|
|
92
91
|
df = (0, built_in_source_1.standaloneSourceFile)(request[i], dfData, `root-${i}`, df);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
94
|
+
// finally, resolve linkages
|
|
95
|
+
(0, built_in_function_definition_1.updateNestedFunctionCalls)(df.graph, df.environment);
|
|
95
96
|
resolveLinkToSideEffects(ast, df.graph);
|
|
96
97
|
return df;
|
|
97
98
|
}
|
|
@@ -114,6 +114,12 @@ export declare class DataflowGraphBuilder extends DataflowGraph {
|
|
|
114
114
|
* @see reads for parameters.
|
|
115
115
|
*/
|
|
116
116
|
definesOnCall(from: NodeId, to: DataflowGraphEdgeTarget): this;
|
|
117
|
+
/**
|
|
118
|
+
* Adds a **defined-by-on-call edge** with from as definition, and to as variable.
|
|
119
|
+
*
|
|
120
|
+
* @see reads for parameters.
|
|
121
|
+
*/
|
|
122
|
+
definedByOnCall(from: NodeId, to: DataflowGraphEdgeTarget): this;
|
|
117
123
|
/**
|
|
118
124
|
* Adds an **argument edge** (E9) with from as function call, and to as argument.
|
|
119
125
|
*
|
|
@@ -212,6 +212,14 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
212
212
|
definesOnCall(from, to) {
|
|
213
213
|
return this.edgeHelper(from, to, edge_1.EdgeType.DefinesOnCall);
|
|
214
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Adds a **defined-by-on-call edge** with from as definition, and to as variable.
|
|
217
|
+
*
|
|
218
|
+
* @see reads for parameters.
|
|
219
|
+
*/
|
|
220
|
+
definedByOnCall(from, to) {
|
|
221
|
+
return this.edgeHelper(from, to, edge_1.EdgeType.DefinedByOnCall);
|
|
222
|
+
}
|
|
215
223
|
/**
|
|
216
224
|
* Adds an **argument edge** (E9) with from as function call, and to as argument.
|
|
217
225
|
*
|
package/dataflow/graph/edge.d.ts
CHANGED
|
@@ -19,9 +19,15 @@ export declare enum EdgeType {
|
|
|
19
19
|
Calls = 4,
|
|
20
20
|
/** The source returns target on call */
|
|
21
21
|
Returns = 8,
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* The edge determines that source (probably argument) defines the target (probably parameter).
|
|
24
|
+
* This may also link a function call to definitions it causes to be active (as part of the closure) of the called function definition.
|
|
25
|
+
*/
|
|
23
26
|
DefinesOnCall = 16,
|
|
24
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Usually the inverse of `defines-on-call` (in the context of arguments and parameters).
|
|
29
|
+
* This may also link an open read (within a function) to the definition that is active at the call site.
|
|
30
|
+
*/
|
|
25
31
|
DefinedByOnCall = 32,
|
|
26
32
|
/** Formal used as argument to a function call */
|
|
27
33
|
Argument = 64,
|
|
@@ -57,8 +63,8 @@ export declare const enum TraverseEdge {
|
|
|
57
63
|
Never = 0,
|
|
58
64
|
/** Traverse the edge as a side effect */
|
|
59
65
|
SideEffect = 1,
|
|
60
|
-
/** Traverse this edge if the definition is relevant */
|
|
61
|
-
|
|
66
|
+
/** Traverse this edge if the definition is relevant (i.e., if two matching edges trigger this state) */
|
|
67
|
+
OnlyIfBoth = 2,
|
|
62
68
|
/** Always traverse this edge */
|
|
63
69
|
Always = 3
|
|
64
70
|
}
|
package/dataflow/graph/edge.js
CHANGED
|
@@ -22,9 +22,15 @@ var EdgeType;
|
|
|
22
22
|
EdgeType[EdgeType["Calls"] = 4] = "Calls";
|
|
23
23
|
/** The source returns target on call */
|
|
24
24
|
EdgeType[EdgeType["Returns"] = 8] = "Returns";
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* The edge determines that source (probably argument) defines the target (probably parameter).
|
|
27
|
+
* This may also link a function call to definitions it causes to be active (as part of the closure) of the called function definition.
|
|
28
|
+
*/
|
|
26
29
|
EdgeType[EdgeType["DefinesOnCall"] = 16] = "DefinesOnCall";
|
|
27
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Usually the inverse of `defines-on-call` (in the context of arguments and parameters).
|
|
32
|
+
* This may also link an open read (within a function) to the definition that is active at the call site.
|
|
33
|
+
*/
|
|
28
34
|
EdgeType[EdgeType["DefinedByOnCall"] = 32] = "DefinedByOnCall";
|
|
29
35
|
/** Formal used as argument to a function call */
|
|
30
36
|
EdgeType[EdgeType["Argument"] = 64] = "Argument";
|
|
@@ -89,13 +95,14 @@ function edgeIncludesType(type, types) {
|
|
|
89
95
|
function edgeDoesNotIncludeType(type, types) {
|
|
90
96
|
return (types & type) === 0;
|
|
91
97
|
}
|
|
92
|
-
const alwaysTraverseEdgeTypes = EdgeType.Reads | EdgeType.DefinedBy | EdgeType.Argument | EdgeType.Calls
|
|
98
|
+
const alwaysTraverseEdgeTypes = EdgeType.Reads | EdgeType.DefinedBy | EdgeType.Argument | EdgeType.Calls;
|
|
99
|
+
const definedByOnCallTypes = EdgeType.DefinesOnCall | EdgeType.DefinedByOnCall;
|
|
93
100
|
function shouldTraverseEdge(types) {
|
|
94
101
|
if (edgeIncludesType(types, alwaysTraverseEdgeTypes)) {
|
|
95
102
|
return 3 /* TraverseEdge.Always */;
|
|
96
103
|
}
|
|
97
|
-
else if (edgeIncludesType(types,
|
|
98
|
-
return 2 /* TraverseEdge.
|
|
104
|
+
else if (edgeIncludesType(types, definedByOnCallTypes)) {
|
|
105
|
+
return 2 /* TraverseEdge.OnlyIfBoth */;
|
|
99
106
|
}
|
|
100
107
|
else if (edgeIncludesType(types, EdgeType.SideEffectOnCall)) {
|
|
101
108
|
return 1 /* TraverseEdge.SideEffect */;
|
|
@@ -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
|
*
|