@eagleoutice/flowr 2.7.6 → 2.8.0
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 +67 -64
- package/cli/wiki.js +1 -1
- package/control-flow/extract-cfg.js +3 -3
- package/control-flow/useless-loop.d.ts +1 -1
- package/control-flow/useless-loop.js +2 -2
- package/dataflow/cluster.js +3 -3
- package/dataflow/environments/built-in-config.d.ts +8 -4
- package/dataflow/environments/built-in.d.ts +27 -14
- package/dataflow/environments/built-in.js +27 -12
- package/dataflow/environments/default-builtin-config.d.ts +614 -3
- package/dataflow/environments/default-builtin-config.js +50 -15
- package/dataflow/environments/environment.js +3 -2
- package/dataflow/environments/identifier.d.ts +5 -1
- package/dataflow/environments/reference-to-maybe.d.ts +2 -2
- package/dataflow/environments/reference-to-maybe.js +23 -14
- package/dataflow/environments/resolve-by-name.d.ts +6 -2
- package/dataflow/environments/resolve-by-name.js +5 -1
- package/dataflow/environments/scoping.js +1 -3
- package/dataflow/eval/resolve/alias-tracking.js +5 -1
- package/dataflow/extractor.js +3 -3
- package/dataflow/fn/exceptions-of-function.d.ts +13 -0
- package/dataflow/fn/exceptions-of-function.js +47 -0
- package/dataflow/fn/higher-order-function.d.ts +1 -1
- package/dataflow/fn/higher-order-function.js +3 -3
- package/dataflow/fn/recursive-function.d.ts +6 -0
- package/dataflow/fn/recursive-function.js +32 -0
- package/dataflow/graph/call-graph.d.ts +10 -0
- package/dataflow/graph/call-graph.js +209 -0
- package/dataflow/graph/dataflowgraph-builder.d.ts +7 -2
- package/dataflow/graph/dataflowgraph-builder.js +14 -9
- package/dataflow/graph/diff-dataflow-graph.js +96 -2
- package/dataflow/graph/graph.d.ts +10 -7
- package/dataflow/graph/graph.js +7 -8
- package/dataflow/graph/vertex.d.ts +6 -3
- package/dataflow/hooks.d.ts +30 -0
- package/dataflow/hooks.js +38 -0
- package/dataflow/info.d.ts +28 -5
- package/dataflow/info.js +66 -31
- package/dataflow/internal/linker.d.ts +13 -3
- package/dataflow/internal/linker.js +155 -53
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +4 -0
- package/dataflow/internal/process/functions/call/argument/unpack-argument.js +7 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +19 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +14 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +30 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +24 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +5 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +59 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.d.ts +34 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +92 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.d.ts +21 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.js +129 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.d.ts +16 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +127 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +5 -3
- package/dataflow/internal/process/functions/call/common.d.ts +13 -1
- package/dataflow/internal/process/functions/call/common.js +33 -2
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +13 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +29 -3
- package/dataflow/internal/process/functions/call/named-call-handling.js +2 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
- package/dataflow/internal/process/functions/process-argument.js +7 -6
- package/dataflow/internal/process/functions/process-parameter.js +2 -1
- package/dataflow/internal/process/process-named-call.d.ts +2 -2
- package/dataflow/internal/process/process-symbol.js +3 -2
- package/dataflow/internal/process/process-value.d.ts +3 -2
- package/dataflow/internal/process/process-value.js +8 -6
- package/dataflow/origin/dfg-get-origin.js +2 -1
- package/dataflow/origin/dfg-get-symbol-refs.js +1 -1
- package/documentation/doc-readme.d.ts +1 -1
- package/documentation/doc-readme.js +6 -6
- package/documentation/doc-util/doc-code.js +1 -1
- package/documentation/doc-util/doc-dfg.d.ts +1 -0
- package/documentation/doc-util/doc-dfg.js +7 -4
- package/documentation/doc-util/doc-query.d.ts +1 -0
- package/documentation/doc-util/doc-query.js +1 -1
- package/documentation/doc-util/doc-repl.d.ts +2 -1
- package/documentation/doc-util/doc-repl.js +11 -3
- package/documentation/wiki-analyzer.js +2 -0
- package/documentation/wiki-dataflow-graph.js +59 -16
- package/documentation/wiki-interface.js +33 -5
- package/documentation/wiki-mk/doc-context.d.ts +2 -1
- package/documentation/wiki-mk/doc-context.js +2 -2
- package/documentation/wiki-mk/doc-maker.js +4 -3
- package/documentation/wiki-normalized-ast.js +6 -0
- package/documentation/wiki-query.js +109 -1
- package/linter/linter-rules.d.ts +1 -1
- package/linter/rules/seeded-randomness.js +17 -12
- package/linter/rules/useless-loop.d.ts +1 -1
- package/package.json +9 -9
- package/project/cache/flowr-analyzer-cache.d.ts +11 -0
- package/project/cache/flowr-analyzer-cache.js +19 -0
- package/project/context/flowr-analyzer-dependencies-context.d.ts +6 -1
- package/project/context/flowr-analyzer-dependencies-context.js +6 -0
- package/project/context/flowr-analyzer-files-context.d.ts +5 -2
- package/project/context/flowr-analyzer-files-context.js +24 -17
- package/project/context/flowr-file.d.ts +9 -4
- package/project/context/flowr-file.js +20 -6
- package/project/flowr-analyzer.d.ts +11 -0
- package/project/flowr-analyzer.js +6 -0
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +8 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +36 -3
- package/project/plugins/file-plugins/files/flowr-jupyter-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-namespace-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-news-file.js +1 -1
- package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +1 -1
- package/project/plugins/file-plugins/flowr-analyzer-description-file-plugin.js +1 -1
- package/project/plugins/file-plugins/flowr-analyzer-file-plugin.d.ts +4 -1
- package/project/plugins/file-plugins/flowr-analyzer-file-plugin.js +3 -0
- package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.d.ts → flowr-analyzer-namespace-files-plugin.d.ts} +1 -1
- package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.js → flowr-analyzer-namespace-files-plugin.js} +4 -4
- package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.d.ts +26 -0
- package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.js +39 -0
- package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.d.ts +26 -0
- package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.js +39 -0
- package/project/plugins/flowr-analyzer-plugin-defaults.js +6 -2
- package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +3 -13
- package/project/plugins/package-version-plugins/package.d.ts +1 -1
- package/project/plugins/package-version-plugins/package.js +3 -3
- package/project/plugins/plugin-registry.d.ts +4 -2
- package/project/plugins/plugin-registry.js +6 -2
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.d.ts +11 -0
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +5 -2
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +4 -12
- package/queries/catalog/call-graph-query/call-graph-query-executor.d.ts +6 -0
- package/queries/catalog/call-graph-query/call-graph-query-executor.js +21 -0
- package/queries/catalog/call-graph-query/call-graph-query-format.d.ts +21 -0
- package/queries/catalog/call-graph-query/call-graph-query-format.js +32 -0
- package/queries/catalog/dataflow-query/dataflow-query-executor.js +4 -3
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +29 -3
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +8 -1
- package/queries/catalog/dependencies-query/function-info/write-functions.js +13 -0
- package/queries/catalog/does-call-query/does-call-query-executor.d.ts +6 -0
- package/queries/catalog/does-call-query/does-call-query-executor.js +100 -0
- package/queries/catalog/does-call-query/does-call-query-format.d.ts +51 -0
- package/queries/catalog/does-call-query/does-call-query-format.js +102 -0
- package/queries/catalog/files-query/files-query-executor.js +4 -4
- package/queries/catalog/files-query/files-query-format.d.ts +2 -1
- package/queries/catalog/files-query/files-query-format.js +18 -2
- package/queries/catalog/id-map-query/id-map-query-executor.js +4 -3
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +18 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +56 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +34 -0
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.js +54 -0
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -28
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +6 -0
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.js +12 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.d.ts +6 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.js +23 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +28 -0
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.js +44 -0
- package/queries/catalog/linter-query/linter-query-format.js +4 -1
- package/queries/catalog/location-map-query/location-map-query-executor.js +1 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-executor.js +4 -3
- package/queries/catalog/project-query/project-query-executor.js +9 -3
- package/queries/catalog/project-query/project-query-format.d.ts +6 -1
- package/queries/catalog/project-query/project-query-format.js +35 -9
- package/queries/query.d.ts +34 -2
- package/queries/query.js +9 -0
- package/r-bridge/data/data.d.ts +10 -5
- package/r-bridge/data/data.js +11 -5
- package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -7
- package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +5 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +8 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +3 -3
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/parser/main/internal/other/normalize-comment.js +0 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +0 -2
- package/r-bridge/roxygen2/roxygen-ast.d.ts +218 -0
- package/r-bridge/roxygen2/roxygen-ast.js +82 -0
- package/r-bridge/roxygen2/roxygen-parse.d.ts +24 -0
- package/r-bridge/roxygen2/roxygen-parse.js +214 -0
- package/reconstruct/auto-select/magic-comments.js +4 -4
- package/slicing/static/slice-call.js +3 -4
- package/slicing/static/static-slicer.js +2 -2
- package/statistics/features/supported/defined-functions/defined-functions.js +1 -1
- package/util/collections/defaultmap.d.ts +3 -3
- package/util/mermaid/dfg.js +5 -5
- package/util/objects.js +1 -1
- package/util/r-author.d.ts +5 -0
- package/util/r-author.js +110 -0
- package/util/r-license.d.ts +10 -1
- package/util/r-license.js +27 -6
- package/util/r-version.d.ts +19 -0
- package/util/r-version.js +106 -0
- package/util/range.d.ts +6 -0
- package/util/range.js +7 -0
- package/util/simple-df/dfg-ascii.js +2 -2
- package/util/text/args.d.ts +9 -0
- package/util/text/args.js +65 -0
- package/util/version.js +1 -1
package/dataflow/info.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ import type { IdentifierReference } from './environments/identifier';
|
|
|
4
4
|
import type { REnvironmentInformation } from './environments/environment';
|
|
5
5
|
import { DataflowGraph } from './graph/graph';
|
|
6
6
|
import type { GenericDifferenceInformation, WriteableDifferenceReport } from '../util/diff';
|
|
7
|
+
import type { HookInformation } from './hooks';
|
|
7
8
|
/**
|
|
8
9
|
* A control dependency links a vertex to the control flow element which
|
|
9
10
|
* may have an influence on its execution.
|
|
10
11
|
* Within `if(p) a else b`, `a` and `b` have a control dependency on the `if` (which in turn decides based on `p`).
|
|
11
12
|
* @see {@link happensInEveryBranch} - to check whether a list of control dependencies is exhaustive
|
|
13
|
+
* @see {@link negateControlDependency} - to easily negate a control dependency
|
|
12
14
|
*/
|
|
13
15
|
export interface ControlDependency {
|
|
14
16
|
/** The id of the node that causes the control dependency to be active (e.g., the condition of an if) */
|
|
@@ -18,6 +20,11 @@ export interface ControlDependency {
|
|
|
18
20
|
/** whether this control dependency was created due to iteration (e.g., a loop) */
|
|
19
21
|
readonly byIteration?: boolean;
|
|
20
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Negates the given control dependency (i.e., flips the `when` flag).
|
|
25
|
+
* This keeps undefined `when` values intact as undefined.
|
|
26
|
+
*/
|
|
27
|
+
export declare function negateControlDependency(cd: ControlDependency): ControlDependency;
|
|
21
28
|
/**
|
|
22
29
|
* Classifies the type of exit point encountered.
|
|
23
30
|
* @see {@link ExitPoint}
|
|
@@ -30,8 +37,14 @@ export declare const enum ExitPointType {
|
|
|
30
37
|
/** The exit point is an explicit `break` call (or an alias of it) */
|
|
31
38
|
Break = 2,
|
|
32
39
|
/** The exit point is an explicit `next` call (or an alias of it) */
|
|
33
|
-
Next = 3
|
|
40
|
+
Next = 3,
|
|
41
|
+
/** The exit point is caused by an error being thrown, e.g., by `stop` or `stopifnot` */
|
|
42
|
+
Error = 4
|
|
34
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Checks whether the given exit point type propagates calls (i.e., whether it aborts the current function execution).
|
|
46
|
+
*/
|
|
47
|
+
export declare function doesExitPointPropagateCalls(type: ExitPointType): boolean;
|
|
35
48
|
/**
|
|
36
49
|
* An exit point describes the position which ends the current control flow structure.
|
|
37
50
|
* This may be as innocent as the last expression or explicit with a `return`/`break`/`next`.
|
|
@@ -50,18 +63,28 @@ export interface ExitPoint {
|
|
|
50
63
|
* (e.g., if the `return` is contained within an `if` statement).
|
|
51
64
|
* @see {@link happensInEveryBranch} - to check whether control dependencies are exhaustive
|
|
52
65
|
*/
|
|
53
|
-
readonly controlDependencies
|
|
66
|
+
readonly controlDependencies?: ControlDependency[] | undefined;
|
|
54
67
|
}
|
|
55
68
|
/**
|
|
56
|
-
* Adds all non-default exit points to the existing list.
|
|
69
|
+
* Adds all non-default exit points to the existing list and updates the `invertExitCds` accordingly.
|
|
57
70
|
*/
|
|
58
|
-
export declare function addNonDefaultExitPoints(existing: ExitPoint[], add: readonly ExitPoint[]): void;
|
|
71
|
+
export declare function addNonDefaultExitPoints(existing: ExitPoint[], invertExitCds: ControlDependency[], activeCds: ControlDependency[] | undefined, add: readonly ExitPoint[]): void;
|
|
72
|
+
/**
|
|
73
|
+
* Overwrites the existing exit points with the given ones, taking care of cds.
|
|
74
|
+
*/
|
|
75
|
+
export declare function overwriteExitPoints(existing: readonly ExitPoint[], replace: ExitPoint[]): ExitPoint[];
|
|
59
76
|
/** The control flow information for the current DataflowInformation. */
|
|
60
77
|
export interface DataflowCfgInformation {
|
|
61
78
|
/** The entry node into the subgraph */
|
|
62
79
|
entryPoint: NodeId;
|
|
63
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* All already identified exit points (active 'return'/'break'/'next'-likes) of the respective structure.
|
|
82
|
+
* This also tracks (local knowledge of) exceptions thrown within the structure.
|
|
83
|
+
* See the {@link ExitPointType#Error|Error} type for more information.
|
|
84
|
+
*/
|
|
64
85
|
exitPoints: readonly ExitPoint[];
|
|
86
|
+
/** Registered hooks within the current subtree */
|
|
87
|
+
hooks: HookInformation[];
|
|
65
88
|
}
|
|
66
89
|
/**
|
|
67
90
|
* The dataflow information is one of the fundamental structures we have in the dataflow analysis.
|
package/dataflow/info.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.negateControlDependency = negateControlDependency;
|
|
4
|
+
exports.doesExitPointPropagateCalls = doesExitPointPropagateCalls;
|
|
3
5
|
exports.addNonDefaultExitPoints = addNonDefaultExitPoints;
|
|
6
|
+
exports.overwriteExitPoints = overwriteExitPoints;
|
|
4
7
|
exports.initializeCleanDataflowInformation = initializeCleanDataflowInformation;
|
|
5
8
|
exports.happensInEveryBranch = happensInEveryBranch;
|
|
6
9
|
exports.happensInEveryBranchSet = happensInEveryBranchSet;
|
|
@@ -9,11 +12,48 @@ exports.filterOutLoopExitPoints = filterOutLoopExitPoints;
|
|
|
9
12
|
exports.diffControlDependency = diffControlDependency;
|
|
10
13
|
exports.diffControlDependencies = diffControlDependencies;
|
|
11
14
|
const graph_1 = require("./graph/graph");
|
|
15
|
+
const assert_1 = require("../util/assert");
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
17
|
+
* Negates the given control dependency (i.e., flips the `when` flag).
|
|
18
|
+
* This keeps undefined `when` values intact as undefined.
|
|
14
19
|
*/
|
|
15
|
-
function
|
|
16
|
-
|
|
20
|
+
function negateControlDependency(cd) {
|
|
21
|
+
return {
|
|
22
|
+
...cd,
|
|
23
|
+
when: cd.when === undefined ? undefined : !cd.when,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Checks whether the given exit point type propagates calls (i.e., whether it aborts the current function execution).
|
|
28
|
+
*/
|
|
29
|
+
function doesExitPointPropagateCalls(type) {
|
|
30
|
+
return type === 4 /* ExitPointType.Error */;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Adds all non-default exit points to the existing list and updates the `invertExitCds` accordingly.
|
|
34
|
+
*/
|
|
35
|
+
function addNonDefaultExitPoints(existing, invertExitCds, activeCds, add) {
|
|
36
|
+
const toAdd = add.filter(({ type }) => type !== 0 /* ExitPointType.Default */);
|
|
37
|
+
if (toAdd.length === 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const invertedCds = toAdd.flatMap(e => e.controlDependencies?.filter(icd => !activeCds?.some(e => e.id === icd.id && e.when === icd.when)).map(negateControlDependency)).filter(assert_1.isNotUndefined);
|
|
41
|
+
existing.push(...toAdd);
|
|
42
|
+
for (const icd of invertedCds) {
|
|
43
|
+
if (!invertExitCds.some(e => e.id === icd.id && e.when === icd.when)) {
|
|
44
|
+
invertExitCds.push(icd);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Overwrites the existing exit points with the given ones, taking care of cds.
|
|
50
|
+
*/
|
|
51
|
+
function overwriteExitPoints(existing, replace) {
|
|
52
|
+
const replaceCds = replace.flatMap(e => e.controlDependencies);
|
|
53
|
+
if (replaceCds.length === 0 || replaceCds.some(r => r === undefined) || happensInEveryBranch(replaceCds.filter(e => e !== undefined))) {
|
|
54
|
+
return replace;
|
|
55
|
+
}
|
|
56
|
+
return existing.concat(replace);
|
|
17
57
|
}
|
|
18
58
|
/**
|
|
19
59
|
* Initializes an empty {@link DataflowInformation} object with the given entry point and data.
|
|
@@ -28,7 +68,8 @@ function initializeCleanDataflowInformation(entryPoint, data) {
|
|
|
28
68
|
environment: data.environment,
|
|
29
69
|
graph: new graph_1.DataflowGraph(data.completeAst.idMap),
|
|
30
70
|
entryPoint,
|
|
31
|
-
exitPoints: [{ nodeId: entryPoint, type: 0 /* ExitPointType.Default
|
|
71
|
+
exitPoints: [{ nodeId: entryPoint, type: 0 /* ExitPointType.Default */ }],
|
|
72
|
+
hooks: []
|
|
32
73
|
};
|
|
33
74
|
}
|
|
34
75
|
/**
|
|
@@ -37,28 +78,21 @@ function initializeCleanDataflowInformation(entryPoint, data) {
|
|
|
37
78
|
* @see {@link happensInEveryBranchSet} - for the set-based version
|
|
38
79
|
*/
|
|
39
80
|
function happensInEveryBranch(controlDependencies) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
else if (controlDependencies.length === 0) {
|
|
45
|
-
/* this happens only when we have no idea and require more analysis */
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return coversSet(controlDependencies);
|
|
81
|
+
/* this happens only when we have no idea and require more analysis */
|
|
82
|
+
return controlDependencies === undefined || (controlDependencies.length !== 0 && coversSet(controlDependencies));
|
|
49
83
|
}
|
|
50
84
|
function coversSet(controlDependencies) {
|
|
51
|
-
const trues =
|
|
52
|
-
const
|
|
85
|
+
const trues = new Set();
|
|
86
|
+
const falses = new Set();
|
|
53
87
|
for (const { id, when } of controlDependencies) {
|
|
54
88
|
if (when) {
|
|
55
|
-
trues.
|
|
89
|
+
trues.add(id);
|
|
56
90
|
}
|
|
57
|
-
else {
|
|
58
|
-
|
|
91
|
+
else if (when === false) {
|
|
92
|
+
falses.add(id);
|
|
59
93
|
}
|
|
60
94
|
}
|
|
61
|
-
return trues.
|
|
95
|
+
return trues.symmetricDifference(falses).size === 0;
|
|
62
96
|
}
|
|
63
97
|
/**
|
|
64
98
|
* Checks whether the given control dependencies are exhaustive (i.e. if for every control dependency on a boolean,
|
|
@@ -66,28 +100,29 @@ function coversSet(controlDependencies) {
|
|
|
66
100
|
* @see {@link happensInEveryBranch} - for the array-based version
|
|
67
101
|
*/
|
|
68
102
|
function happensInEveryBranchSet(controlDependencies) {
|
|
69
|
-
|
|
70
|
-
/* the cds are unconstrained */
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
else if (controlDependencies.size === 0) {
|
|
74
|
-
/* this happens only when we have no idea and require more analysis */
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
return coversSet(controlDependencies);
|
|
103
|
+
return controlDependencies === undefined || (controlDependencies.size !== 0 && coversSet(controlDependencies));
|
|
78
104
|
}
|
|
79
105
|
/**
|
|
80
106
|
* Checks whether the given dataflow information always exits (i.e., if there is a non-default exit point in every branch).
|
|
81
107
|
* @see {@link ExitPoint} - for the different types of exit points
|
|
82
108
|
*/
|
|
83
109
|
function alwaysExits(data) {
|
|
84
|
-
|
|
110
|
+
let cds = [];
|
|
111
|
+
for (const e of data.exitPoints) {
|
|
112
|
+
if (e.type !== 0 /* ExitPointType.Default */) {
|
|
113
|
+
if (e.controlDependencies === undefined) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
cds = cds.concat(e.controlDependencies);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return happensInEveryBranch(cds);
|
|
85
120
|
}
|
|
86
121
|
/**
|
|
87
122
|
* Filters out exit points which end their cascade within a loop.
|
|
88
123
|
*/
|
|
89
124
|
function filterOutLoopExitPoints(exitPoints) {
|
|
90
|
-
return exitPoints.filter(({ type }) => type
|
|
125
|
+
return exitPoints.filter(({ type }) => type !== 2 /* ExitPointType.Break */ && type !== 3 /* ExitPointType.Next */);
|
|
91
126
|
}
|
|
92
127
|
/**
|
|
93
128
|
* Calculates the difference between two control dependencies.
|
|
@@ -100,7 +135,7 @@ function diffControlDependency(a, b, info) {
|
|
|
100
135
|
return;
|
|
101
136
|
}
|
|
102
137
|
if (a.id !== b.id) {
|
|
103
|
-
info.report.addComment(`${info.position}Different control dependency ids. ${info.leftname}: ${a.id} vs. ${info.rightname}: ${b.id}`);
|
|
138
|
+
info.report.addComment(`${info.position}Different control dependency ids. ${info.leftname}: ${JSON.stringify(a.id)} vs. ${info.rightname}: ${JSON.stringify(b.id)}`);
|
|
104
139
|
}
|
|
105
140
|
if (a.when !== b.when) {
|
|
106
141
|
info.report.addComment(`${info.position}Different control dependency when. ${info.leftname}: ${a.when} vs. ${info.rightname}: ${b.when}`);
|
|
@@ -21,12 +21,21 @@ export declare function produceNameSharedIdMap(references: IdentifierReference[]
|
|
|
21
21
|
* Links the given arguments to the given parameters within the given graph.
|
|
22
22
|
* This follows the `pmatch` semantics of R
|
|
23
23
|
* @see https://cran.r-project.org/doc/manuals/R-lang.html#Argument-matching
|
|
24
|
+
* This returns the resolved map from argument ids to parameter ids.
|
|
25
|
+
* If you just want to match by name, use {@link pMatch}.
|
|
24
26
|
*/
|
|
25
|
-
export declare function linkArgumentsOnCall(args: FunctionArgument[], params: RParameter<ParentInformation>[], graph: DataflowGraph):
|
|
27
|
+
export declare function linkArgumentsOnCall(args: readonly FunctionArgument[], params: readonly RParameter<ParentInformation>[], graph: DataflowGraph): Map<NodeId, NodeId>;
|
|
28
|
+
/**
|
|
29
|
+
* Links the given arguments to the given parameters within the given graph by name only.
|
|
30
|
+
* @note
|
|
31
|
+
* To obtain the arguments from a {@link RFunctionCall}[], either use {@link processAllArguments} (also available via {@link processKnownFunctionCall})
|
|
32
|
+
* or convert them with {@link convertFnArguments}.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pMatch<Targets extends NodeId>(args: readonly FunctionArgument[], params: Record<string, Targets>): Map<NodeId, Targets>;
|
|
26
35
|
/**
|
|
27
36
|
* Links a function call with a single target function definition.
|
|
28
37
|
*/
|
|
29
|
-
export declare function linkFunctionCallWithSingleTarget(graph: DataflowGraph,
|
|
38
|
+
export declare function linkFunctionCallWithSingleTarget(graph: DataflowGraph, { subflow: fnSubflow, exitPoints, id: fnId, params }: DataflowGraphVertexFunctionDefinition, info: DataflowGraphVertexFunctionCall, idMap: AstIdMap): ExitPoint[];
|
|
30
39
|
/**
|
|
31
40
|
* Returns the called functions within the current graph, which can be used to merge the environments with the call.
|
|
32
41
|
* Furthermore, it links the corresponding arguments.
|
|
@@ -37,6 +46,7 @@ export declare function linkFunctionCallWithSingleTarget(graph: DataflowGraph, d
|
|
|
37
46
|
export declare function linkFunctionCalls(graph: DataflowGraph, idMap: AstIdMap, thisGraph: DataflowGraph): {
|
|
38
47
|
functionCall: NodeId;
|
|
39
48
|
called: readonly DataflowGraphVertexInfo[];
|
|
49
|
+
propagateExitPoints: readonly ExitPoint[];
|
|
40
50
|
}[];
|
|
41
51
|
/**
|
|
42
52
|
* convenience function returning all known call targets, as well as the name source which defines them
|
|
@@ -45,7 +55,7 @@ export declare function getAllFunctionCallTargets(call: NodeId, graph: DataflowG
|
|
|
45
55
|
/**
|
|
46
56
|
* Finds all linked function definitions starting from the given set of read ids.
|
|
47
57
|
*/
|
|
48
|
-
export declare function getAllLinkedFunctionDefinitions(functionDefinitionReadIds: ReadonlySet<NodeId>, dataflowGraph: DataflowGraph): [Set<
|
|
58
|
+
export declare function getAllLinkedFunctionDefinitions(functionDefinitionReadIds: ReadonlySet<NodeId>, dataflowGraph: DataflowGraph): [Set<Required<DataflowGraphVertexFunctionDefinition>>, Set<BuiltIn>];
|
|
49
59
|
/**
|
|
50
60
|
* This method links a set of read variables to definitions in an environment.
|
|
51
61
|
* @param referencesToLinkAgainstEnvironment - The set of references to link against the environment
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.findNonLocalReads = findNonLocalReads;
|
|
4
4
|
exports.produceNameSharedIdMap = produceNameSharedIdMap;
|
|
5
5
|
exports.linkArgumentsOnCall = linkArgumentsOnCall;
|
|
6
|
+
exports.pMatch = pMatch;
|
|
6
7
|
exports.linkFunctionCallWithSingleTarget = linkFunctionCallWithSingleTarget;
|
|
7
8
|
exports.linkFunctionCalls = linkFunctionCalls;
|
|
8
9
|
exports.getAllFunctionCallTargets = getAllFunctionCallTargets;
|
|
@@ -24,6 +25,7 @@ const vertex_1 = require("../graph/vertex");
|
|
|
24
25
|
const resolve_by_name_1 = require("../environments/resolve-by-name");
|
|
25
26
|
const built_in_1 = require("../environments/built-in");
|
|
26
27
|
const prefix_1 = require("../../util/prefix");
|
|
28
|
+
const info_1 = require("../info");
|
|
27
29
|
/**
|
|
28
30
|
* Find all reads within the graph that do not reference a local definition in the graph.
|
|
29
31
|
*/
|
|
@@ -81,26 +83,34 @@ function produceNameSharedIdMap(references) {
|
|
|
81
83
|
* Links the given arguments to the given parameters within the given graph.
|
|
82
84
|
* This follows the `pmatch` semantics of R
|
|
83
85
|
* @see https://cran.r-project.org/doc/manuals/R-lang.html#Argument-matching
|
|
86
|
+
* This returns the resolved map from argument ids to parameter ids.
|
|
87
|
+
* If you just want to match by name, use {@link pMatch}.
|
|
84
88
|
*/
|
|
85
89
|
function linkArgumentsOnCall(args, params, graph) {
|
|
86
90
|
const nameArgMap = new Map(args.filter(graph_1.isNamedArgument).map(a => [a.name, a]));
|
|
87
91
|
const nameParamMap = new Map(params.filter(p => p?.name?.content !== undefined)
|
|
88
92
|
.map(p => [p.name.content, p]));
|
|
93
|
+
const maps = new Map();
|
|
89
94
|
const specialDotParameter = params.find(p => p.special);
|
|
95
|
+
const sid = specialDotParameter?.name.info.id;
|
|
90
96
|
// all parameters matched by name
|
|
91
97
|
const matchedParameters = new Set();
|
|
98
|
+
const paramNames = nameParamMap.keys().toArray();
|
|
92
99
|
// first map names
|
|
93
100
|
for (const [name, { nodeId: argId }] of nameArgMap) {
|
|
94
|
-
const pmatchName = (0, prefix_1.findByPrefixIfUnique)(name,
|
|
101
|
+
const pmatchName = (0, prefix_1.findByPrefixIfUnique)(name, paramNames) ?? name;
|
|
95
102
|
const param = nameParamMap.get(pmatchName);
|
|
96
103
|
if (param?.name) {
|
|
97
|
-
|
|
98
|
-
graph.addEdge(
|
|
104
|
+
const pid = param.name.info.id;
|
|
105
|
+
graph.addEdge(argId, pid, edge_1.EdgeType.DefinesOnCall);
|
|
106
|
+
graph.addEdge(pid, argId, edge_1.EdgeType.DefinedByOnCall);
|
|
107
|
+
maps.set(argId, pid);
|
|
99
108
|
matchedParameters.add(name);
|
|
100
109
|
}
|
|
101
|
-
else if (
|
|
102
|
-
graph.addEdge(argId,
|
|
103
|
-
graph.addEdge(
|
|
110
|
+
else if (sid) {
|
|
111
|
+
graph.addEdge(argId, sid, edge_1.EdgeType.DefinesOnCall);
|
|
112
|
+
graph.addEdge(sid, argId, edge_1.EdgeType.DefinedByOnCall);
|
|
113
|
+
maps.set(argId, sid);
|
|
104
114
|
}
|
|
105
115
|
}
|
|
106
116
|
const remainingParameter = params.filter(p => !p?.name || !matchedParameters.has(p.name.content));
|
|
@@ -110,10 +120,12 @@ function linkArgumentsOnCall(args, params, graph) {
|
|
|
110
120
|
if (arg === r_function_call_1.EmptyArgument) {
|
|
111
121
|
continue;
|
|
112
122
|
}
|
|
123
|
+
const aid = arg.nodeId;
|
|
113
124
|
if (remainingParameter.length <= i) {
|
|
114
|
-
if (
|
|
115
|
-
graph.addEdge(
|
|
116
|
-
graph.addEdge(
|
|
125
|
+
if (sid) {
|
|
126
|
+
graph.addEdge(aid, sid, edge_1.EdgeType.DefinesOnCall);
|
|
127
|
+
graph.addEdge(sid, aid, edge_1.EdgeType.DefinedByOnCall);
|
|
128
|
+
maps.set(aid, sid);
|
|
117
129
|
}
|
|
118
130
|
else {
|
|
119
131
|
logger_1.dataflowLogger.warn(`skipping argument ${i} as there is no corresponding parameter - R should block that`);
|
|
@@ -121,13 +133,64 @@ function linkArgumentsOnCall(args, params, graph) {
|
|
|
121
133
|
continue;
|
|
122
134
|
}
|
|
123
135
|
const param = remainingParameter[i];
|
|
124
|
-
logger_1.dataflowLogger.trace(`mapping unnamed argument ${i} (id: ${
|
|
136
|
+
logger_1.dataflowLogger.trace(`mapping unnamed argument ${i} (id: ${aid}) to parameter "${param.name?.content ?? '??'}"`);
|
|
125
137
|
if (param.name) {
|
|
126
|
-
|
|
127
|
-
graph.addEdge(
|
|
138
|
+
const pid = param.name.info.id;
|
|
139
|
+
graph.addEdge(aid, pid, edge_1.EdgeType.DefinesOnCall);
|
|
140
|
+
graph.addEdge(pid, aid, edge_1.EdgeType.DefinedByOnCall);
|
|
141
|
+
maps.set(aid, pid);
|
|
128
142
|
}
|
|
129
143
|
}
|
|
144
|
+
return maps;
|
|
130
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Links the given arguments to the given parameters within the given graph by name only.
|
|
148
|
+
* @note
|
|
149
|
+
* To obtain the arguments from a {@link RFunctionCall}[], either use {@link processAllArguments} (also available via {@link processKnownFunctionCall})
|
|
150
|
+
* or convert them with {@link convertFnArguments}.
|
|
151
|
+
*/
|
|
152
|
+
function pMatch(args, params) {
|
|
153
|
+
const nameArgMap = new Map(args.filter(graph_1.isNamedArgument).map(a => [a.name, a]));
|
|
154
|
+
const maps = new Map();
|
|
155
|
+
const sid = params['...'];
|
|
156
|
+
const paramNames = Object.keys(params);
|
|
157
|
+
// all parameters matched by name
|
|
158
|
+
const matchedParameters = new Set();
|
|
159
|
+
// first map names
|
|
160
|
+
for (const [name, { nodeId: argId }] of nameArgMap) {
|
|
161
|
+
const pmatchName = (0, prefix_1.findByPrefixIfUnique)(name, paramNames) ?? name;
|
|
162
|
+
const param = params[pmatchName];
|
|
163
|
+
if (param) {
|
|
164
|
+
maps.set(argId, param);
|
|
165
|
+
}
|
|
166
|
+
else if (sid) {
|
|
167
|
+
maps.set(argId, sid);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const remainingParameter = paramNames.filter(p => !matchedParameters.has(p));
|
|
171
|
+
const remainingArguments = args.filter(a => !(0, graph_1.isNamedArgument)(a));
|
|
172
|
+
for (let i = 0; i < remainingArguments.length; i++) {
|
|
173
|
+
const arg = remainingArguments[i];
|
|
174
|
+
if (arg === r_function_call_1.EmptyArgument) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const aid = arg.nodeId;
|
|
178
|
+
if (remainingParameter.length <= i) {
|
|
179
|
+
if (sid) {
|
|
180
|
+
maps.set(aid, sid);
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const param = params[remainingParameter[i]];
|
|
185
|
+
if (param) {
|
|
186
|
+
maps.set(aid, param);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return maps;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Links the function call arguments to the target function definition and returns a map from argument ids to parameter ids.
|
|
193
|
+
*/
|
|
131
194
|
function linkFunctionCallArguments(targetId, idMap, functionCallName, functionRootId, callArgs, finalGraph) {
|
|
132
195
|
// we get them by just choosing the rhs of the definition
|
|
133
196
|
const linkedFunction = idMap.get(targetId);
|
|
@@ -139,16 +202,16 @@ function linkFunctionCallArguments(targetId, idMap, functionCallName, functionRo
|
|
|
139
202
|
logger_1.dataflowLogger.trace(`function call definition base ${functionCallName} does not lead to a function definition (${functionRootId}) but got ${linkedFunction.type}`);
|
|
140
203
|
return;
|
|
141
204
|
}
|
|
142
|
-
linkArgumentsOnCall(callArgs, linkedFunction.parameters, finalGraph);
|
|
205
|
+
return linkArgumentsOnCall(callArgs, linkedFunction.parameters, finalGraph);
|
|
143
206
|
}
|
|
144
207
|
/**
|
|
145
208
|
* Links a function call with a single target function definition.
|
|
146
209
|
*/
|
|
147
|
-
function linkFunctionCallWithSingleTarget(graph,
|
|
210
|
+
function linkFunctionCallWithSingleTarget(graph, { subflow: fnSubflow, exitPoints, id: fnId, params }, info, idMap) {
|
|
148
211
|
const id = info.id;
|
|
149
212
|
if (info.environment !== undefined) {
|
|
150
213
|
// for each open ingoing reference, try to resolve it here, and if so, add a read edge from the call to signal that it reads it
|
|
151
|
-
for (const ingoing of
|
|
214
|
+
for (const ingoing of fnSubflow.in) {
|
|
152
215
|
const defs = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, info.environment, ingoing.type) : undefined;
|
|
153
216
|
if (defs === undefined) {
|
|
154
217
|
continue;
|
|
@@ -161,15 +224,32 @@ function linkFunctionCallWithSingleTarget(graph, def, info, idMap) {
|
|
|
161
224
|
}
|
|
162
225
|
}
|
|
163
226
|
}
|
|
164
|
-
const
|
|
227
|
+
const propagateExitPoints = [];
|
|
165
228
|
for (const exitPoint of exitPoints) {
|
|
166
|
-
graph.addEdge(id, exitPoint, edge_1.EdgeType.Returns);
|
|
229
|
+
graph.addEdge(id, exitPoint.nodeId, edge_1.EdgeType.Returns);
|
|
230
|
+
if ((0, info_1.doesExitPointPropagateCalls)(exitPoint.type)) {
|
|
231
|
+
// add the exit point to the call!
|
|
232
|
+
propagateExitPoints.push(exitPoint);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const defName = (0, node_id_1.recoverName)(fnId, idMap);
|
|
236
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `recording expr-list-level call from ${(0, node_id_1.recoverName)(info.id, idMap)} to ${defName}`);
|
|
237
|
+
graph.addEdge(id, fnId, edge_1.EdgeType.Calls);
|
|
238
|
+
applyForForcedArgs(graph, info.id, params, linkFunctionCallArguments(fnId, idMap, defName, id, info.args, graph));
|
|
239
|
+
return propagateExitPoints;
|
|
240
|
+
}
|
|
241
|
+
/** for each parameter that we link that gets forced, add a reads edge from the call to argument to show that it reads it */
|
|
242
|
+
function applyForForcedArgs(graph, callId, readParams, maps) {
|
|
243
|
+
if (maps === undefined) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
for (const [arg, param] of maps.entries()) {
|
|
247
|
+
if (readParams[String(param)]) {
|
|
248
|
+
graph.addEdge(callId, arg, edge_1.EdgeType.Reads);
|
|
249
|
+
}
|
|
167
250
|
}
|
|
168
|
-
const defName = (0, node_id_1.recoverName)(def.id, idMap);
|
|
169
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `recording expression-list-level call from ${(0, node_id_1.recoverName)(info.id, idMap)} to ${defName}`);
|
|
170
|
-
graph.addEdge(id, def.id, edge_1.EdgeType.Calls);
|
|
171
|
-
linkFunctionCallArguments(def.id, idMap, defName, id, info.args, graph);
|
|
172
251
|
}
|
|
252
|
+
const FCallLinkReadBits = edge_1.EdgeType.Reads | edge_1.EdgeType.Calls | edge_1.EdgeType.DefinedByOnCall;
|
|
173
253
|
/* there is _a lot_ potential for optimization here */
|
|
174
254
|
function linkFunctionCall(graph, id, info, idMap, thisGraph, calledFunctionDefinitions) {
|
|
175
255
|
const edges = graph.outgoingEdges(id);
|
|
@@ -177,16 +257,26 @@ function linkFunctionCall(graph, id, info, idMap, thisGraph, calledFunctionDefin
|
|
|
177
257
|
/* no outgoing edges */
|
|
178
258
|
return;
|
|
179
259
|
}
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
&& (0, edge_1.
|
|
183
|
-
|
|
260
|
+
const functionDefinitionReadIds = new Set();
|
|
261
|
+
for (const [t, { types }] of edges.entries()) {
|
|
262
|
+
if (!(0, built_in_1.isBuiltIn)(t) && (0, edge_1.edgeDoesNotIncludeType)(types, edge_1.EdgeType.Argument) && (0, edge_1.edgeIncludesType)(types, FCallLinkReadBits)) {
|
|
263
|
+
functionDefinitionReadIds.add(t);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const [functionDefs] = getAllLinkedFunctionDefinitions(new Set(functionDefinitionReadIds), graph);
|
|
267
|
+
const propagateExitPoints = [];
|
|
184
268
|
for (const def of functionDefs.values()) {
|
|
185
|
-
|
|
186
|
-
|
|
269
|
+
// we can skip this if we already linked it
|
|
270
|
+
const oEdge = graph.outgoingEdges(id)?.get(def.id);
|
|
271
|
+
if (oEdge && (0, edge_1.edgeIncludesType)(oEdge.types, edge_1.EdgeType.Calls)) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
for (const ep of linkFunctionCallWithSingleTarget(graph, def, info, idMap)) {
|
|
275
|
+
propagateExitPoints.push(ep);
|
|
276
|
+
}
|
|
187
277
|
}
|
|
188
278
|
if (thisGraph.isRoot(id) && functionDefs.size > 0) {
|
|
189
|
-
calledFunctionDefinitions.push({ functionCall: id, called:
|
|
279
|
+
calledFunctionDefinitions.push({ functionCall: id, called: functionDefs.values().toArray(), propagateExitPoints });
|
|
190
280
|
}
|
|
191
281
|
}
|
|
192
282
|
/**
|
|
@@ -199,7 +289,9 @@ function linkFunctionCall(graph, id, info, idMap, thisGraph, calledFunctionDefin
|
|
|
199
289
|
function linkFunctionCalls(graph, idMap, thisGraph) {
|
|
200
290
|
const calledFunctionDefinitions = [];
|
|
201
291
|
for (const [id, info] of thisGraph.verticesOfType(vertex_1.VertexType.FunctionCall)) {
|
|
202
|
-
|
|
292
|
+
if (!info.onlyBuiltin) {
|
|
293
|
+
linkFunctionCall(graph, id, info, idMap, thisGraph, calledFunctionDefinitions);
|
|
294
|
+
}
|
|
203
295
|
}
|
|
204
296
|
return calledFunctionDefinitions;
|
|
205
297
|
}
|
|
@@ -227,21 +319,25 @@ function getAllFunctionCallTargets(call, graph, environment) {
|
|
|
227
319
|
for (const target of functionCallTargets) {
|
|
228
320
|
found.push(target.id);
|
|
229
321
|
}
|
|
230
|
-
found = found.concat(
|
|
322
|
+
found = found.concat(Array.from(builtInTargets), functionCallDefs);
|
|
231
323
|
}
|
|
232
324
|
return found;
|
|
233
325
|
}
|
|
326
|
+
const LinkedFnFollowBits = edge_1.EdgeType.Reads | edge_1.EdgeType.DefinedBy | edge_1.EdgeType.DefinedByOnCall;
|
|
234
327
|
/**
|
|
235
328
|
* Finds all linked function definitions starting from the given set of read ids.
|
|
236
329
|
*/
|
|
237
330
|
function getAllLinkedFunctionDefinitions(functionDefinitionReadIds, dataflowGraph) {
|
|
238
|
-
let potential = functionDefinitionReadIds.values().toArray();
|
|
239
|
-
const visited = new Set();
|
|
240
331
|
const result = new Set();
|
|
241
332
|
const builtIns = new Set();
|
|
242
|
-
|
|
333
|
+
if (functionDefinitionReadIds.size === 0) {
|
|
334
|
+
return [result, builtIns];
|
|
335
|
+
}
|
|
336
|
+
const potential = Array.from(functionDefinitionReadIds);
|
|
337
|
+
const visited = new Set();
|
|
338
|
+
while (potential.length !== 0) {
|
|
243
339
|
const currentId = potential.pop();
|
|
244
|
-
|
|
340
|
+
visited.add(currentId);
|
|
245
341
|
if ((0, built_in_1.isBuiltIn)(currentId)) {
|
|
246
342
|
builtIns.add(currentId);
|
|
247
343
|
continue;
|
|
@@ -250,24 +346,29 @@ function getAllLinkedFunctionDefinitions(functionDefinitionReadIds, dataflowGrap
|
|
|
250
346
|
if (currentInfo === undefined) {
|
|
251
347
|
continue;
|
|
252
348
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
.
|
|
257
|
-
if (returnEdges.length > 0) {
|
|
258
|
-
// only traverse return edges and do not follow `calls` etc. as this indicates that we have a function call which returns a result, and not the function calls itself
|
|
259
|
-
potential = potential.concat(returnEdges.map(([target]) => target).filter(id => !visited.has(id)));
|
|
349
|
+
const [vertex, edges] = currentInfo;
|
|
350
|
+
// Found a function definition
|
|
351
|
+
if (vertex.subflow !== undefined) {
|
|
352
|
+
result.add(vertex);
|
|
260
353
|
continue;
|
|
261
354
|
}
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
355
|
+
let hasReturnEdge = false;
|
|
356
|
+
for (const [target, { types }] of edges) {
|
|
357
|
+
if ((0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Returns)) {
|
|
358
|
+
hasReturnEdge = true;
|
|
359
|
+
if (!visited.has(target)) {
|
|
360
|
+
potential.push(target);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (hasReturnEdge) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
for (const [target, { types }] of edges) {
|
|
368
|
+
if ((0, edge_1.edgeIncludesType)(types, LinkedFnFollowBits) && !visited.has(target)) {
|
|
369
|
+
potential.push(target);
|
|
370
|
+
}
|
|
266
371
|
}
|
|
267
|
-
// trace all joined reads
|
|
268
|
-
potential = potential.concat(followEdges
|
|
269
|
-
.map(([target]) => target)
|
|
270
|
-
.filter(id => !visited.has(id)));
|
|
271
372
|
}
|
|
272
373
|
return [result, builtIns];
|
|
273
374
|
}
|
|
@@ -327,10 +428,10 @@ function linkCircularRedefinitionsWithinALoop(graph, openIns, outgoing) {
|
|
|
327
428
|
}
|
|
328
429
|
}
|
|
329
430
|
for (const [name, targets] of openIns.entries()) {
|
|
330
|
-
for (const
|
|
331
|
-
if (
|
|
431
|
+
for (const { name: outName, nodeId } of lastOutgoing.values()) {
|
|
432
|
+
if (outName === name) {
|
|
332
433
|
for (const target of targets) {
|
|
333
|
-
graph.addEdge(target.nodeId,
|
|
434
|
+
graph.addEdge(target.nodeId, nodeId, edge_1.EdgeType.Reads);
|
|
334
435
|
}
|
|
335
436
|
}
|
|
336
437
|
}
|
|
@@ -344,8 +445,9 @@ function reapplyLoopExitPoints(exits, references) {
|
|
|
344
445
|
const exitCds = new Set(exits.flatMap(e => e.controlDependencies).filter(assert_1.isNotUndefined));
|
|
345
446
|
for (const ref of references) {
|
|
346
447
|
for (const cd of exitCds) {
|
|
448
|
+
const { id: cId, when: cWhen } = cd;
|
|
347
449
|
if (ref.controlDependencies) {
|
|
348
|
-
if (!ref.controlDependencies?.find(c => c.id ===
|
|
450
|
+
if (!ref.controlDependencies?.find(c => c.id === cId && c.when === cWhen)) {
|
|
349
451
|
ref.controlDependencies.push({ ...cd, byIteration: true });
|
|
350
452
|
}
|
|
351
453
|
}
|
|
@@ -10,3 +10,7 @@ export declare function unpackNonameArg<OtherInfo>(arg: RFunctionArgument<OtherI
|
|
|
10
10
|
* @see {@link unpackNonameArg} - to specifically retrieve non-named arguments
|
|
11
11
|
*/
|
|
12
12
|
export declare function unpackArg<OtherInfo>(arg: RFunctionArgument<OtherInfo> | undefined): RNode<OtherInfo> | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Try to unpack the given argument, if it is not empty.
|
|
15
|
+
*/
|
|
16
|
+
export declare function tryUnpackNoNameArg<OtherInfo>(arg: RFunctionArgument<OtherInfo>): RNode<OtherInfo> | RFunctionArgument<OtherInfo>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.unpackNonameArg = unpackNonameArg;
|
|
4
4
|
exports.unpackArg = unpackArg;
|
|
5
|
+
exports.tryUnpackNoNameArg = tryUnpackNoNameArg;
|
|
5
6
|
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
6
7
|
/**
|
|
7
8
|
* Retrieve the value from an argument, if it is not empty.
|
|
@@ -17,4 +18,10 @@ function unpackNonameArg(arg) {
|
|
|
17
18
|
function unpackArg(arg) {
|
|
18
19
|
return arg === r_function_call_1.EmptyArgument ? undefined : arg?.value;
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Try to unpack the given argument, if it is not empty.
|
|
23
|
+
*/
|
|
24
|
+
function tryUnpackNoNameArg(arg) {
|
|
25
|
+
return unpackNonameArg(arg) ?? arg;
|
|
26
|
+
}
|
|
20
27
|
//# sourceMappingURL=unpack-argument.js.map
|
|
@@ -13,7 +13,7 @@ export interface BuiltInApplyConfiguration extends MergeableRecord {
|
|
|
13
13
|
/** Should we unquote the function if it is given as a string? */
|
|
14
14
|
readonly unquoteFunction?: boolean;
|
|
15
15
|
/** Should the function be resolved in the global environment? */
|
|
16
|
-
readonly resolveInEnvironment
|
|
16
|
+
readonly resolveInEnvironment?: 'global' | 'local';
|
|
17
17
|
/** Should the value of the function be resolved? */
|
|
18
18
|
readonly resolveValue?: boolean;
|
|
19
19
|
}
|