@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.
Files changed (27) hide show
  1. package/README.md +16 -16
  2. package/dataflow/environments/default-builtin-config.d.ts +1 -0
  3. package/dataflow/environments/default-builtin-config.js +1 -1
  4. package/dataflow/eval/resolve/resolve-argument.js +2 -2
  5. package/dataflow/graph/dataflowgraph-builder.d.ts +3 -2
  6. package/dataflow/graph/dataflowgraph-builder.js +4 -3
  7. package/dataflow/graph/diff-dataflow-graph.d.ts +1 -1
  8. package/dataflow/graph/diff-dataflow-graph.js +5 -1
  9. package/dataflow/graph/graph.d.ts +66 -10
  10. package/dataflow/graph/graph.js +85 -22
  11. package/dataflow/graph/vertex.d.ts +11 -1
  12. package/dataflow/internal/linker.d.ts +1 -1
  13. package/dataflow/internal/linker.js +12 -4
  14. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -0
  15. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +10 -2
  16. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +4 -0
  17. package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +1 -1
  18. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +3 -3
  19. package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +20 -14
  20. package/documentation/wiki-dataflow-graph.js +8 -4
  21. package/linter/rules/seeded-randomness.js +2 -2
  22. package/package.json +1 -1
  23. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +3 -3
  24. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +2 -2
  25. package/slicing/static/slice-call.js +1 -1
  26. package/util/mermaid/dfg.js +5 -5
  27. 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.0, R grammar v14 (tree-sitter engine)
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: 1, processTimeMs: 0
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: 1
56
+ ╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 0
57
57
  ╰ Dead Code (dead-code):
58
- ╰ Metadata: consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0
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 2 ms)
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
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 1</code>\
85
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 1, processTimeMs: 0</code>\
86
86
  &nbsp;&nbsp;&nbsp;╰ **File Path Validity** (file-path-validity):\
87
87
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
88
88
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
@@ -96,7 +96,7 @@ It offers a wide variety of features, for example:
96
96
  &nbsp;&nbsp;&nbsp;╰ **Unused Definitions** (unused-definitions):\
97
97
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 0, searchTimeMs: 0, processTimeMs: 0</code>\
98
98
  &nbsp;&nbsp;&nbsp;╰ **Naming Convention** (naming-convention):\
99
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numMatches: 0, numBreak: 0, searchTimeMs: 0, processTimeMs: 0</code>\
99
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numMatches: 0, numBreak: 0, searchTimeMs: 1, processTimeMs: 0</code>\
100
100
  &nbsp;&nbsp;&nbsp;╰ **Network Functions** (network-functions):\
101
101
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0</code>\
102
102
  &nbsp;&nbsp;&nbsp;╰ **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.2 ms_ (including parsing and normalization and the query) within the generation environment.
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": 0,
130
- "processTimeMs": 1
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": 0,
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.0, R grammar v14 (tree-sitter engine)
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 ≈3 ms (1ms accuracy, total 4 ms)
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!">117.5 ms</span></i> (as of Feb 2, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/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.0, R grammar v14 (tree-sitter engine)
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.7 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
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
 
@@ -426,6 +426,7 @@ export declare const DefaultBuiltinConfig: [{
426
426
  readonly idx: 2;
427
427
  readonly name: "definition";
428
428
  };
429
+ readonly modesForFn: ["s4"];
429
430
  };
430
431
  readonly assumePrimitive: true;
431
432
  }, {
@@ -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.getReferenceOfArgument).filter(assert_1.isNotUndefined);
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 = (0, graph_1.getReferenceOfArgument)(vertex.args[argumentIndex]);
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, type FunctionArgument } from './graph';
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 === r_function_call_1.EmptyArgument) {
109
+ if (graph_1.FunctionArgument.isEmpty(arg)) {
109
110
  continue;
110
111
  }
111
- if ((0, graph_1.isPositionalArgument)(arg)) {
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 { type FunctionArgument, type OutgoingEdges } from './graph';
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 ((0, graph_1.isNamedArgument)(aArg) && (0, graph_1.isNamedArgument)(bArg)) {
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
- * Check if the given argument is a {@link NamedFunctionArgument}.
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 declare function isNamedArgument(arg: FunctionArgument): arg is NamedFunctionArgument;
48
+ export type FunctionArgument = NamedFunctionArgument | PositionalFunctionArgument | typeof EmptyArgument;
51
49
  /**
52
- * Returns the reference of a non-empty argument.
50
+ * Helper functions to work with {@link FunctionArgument}s.
51
+ * @see {@link EmptyArgument} - the marker for empty arguments
53
52
  */
54
- export declare function getReferenceOfArgument(arg: FunctionArgument): NodeId | undefined;
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
  */
@@ -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
- * Check if the given argument is a {@link PositionalFunctionArgument}.
14
+ * Helper functions to work with {@link FunctionArgument}s.
15
+ * @see {@link EmptyArgument} - the marker for empty arguments
18
16
  */
19
- function isPositionalArgument(arg) {
20
- return arg !== r_function_call_1.EmptyArgument && arg.name === undefined;
21
- }
22
- /**
23
- * Check if the given argument is a {@link NamedFunctionArgument}.
24
- */
25
- function isNamedArgument(arg) {
26
- return arg !== r_function_call_1.EmptyArgument && arg.name !== undefined;
27
- }
28
- /**
29
- * Returns the reference of a non-empty argument.
30
- */
31
- function getReferenceOfArgument(arg) {
32
- if (arg !== r_function_call_1.EmptyArgument) {
33
- return arg?.nodeId;
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
- return undefined;
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
- /** The arguments of the function call, in order (as they are passed to the respective call if executed in R). */
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, type FunctionArgument } from '../graph/graph';
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.isNamedArgument).map(a => [a.name, a]));
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(a => !(0, graph_1.isNamedArgument)(a));
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.isNamedArgument).map(a => [a.name, a]));
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(a => !(0, graph_1.isNamedArgument)(a));
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 = (0, graph_1.getReferenceOfArgument)(arg);
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
139
+ fullRange: r,
134
140
  },
135
141
  lexeme: 'function',
136
- location: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
160
+ location: r,
155
161
  };
156
162
  const param = {
157
163
  type: type_1.RType.Parameter,
158
- location: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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
- Some of these functions have been explained in their respective wiki pages. However, some are part of the [Dataflow Graph API](${doc_files_1.FlowrWikiBaseRef}/Dataflow-Graph) and so we explain them here.
1013
- If you are interested in which features we support and which features are still to be worked on, please refer to our [capabilities](${doc_files_1.FlowrWikiBaseRef}/Capabilities) page.
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 = (0, graph_1.getReferenceOfArgument)(a.args[argIdx]);
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.getReferenceOfArgument);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -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 => arg !== r_function_call_1.EmptyArgument && arg.name === argument.name) : -1;
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.getReferenceOfArgument);
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 = (0, graph_1.getReferenceOfArgument)(arg);
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: (0, range_1.invalidRange)(),
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: (0, range_1.invalidRange)(),
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 = (0, graph_1.getReferenceOfArgument)(arg);
37
+ const valueRoot = graph_1.FunctionArgument.getReference(arg);
38
38
  if (!valueRoot) {
39
39
  return;
40
40
  }
@@ -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 ((0, graph_1.isNamedArgument)(arg)) {
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 ((0, graph_1.isPositionalArgument)(arg)) {
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}["${[...types].join(':')}"]`;
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.1';
9
+ const version = '2.9.2';
10
10
  /**
11
11
  * Retrieves the current flowR version as a new {@link SemVer} object.
12
12
  */