@eagleoutice/flowr 2.7.5 → 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 +68 -65
- 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 -11
- 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 +11 -3
- package/project/plugins/file-plugins/files/flowr-description-file.js +38 -28
- 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 +8 -3
- 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 +32 -0
- package/util/r-license.js +217 -0
- 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
|
@@ -35,6 +35,21 @@ function processApply(name, args, rootId, data, config) {
|
|
|
35
35
|
index = mayFn;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
// shift the index to point to the index'd unnamed argument
|
|
39
|
+
let posArgsFound = 0;
|
|
40
|
+
for (let i = 0; i < args.length; i++) {
|
|
41
|
+
const arg = args[i];
|
|
42
|
+
if (arg !== r_function_call_1.EmptyArgument && arg.name) {
|
|
43
|
+
// do nothing
|
|
44
|
+
}
|
|
45
|
+
else if (posArgsFound === index) {
|
|
46
|
+
index = i;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
posArgsFound++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
38
53
|
/* validate, that we indeed have so many arguments to fill this one :D */
|
|
39
54
|
if (index >= args.length) {
|
|
40
55
|
logger_1.dataflowLogger.warn(`Function argument at index ${index} not found, skipping`);
|
|
@@ -62,7 +77,8 @@ function processApply(name, args, rootId, data, config) {
|
|
|
62
77
|
if (resolveValue) {
|
|
63
78
|
const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: data.environment, idMap: data.completeAst.idMap, resolve: data.ctx.config.solver.variables, ctx: data.ctx }));
|
|
64
79
|
if (resolved?.elements.length === 1 && resolved.elements[0].type === 'string') {
|
|
65
|
-
|
|
80
|
+
const r = resolved.elements[0];
|
|
81
|
+
functionName = (0, r_value_1.isValue)(r.value) ? r.value.str : undefined;
|
|
66
82
|
}
|
|
67
83
|
}
|
|
68
84
|
else {
|
|
@@ -102,7 +118,7 @@ function processApply(name, args, rootId, data, config) {
|
|
|
102
118
|
name: functionName,
|
|
103
119
|
/* can never be a direct built-in-call */
|
|
104
120
|
onlyBuiltin: false,
|
|
105
|
-
|
|
121
|
+
controlDependencies: data.controlDependencies,
|
|
106
122
|
args: allOtherArguments, // same reference
|
|
107
123
|
origin: ['function']
|
|
108
124
|
}, data.ctx.env.makeCleanEnv());
|
|
@@ -151,7 +167,7 @@ function processApply(name, args, rootId, data, config) {
|
|
|
151
167
|
args: allOtherArguments,
|
|
152
168
|
environment: resolveInEnvironment === 'global' ? undefined : data.environment,
|
|
153
169
|
onlyBuiltin: resolveInEnvironment === 'global',
|
|
154
|
-
|
|
170
|
+
controlDependencies: data.controlDependencies,
|
|
155
171
|
origin: ['function']
|
|
156
172
|
});
|
|
157
173
|
}
|
|
@@ -22,6 +22,20 @@ export interface AssignmentConfiguration extends ForceArguments {
|
|
|
22
22
|
readonly indicesCollection?: ContainerIndicesCollection;
|
|
23
23
|
readonly mayHaveMoreArgs?: boolean;
|
|
24
24
|
}
|
|
25
|
+
export interface ExtendedAssignmentConfiguration extends AssignmentConfiguration {
|
|
26
|
+
readonly source: {
|
|
27
|
+
idx?: number;
|
|
28
|
+
name: string;
|
|
29
|
+
};
|
|
30
|
+
readonly target: {
|
|
31
|
+
idx?: number;
|
|
32
|
+
name: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* In contrast to `processAssignment`, this function allows more flexible handling of assignment-like functions.
|
|
37
|
+
*/
|
|
38
|
+
export declare function processAssignmentLike<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: ExtendedAssignmentConfiguration): DataflowInformation;
|
|
25
39
|
/**
|
|
26
40
|
* Processes an assignment, i.e., `<target> <- <source>`.
|
|
27
41
|
* Handling it as a function call \`<-\` `(<target>, <source>)`.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processAssignmentLike = processAssignmentLike;
|
|
3
4
|
exports.processAssignment = processAssignment;
|
|
4
5
|
exports.markAsAssignment = markAsAssignment;
|
|
5
6
|
const known_call_handling_1 = require("../known-call-handling");
|
|
@@ -8,6 +9,7 @@ const unpack_argument_1 = require("../argument/unpack-argument");
|
|
|
8
9
|
const process_named_call_1 = require("../../../process-named-call");
|
|
9
10
|
const make_argument_1 = require("../argument/make-argument");
|
|
10
11
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
12
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
11
13
|
const logger_1 = require("../../../../../logger");
|
|
12
14
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
13
15
|
const overwrite_1 = require("../../../../../environments/overwrite");
|
|
@@ -69,6 +71,30 @@ function tryReplacementPassingIndices(rootId, functionName, data, name, args, in
|
|
|
69
71
|
(0, named_call_handling_1.markAsOnlyBuiltIn)(info.graph, functionName.info.id);
|
|
70
72
|
return info;
|
|
71
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* In contrast to `processAssignment`, this function allows more flexible handling of assignment-like functions.
|
|
76
|
+
*/
|
|
77
|
+
function processAssignmentLike(name,
|
|
78
|
+
/* we expect them to be ordered in the sense that we have (source, target): `<source> <- <target>` */
|
|
79
|
+
args, rootId, data, config) {
|
|
80
|
+
const argsWithNames = new Map();
|
|
81
|
+
const argsWithoutNames = [];
|
|
82
|
+
for (const arg of args) {
|
|
83
|
+
const name = arg !== r_function_call_1.EmptyArgument ? arg.name?.content : undefined;
|
|
84
|
+
if (name !== undefined) {
|
|
85
|
+
argsWithNames.set(name, arg);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
argsWithoutNames.push(arg);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const source = argsWithNames.get(config.source.name) ?? (config.source.idx !== undefined ? argsWithoutNames[config.source.idx] : undefined);
|
|
92
|
+
const target = argsWithNames.get(config.target.name) ?? (config.target.idx !== undefined ? argsWithoutNames[config.target.idx] : undefined);
|
|
93
|
+
if (source && target) {
|
|
94
|
+
args = [target, source];
|
|
95
|
+
}
|
|
96
|
+
return processAssignment(name, args, rootId, data, { ...config, mayHaveMoreArgs: true });
|
|
97
|
+
}
|
|
72
98
|
/**
|
|
73
99
|
* Processes an assignment, i.e., `<target> <- <source>`.
|
|
74
100
|
* Handling it as a function call \`<-\` `(<target>, <source>)`.
|
|
@@ -338,6 +364,10 @@ function processAssignmentToSymbol(config) {
|
|
|
338
364
|
if (quoteSource) {
|
|
339
365
|
information.graph.addEdge(rootId, source.info.id, edge_1.EdgeType.NonStandardEvaluation);
|
|
340
366
|
}
|
|
367
|
+
else {
|
|
368
|
+
// we read the source
|
|
369
|
+
information.graph.addEdge(rootId, source.info.id, edge_1.EdgeType.Reads);
|
|
370
|
+
}
|
|
341
371
|
return {
|
|
342
372
|
...information,
|
|
343
373
|
unknownReferences: [],
|
|
@@ -53,7 +53,7 @@ function processEvalCall(name, args, rootId, data, config) {
|
|
|
53
53
|
result.push(r);
|
|
54
54
|
// add a returns edge from the eval to the result
|
|
55
55
|
for (const e of r.exitPoints) {
|
|
56
|
-
information.graph.addEdge(rootId, e, edge_1.EdgeType.Returns);
|
|
56
|
+
information.graph.addEdge(rootId, e.nodeId, edge_1.EdgeType.Returns);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
return {
|
|
@@ -64,6 +64,7 @@ function processEvalCall(name, args, rootId, data, config) {
|
|
|
64
64
|
in: information.in.concat(result.flatMap(r => r.in)),
|
|
65
65
|
unknownReferences: information.unknownReferences.concat(result.flatMap(r => r.unknownReferences)),
|
|
66
66
|
exitPoints: information.exitPoints.concat(result.flatMap(r => r.exitPoints)),
|
|
67
|
+
hooks: information.hooks.concat(result.flatMap(r => r.hooks)),
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(args)} for eval is currently not supported, skipping`);
|
|
@@ -47,12 +47,6 @@ function linkReadNameToWriteIfPossible(read, environments, listEnvironments, rem
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
function processNextExpression(currentElement, environment, listEnvironments, remainingRead, nextGraph) {
|
|
51
|
-
// all inputs that have not been written until now are read!
|
|
52
|
-
for (const read of currentElement.in.concat(currentElement.unknownReferences)) {
|
|
53
|
-
linkReadNameToWriteIfPossible(read, environment, listEnvironments, remainingRead, nextGraph);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
50
|
function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextGraph, localDefs) {
|
|
57
51
|
for (const { functionCall, called } of calledEnvs) {
|
|
58
52
|
let callDependencies = null;
|
|
@@ -87,7 +81,7 @@ function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextG
|
|
|
87
81
|
};
|
|
88
82
|
}
|
|
89
83
|
if (callDependencies === null) {
|
|
90
|
-
callDependencies = nextGraph.getVertex(functionCall, true)?.
|
|
84
|
+
callDependencies = nextGraph.getVertex(functionCall, true)?.controlDependencies;
|
|
91
85
|
}
|
|
92
86
|
inputEnvironment = (0, overwrite_1.overwriteEnvironment)(inputEnvironment, environment, callDependencies);
|
|
93
87
|
}
|
|
@@ -108,11 +102,11 @@ function processExpressionList(name, args, rootId, data) {
|
|
|
108
102
|
const nextGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
|
|
109
103
|
let out = [];
|
|
110
104
|
const exitPoints = [];
|
|
111
|
-
|
|
105
|
+
const activeCdsAtStart = data.controlDependencies;
|
|
106
|
+
const invertExitCds = [];
|
|
112
107
|
const processedExpressions = [];
|
|
113
108
|
let defaultReturnExpr = undefined;
|
|
114
109
|
for (const expression of expressions) {
|
|
115
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `processing expression ${++expressionCounter} of ${expressions.length}`);
|
|
116
110
|
if (expression === undefined) {
|
|
117
111
|
processedExpressions.push(undefined);
|
|
118
112
|
continue;
|
|
@@ -126,16 +120,25 @@ function processExpressionList(name, args, rootId, data) {
|
|
|
126
120
|
// if the expression contained next or break anywhere before the next loop, the "overwrite" should be an "append", because we do not know if the rest is executed
|
|
127
121
|
// update the environments for the next iteration with the previous writes
|
|
128
122
|
if (exitPoints.length > 0) {
|
|
129
|
-
processed.out = (0, reference_to_maybe_1.makeAllMaybe)(processed.out, nextGraph, processed.environment, true);
|
|
130
|
-
processed.in = (0, reference_to_maybe_1.makeAllMaybe)(processed.in, nextGraph, processed.environment, false);
|
|
123
|
+
processed.out = (0, reference_to_maybe_1.makeAllMaybe)(processed.out, nextGraph, processed.environment, true, invertExitCds);
|
|
124
|
+
processed.in = (0, reference_to_maybe_1.makeAllMaybe)(processed.in, nextGraph, processed.environment, false, invertExitCds);
|
|
131
125
|
processed.unknownReferences = (0, reference_to_maybe_1.makeAllMaybe)(processed.unknownReferences, nextGraph, processed.environment, false);
|
|
132
126
|
}
|
|
133
|
-
(0, info_1.addNonDefaultExitPoints)(exitPoints, processed.exitPoints);
|
|
134
127
|
out = out.concat(processed.out);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
128
|
+
// all inputs that have not been written until now are read!
|
|
129
|
+
for (const read of processed.in.concat(processed.unknownReferences)) {
|
|
130
|
+
linkReadNameToWriteIfPossible(read, environment, listEnvironments, remainingRead, nextGraph);
|
|
131
|
+
}
|
|
138
132
|
const calledEnvs = (0, linker_1.linkFunctionCalls)(nextGraph, data.completeAst.idMap, processed.graph);
|
|
133
|
+
for (const c of calledEnvs) {
|
|
134
|
+
if (c.propagateExitPoints.length > 0) {
|
|
135
|
+
for (const exit of c.propagateExitPoints) {
|
|
136
|
+
processed.exitPoints.push(exit);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
(0, info_1.addNonDefaultExitPoints)(exitPoints, invertExitCds, activeCdsAtStart, processed.exitPoints);
|
|
141
|
+
environment = exitPoints.length > 0 ? (0, overwrite_1.overwriteEnvironment)(environment, processed.environment) : processed.environment;
|
|
139
142
|
// if the called function has global redefinitions, we have to keep them within our environment
|
|
140
143
|
environment = updateSideEffectsForCalledFunctions(calledEnvs, environment, nextGraph, processed.out);
|
|
141
144
|
for (const { nodeId } of processed.out) {
|
|
@@ -149,10 +152,13 @@ function processExpressionList(name, args, rootId, data) {
|
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
if (defaultReturnExpr) {
|
|
152
|
-
exitPoints.push({
|
|
155
|
+
exitPoints.push(data.controlDependencies ? {
|
|
153
156
|
type: 0 /* ExitPointType.Default */,
|
|
154
157
|
nodeId: defaultReturnExpr.entryPoint,
|
|
155
158
|
controlDependencies: data.controlDependencies
|
|
159
|
+
} : {
|
|
160
|
+
type: 0 /* ExitPointType.Default */,
|
|
161
|
+
nodeId: defaultReturnExpr.entryPoint
|
|
156
162
|
});
|
|
157
163
|
}
|
|
158
164
|
const ingoing = remainingRead.values().toArray().flat();
|
|
@@ -186,7 +192,8 @@ function processExpressionList(name, args, rootId, data) {
|
|
|
186
192
|
graph: nextGraph,
|
|
187
193
|
/* if we have no group, we take the last evaluated expr */
|
|
188
194
|
entryPoint: meId,
|
|
189
|
-
exitPoints: exitPoints
|
|
195
|
+
exitPoints: exitPoints,
|
|
196
|
+
hooks: processedExpressions.flatMap(p => p?.hooks ?? []),
|
|
190
197
|
};
|
|
191
198
|
}
|
|
192
199
|
//# sourceMappingURL=built-in-expression-list.js.map
|
|
@@ -73,7 +73,8 @@ function processForLoop(name, args, rootId, data) {
|
|
|
73
73
|
graph: nextGraph,
|
|
74
74
|
entryPoint: name.info.id,
|
|
75
75
|
exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
|
|
76
|
-
environment: outEnvironment
|
|
76
|
+
environment: outEnvironment,
|
|
77
|
+
hooks: variable.hooks.concat(vector.hooks, body.hooks),
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
//# sourceMappingURL=built-in-for-loop.js.map
|
|
@@ -12,7 +12,11 @@ import type { ReadOnlyFlowrAnalyzerContext } from '../../../../../../project/con
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function processFunctionDefinition<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Retrieve the active environment when entering a function definition or call
|
|
16
|
+
* @param callerEnvironment - environment at the call site / function definition site
|
|
17
|
+
* @param baseEnvironment - base environment within the function definition / call
|
|
18
|
+
* @param ctx - analyzer context
|
|
19
|
+
* @returns active environment within the function definition / call
|
|
16
20
|
*/
|
|
17
21
|
export declare function retrieveActiveEnvironment(callerEnvironment: REnvironmentInformation | undefined, baseEnvironment: REnvironmentInformation, ctx: ReadOnlyFlowrAnalyzerContext): REnvironmentInformation;
|
|
18
22
|
/**
|
|
@@ -5,6 +5,7 @@ exports.retrieveActiveEnvironment = retrieveActiveEnvironment;
|
|
|
5
5
|
exports.updateNestedFunctionClosures = updateNestedFunctionClosures;
|
|
6
6
|
exports.updateNestedFunctionCalls = updateNestedFunctionCalls;
|
|
7
7
|
const processor_1 = require("../../../../../processor");
|
|
8
|
+
const info_1 = require("../../../../../info");
|
|
8
9
|
const linker_1 = require("../../../../linker");
|
|
9
10
|
const known_call_handling_1 = require("../known-call-handling");
|
|
10
11
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
@@ -20,6 +21,8 @@ const resolve_by_name_1 = require("../../../../../environments/resolve-by-name")
|
|
|
20
21
|
const edge_1 = require("../../../../../graph/edge");
|
|
21
22
|
const log_1 = require("../../../../../../util/log");
|
|
22
23
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
24
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
25
|
+
const hooks_1 = require("../../../../../hooks");
|
|
23
26
|
/**
|
|
24
27
|
* Process a function definition, i.e., `function(a, b) { ... }`
|
|
25
28
|
*/
|
|
@@ -31,19 +34,23 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
31
34
|
/* we remove the last argument, as it is the body */
|
|
32
35
|
const parameters = args.slice(0, -1);
|
|
33
36
|
const bodyArg = (0, unpack_argument_1.unpackNonameArg)(args[args.length - 1]);
|
|
34
|
-
(0, assert_1.guard)(bodyArg !== undefined, () => `Function Definition ${JSON.stringify(args)} has
|
|
37
|
+
(0, assert_1.guard)(bodyArg !== undefined, () => `Function Definition ${JSON.stringify(args)} has no body! This is bad!`);
|
|
35
38
|
const originalEnvironment = data.environment;
|
|
36
39
|
// within a function def we do not pass on the outer binds as they could be overwritten when called
|
|
37
40
|
data = prepareFunctionEnvironment(data);
|
|
38
41
|
const subgraph = new graph_1.DataflowGraph(data.completeAst.idMap);
|
|
39
42
|
let readInParameters = [];
|
|
43
|
+
const paramIds = [];
|
|
40
44
|
for (const param of parameters) {
|
|
41
|
-
(0, assert_1.guard)(param !== r_function_call_1.EmptyArgument, () => `Empty
|
|
45
|
+
(0, assert_1.guard)(param !== r_function_call_1.EmptyArgument, () => `Empty param arg in function definition ${name.content}, ${JSON.stringify(args)}`);
|
|
42
46
|
const processed = (0, processor_1.processDataflowFor)(param, data);
|
|
47
|
+
if (param.value?.type === type_1.RType.Parameter) {
|
|
48
|
+
paramIds.push(param.value.name.info.id);
|
|
49
|
+
}
|
|
43
50
|
subgraph.mergeWith(processed.graph);
|
|
44
51
|
const read = processed.in.concat(processed.unknownReferences);
|
|
45
52
|
(0, linker_1.linkInputs)(read, data.environment, readInParameters, subgraph, false);
|
|
46
|
-
data =
|
|
53
|
+
data.environment = (0, overwrite_1.overwriteEnvironment)(data.environment, processed.environment);
|
|
47
54
|
}
|
|
48
55
|
const paramsEnvironments = data.environment;
|
|
49
56
|
const body = (0, processor_1.processDataflowFor)(bodyArg, data);
|
|
@@ -51,7 +58,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
51
58
|
// This is the correct behavior, even if someone uses non-`=` arguments in functions.
|
|
52
59
|
const bodyEnvironment = body.environment;
|
|
53
60
|
readInParameters = findPromiseLinkagesForParameters(subgraph, readInParameters, paramsEnvironments, body);
|
|
54
|
-
const readInBody =
|
|
61
|
+
const readInBody = body.in.concat(body.unknownReferences);
|
|
55
62
|
// there is no uncertainty regarding the arguments, as if a function header is executed, so is its body
|
|
56
63
|
const remainingRead = (0, linker_1.linkInputs)(readInBody, paramsEnvironments, readInParameters.slice(), body.graph, true /* functions do not have to be called */);
|
|
57
64
|
// functions can be called multiple times,
|
|
@@ -59,7 +66,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
59
66
|
/* theoretically, we should just check if there is a global effect-write somewhere within */
|
|
60
67
|
if (remainingRead.length > 0) {
|
|
61
68
|
const nameIdShares = (0, linker_1.produceNameSharedIdMap)(remainingRead);
|
|
62
|
-
const definedInLocalEnvironment = new Set(
|
|
69
|
+
const definedInLocalEnvironment = new Set(Array.from(bodyEnvironment.current.memory.values()).flat().map(d => d.nodeId));
|
|
63
70
|
// Everything that is in body.out but not within the local environment populated for the function scope is a potential escape ~> global definition
|
|
64
71
|
const globalBodyOut = body.out.filter(d => !definedInLocalEnvironment.has(d.nodeId));
|
|
65
72
|
(0, linker_1.linkCircularRedefinitionsWithinALoop)(body.graph, nameIdShares, globalBodyOut);
|
|
@@ -72,28 +79,50 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
72
79
|
tag: vertex_1.VertexType.Use,
|
|
73
80
|
id: read.nodeId,
|
|
74
81
|
environment: undefined,
|
|
75
|
-
|
|
82
|
+
controlDependencies: undefined
|
|
76
83
|
}, data.ctx.env.makeCleanEnv());
|
|
77
84
|
}
|
|
78
85
|
}
|
|
86
|
+
const compactedHooks = (0, hooks_1.compactHookStates)(body.hooks);
|
|
87
|
+
const exitHooks = (0, hooks_1.getHookInformation)(compactedHooks, hooks_1.KnownHooks.OnFnExit);
|
|
79
88
|
const flow = {
|
|
80
89
|
unknownReferences: [],
|
|
81
90
|
in: remainingRead,
|
|
82
91
|
out: [],
|
|
83
92
|
entryPoint: body.entryPoint,
|
|
84
93
|
graph: new Set(subgraph.rootIds()),
|
|
85
|
-
environment: outEnvironment
|
|
94
|
+
environment: outEnvironment,
|
|
95
|
+
hooks: compactedHooks
|
|
86
96
|
};
|
|
87
97
|
updateNestedFunctionClosures(subgraph, outEnvironment, name.info.id);
|
|
88
98
|
const exitPoints = body.exitPoints;
|
|
99
|
+
const readParams = {};
|
|
100
|
+
for (const paramId of paramIds) {
|
|
101
|
+
const ingoing = subgraph.ingoingEdges(paramId);
|
|
102
|
+
readParams[paramId] = ingoing?.values().some(({ types }) => (0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Reads)) ?? false;
|
|
103
|
+
}
|
|
104
|
+
let afterHookExitPoints = exitPoints?.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 0 /* ExitPointType.Default */ || e.type === 4 /* ExitPointType.Error */) ?? [];
|
|
105
|
+
for (const hook of exitHooks) {
|
|
106
|
+
const vert = subgraph.getVertex(hook.id);
|
|
107
|
+
if (vert?.tag !== vertex_1.VertexType.FunctionDefinition) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// call all hooks
|
|
111
|
+
subgraph.addEdge(rootId, hook.id, edge_1.EdgeType.Calls);
|
|
112
|
+
const hookExitPoints = vert.exitPoints.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 4 /* ExitPointType.Error */);
|
|
113
|
+
if (hookExitPoints.length > 0) {
|
|
114
|
+
afterHookExitPoints = (0, info_1.overwriteExitPoints)(afterHookExitPoints, hookExitPoints);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
89
117
|
const graph = new graph_1.DataflowGraph(data.completeAst.idMap).mergeWith(subgraph, false);
|
|
90
118
|
graph.addVertex({
|
|
91
119
|
tag: vertex_1.VertexType.FunctionDefinition,
|
|
92
120
|
id: name.info.id,
|
|
93
121
|
environment: (0, scoping_1.popLocalEnvironment)(outEnvironment),
|
|
94
|
-
|
|
122
|
+
controlDependencies: data.controlDependencies,
|
|
123
|
+
params: readParams,
|
|
95
124
|
subflow: flow,
|
|
96
|
-
exitPoints:
|
|
125
|
+
exitPoints: afterHookExitPoints
|
|
97
126
|
}, data.ctx.env.makeCleanEnv());
|
|
98
127
|
return {
|
|
99
128
|
/* nothing escapes a function definition, but the function itself, will be forced in assignment: { nodeId: functionDefinition.info.id, scope: data.activeScope, used: 'always', name: functionDefinition.info.id as string } */
|
|
@@ -103,13 +132,16 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
103
132
|
exitPoints: [],
|
|
104
133
|
entryPoint: name.info.id,
|
|
105
134
|
graph,
|
|
106
|
-
environment: originalEnvironment
|
|
135
|
+
environment: originalEnvironment,
|
|
136
|
+
hooks: []
|
|
107
137
|
};
|
|
108
138
|
}
|
|
109
|
-
// this is no longer necessary when we update environments to be back to front (e.g., with a list of environments)
|
|
110
|
-
// this favors the bigger environment
|
|
111
139
|
/**
|
|
112
|
-
*
|
|
140
|
+
* Retrieve the active environment when entering a function definition or call
|
|
141
|
+
* @param callerEnvironment - environment at the call site / function definition site
|
|
142
|
+
* @param baseEnvironment - base environment within the function definition / call
|
|
143
|
+
* @param ctx - analyzer context
|
|
144
|
+
* @returns active environment within the function definition / call
|
|
113
145
|
*/
|
|
114
146
|
function retrieveActiveEnvironment(callerEnvironment, baseEnvironment, ctx) {
|
|
115
147
|
callerEnvironment ??= ctx.env.makeCleanEnv();
|
|
@@ -168,9 +200,10 @@ function updateNestedFunctionCalls(graph, outEnvironment) {
|
|
|
168
200
|
// track *all* function definitions - including those nested within the current graph,
|
|
169
201
|
// try to resolve their 'in' by only using the lowest scope which will be popped after this definition
|
|
170
202
|
for (const [id, { onlyBuiltin, environment, name }] of graph.verticesOfType(vertex_1.VertexType.FunctionCall)) {
|
|
171
|
-
if (
|
|
203
|
+
if (onlyBuiltin || !name) {
|
|
172
204
|
continue;
|
|
173
205
|
}
|
|
206
|
+
let effectiveEnvironment = outEnvironment;
|
|
174
207
|
// only the call environment counts!
|
|
175
208
|
if (environment) {
|
|
176
209
|
while (outEnvironment.level > environment.level) {
|
|
@@ -179,16 +212,21 @@ function updateNestedFunctionCalls(graph, outEnvironment) {
|
|
|
179
212
|
while (outEnvironment.level < environment.level) {
|
|
180
213
|
outEnvironment = (0, scoping_1.pushLocalEnvironment)(outEnvironment);
|
|
181
214
|
}
|
|
215
|
+
effectiveEnvironment = (0, overwrite_1.overwriteEnvironment)(outEnvironment, environment);
|
|
182
216
|
}
|
|
183
|
-
const
|
|
184
|
-
const targets = (0, linker_1.getAllFunctionCallTargets)(id, graph, effectiveEnvironment);
|
|
217
|
+
const targets = new Set((0, linker_1.getAllFunctionCallTargets)(id, graph, effectiveEnvironment));
|
|
185
218
|
for (const target of targets) {
|
|
219
|
+
if ((0, built_in_1.isBuiltIn)(target)) {
|
|
220
|
+
graph.addEdge(id, target, edge_1.EdgeType.Calls);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
186
223
|
const targetVertex = graph.getVertex(target);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
224
|
+
// support reads on symbols
|
|
225
|
+
if (targetVertex?.tag === vertex_1.VertexType.Use) {
|
|
226
|
+
graph.addEdge(id, target, edge_1.EdgeType.Reads);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
else if (targetVertex?.tag !== vertex_1.VertexType.FunctionDefinition) {
|
|
192
230
|
continue;
|
|
193
231
|
}
|
|
194
232
|
graph.addEdge(id, target, edge_1.EdgeType.Calls);
|
|
@@ -76,8 +76,8 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
76
76
|
else {
|
|
77
77
|
finalEnvironment = (0, append_1.appendEnvironment)(thenEnvironment, otherwise ? otherwise.environment : cond.environment);
|
|
78
78
|
}
|
|
79
|
-
const cdTrue = { id: rootId, when: true };
|
|
80
|
-
const cdFalse = { id: rootId, when: false };
|
|
79
|
+
const cdTrue = [{ id: rootId, when: true }];
|
|
80
|
+
const cdFalse = [{ id: rootId, when: false }];
|
|
81
81
|
// again within an if-then-else we consider all actives to be read
|
|
82
82
|
const ingoing = cond.in.concat(makeThenMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(then?.in, nextGraph, finalEnvironment, false, cdTrue) : then?.in ?? [], makeOtherwiseMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(otherwise?.in, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.in ?? [], cond.unknownReferences, makeThenMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(then?.unknownReferences, nextGraph, finalEnvironment, false, cdTrue) : then?.unknownReferences ?? [], makeOtherwiseMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(otherwise?.unknownReferences, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.unknownReferences ?? []);
|
|
83
83
|
// we assign all with a maybe marker
|
|
@@ -102,7 +102,8 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
102
102
|
exitPoints,
|
|
103
103
|
entryPoint: rootId,
|
|
104
104
|
environment: finalEnvironment,
|
|
105
|
-
graph: nextGraph
|
|
105
|
+
graph: nextGraph,
|
|
106
|
+
hooks: cond.hooks.concat(then?.hooks ?? [], otherwise?.hooks ?? []),
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
//# sourceMappingURL=built-in-if-then-else.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
2
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
5
|
+
import { type RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
6
|
+
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
import type { KnownHooks } from '../../../../../hooks';
|
|
8
|
+
export interface RegisterHookConfig {
|
|
9
|
+
/** name of the hook to register, 'fn-exit' if it triggers on exit */
|
|
10
|
+
hook: KnownHooks;
|
|
11
|
+
args: {
|
|
12
|
+
/** the expression to register as hook */
|
|
13
|
+
expr: {
|
|
14
|
+
idx?: number;
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
/** argument to control whether to add or replace the current hook */
|
|
18
|
+
add?: {
|
|
19
|
+
idx?: number;
|
|
20
|
+
name: string;
|
|
21
|
+
default: boolean;
|
|
22
|
+
};
|
|
23
|
+
/** argument to control whether to run the hook before or after other hooks */
|
|
24
|
+
after?: {
|
|
25
|
+
idx?: number;
|
|
26
|
+
name: string;
|
|
27
|
+
default: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Process a hook such as `on.exit`
|
|
33
|
+
*/
|
|
34
|
+
export declare function processRegisterHook<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: RegisterHookConfig): DataflowInformation;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processRegisterHook = processRegisterHook;
|
|
4
|
+
const known_call_handling_1 = require("../known-call-handling");
|
|
5
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
6
|
+
const linker_1 = require("../../../../linker");
|
|
7
|
+
const common_1 = require("../common");
|
|
8
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
|
+
const range_1 = require("../../../../../../util/range");
|
|
10
|
+
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
11
|
+
const general_1 = require("../../../../../eval/values/general");
|
|
12
|
+
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
13
|
+
/**
|
|
14
|
+
* Process a hook such as `on.exit`
|
|
15
|
+
*/
|
|
16
|
+
function processRegisterHook(name, args, rootId, data, config) {
|
|
17
|
+
const params = {
|
|
18
|
+
[config.args.expr.name]: 'expr',
|
|
19
|
+
};
|
|
20
|
+
if (config.args.add) {
|
|
21
|
+
params[config.args.add.name] = 'add';
|
|
22
|
+
}
|
|
23
|
+
if (config.args.after) {
|
|
24
|
+
params[config.args.after.name] = 'after';
|
|
25
|
+
}
|
|
26
|
+
params['...'] = '...';
|
|
27
|
+
const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
|
|
28
|
+
const exprIds = new Set(argMaps.entries().filter(([, v]) => v === 'expr').map(([k]) => k));
|
|
29
|
+
const addIds = config.args.add ? new Set(argMaps.entries().filter(([, v]) => v === 'add').map(([k]) => k)) : new Set();
|
|
30
|
+
const afterIds = config.args.after ? new Set(argMaps.entries().filter(([, v]) => v === 'after').map(([k]) => k)) : new Set();
|
|
31
|
+
const wrappedFunctions = new Set();
|
|
32
|
+
// we automatically transform the expr to a function definition that takes no arguments
|
|
33
|
+
const transformed = args.map(arg => {
|
|
34
|
+
if (arg === r_function_call_1.EmptyArgument) {
|
|
35
|
+
return r_function_call_1.EmptyArgument;
|
|
36
|
+
}
|
|
37
|
+
else if (exprIds.has(arg.info.id) && arg.value) {
|
|
38
|
+
const val = arg.value;
|
|
39
|
+
const wrapId = `${val.info.id}-hook-fn`;
|
|
40
|
+
wrappedFunctions.add(wrapId);
|
|
41
|
+
const wrapped = {
|
|
42
|
+
type: type_1.RType.FunctionDefinition,
|
|
43
|
+
location: val.location ?? (0, range_1.invalidRange)(),
|
|
44
|
+
parameters: [],
|
|
45
|
+
body: val,
|
|
46
|
+
lexeme: 'function',
|
|
47
|
+
info: {
|
|
48
|
+
...val.info,
|
|
49
|
+
id: wrapId,
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
data.completeAst.idMap.set(wrapId, wrapped);
|
|
53
|
+
return {
|
|
54
|
+
...arg,
|
|
55
|
+
value: wrapped
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return arg;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: transformed, rootId, data, origin: 'builtin:register-hook' });
|
|
63
|
+
const resolveArgs = {
|
|
64
|
+
graph: res.information.graph,
|
|
65
|
+
environment: res.information.environment,
|
|
66
|
+
resolve: data.ctx.config.solver.variables,
|
|
67
|
+
ctx: data.ctx,
|
|
68
|
+
idMap: data.completeAst.idMap,
|
|
69
|
+
full: true
|
|
70
|
+
};
|
|
71
|
+
const shouldAdd = addIds.size === 0 ? config.args.add?.default :
|
|
72
|
+
Array.from(addIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
|
|
73
|
+
.some(v => v.type === 'logical' && v.value !== false);
|
|
74
|
+
const shouldBeAfter = afterIds.size === 0 ? config.args.after?.default :
|
|
75
|
+
Array.from(afterIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
|
|
76
|
+
.some(v => v.type === 'logical' && v.value !== false);
|
|
77
|
+
const info = res.information;
|
|
78
|
+
const hooks = Array.from(wrappedFunctions, id => ({
|
|
79
|
+
type: config.hook,
|
|
80
|
+
id,
|
|
81
|
+
cds: data.controlDependencies,
|
|
82
|
+
add: shouldAdd,
|
|
83
|
+
after: shouldBeAfter
|
|
84
|
+
}));
|
|
85
|
+
info.hooks.push(...hooks);
|
|
86
|
+
if (data.environment.level <= 1) {
|
|
87
|
+
// if we are at the root level, we need to assume that the hook can cause unknown side-effects
|
|
88
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(info.graph, info.environment, rootId);
|
|
89
|
+
}
|
|
90
|
+
return info;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=built-in-register-hook.js.map
|
|
@@ -27,6 +27,7 @@ function processRepeatLoop(name, args, rootId, data) {
|
|
|
27
27
|
args: unpacked ? [unpacked] : args,
|
|
28
28
|
rootId,
|
|
29
29
|
data,
|
|
30
|
+
forceArgs: 'all',
|
|
30
31
|
patchData: (d, i) => {
|
|
31
32
|
if (i === 0) {
|
|
32
33
|
return { ...d, controlDependencies: [...d.controlDependencies ?? [], { id: name.info.id }] };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
|
+
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
|
+
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
/**
|
|
8
|
+
* Processes a built-in 'stopifnot' function call.
|
|
9
|
+
* This is special in that it may take a number of boolean expressions either via `...` or
|
|
10
|
+
* via `exprs` for which each expression is now evaluated individually:
|
|
11
|
+
* @example
|
|
12
|
+
* ```r
|
|
13
|
+
* stopifnot(exprs = {
|
|
14
|
+
* all.equal(pi, 3.1415927)
|
|
15
|
+
* 2 < 2
|
|
16
|
+
* all(1:10 < 12)
|
|
17
|
+
* "a" < "b"
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function processStopIfNot<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|