@eagleoutice/flowr 2.9.1 → 2.9.2
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 +16 -16
- package/dataflow/environments/default-builtin-config.d.ts +1 -0
- package/dataflow/environments/default-builtin-config.js +1 -1
- package/dataflow/eval/resolve/resolve-argument.js +2 -2
- package/dataflow/graph/dataflowgraph-builder.d.ts +3 -2
- package/dataflow/graph/dataflowgraph-builder.js +4 -3
- package/dataflow/graph/diff-dataflow-graph.d.ts +1 -1
- package/dataflow/graph/diff-dataflow-graph.js +5 -1
- package/dataflow/graph/graph.d.ts +66 -10
- package/dataflow/graph/graph.js +85 -22
- package/dataflow/graph/vertex.d.ts +11 -1
- package/dataflow/internal/linker.d.ts +1 -1
- package/dataflow/internal/linker.js +12 -4
- 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 +10 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +4 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +20 -14
- package/documentation/wiki-dataflow-graph.js +8 -4
- package/linter/rules/seeded-randomness.js +2 -2
- package/package.json +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +3 -3
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +2 -2
- package/slicing/static/slice-call.js +1 -1
- package/util/mermaid/dfg.js +5 -5
- package/util/version.js +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ It offers a wide variety of features, for example:
|
|
|
24
24
|
|
|
25
25
|
```shell
|
|
26
26
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
27
|
-
flowR repl using flowR v2.9.
|
|
27
|
+
flowR repl using flowR v2.9.1, R grammar v14 (tree-sitter engine)
|
|
28
28
|
R> :query @linter "read.csv(\"/root/x.txt\")"
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -39,7 +39,7 @@ It offers a wide variety of features, for example:
|
|
|
39
39
|
╰ File Path Validity (file-path-validity):
|
|
40
40
|
╰ certain:
|
|
41
41
|
╰ Path `/root/x.txt` at 1.1-23
|
|
42
|
-
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs:
|
|
42
|
+
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs: 1
|
|
43
43
|
╰ Seeded Randomness (seeded-randomness):
|
|
44
44
|
╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs: 0
|
|
45
45
|
╰ Absolute Paths (absolute-file-paths):
|
|
@@ -53,12 +53,12 @@ It offers a wide variety of features, for example:
|
|
|
53
53
|
╰ Network Functions (network-functions):
|
|
54
54
|
╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0
|
|
55
55
|
╰ Dataframe Access Validation (dataframe-access-validation):
|
|
56
|
-
╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs:
|
|
56
|
+
╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 0
|
|
57
57
|
╰ Dead Code (dead-code):
|
|
58
|
-
╰ Metadata: consideredNodes: 5, searchTimeMs:
|
|
58
|
+
╰ Metadata: consideredNodes: 5, searchTimeMs: 1, processTimeMs: 0
|
|
59
59
|
╰ Useless Loops (useless-loop):
|
|
60
60
|
╰ Metadata: numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0
|
|
61
|
-
All queries together required ≈2 ms (1ms accuracy, total
|
|
61
|
+
All queries together required ≈2 ms (1ms accuracy, total 3 ms)
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
|
|
@@ -82,7 +82,7 @@ It offers a wide variety of features, for example:
|
|
|
82
82
|
|
|
83
83
|
Query: **linter** (2 ms)\
|
|
84
84
|
╰ **Deprecated Functions** (deprecated-functions):\
|
|
85
|
-
╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs:
|
|
85
|
+
╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 1, processTimeMs: 0</code>\
|
|
86
86
|
╰ **File Path Validity** (file-path-validity):\
|
|
87
87
|
╰ certain:\
|
|
88
88
|
╰ Path `/root/x.txt` at 1.1-23\
|
|
@@ -96,7 +96,7 @@ It offers a wide variety of features, for example:
|
|
|
96
96
|
╰ **Unused Definitions** (unused-definitions):\
|
|
97
97
|
╰ _Metadata_: <code>totalConsidered: 0, searchTimeMs: 0, processTimeMs: 0</code>\
|
|
98
98
|
╰ **Naming Convention** (naming-convention):\
|
|
99
|
-
╰ _Metadata_: <code>numMatches: 0, numBreak: 0, searchTimeMs:
|
|
99
|
+
╰ _Metadata_: <code>numMatches: 0, numBreak: 0, searchTimeMs: 1, processTimeMs: 0</code>\
|
|
100
100
|
╰ **Network Functions** (network-functions):\
|
|
101
101
|
╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0</code>\
|
|
102
102
|
╰ **Dataframe Access Validation** (dataframe-access-validation):\
|
|
@@ -109,7 +109,7 @@ It offers a wide variety of features, for example:
|
|
|
109
109
|
|
|
110
110
|
<details> <summary style="color:gray">Show Detailed Results as Json</summary>
|
|
111
111
|
|
|
112
|
-
The analysis required _2.
|
|
112
|
+
The analysis required _2.3 ms_ (including parsing and normalization and the query) within the generation environment.
|
|
113
113
|
|
|
114
114
|
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
|
|
115
115
|
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
|
|
@@ -126,8 +126,8 @@ It offers a wide variety of features, for example:
|
|
|
126
126
|
".meta": {
|
|
127
127
|
"totalCalls": 0,
|
|
128
128
|
"totalFunctionDefinitions": 0,
|
|
129
|
-
"searchTimeMs":
|
|
130
|
-
"processTimeMs":
|
|
129
|
+
"searchTimeMs": 1,
|
|
130
|
+
"processTimeMs": 0
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"file-path-validity": {
|
|
@@ -198,7 +198,7 @@ It offers a wide variety of features, for example:
|
|
|
198
198
|
".meta": {
|
|
199
199
|
"numMatches": 0,
|
|
200
200
|
"numBreak": 0,
|
|
201
|
-
"searchTimeMs":
|
|
201
|
+
"searchTimeMs": 1,
|
|
202
202
|
"processTimeMs": 0
|
|
203
203
|
}
|
|
204
204
|
},
|
|
@@ -308,7 +308,7 @@ It offers a wide variety of features, for example:
|
|
|
308
308
|
|
|
309
309
|
```shell
|
|
310
310
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
311
|
-
flowR repl using flowR v2.9.
|
|
311
|
+
flowR repl using flowR v2.9.1, R grammar v14 (tree-sitter engine)
|
|
312
312
|
R> :query @static-slice (11@sum) file://test/testfiles/example.R
|
|
313
313
|
```
|
|
314
314
|
|
|
@@ -322,7 +322,7 @@ It offers a wide variety of features, for example:
|
|
|
322
322
|
N <- 10
|
|
323
323
|
for(i in 1:(N-1)) sum <- sum + i + w
|
|
324
324
|
sum
|
|
325
|
-
All queries together required ≈
|
|
325
|
+
All queries together required ≈4 ms (1ms accuracy, total 4 ms)
|
|
326
326
|
```
|
|
327
327
|
|
|
328
328
|
|
|
@@ -356,7 +356,7 @@ It offers a wide variety of features, for example:
|
|
|
356
356
|
|
|
357
357
|
|
|
358
358
|
* 🚀 **fast call-graph, data-, and control-flow graphs**\
|
|
359
|
-
Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">
|
|
359
|
+
Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">118 ms</span></i> (as of Feb 3, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
|
|
360
360
|
_flowR_ can analyze the data- and control-flow of the average real-world R script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
|
|
361
361
|
and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for more details on the dataflow graphs as well as call graphs.
|
|
362
362
|
|
|
@@ -392,7 +392,7 @@ It offers a wide variety of features, for example:
|
|
|
392
392
|
|
|
393
393
|
```shell
|
|
394
394
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
395
|
-
flowR repl using flowR v2.9.
|
|
395
|
+
flowR repl using flowR v2.9.1, R grammar v14 (tree-sitter engine)
|
|
396
396
|
R> :dataflow* test/testfiles/example.R
|
|
397
397
|
```
|
|
398
398
|
|
|
@@ -697,7 +697,7 @@ It offers a wide variety of features, for example:
|
|
|
697
697
|
```
|
|
698
698
|
|
|
699
699
|
|
|
700
|
-
(The analysis required _1.
|
|
700
|
+
(The analysis required _1.9 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
|
|
701
701
|
|
|
702
702
|
|
|
703
703
|
|
|
@@ -258,7 +258,7 @@ exports.DefaultBuiltinConfig = [
|
|
|
258
258
|
{ type: 'function', names: ['<-', '='], processor: built_in_1.BuiltInProcName.Assignment, config: { canBeReplacement: true }, assumePrimitive: true },
|
|
259
259
|
{ type: 'function', names: [':='], processor: built_in_1.BuiltInProcName.Assignment, config: {}, assumePrimitive: true },
|
|
260
260
|
{ type: 'function', names: ['assign', 'setValidity'], processor: built_in_1.BuiltInProcName.Assignment, config: { targetVariable: true, mayHaveMoreArgs: true }, assumePrimitive: true },
|
|
261
|
-
{ type: 'function', names: ['setMethod'], processor: built_in_1.BuiltInProcName.AssignmentLike, config: { targetVariable: true, canBeReplacement: false, target: { idx: 0, name: 'f' }, source: { idx: 2, name: 'definition' } }, assumePrimitive: true },
|
|
261
|
+
{ type: 'function', names: ['setMethod'], processor: built_in_1.BuiltInProcName.AssignmentLike, config: { targetVariable: true, canBeReplacement: false, target: { idx: 0, name: 'f' }, source: { idx: 2, name: 'definition' }, modesForFn: ['s4'] }, assumePrimitive: true },
|
|
262
262
|
{ type: 'function', names: ['delayedAssign'], processor: built_in_1.BuiltInProcName.Assignment, config: { quoteSource: true, targetVariable: true }, assumePrimitive: true },
|
|
263
263
|
{ type: 'function', names: ['<<-'], processor: built_in_1.BuiltInProcName.Assignment, config: { superAssignment: true, canBeReplacement: true }, assumePrimitive: true },
|
|
264
264
|
{ type: 'function', names: ['->'], processor: built_in_1.BuiltInProcName.Assignment, config: { swapSourceAndTarget: true, canBeReplacement: true }, assumePrimitive: true },
|
|
@@ -26,7 +26,7 @@ function getArgumentStringValue(variableResolve, graph, vertex, argumentIndex, a
|
|
|
26
26
|
}
|
|
27
27
|
if (argumentIndex === 'unnamed') {
|
|
28
28
|
// return all unnamed arguments
|
|
29
|
-
const references = vertex.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.
|
|
29
|
+
const references = vertex.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.FunctionArgument.getReference).filter(assert_1.isNotUndefined);
|
|
30
30
|
const map = new Map();
|
|
31
31
|
for (const ref of references) {
|
|
32
32
|
let valueNode = graph.idMap?.get(ref);
|
|
@@ -42,7 +42,7 @@ function getArgumentStringValue(variableResolve, graph, vertex, argumentIndex, a
|
|
|
42
42
|
return map;
|
|
43
43
|
}
|
|
44
44
|
if (argumentIndex < vertex.args.length) {
|
|
45
|
-
const arg =
|
|
45
|
+
const arg = graph_1.FunctionArgument.getReference(vertex.args[argumentIndex]);
|
|
46
46
|
if (!arg) {
|
|
47
47
|
return undefined;
|
|
48
48
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
2
2
|
import type { AstIdMap } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
3
|
-
import { type DataflowFunctionFlowInformation, DataflowGraph,
|
|
3
|
+
import { type DataflowFunctionFlowInformation, DataflowGraph, FunctionArgument } from './graph';
|
|
4
4
|
import { type IEnvironment, type REnvironmentInformation } from '../environments/environment';
|
|
5
|
-
import { type DataflowGraphVertexArgument, type DataflowGraphVertexAstLink, type DataflowGraphVertexInfo, type DataflowGraphVertexUse, type FunctionOriginInformation } from './vertex';
|
|
5
|
+
import { type DataflowGraphVertexFunctionDefinition, type DataflowGraphVertexArgument, type DataflowGraphVertexAstLink, type DataflowGraphVertexInfo, type DataflowGraphVertexUse, type FunctionOriginInformation } from './vertex';
|
|
6
6
|
import type { ControlDependency, ExitPoint } from '../info';
|
|
7
7
|
import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
|
|
8
8
|
import type { FlowrSearchLike } from '../../search/flowr-search-builder';
|
|
@@ -39,6 +39,7 @@ export declare class DataflowGraphBuilder<Vertex extends DataflowGraphVertexInfo
|
|
|
39
39
|
builtInEnvironment?: IEnvironment;
|
|
40
40
|
cds?: ControlDependency[];
|
|
41
41
|
readParams?: [NodeId, boolean][];
|
|
42
|
+
mode?: DataflowGraphVertexFunctionDefinition['mode'];
|
|
42
43
|
}, asRoot?: boolean): this;
|
|
43
44
|
/**
|
|
44
45
|
* Adds a **vertex** for a **function call** (V2).
|
|
@@ -57,8 +57,9 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
57
57
|
out: subflow.out.map(o => ({ ...o, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(o.nodeId), cds: o.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })) })),
|
|
58
58
|
in: subflow.in.map(o => ({ ...o, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(o.nodeId), cds: o.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })) })),
|
|
59
59
|
unknownReferences: subflow.unknownReferences.map(o => ({ ...o, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(o.nodeId), cds: o.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })) })),
|
|
60
|
-
hooks: subflow.hooks ?? []
|
|
60
|
+
hooks: subflow.hooks ?? [],
|
|
61
61
|
},
|
|
62
|
+
mode: info?.mode,
|
|
62
63
|
exitPoints: exitPoints.map(e => typeof e === 'object' ? ({ ...e, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(e.nodeId), cds: e.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })) }) :
|
|
63
64
|
({ nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(e), type: 0 /* ExitPointType.Default */, cds: undefined })),
|
|
64
65
|
cds: info?.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })),
|
|
@@ -105,10 +106,10 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
105
106
|
/** automatically adds argument links if they do not already exist */
|
|
106
107
|
addArgumentLinks(id, args) {
|
|
107
108
|
for (const arg of args) {
|
|
108
|
-
if (arg
|
|
109
|
+
if (graph_1.FunctionArgument.isEmpty(arg)) {
|
|
109
110
|
continue;
|
|
110
111
|
}
|
|
111
|
-
if (
|
|
112
|
+
if (graph_1.FunctionArgument.isPositional(arg)) {
|
|
112
113
|
this.argument(id, arg.nodeId);
|
|
113
114
|
if (typeof arg.nodeId === 'string' && arg.nodeId.endsWith('-arg')) {
|
|
114
115
|
const withoutSuffix = arg.nodeId.slice(0, -4);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FunctionArgument, type OutgoingEdges } from './graph';
|
|
2
2
|
import { type GenericDiffConfiguration, type GenericDifferenceInformation } from '../../util/diff';
|
|
3
3
|
import { type NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
4
|
import { type GraphDiffContext, type NamedGraph, GraphDifferenceReport } from '../../util/diff-graph';
|
|
@@ -116,7 +116,7 @@ function diffFunctionArguments(fn, a, b, ctx) {
|
|
|
116
116
|
ctx.report.addComment(`${ctx.position}In argument #${i} (of ${ctx.leftname}, empty) the argument differs: ${JSON.stringify(aArg)} vs ${JSON.stringify(bArg)}.`);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
else if (
|
|
119
|
+
else if (graph_1.FunctionArgument.isNamed(aArg) && graph_1.FunctionArgument.isNamed(bArg)) {
|
|
120
120
|
// must have the same name
|
|
121
121
|
if (aArg.name !== bArg.name) {
|
|
122
122
|
ctx.report.addComment(`${ctx.position}In argument #${i} (of ${ctx.leftname}, named) the name differs: ${aArg.name} vs ${bArg.name}.`);
|
|
@@ -233,6 +233,10 @@ function diffVertices(ctx) {
|
|
|
233
233
|
...ctx,
|
|
234
234
|
position: `${ctx.position}Vertex ${id} differs in subflow in-read-parameters. `
|
|
235
235
|
});
|
|
236
|
+
(0, diff_1.setDifference)(new Set(rInfo.mode ?? []), new Set(lInfo.mode ?? []), {
|
|
237
|
+
...ctx,
|
|
238
|
+
position: `${ctx.position}Vertex ${id} differs in function definition mode. `
|
|
239
|
+
});
|
|
236
240
|
(0, diff_1.setDifference)(lInfo.subflow.graph, rInfo.subflow.graph, {
|
|
237
241
|
...ctx,
|
|
238
242
|
position: `${ctx.position}Vertex ${id} differs in subflow graph. `
|
|
@@ -38,20 +38,76 @@ export interface NamedFunctionArgument extends IdentifierReference {
|
|
|
38
38
|
export interface PositionalFunctionArgument extends Omit<IdentifierReference, 'name'> {
|
|
39
39
|
readonly name?: undefined;
|
|
40
40
|
}
|
|
41
|
-
/** Summarizes either named (`foo(a = 3, b = 2)`), unnamed (`foo(3, 2)`), or empty (`foo(,)`) arguments within a function. */
|
|
42
|
-
export type FunctionArgument = NamedFunctionArgument | PositionalFunctionArgument | typeof EmptyArgument;
|
|
43
|
-
/**
|
|
44
|
-
* Check if the given argument is a {@link PositionalFunctionArgument}.
|
|
45
|
-
*/
|
|
46
|
-
export declare function isPositionalArgument(arg: FunctionArgument): arg is PositionalFunctionArgument;
|
|
47
41
|
/**
|
|
48
|
-
*
|
|
42
|
+
* Summarizes either named (`foo(a = 3, b = 2)`), unnamed (`foo(3, 2)`), or empty (`foo(,)`) arguments within a function.
|
|
43
|
+
* See the {@link FunctionArgument} helper functions to check for the specific types.
|
|
44
|
+
* @see {@link FunctionArgument.isNamed|`FunctionArgument.isNamed`} - to check for named arguments
|
|
45
|
+
* @see {@link FunctionArgument.isPositional|`FunctionArgument.isPositional`} - to check for positional arguments
|
|
46
|
+
* @see {@link FunctionArgument.isEmpty|`FunctionArgument.isEmpty`} - to check for empty arguments
|
|
49
47
|
*/
|
|
50
|
-
export
|
|
48
|
+
export type FunctionArgument = NamedFunctionArgument | PositionalFunctionArgument | typeof EmptyArgument;
|
|
51
49
|
/**
|
|
52
|
-
*
|
|
50
|
+
* Helper functions to work with {@link FunctionArgument}s.
|
|
51
|
+
* @see {@link EmptyArgument} - the marker for empty arguments
|
|
53
52
|
*/
|
|
54
|
-
export declare
|
|
53
|
+
export declare const FunctionArgument: {
|
|
54
|
+
/**
|
|
55
|
+
* Checks whether the given argument is a positional argument.
|
|
56
|
+
* @example
|
|
57
|
+
* ```r
|
|
58
|
+
* foo(b=3, 2) # the second argument is positional
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
readonly isPositional: (this: void, arg: FunctionArgument) => arg is PositionalFunctionArgument;
|
|
62
|
+
/**
|
|
63
|
+
* Checks whether the given argument is a named argument.
|
|
64
|
+
* @example
|
|
65
|
+
* ```r
|
|
66
|
+
* foo(b=3, 2) # the first argument is named
|
|
67
|
+
* ```
|
|
68
|
+
* @see {@link isPositional}
|
|
69
|
+
* @see {@link isEmpty}
|
|
70
|
+
* @see {@link hasName}
|
|
71
|
+
*/
|
|
72
|
+
readonly isNamed: (this: void, arg: FunctionArgument) => arg is NamedFunctionArgument;
|
|
73
|
+
/**
|
|
74
|
+
* Checks whether the given argument is an unnamed argument (either positional or empty).
|
|
75
|
+
* @example
|
|
76
|
+
* ```r
|
|
77
|
+
* foo(, 2) # the first argument is unnamed (empty)
|
|
78
|
+
* foo(3, 2) # both arguments are unnamed (positional)
|
|
79
|
+
* ```
|
|
80
|
+
* @see {@link isNamed}
|
|
81
|
+
*/
|
|
82
|
+
readonly isUnnamed: (this: void, arg: FunctionArgument) => arg is PositionalFunctionArgument | typeof EmptyArgument;
|
|
83
|
+
/**
|
|
84
|
+
* Checks whether the given argument is an empty argument.
|
|
85
|
+
* @example
|
|
86
|
+
* ```r
|
|
87
|
+
* foo(, 2) # the first argument is empty
|
|
88
|
+
* ```
|
|
89
|
+
* @see {@link isNotEmpty}
|
|
90
|
+
*/
|
|
91
|
+
readonly isEmpty: (this: void, arg: FunctionArgument) => arg is typeof EmptyArgument;
|
|
92
|
+
/**
|
|
93
|
+
* Checks whether the given argument is not an empty argument.
|
|
94
|
+
* @see {@link isEmpty}
|
|
95
|
+
*/
|
|
96
|
+
readonly isNotEmpty: (this: void, arg: FunctionArgument) => arg is NamedFunctionArgument | PositionalFunctionArgument;
|
|
97
|
+
/**
|
|
98
|
+
* Returns the reference of a non-empty argument.
|
|
99
|
+
* @example
|
|
100
|
+
* ```r
|
|
101
|
+
* foo(a=3, 2) # returns the node id of either `3` or `2`, but skips a
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
readonly getReference: (this: void, arg: FunctionArgument) => NodeId | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Checks whether the given argument is a named argument with the specified name.
|
|
107
|
+
* @see {@link isNamed}
|
|
108
|
+
*/
|
|
109
|
+
readonly hasName: (this: void, arg: FunctionArgument, name: string | undefined) => arg is NamedFunctionArgument;
|
|
110
|
+
};
|
|
55
111
|
/**
|
|
56
112
|
* Maps the edges target to the edge information
|
|
57
113
|
*/
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DataflowGraph = void 0;
|
|
4
|
-
exports.isPositionalArgument = isPositionalArgument;
|
|
5
|
-
exports.isNamedArgument = isNamedArgument;
|
|
6
|
-
exports.getReferenceOfArgument = getReferenceOfArgument;
|
|
3
|
+
exports.DataflowGraph = exports.FunctionArgument = void 0;
|
|
7
4
|
const assert_1 = require("../../util/assert");
|
|
8
5
|
const vertex_1 = require("./vertex");
|
|
9
6
|
const arrays_1 = require("../../util/collections/arrays");
|
|
@@ -14,26 +11,84 @@ const clone_1 = require("../environments/clone");
|
|
|
14
11
|
const json_1 = require("../../util/json");
|
|
15
12
|
const logger_1 = require("../logger");
|
|
16
13
|
/**
|
|
17
|
-
*
|
|
14
|
+
* Helper functions to work with {@link FunctionArgument}s.
|
|
15
|
+
* @see {@link EmptyArgument} - the marker for empty arguments
|
|
18
16
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
exports.FunctionArgument = {
|
|
18
|
+
/**
|
|
19
|
+
* Checks whether the given argument is a positional argument.
|
|
20
|
+
* @example
|
|
21
|
+
* ```r
|
|
22
|
+
* foo(b=3, 2) # the second argument is positional
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
isPositional(arg) {
|
|
26
|
+
return arg !== r_function_call_1.EmptyArgument && arg.name === undefined;
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Checks whether the given argument is a named argument.
|
|
30
|
+
* @example
|
|
31
|
+
* ```r
|
|
32
|
+
* foo(b=3, 2) # the first argument is named
|
|
33
|
+
* ```
|
|
34
|
+
* @see {@link isPositional}
|
|
35
|
+
* @see {@link isEmpty}
|
|
36
|
+
* @see {@link hasName}
|
|
37
|
+
*/
|
|
38
|
+
isNamed(arg) {
|
|
39
|
+
return arg !== r_function_call_1.EmptyArgument && arg.name !== undefined;
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* Checks whether the given argument is an unnamed argument (either positional or empty).
|
|
43
|
+
* @example
|
|
44
|
+
* ```r
|
|
45
|
+
* foo(, 2) # the first argument is unnamed (empty)
|
|
46
|
+
* foo(3, 2) # both arguments are unnamed (positional)
|
|
47
|
+
* ```
|
|
48
|
+
* @see {@link isNamed}
|
|
49
|
+
*/
|
|
50
|
+
isUnnamed(arg) {
|
|
51
|
+
return arg === r_function_call_1.EmptyArgument || arg.name === undefined;
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* Checks whether the given argument is an empty argument.
|
|
55
|
+
* @example
|
|
56
|
+
* ```r
|
|
57
|
+
* foo(, 2) # the first argument is empty
|
|
58
|
+
* ```
|
|
59
|
+
* @see {@link isNotEmpty}
|
|
60
|
+
*/
|
|
61
|
+
isEmpty(arg) {
|
|
62
|
+
return arg === r_function_call_1.EmptyArgument;
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* Checks whether the given argument is not an empty argument.
|
|
66
|
+
* @see {@link isEmpty}
|
|
67
|
+
*/
|
|
68
|
+
isNotEmpty(arg) {
|
|
69
|
+
return arg !== r_function_call_1.EmptyArgument;
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* Returns the reference of a non-empty argument.
|
|
73
|
+
* @example
|
|
74
|
+
* ```r
|
|
75
|
+
* foo(a=3, 2) # returns the node id of either `3` or `2`, but skips a
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
getReference(arg) {
|
|
79
|
+
if (arg !== r_function_call_1.EmptyArgument) {
|
|
80
|
+
return arg?.nodeId;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* Checks whether the given argument is a named argument with the specified name.
|
|
86
|
+
* @see {@link isNamed}
|
|
87
|
+
*/
|
|
88
|
+
hasName(arg, name) {
|
|
89
|
+
return exports.FunctionArgument.isNamed(arg) && arg.name === name;
|
|
34
90
|
}
|
|
35
|
-
|
|
36
|
-
}
|
|
91
|
+
};
|
|
37
92
|
/**
|
|
38
93
|
* The dataflow graph holds the dataflow information found within the given AST.
|
|
39
94
|
* We differentiate the directed edges in {@link EdgeType} and the vertices indicated by {@link DataflowGraphVertexArgument}
|
|
@@ -402,6 +457,14 @@ function mergeNodeInfos(current, next) {
|
|
|
402
457
|
else if (current.tag === vertex_1.VertexType.FunctionDefinition) {
|
|
403
458
|
(0, assert_1.guard)(current.scope === next.scope, 'nodes to be joined for the same id must have the same scope');
|
|
404
459
|
current.exitPoints = (0, arrays_1.uniqueArrayMerge)(current.exitPoints, next.exitPoints);
|
|
460
|
+
if (next.tag === vertex_1.VertexType.FunctionDefinition && next.mode && next.mode.length > 0) {
|
|
461
|
+
current.mode ??= [];
|
|
462
|
+
for (const m of next.mode) {
|
|
463
|
+
if (!current.mode.includes(m)) {
|
|
464
|
+
current.mode.push(m);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
405
468
|
}
|
|
406
469
|
return current;
|
|
407
470
|
}
|
|
@@ -96,9 +96,13 @@ export interface DataflowGraphVertexFunctionCall extends DataflowGraphVertexBase
|
|
|
96
96
|
* Please be aware that this name can differ from the lexeme.
|
|
97
97
|
* For example, if the function is a replacement function, in this case, the actually called fn will
|
|
98
98
|
* have the compound name (e.g., `[<-`).
|
|
99
|
+
* @see {@link Identifier} - for more information on identifiers
|
|
99
100
|
*/
|
|
100
101
|
readonly name: Identifier;
|
|
101
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* The arguments of the function call, in order (as they are passed to the respective call if executed in R.
|
|
104
|
+
* @see {@link FunctionArgument} - for more information on function arguments
|
|
105
|
+
*/
|
|
102
106
|
args: FunctionArgument[];
|
|
103
107
|
/** a performance flag to indicate that the respective call is _only_ calling a builtin function without any df graph attached */
|
|
104
108
|
onlyBuiltin: boolean;
|
|
@@ -141,6 +145,12 @@ export interface DataflowGraphVertexFunctionDefinition extends DataflowGraphVert
|
|
|
141
145
|
params: Record<NodeId, boolean>;
|
|
142
146
|
/** The environment in which the function is defined (this is only attached if the DFG deems it necessary). */
|
|
143
147
|
environment?: REnvironmentInformation;
|
|
148
|
+
/**
|
|
149
|
+
* If the function is a (potential) S3/S4/S7 dispatch
|
|
150
|
+
* Please note that flowR may create these flags *on use* (e.g. `s3` as otherwise any func with a `.` would be considered S3).
|
|
151
|
+
* This is more of a convenience flag for later processing.
|
|
152
|
+
*/
|
|
153
|
+
mode?: ('s3' | 's4' | 's7')[];
|
|
144
154
|
}
|
|
145
155
|
/**
|
|
146
156
|
* What is to be passed to construct a vertex in the {@link DataflowGraph|dataflow graph}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DefaultMap } from '../../util/collections/defaultmap';
|
|
2
2
|
import { type NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
3
|
import { Identifier, type IdentifierReference } from '../environments/identifier';
|
|
4
|
-
import { type DataflowGraph,
|
|
4
|
+
import { type DataflowGraph, FunctionArgument } from '../graph/graph';
|
|
5
5
|
import type { RParameter } from '../../r-bridge/lang-4.x/ast/model/nodes/r-parameter';
|
|
6
6
|
import type { AstIdMap, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
7
7
|
import { type DataflowGraphVertexFunctionCall, type DataflowGraphVertexFunctionDefinition, type DataflowGraphVertexInfo } from '../graph/vertex';
|
|
@@ -78,7 +78,7 @@ function produceNameSharedIdMap(references) {
|
|
|
78
78
|
* If you just want to match by name, use {@link pMatch}.
|
|
79
79
|
*/
|
|
80
80
|
function linkArgumentsOnCall(args, params, graph) {
|
|
81
|
-
const nameArgMap = new Map(args.filter(graph_1.
|
|
81
|
+
const nameArgMap = new Map(args.filter(graph_1.FunctionArgument.isNamed).map(a => [a.name, a]));
|
|
82
82
|
const nameParamMap = new Map(params.filter(p => p?.name?.content !== undefined)
|
|
83
83
|
.map(p => [p.name.content, p]));
|
|
84
84
|
const maps = new Map();
|
|
@@ -105,7 +105,7 @@ function linkArgumentsOnCall(args, params, graph) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
const remainingParameter = params.filter(p => !p?.name || !matchedParameters.has(p.name.content));
|
|
108
|
-
const remainingArguments = args.filter(
|
|
108
|
+
const remainingArguments = args.filter(graph_1.FunctionArgument.isUnnamed);
|
|
109
109
|
for (let i = 0; i < remainingArguments.length; i++) {
|
|
110
110
|
const arg = remainingArguments[i];
|
|
111
111
|
if (arg === r_function_call_1.EmptyArgument) {
|
|
@@ -164,7 +164,7 @@ function invertArgumentMap(maps) {
|
|
|
164
164
|
* You can use {@link getAllIdsWithTarget} to get all argument ids that map to a given parameter.
|
|
165
165
|
*/
|
|
166
166
|
function pMatch(args, params) {
|
|
167
|
-
const nameArgMap = new Map(args.filter(graph_1.
|
|
167
|
+
const nameArgMap = new Map(args.filter(graph_1.FunctionArgument.isNamed).map(a => [a.name, a]));
|
|
168
168
|
const maps = new Map();
|
|
169
169
|
const sid = params['...'];
|
|
170
170
|
const paramNames = Object.keys(params);
|
|
@@ -183,7 +183,7 @@ function pMatch(args, params) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
const remainingParameter = paramNames.filter(p => !matchedParameters.has(p));
|
|
186
|
-
const remainingArguments = args.filter(
|
|
186
|
+
const remainingArguments = args.filter(graph_1.FunctionArgument.isUnnamed);
|
|
187
187
|
for (let i = 0; i < remainingArguments.length; i++) {
|
|
188
188
|
const arg = remainingArguments[i];
|
|
189
189
|
if (arg === r_function_call_1.EmptyArgument) {
|
|
@@ -239,6 +239,14 @@ function linkFunctionCallWithSingleTarget(graph, { subflow: fnSubflow, exitPoint
|
|
|
239
239
|
for (const v of value) {
|
|
240
240
|
graph.addEdge(id, v, edge_1.EdgeType.Calls);
|
|
241
241
|
graph.addEdge(ingoing.nodeId, v, edge_1.EdgeType.Calls);
|
|
242
|
+
// add s7 to vertex
|
|
243
|
+
const vInfo = graph.getVertex(v);
|
|
244
|
+
if (vInfo && vInfo.tag === vertex_1.VertexType.FunctionDefinition) {
|
|
245
|
+
vInfo.mode ??= [];
|
|
246
|
+
if (!vInfo.mode.includes('s7')) {
|
|
247
|
+
vInfo.mode.push('s7');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
242
250
|
}
|
|
243
251
|
}
|
|
244
252
|
}
|
|
@@ -6,6 +6,7 @@ import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/node
|
|
|
6
6
|
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
7
|
import { type NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
8
|
import { Identifier, type InGraphIdentifierDefinition } from '../../../../../environments/identifier';
|
|
9
|
+
import type { DataflowGraphVertexFunctionDefinition } from '../../../../../graph/vertex';
|
|
9
10
|
import type { ForceArguments } from '../common';
|
|
10
11
|
import type { REnvironmentInformation } from '../../../../../environments/environment';
|
|
11
12
|
import type { DataflowGraph } from '../../../../../graph/graph';
|
|
@@ -19,6 +20,7 @@ export interface AssignmentConfiguration extends ForceArguments {
|
|
|
19
20
|
/** is the target a variable pointing at the actual name? */
|
|
20
21
|
readonly targetVariable?: boolean;
|
|
21
22
|
readonly mayHaveMoreArgs?: boolean;
|
|
23
|
+
readonly modesForFn?: DataflowGraphVertexFunctionDefinition['mode'];
|
|
22
24
|
}
|
|
23
25
|
export interface ExtendedAssignmentConfiguration extends AssignmentConfiguration {
|
|
24
26
|
readonly source: {
|
|
@@ -265,10 +265,18 @@ function processAssignmentToString(target, args, name, rootId, data, config, sou
|
|
|
265
265
|
information: res.information
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
|
-
function checkTargetReferenceType(sourceInfo) {
|
|
268
|
+
function checkTargetReferenceType(sourceInfo, fnModes) {
|
|
269
269
|
const vert = sourceInfo.graph.getVertex(sourceInfo.entryPoint);
|
|
270
270
|
switch (vert?.tag) {
|
|
271
271
|
case vertex_1.VertexType.FunctionDefinition:
|
|
272
|
+
if (fnModes && fnModes.length > 0) {
|
|
273
|
+
vert.mode ??= [];
|
|
274
|
+
for (const m of fnModes) {
|
|
275
|
+
if (!vert.mode.includes(m)) {
|
|
276
|
+
vert.mode.push(m);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
272
280
|
return identifier_1.ReferenceType.Function;
|
|
273
281
|
case vertex_1.VertexType.Use:
|
|
274
282
|
case vertex_1.VertexType.FunctionCall:
|
|
@@ -310,7 +318,7 @@ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignme
|
|
|
310
318
|
*/
|
|
311
319
|
function processAssignmentToSymbol(config) {
|
|
312
320
|
const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], targetId, targetName, rootId, data, information, makeMaybe, quoteSource } = config;
|
|
313
|
-
const referenceType = checkTargetReferenceType(sourceArg);
|
|
321
|
+
const referenceType = checkTargetReferenceType(sourceArg, config.modesForFn);
|
|
314
322
|
const useSourceIds = [sourceArg.graph.hasVertex(source.info.id) ? source.info.id : sourceArg.entryPoint];
|
|
315
323
|
const aliases = (0, alias_tracking_1.getAliases)(useSourceIds, information.graph, information.environment);
|
|
316
324
|
const writeNodes = targetName ? [{
|
|
@@ -266,6 +266,10 @@ function updateNestedFunctionCalls(graph, outEnvironment) {
|
|
|
266
266
|
graph.addEdge(id, exitPoint.nodeId, edge_1.EdgeType.Returns);
|
|
267
267
|
}
|
|
268
268
|
if (treatAsS3) {
|
|
269
|
+
targetVertex.mode ??= [];
|
|
270
|
+
if (!targetVertex.mode.includes('s3')) {
|
|
271
|
+
targetVertex.mode.push('s3');
|
|
272
|
+
}
|
|
269
273
|
// collect all next method calls to link them to the same targets!
|
|
270
274
|
for (const s of targetVertex.subflow.graph) {
|
|
271
275
|
const v = graph.getVertex(s);
|
|
@@ -41,7 +41,7 @@ function processRegisterHook(name, args, rootId, data, config) {
|
|
|
41
41
|
wrappedFunctions.add(wrapId);
|
|
42
42
|
const wrapped = {
|
|
43
43
|
type: type_1.RType.FunctionDefinition,
|
|
44
|
-
location: val.location ?? (0, range_1.invalidRange)(),
|
|
44
|
+
location: val.location ?? name.location ?? (0, range_1.invalidRange)(),
|
|
45
45
|
parameters: [],
|
|
46
46
|
body: val,
|
|
47
47
|
lexeme: 'function',
|
|
@@ -8,7 +8,6 @@ const common_1 = require("../common");
|
|
|
8
8
|
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
9
9
|
const logger_1 = require("../../../../../logger");
|
|
10
10
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
11
|
-
const graph_1 = require("../../../../../graph/graph");
|
|
12
11
|
const edge_1 = require("../../../../../graph/edge");
|
|
13
12
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
14
13
|
const built_in_access_1 = require("./built-in-access");
|
|
@@ -19,6 +18,7 @@ const built_in_s_seven_dispatch_1 = require("./built-in-s-seven-dispatch");
|
|
|
19
18
|
const make_argument_1 = require("../argument/make-argument");
|
|
20
19
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
21
20
|
const range_1 = require("../../../../../../util/range");
|
|
21
|
+
const graph_1 = require("../../../../../graph/graph");
|
|
22
22
|
/**
|
|
23
23
|
* Process a replacement function call like `<-`, `[[<-`, `$<-`, etc.
|
|
24
24
|
* These are automatically created when doing assignments like `x[y] <- value` or in general `fun(x) <- value` will call `fun<- (x, value)`.
|
|
@@ -44,7 +44,7 @@ args, rootId, data, config) {
|
|
|
44
44
|
type: type_1.RType.Symbol,
|
|
45
45
|
info: uArg.info,
|
|
46
46
|
lexeme: tarName,
|
|
47
|
-
location: uArg.location ?? (0, range_1.invalidRange)()
|
|
47
|
+
location: uArg.location ?? targetArg.location ?? name.location ?? (0, range_1.invalidRange)()
|
|
48
48
|
}, data.completeAst.idMap);
|
|
49
49
|
}
|
|
50
50
|
/* we assign the first argument by the last for now and maybe mark as maybe!, we can keep the symbol as we now know we have an assignment */
|
|
@@ -92,7 +92,7 @@ args, rootId, data, config) {
|
|
|
92
92
|
}
|
|
93
93
|
/* a replacement reads all of its call args as well, at least as far as I am aware of */
|
|
94
94
|
for (const arg of callArgs) {
|
|
95
|
-
const ref =
|
|
95
|
+
const ref = graph_1.FunctionArgument.getReference(arg);
|
|
96
96
|
if (ref !== undefined) {
|
|
97
97
|
res.graph.addEdge(rootId, ref, edge_1.EdgeType.Reads);
|
|
98
98
|
}
|
|
@@ -15,6 +15,7 @@ const assert_1 = require("../../../../../../util/assert");
|
|
|
15
15
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
16
16
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
17
17
|
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
18
|
+
const vertex_1 = require("../../../../../graph/vertex");
|
|
18
19
|
/**
|
|
19
20
|
* Process an S7 new generic dispatch call like `new_generic` or `setGeneric`.
|
|
20
21
|
*/
|
|
@@ -62,11 +63,16 @@ function processS7NewGeneric(name, args, rootId, data, config) {
|
|
|
62
63
|
const info = (0, known_call_handling_1.processKnownFunctionCall)({ name, forceArgs: 'all', args: effectiveArgs, rootId, data, origin: built_in_1.BuiltInProcName.S7NewGeneric }).information;
|
|
63
64
|
info.graph.addEdge(rootId, funArg, edge_1.EdgeType.Returns);
|
|
64
65
|
info.entryPoint = funArg;
|
|
66
|
+
const fArg = info.graph.getVertex(funArg);
|
|
67
|
+
if (fArg?.tag === vertex_1.VertexType.FunctionDefinition) {
|
|
68
|
+
fArg.mode ??= ['s4', 's7'];
|
|
69
|
+
}
|
|
65
70
|
return info;
|
|
66
71
|
}
|
|
67
72
|
// 'function([dispatch_args],...) S7_dispatch()'; returns the value id
|
|
68
73
|
function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
69
74
|
const argNameId = rootId + '-s7-new-generic-fun-arg-name';
|
|
75
|
+
const r = name.location ?? (0, range_1.invalidRange)();
|
|
70
76
|
const argName = {
|
|
71
77
|
type: type_1.RType.Symbol,
|
|
72
78
|
lexeme: 'fun',
|
|
@@ -75,13 +81,13 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
75
81
|
id: argNameId,
|
|
76
82
|
nesting: name.info.nesting,
|
|
77
83
|
role: "arg-name" /* RoleInParent.ArgumentName */,
|
|
78
|
-
fullRange:
|
|
84
|
+
fullRange: r,
|
|
79
85
|
adToks: undefined,
|
|
80
86
|
file: name.info.file,
|
|
81
87
|
parent: rootId,
|
|
82
88
|
index: 0
|
|
83
89
|
},
|
|
84
|
-
location:
|
|
90
|
+
location: r,
|
|
85
91
|
};
|
|
86
92
|
idMap.set(argNameId, argName);
|
|
87
93
|
const funcNameId = rootId + '-s7-new-generic-fun-name';
|
|
@@ -92,18 +98,18 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
92
98
|
id: funcNameId,
|
|
93
99
|
nesting: name.info.nesting,
|
|
94
100
|
role: "call-name" /* RoleInParent.FunctionCallName */,
|
|
95
|
-
fullRange:
|
|
101
|
+
fullRange: r,
|
|
96
102
|
adToks: undefined,
|
|
97
103
|
file: name.info.file,
|
|
98
104
|
parent: rootId,
|
|
99
105
|
index: 0
|
|
100
106
|
},
|
|
101
|
-
location:
|
|
107
|
+
location: r,
|
|
102
108
|
content: identifier_1.Identifier.make('S7_dispatch', 's7'),
|
|
103
109
|
};
|
|
104
110
|
const funcBody = {
|
|
105
111
|
type: type_1.RType.FunctionCall,
|
|
106
|
-
location:
|
|
112
|
+
location: r,
|
|
107
113
|
lexeme: 'S7_dispatch',
|
|
108
114
|
named: true,
|
|
109
115
|
functionName: funcName,
|
|
@@ -112,7 +118,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
112
118
|
id: rootId + '-s7-new-generic-fun-body',
|
|
113
119
|
nesting: name.info.nesting,
|
|
114
120
|
role: "fun-body" /* RoleInParent.FunctionDefinitionBody */,
|
|
115
|
-
fullRange:
|
|
121
|
+
fullRange: r,
|
|
116
122
|
adToks: undefined,
|
|
117
123
|
file: name.info.file,
|
|
118
124
|
parent: rootId,
|
|
@@ -130,10 +136,10 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
130
136
|
parent: rootId,
|
|
131
137
|
index: args + 1,
|
|
132
138
|
adToks: undefined,
|
|
133
|
-
fullRange:
|
|
139
|
+
fullRange: r,
|
|
134
140
|
},
|
|
135
141
|
lexeme: 'function',
|
|
136
|
-
location:
|
|
142
|
+
location: r,
|
|
137
143
|
parameters: [...names.filter(assert_1.isNotUndefined), '...'].map((n, i) => {
|
|
138
144
|
const paramId = fdefId + `-param-${i}`;
|
|
139
145
|
const paramNameId = paramId + '-name';
|
|
@@ -145,17 +151,17 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
145
151
|
id: paramNameId,
|
|
146
152
|
nesting: name.info.nesting,
|
|
147
153
|
role: "param-name" /* RoleInParent.ParameterName */,
|
|
148
|
-
fullRange:
|
|
154
|
+
fullRange: r,
|
|
149
155
|
adToks: undefined,
|
|
150
156
|
file: name.info.file,
|
|
151
157
|
index: i,
|
|
152
158
|
parent: paramId
|
|
153
159
|
},
|
|
154
|
-
location:
|
|
160
|
+
location: r,
|
|
155
161
|
};
|
|
156
162
|
const param = {
|
|
157
163
|
type: type_1.RType.Parameter,
|
|
158
|
-
location:
|
|
164
|
+
location: r,
|
|
159
165
|
lexeme: n,
|
|
160
166
|
name: paramName,
|
|
161
167
|
defaultValue: undefined,
|
|
@@ -168,7 +174,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
168
174
|
index: i,
|
|
169
175
|
adToks: undefined,
|
|
170
176
|
file: name.info.file,
|
|
171
|
-
fullRange:
|
|
177
|
+
fullRange: r,
|
|
172
178
|
}
|
|
173
179
|
};
|
|
174
180
|
idMap.set(paramNameId, paramName);
|
|
@@ -184,12 +190,12 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
|
|
|
184
190
|
const argument = {
|
|
185
191
|
type: type_1.RType.Argument,
|
|
186
192
|
lexeme: 'fun',
|
|
187
|
-
location:
|
|
193
|
+
location: r,
|
|
188
194
|
info: {
|
|
189
195
|
id: argId,
|
|
190
196
|
nesting: name.info.nesting,
|
|
191
197
|
role: "call-arg" /* RoleInParent.FunctionCallArgument */,
|
|
192
|
-
fullRange:
|
|
198
|
+
fullRange: r,
|
|
193
199
|
adToks: undefined,
|
|
194
200
|
file: name.info.file,
|
|
195
201
|
parent: rootId,
|
|
@@ -1004,13 +1004,17 @@ Depending on what you are interested in, there exists a plethora of functions an
|
|
|
1004
1004
|
* ${ctx.link(node_id_1.recoverName)} and ${ctx.link(node_id_1.recoverContent)} to get the name or content of a vertex in the dataflow graph
|
|
1005
1005
|
* ${ctx.link(alias_tracking_1.resolveIdToValue)} to resolve the value of a variable or id (if possible, see [below](#dfg-resolving-values))
|
|
1006
1006
|
* ${ctx.link(alias_tracking_1.getAliases)} to get all (potentially currently) aliases of a given definition
|
|
1007
|
-
* ${ctx.link('DfEdge', undefined, { type: 'variable' })} to get helpful functions wrt. edges (see [below](#dfg-resolving-values))
|
|
1008
|
-
* ${ctx.link('Identifier', undefined, { type: 'variable' })} to get helpful functions wrt. identifiers
|
|
1009
1007
|
* ${ctx.link(identify_link_to_last_call_relation_1.getValueOfArgument)} to get the (syntactical) value of an argument in a function call
|
|
1010
1008
|
* ${ctx.link(dfg_get_origin_1.getOriginInDfg)} to get information about where a read, call, ... comes from (see [below](#dfg-resolving-values))
|
|
1011
1009
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1010
|
+
FlowR also provides various helper objects (with the same name as the corresponding type) to help you work with the dataflow graph:
|
|
1011
|
+
|
|
1012
|
+
* ${ctx.link('DfEdge', undefined, { type: 'variable' })} to get helpful functions wrt. edges (see [below](#dfg-resolving-values))
|
|
1013
|
+
* ${ctx.link('Identifier', undefined, { type: 'variable' })} to get helpful functions wrt. identifiers
|
|
1014
|
+
* ${ctx.link('FunctionArgument', undefined, { type: 'variable' })} to get helpful functions wrt. function arguments
|
|
1015
|
+
|
|
1016
|
+
Some of these functions have been explained in their respective wiki pages. However, some are part of the ${ctx.linkPage('wiki/Dataflow Graph', 'Dataflow Graph API')} and so we explain them here.
|
|
1017
|
+
If you are interested in which features we support and which features are still to be worked on, please refer to our ${ctx.linkPage('wiki/Capabilities', 'capabilities')} page.
|
|
1014
1018
|
|
|
1015
1019
|
${(0, doc_structure_1.section)('Resolving Values', 3, 'dfg-resolving-values')}
|
|
1016
1020
|
|
|
@@ -86,7 +86,7 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
86
86
|
// assignments have to be queried for their destination
|
|
87
87
|
for (const a of assignment ?? []) {
|
|
88
88
|
const argIdx = assignmentArgIndexes.get(identifier_1.Identifier.getName(a.name));
|
|
89
|
-
const dest =
|
|
89
|
+
const dest = graph_1.FunctionArgument.getReference(a.args[argIdx]);
|
|
90
90
|
if (dest !== undefined && assignmentProducers.has((0, node_id_1.recoverName)(dest, dataflow.graph.idMap))) {
|
|
91
91
|
// we either have arg index 0 or 1 for the assignmentProducers destination, so we select the assignment value as 1-argIdx here
|
|
92
92
|
if (isConstantArgument(dataflow.graph, a, 1 - argIdx, analyzer.inspectContext())) {
|
|
@@ -143,7 +143,7 @@ function getDefaultAssignments() {
|
|
|
143
143
|
return default_builtin_config_1.DefaultBuiltinConfig.filter(b => b.type === 'function' && (b.processor === built_in_1.BuiltInProcName.Assignment || b.processor === built_in_1.BuiltInProcName.AssignmentLike));
|
|
144
144
|
}
|
|
145
145
|
function isConstantArgument(graph, call, argIndex, ctx) {
|
|
146
|
-
const args = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.
|
|
146
|
+
const args = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.FunctionArgument.getReference);
|
|
147
147
|
const values = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(args[argIndex], { graph: graph, resolve: config_1.VariableResolve.Alias, ctx }));
|
|
148
148
|
return values?.elements.every(v => v.type === 'number' ||
|
|
149
149
|
v.type === 'logical' ||
|
package/package.json
CHANGED
|
@@ -91,15 +91,15 @@ function getValueOfArgument(graph, call, argument, additionalAllowedTypes) {
|
|
|
91
91
|
if (!call) {
|
|
92
92
|
return undefined;
|
|
93
93
|
}
|
|
94
|
-
const totalIndex = argument.name ? call.args.findIndex(arg =>
|
|
94
|
+
const totalIndex = argument.name ? call.args.findIndex(arg => graph_1.FunctionArgument.hasName(arg, argument.name)) : -1;
|
|
95
95
|
let refAtIndex;
|
|
96
96
|
if (totalIndex < 0) {
|
|
97
|
-
const references = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.
|
|
97
|
+
const references = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.FunctionArgument.getReference);
|
|
98
98
|
refAtIndex = references[argument.index];
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
101
|
const arg = call.args[totalIndex];
|
|
102
|
-
refAtIndex =
|
|
102
|
+
refAtIndex = graph_1.FunctionArgument.getReference(arg);
|
|
103
103
|
}
|
|
104
104
|
if (refAtIndex === undefined) {
|
|
105
105
|
return undefined;
|
|
@@ -74,7 +74,7 @@ function convertTreeNode(node) {
|
|
|
74
74
|
children: [],
|
|
75
75
|
grouping: undefined,
|
|
76
76
|
info: {
|
|
77
|
-
fullRange:
|
|
77
|
+
fullRange: undefined,
|
|
78
78
|
adToks: [],
|
|
79
79
|
treeSitterId: -1,
|
|
80
80
|
}
|
|
@@ -586,7 +586,7 @@ function convertTreeNode(node) {
|
|
|
586
586
|
children: [],
|
|
587
587
|
grouping: undefined,
|
|
588
588
|
info: {
|
|
589
|
-
fullRange:
|
|
589
|
+
fullRange: undefined,
|
|
590
590
|
adToks: [],
|
|
591
591
|
treeSitterId: -1,
|
|
592
592
|
}
|
|
@@ -34,7 +34,7 @@ function getAllFunctionCallTargetsForSlice(dataflowGraph, callerInfo, baseEnviro
|
|
|
34
34
|
return [functionCallTargets, activeEnvironment];
|
|
35
35
|
}
|
|
36
36
|
function includeArgumentFunctionCallClosure(arg, activeEnvironment, queue, dataflowGraph) {
|
|
37
|
-
const valueRoot =
|
|
37
|
+
const valueRoot = graph_1.FunctionArgument.getReference(arg);
|
|
38
38
|
if (!valueRoot) {
|
|
39
39
|
return;
|
|
40
40
|
}
|
package/util/mermaid/dfg.js
CHANGED
|
@@ -84,11 +84,11 @@ function printArg(arg) {
|
|
|
84
84
|
else if (arg === r_function_call_1.EmptyArgument) {
|
|
85
85
|
return '[empty]';
|
|
86
86
|
}
|
|
87
|
-
else if (
|
|
87
|
+
else if (graph_1.FunctionArgument.isNamed(arg)) {
|
|
88
88
|
const deps = arg.cds ? ', :may:' + arg.cds.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
|
|
89
89
|
return `${arg.name} (${arg.nodeId}${deps})`;
|
|
90
90
|
}
|
|
91
|
-
else if (
|
|
91
|
+
else if (graph_1.FunctionArgument.isPositional(arg)) {
|
|
92
92
|
const deps = arg.cds ? ' (:may:' + arg.cds.map(c => c.id + (c.when ? '+' : '-')).join(',') + ')' : '';
|
|
93
93
|
return `${arg.nodeId}${deps}`;
|
|
94
94
|
}
|
|
@@ -99,12 +99,12 @@ function printArg(arg) {
|
|
|
99
99
|
function displayFunctionArgMapping(argMapping) {
|
|
100
100
|
const result = [];
|
|
101
101
|
for (const arg of argMapping) {
|
|
102
|
-
result.push(printArg(arg));
|
|
102
|
+
result.push((0, mermaid_1.escapeMarkdown)(printArg(arg)));
|
|
103
103
|
}
|
|
104
104
|
return result.length === 0 ? '' : `\n (${result.join(', ')})`;
|
|
105
105
|
}
|
|
106
106
|
function encodeEdge(from, to, types) {
|
|
107
|
-
return `${from}->${to}["${
|
|
107
|
+
return `${from}->${to}["${Array.from(types).join(':')}"]`;
|
|
108
108
|
}
|
|
109
109
|
function mermaidNodeBrackets(tag) {
|
|
110
110
|
let open;
|
|
@@ -169,7 +169,7 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark, includeOnlyIds) {
|
|
|
169
169
|
const deps = info.cds ? ', :may:' + info.cds.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
|
|
170
170
|
const lnks = info.link?.origin ? ', :links:' + info.link.origin.join(',') : '';
|
|
171
171
|
const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
|
|
172
|
-
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps}${lnks})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
|
|
172
|
+
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps}${lnks})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : '' + (info.tag === vertex_1.VertexType.FunctionDefinition && info.mode && info.mode.length > 0 ? (0, mermaid_1.escapeMarkdown)(JSON.stringify(info.mode)) : '')}\`"${close}`);
|
|
173
173
|
}
|
|
174
174
|
if (mark?.has(id)) {
|
|
175
175
|
mermaid.nodeLines.push(` style ${idPrefix}${id} ${mermaid.markStyle.vertex} `);
|
package/util/version.js
CHANGED
|
@@ -6,7 +6,7 @@ exports.printVersionInformation = printVersionInformation;
|
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
7
|
const assert_1 = require("./assert");
|
|
8
8
|
// this is automatically replaced with the current version by release-it
|
|
9
|
-
const version = '2.9.
|
|
9
|
+
const version = '2.9.2';
|
|
10
10
|
/**
|
|
11
11
|
* Retrieves the current flowR version as a new {@link SemVer} object.
|
|
12
12
|
*/
|