@eagleoutice/flowr 2.10.1 → 2.10.3
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 +31 -20
- package/abstract-interpretation/absint-visitor.d.ts +13 -8
- package/abstract-interpretation/absint-visitor.js +35 -26
- package/abstract-interpretation/data-frame/dataframe-domain.d.ts +1 -2
- package/abstract-interpretation/data-frame/dataframe-domain.js +14 -15
- package/abstract-interpretation/data-frame/mappers/access-mapper.js +2 -15
- package/abstract-interpretation/data-frame/mappers/arguments.d.ts +11 -17
- package/abstract-interpretation/data-frame/mappers/arguments.js +18 -18
- package/abstract-interpretation/data-frame/mappers/function-mapper.d.ts +41 -15
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +74 -48
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +2 -1
- package/abstract-interpretation/data-frame/semantics.d.ts +1 -1
- package/abstract-interpretation/data-frame/semantics.js +31 -35
- package/abstract-interpretation/data-frame/shape-inference.js +1 -1
- package/abstract-interpretation/domains/interval-domain.d.ts +1 -0
- package/abstract-interpretation/domains/interval-domain.js +3 -0
- package/abstract-interpretation/domains/product-domain.d.ts +9 -0
- package/abstract-interpretation/domains/product-domain.js +26 -6
- package/abstract-interpretation/domains/state-abstract-domain.d.ts +36 -22
- package/abstract-interpretation/domains/state-abstract-domain.js +169 -62
- package/abstract-interpretation/unsupported-functions.d.ts +10 -0
- package/abstract-interpretation/unsupported-functions.js +45 -0
- package/benchmark/slicer.js +10 -13
- package/cli/flowr.js +1 -1
- package/control-flow/control-flow-graph.js +13 -9
- package/control-flow/semantic-cfg-guided-visitor.d.ts +6 -0
- package/control-flow/semantic-cfg-guided-visitor.js +6 -0
- package/dataflow/environments/built-in-proc-name.d.ts +6 -0
- package/dataflow/environments/built-in-proc-name.js +6 -0
- package/dataflow/environments/built-in.d.ts +7 -5
- package/dataflow/environments/built-in.js +2 -0
- package/dataflow/environments/default-builtin-config.d.ts +442 -6
- package/dataflow/environments/default-builtin-config.js +158 -3
- package/dataflow/environments/overwrite.js +2 -5
- package/dataflow/graph/df-helper.d.ts +14 -4
- package/dataflow/graph/df-helper.js +36 -6
- package/dataflow/graph/graph.d.ts +10 -0
- package/dataflow/graph/graph.js +12 -0
- package/dataflow/instrument/instrument-dataflow-count.d.ts +10 -0
- package/dataflow/instrument/instrument-dataflow-count.js +10 -0
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +6 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-get.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-library.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-local.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.d.ts +23 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +80 -12
- package/dataflow/internal/process/functions/call/built-in/built-in-purrr-formula.d.ts +41 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-purrr-formula.js +179 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.d.ts +7 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +62 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-recall.d.ts +7 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-recall.js +15 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-dispatch.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-s-three-dispatch.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-special-bin-op.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.d.ts +2 -2
- package/dataflow/internal/process/functions/call/common.d.ts +2 -2
- package/dataflow/internal/process/functions/call/common.js +4 -3
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -2
- package/dataflow/internal/process/functions/call/named-call-handling.d.ts +2 -2
- package/documentation/wiki-absint.js +6 -5
- package/documentation/wiki-analyzer.js +0 -2
- package/documentation/wiki-cfg.js +3 -3
- package/documentation/wiki-linter.js +1 -0
- package/documentation/wiki-normalized-ast.js +7 -7
- package/documentation/wiki-query.js +29 -0
- package/linter/linter-rules.d.ts +24 -1
- package/linter/linter-rules.js +3 -1
- package/linter/rules/dataframe-access-validation.d.ts +1 -1
- package/linter/rules/dataframe-access-validation.js +3 -4
- package/linter/rules/roxygen-arguments.d.ts +35 -0
- package/linter/rules/roxygen-arguments.js +100 -0
- package/package.json +4 -5
- package/project/context/flowr-analyzer-context.d.ts +1 -8
- package/project/context/flowr-analyzer-context.js +1 -7
- package/project/context/flowr-analyzer-environment-context.d.ts +5 -0
- package/project/context/flowr-analyzer-environment-context.js +6 -0
- package/project/context/flowr-analyzer-files-context.d.ts +6 -0
- package/project/context/flowr-analyzer-files-context.js +4 -2
- package/project/flowr-analyzer-builder.js +1 -4
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +1 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +10 -5
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +1 -1
- package/queries/catalog/dependencies-query/function-info/library-functions.js +2 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.js +7 -2
- package/queries/catalog/files-query/files-query-executor.js +0 -1
- package/queries/catalog/input-sources-query/simple-input-classifier.d.ts +2 -0
- package/queries/catalog/input-sources-query/simple-input-classifier.js +5 -3
- package/r-bridge/data/data.d.ts +2 -2
- package/r-bridge/data/data.js +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +13 -5
- package/r-bridge/lang-4.x/ast/model/nodes/r-argument.js +14 -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-pipe.d.ts +9 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.js +13 -0
- package/r-bridge/lang-4.x/ast/model/versions.d.ts +2 -0
- package/r-bridge/lang-4.x/ast/model/versions.js +3 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.d.ts +1 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +1 -1
- package/r-bridge/roxygen2/documentation-provider.js +15 -6
- package/r-bridge/roxygen2/roxygen-ast.d.ts +3 -1
- package/search/flowr-search-builder.js +3 -2
- package/util/mermaid/ast.js +2 -1
- package/util/record.d.ts +23 -0
- package/util/record.js +33 -0
- package/util/version.js +1 -1
- package/abstract-interpretation/domains/mapped-abstract-domain.d.ts +0 -41
- package/abstract-interpretation/domains/mapped-abstract-domain.js +0 -213
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
/**
|
|
8
8
|
* Processes a built-in 'get' function call.
|
|
9
9
|
*/
|
|
10
|
-
export declare function processGet<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
10
|
+
export declare function processGet<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -2,7 +2,7 @@ import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
|
2
2
|
import { type DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
4
4
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
|
-
import type {
|
|
5
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
/** `if(<cond>) <then> else <else>` built-in function configuration, make sure to not reuse indices */
|
|
8
8
|
export interface IfThenElseConfig {
|
|
@@ -20,4 +20,4 @@ export interface IfThenElseConfig {
|
|
|
20
20
|
* For example, `if(cond) thenExpr else elseExpr` and `if(cond) thenExpr`.
|
|
21
21
|
* The arguments will be either `[cond, thenExpr]` or `[cond, thenExpr, elseExpr]`.
|
|
22
22
|
*/
|
|
23
|
-
export declare function processIfThenElse<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
23
|
+
export declare function processIfThenElse<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config?: IfThenElseConfig): DataflowInformation;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
/**
|
|
8
8
|
* Process a library call like `library` or `require`
|
|
9
9
|
*/
|
|
10
|
-
export declare function processLibrary<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
10
|
+
export declare function processLibrary<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
2
2
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
4
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
@@ -12,4 +12,4 @@ import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
|
12
12
|
* list(a = 1, b = 2)
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export declare function processList<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
15
|
+
export declare function processList<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
export interface LocalFunctionConfiguration {
|
|
@@ -15,4 +15,4 @@ export interface LocalFunctionConfiguration {
|
|
|
15
15
|
/**
|
|
16
16
|
* Processes a built-in 'local' function call.
|
|
17
17
|
*/
|
|
18
|
-
export declare function processLocal<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
18
|
+
export declare function processLocal<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: LocalFunctionConfiguration): DataflowInformation;
|
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
-
import type {
|
|
3
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
4
4
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
import type { BrandedIdentifier } from '../../../../../environments/identifier';
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* Configuration options for the basic R pipe
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
interface PipeConfiguration {
|
|
12
|
+
pipePlaceholderName: BrandedIdentifier;
|
|
13
|
+
/**
|
|
14
|
+
* this is for a pipe like `%<>%` which assigns its lhs
|
|
15
|
+
*/
|
|
16
|
+
assignLhs: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to return the lhs (e.g., with the TPipe)
|
|
19
|
+
*/
|
|
20
|
+
returnLhs: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* If so, also allow a symbol instead of a function as rhs, if it is the case, this automatically converts the symbol on the rhs to a function call
|
|
23
|
+
*/
|
|
24
|
+
rhsMightBeSymbol?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Support for R's pipe functions like `|>` or magrittr's `%>%`
|
|
28
|
+
*/
|
|
29
|
+
export declare function processPipe<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, { pipePlaceholderName, assignLhs, returnLhs, rhsMightBeSymbol }: PipeConfiguration): DataflowInformation;
|
|
30
|
+
export {};
|
|
@@ -4,41 +4,109 @@ exports.processPipe = processPipe;
|
|
|
4
4
|
const known_call_handling_1 = require("../known-call-handling");
|
|
5
5
|
const assert_1 = require("../../../../../../util/assert");
|
|
6
6
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
7
|
+
const model_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/model");
|
|
7
8
|
const logger_1 = require("../../../../../logger");
|
|
8
9
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
10
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
10
11
|
const edge_1 = require("../../../../../graph/edge");
|
|
11
12
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
13
|
+
const make_argument_1 = require("../argument/make-argument");
|
|
14
|
+
const built_in_assignment_1 = require("./built-in-assignment");
|
|
12
15
|
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
16
|
+
const log_1 = require("../../../../../../util/log");
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
18
|
+
* Support for R's pipe functions like `|>` or magrittr's `%>%`
|
|
15
19
|
*/
|
|
16
|
-
function processPipe(name, args, rootId, data) {
|
|
17
|
-
const
|
|
20
|
+
function processPipe(name, args, rootId, data, { pipePlaceholderName, assignLhs, returnLhs, rhsMightBeSymbol = false }) {
|
|
21
|
+
const fCallInfo = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.Pipe });
|
|
22
|
+
const processedArguments = fCallInfo.processedArguments;
|
|
23
|
+
let information = fCallInfo.information;
|
|
18
24
|
if (args.length !== 2) {
|
|
19
25
|
logger_1.dataflowLogger.warn(`Pipe ${identifier_1.Identifier.toString(name.content)} has something else than 2 arguments, skipping`);
|
|
20
26
|
return information;
|
|
21
27
|
}
|
|
22
28
|
const [lhs, rhs] = args.map(e => (0, unpack_argument_1.unpackNonameArg)(e));
|
|
23
29
|
(0, assert_1.guard)(lhs !== undefined && rhs !== undefined, () => `lhs and rhs must be present, but ${JSON.stringify(lhs)} and ${JSON.stringify(rhs)} were found instead.`);
|
|
24
|
-
|
|
30
|
+
// If this is an assigning pipe (e.g., %<>%), perform the assignment writeback using the built-in
|
|
31
|
+
// assignment processor: target <- source where target is the original lhs and source is the rhs call
|
|
32
|
+
if (assignLhs) {
|
|
33
|
+
// create unnamed args for target and source
|
|
34
|
+
const targetArg = (0, make_argument_1.toUnnamedArgument)(lhs, data.completeAst.idMap);
|
|
35
|
+
const sourceArg = (0, make_argument_1.toUnnamedArgument)(rhs, data.completeAst.idMap);
|
|
36
|
+
// construct a synthetic symbol for the assignment operator '<-'
|
|
37
|
+
const assignSym = {
|
|
38
|
+
type: type_1.RType.Symbol,
|
|
39
|
+
info: name.info,
|
|
40
|
+
content: identifier_1.Identifier.make('<-', 'base'),
|
|
41
|
+
lexeme: '<-',
|
|
42
|
+
location: name.location
|
|
43
|
+
};
|
|
44
|
+
information = (0, built_in_assignment_1.processAssignment)(assignSym, [targetArg, sourceArg], rootId, data, { canBeReplacement: true, mayHaveMoreArgs: true });
|
|
45
|
+
}
|
|
46
|
+
let treatedAsFunctionCall = false;
|
|
47
|
+
if (rhs.type === type_1.RType.Symbol && rhsMightBeSymbol) {
|
|
48
|
+
// convert a plain symbol on the RHS into a function-call vertex so we can treat it like `df %>% head`
|
|
49
|
+
const maybeVertex = information.graph.getVertex(rhs.info.id);
|
|
50
|
+
if (maybeVertex && maybeVertex.tag === vertex_1.VertexType.Use) {
|
|
51
|
+
information.graph.updateToFunctionCall({
|
|
52
|
+
tag: vertex_1.VertexType.FunctionCall,
|
|
53
|
+
id: rhs.info.id,
|
|
54
|
+
name: rhs.content,
|
|
55
|
+
args: [],
|
|
56
|
+
environment: data.environment,
|
|
57
|
+
onlyBuiltin: false,
|
|
58
|
+
cds: data.cds,
|
|
59
|
+
origin: [built_in_proc_name_1.BuiltInProcName.Function]
|
|
60
|
+
});
|
|
61
|
+
treatedAsFunctionCall = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (treatedAsFunctionCall || rhs.type === type_1.RType.FunctionCall) {
|
|
25
65
|
const functionCallNode = information.graph.getVertex(rhs.info.id);
|
|
26
66
|
(0, assert_1.guard)(functionCallNode?.tag === vertex_1.VertexType.FunctionCall, () => `Expected function call node with id ${rhs.info.id} to be a function call node, but got ${functionCallNode?.tag} instead.`);
|
|
27
|
-
// make the lhs an argument node:
|
|
67
|
+
// make the lhs an argument node (or link it to placeholders within the rhs call):
|
|
28
68
|
const argId = lhs.info.id;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
69
|
+
// find all symbol occurrences inside the rhs function call AST that match the placeholder name
|
|
70
|
+
const occurrenceIds = [];
|
|
71
|
+
model_1.RNode.visitAst(rhs, (node) => {
|
|
72
|
+
if (node.type === type_1.RType.Symbol && node.content === pipePlaceholderName) {
|
|
73
|
+
occurrenceIds.push(node.info.id);
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
35
76
|
});
|
|
36
|
-
|
|
77
|
+
if (occurrenceIds.length > 0) {
|
|
78
|
+
if (occurrenceIds.length !== 1) {
|
|
79
|
+
log_1.log.warn(`Expected exactly one occurrence of the pipe placeholder '${identifier_1.Identifier.toString(pipePlaceholderName)}' in the rhs of the pipe, but found ${occurrenceIds.length}. Linking all occurrences to the lhs.`);
|
|
80
|
+
}
|
|
81
|
+
for (const occId of occurrenceIds) {
|
|
82
|
+
information.graph.addEdge(occId, argId, edge_1.EdgeType.Reads);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
logger_1.dataflowLogger.trace(`Linking pipe arg ${argId} as first argument of ${rhs.info.id}`);
|
|
87
|
+
functionCallNode.args.unshift({
|
|
88
|
+
name: undefined,
|
|
89
|
+
nodeId: argId,
|
|
90
|
+
cds: data.cds,
|
|
91
|
+
type: identifier_1.ReferenceType.Function
|
|
92
|
+
});
|
|
93
|
+
information.graph.addEdge(functionCallNode.id, argId, edge_1.EdgeType.Argument | edge_1.EdgeType.Reads);
|
|
94
|
+
}
|
|
37
95
|
}
|
|
38
96
|
else {
|
|
39
97
|
logger_1.dataflowLogger.warn(`Expected rhs of pipe to be a function call, but got ${rhs.type} instead.`);
|
|
40
98
|
}
|
|
41
99
|
const firstArgument = processedArguments[0];
|
|
100
|
+
// If requested, return the lhs value (tee/TPipe semantics): add a Returns edge to the lhs entry
|
|
101
|
+
if (firstArgument && returnLhs) {
|
|
102
|
+
information.graph.addEdge(rootId, firstArgument.entryPoint, edge_1.EdgeType.Returns);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const secondArgument = processedArguments[1];
|
|
106
|
+
if (secondArgument && !returnLhs) {
|
|
107
|
+
information.graph.addEdge(rootId, secondArgument.entryPoint, edge_1.EdgeType.Returns);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
42
110
|
const uniqueIn = information.in.slice();
|
|
43
111
|
for (const ing of (firstArgument?.in ?? [])) {
|
|
44
112
|
if (!uniqueIn.some(e => e.nodeId === ing.nodeId)) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
4
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
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
|
+
interface BuiltInPurrrFormulaConfiguration {
|
|
8
|
+
/**
|
|
9
|
+
* Maps the created variable/variable to bind in the formula, to the argument that produces it.
|
|
10
|
+
* For example:
|
|
11
|
+
* ```ts
|
|
12
|
+
* {
|
|
13
|
+
* '.x': { index: 0, name: '.x' },
|
|
14
|
+
* '.y': { index: 1, name: '.y' }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
args: Record<string, {
|
|
19
|
+
index: number;
|
|
20
|
+
name: string;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* This represents the special argument that represents the formula.
|
|
24
|
+
* We map all additional arguments that are not in `ignore` to this list.
|
|
25
|
+
*/
|
|
26
|
+
'.f': {
|
|
27
|
+
index: number;
|
|
28
|
+
name: string;
|
|
29
|
+
};
|
|
30
|
+
/** arguments to additionally ignore when mapping the formulae */
|
|
31
|
+
ignore?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* if given, this is a name that indexes into the 'args' map and indicates whatever this function is to return
|
|
34
|
+
*/
|
|
35
|
+
returnArg?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Support for R's purr formula: `map(df, ~ .x + 1)`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function processPurrrFormula<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: BuiltInPurrrFormulaConfiguration): DataflowInformation;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processPurrrFormula = processPurrrFormula;
|
|
4
|
+
const known_call_handling_1 = require("../known-call-handling");
|
|
5
|
+
const linker_1 = require("../../../../linker");
|
|
6
|
+
const df_helper_1 = require("../../../../../graph/df-helper");
|
|
7
|
+
const vertex_1 = require("../../../../../graph/vertex");
|
|
8
|
+
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
9
|
+
const identifier_1 = require("../../../../../environments/identifier");
|
|
10
|
+
const common_1 = require("../common");
|
|
11
|
+
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
12
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
13
|
+
const model_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/model");
|
|
14
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
15
|
+
const edge_1 = require("../../../../../graph/edge");
|
|
16
|
+
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
17
|
+
const logger_1 = require("../../../../../logger");
|
|
18
|
+
const graph_1 = require("../../../../../graph/graph");
|
|
19
|
+
function linkOnSymbol(rootId, filteredArgs, node, graph, data) {
|
|
20
|
+
// If the formula is a symbol naming a function, try to resolve it in the call environment.
|
|
21
|
+
try {
|
|
22
|
+
const defs = (0, resolve_by_name_1.resolveByName)(node.content, data.environment, identifier_1.ReferenceType.Function) ?? [];
|
|
23
|
+
graph.addEdge(rootId, node.info.id, edge_1.EdgeType.Calls);
|
|
24
|
+
for (const def of defs) {
|
|
25
|
+
// Mark the call as calling this target
|
|
26
|
+
graph.addEdge(rootId, def.nodeId, edge_1.EdgeType.Calls);
|
|
27
|
+
// If the target directly maps to a function definition AST, try to link arguments to parameters
|
|
28
|
+
let linked = data.completeAst.idMap.get(def.nodeId);
|
|
29
|
+
if (linked?.type !== type_1.RType.FunctionDefinition) {
|
|
30
|
+
for (const vid of def.value) {
|
|
31
|
+
const candidate = data.completeAst.idMap.get(vid);
|
|
32
|
+
if (candidate && candidate.type === type_1.RType.FunctionDefinition) {
|
|
33
|
+
linked = candidate;
|
|
34
|
+
// also mark that we call the resolved function-definition node
|
|
35
|
+
graph.addEdge(rootId, vid, edge_1.EdgeType.Calls);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// we may find a candidate in the first check
|
|
41
|
+
if (linked?.type === type_1.RType.FunctionDefinition) {
|
|
42
|
+
try {
|
|
43
|
+
return (0, linker_1.linkArgumentsOnCall)(filteredArgs, linked.parameters, graph);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
logger_1.dataflowLogger.warn('Failed to link arguments to parameters for purr formula (symbol target), some bindings may be missing', { error: e });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
logger_1.dataflowLogger.warn('Failed to resolve symbol for purrr formula .f', { error: e });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Support for R's purr formula: `map(df, ~ .x + 1)`.
|
|
57
|
+
*/
|
|
58
|
+
function processPurrrFormula(name, args, rootId, data, config) {
|
|
59
|
+
const { information, callArgs } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.PurrrFormula });
|
|
60
|
+
const params = {};
|
|
61
|
+
for (const key of Object.keys(config.args)) {
|
|
62
|
+
params[config.args[key].name] = config.args[key].name;
|
|
63
|
+
}
|
|
64
|
+
// formula parameter
|
|
65
|
+
params[config['.f'].name] = config['.f'].name;
|
|
66
|
+
params['...'] = '...';
|
|
67
|
+
const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
|
|
68
|
+
const formulaArgId = argMaps.get(config['.f'].name)?.[0];
|
|
69
|
+
if (!formulaArgId) {
|
|
70
|
+
// nothing to do if we couldn't find the formula argument
|
|
71
|
+
return information;
|
|
72
|
+
}
|
|
73
|
+
const formulaArg = r_argument_1.RArgument.getWithId(args, formulaArgId);
|
|
74
|
+
const formulaNode = formulaArg ? (0, unpack_argument_1.unpackNonameArg)(formulaArg) : undefined;
|
|
75
|
+
if (!formulaNode) {
|
|
76
|
+
return information;
|
|
77
|
+
}
|
|
78
|
+
let argToParamMap = new Map();
|
|
79
|
+
// Prepare the list of call arguments to consider for linking (exclude the formula argument and ignored args)
|
|
80
|
+
const filteredCallArgs = [];
|
|
81
|
+
for (const arg of callArgs) {
|
|
82
|
+
const aid = graph_1.FunctionArgument.getId(arg);
|
|
83
|
+
if (aid === formulaArgId || aid === formulaNode.info.id || config.ignore?.includes(graph_1.FunctionArgument.getName(arg) ?? '')) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
filteredCallArgs.push(arg);
|
|
87
|
+
}
|
|
88
|
+
if (formulaNode.type === type_1.RType.FunctionDefinition) {
|
|
89
|
+
const fdef = formulaNode;
|
|
90
|
+
information.graph.addEdge(rootId, fdef.info.id, edge_1.EdgeType.Calls);
|
|
91
|
+
try {
|
|
92
|
+
argToParamMap = (0, linker_1.linkArgumentsOnCall)(filteredCallArgs, fdef.parameters, information.graph);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
logger_1.dataflowLogger.warn('Failed to link arguments to parameters for purr formula, some bindings may be missing', { error: e });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (formulaNode.type === type_1.RType.Symbol) {
|
|
99
|
+
linkOnSymbol(rootId, filteredCallArgs, formulaNode, information.graph, data);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
try {
|
|
103
|
+
df_helper_1.Dataflow.visitDfg(information.graph, formulaNode.info.id, (vtx) => {
|
|
104
|
+
if (vtx.tag === vertex_1.VertexType.FunctionCall) {
|
|
105
|
+
information.graph.addEdge(rootId, vtx.id, edge_1.EdgeType.Calls);
|
|
106
|
+
const targets = (0, linker_1.getAllFunctionCallTargets)(vtx.id, information.graph, vtx.environment);
|
|
107
|
+
for (const t of targets) {
|
|
108
|
+
information.graph.addEdge(rootId, t, edge_1.EdgeType.Calls);
|
|
109
|
+
const linked = data.completeAst.idMap.get(t);
|
|
110
|
+
if (linked && linked.type === type_1.RType.FunctionDefinition) {
|
|
111
|
+
try {
|
|
112
|
+
const map = (0, linker_1.linkArgumentsOnCall)(filteredCallArgs, linked.parameters, information.graph);
|
|
113
|
+
for (const [argId, paramId] of map.entries()) {
|
|
114
|
+
if (!argToParamMap.has(argId)) {
|
|
115
|
+
argToParamMap.set(argId, paramId);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
logger_1.dataflowLogger.warn('Failed to link arguments to parameters for purrr formula (list target)', { error: e });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return !vtx.origin.includes(built_in_proc_name_1.BuiltInProcName.List);
|
|
125
|
+
}
|
|
126
|
+
else if (vtx.tag === vertex_1.VertexType.Use) {
|
|
127
|
+
const node = data.completeAst.idMap.get(vtx.id);
|
|
128
|
+
if (node?.type === type_1.RType.Symbol) {
|
|
129
|
+
linkOnSymbol(rootId, filteredCallArgs, node, information.graph, data);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
logger_1.dataflowLogger.warn('Failed to traverse sub-dfg for purrr formula .f', { error: e });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const ignore = new Set(config.ignore ?? []);
|
|
140
|
+
model_1.RNode.visitAst(formulaNode, (node) => {
|
|
141
|
+
if (node.type === type_1.RType.Symbol) {
|
|
142
|
+
const sym = node;
|
|
143
|
+
const name = sym.content;
|
|
144
|
+
if (ignore.has(name)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
const mappingKey = config.args[name]?.name;
|
|
148
|
+
if (mappingKey) {
|
|
149
|
+
const pid = (argMaps.get(mappingKey) ?? [])[0];
|
|
150
|
+
if (!pid) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
const arg = r_argument_1.RArgument.getWithId(args, pid);
|
|
154
|
+
const producedNode = arg ? (0, unpack_argument_1.unpackNonameArg)(arg) : undefined;
|
|
155
|
+
if (!producedNode) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
// If this argument was linked to a parameter on the call, skip adding edge
|
|
159
|
+
const resultId = producedNode.info.id;
|
|
160
|
+
if (!argToParamMap.has(resultId)) {
|
|
161
|
+
information.graph.addEdge(node.info.id, resultId, edge_1.EdgeType.Reads);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
});
|
|
167
|
+
if (config.returnArg) {
|
|
168
|
+
const returnArgId = argMaps.get(config.returnArg)?.[0];
|
|
169
|
+
if (returnArgId) {
|
|
170
|
+
const returnArg = r_argument_1.RArgument.getWithId(args, returnArgId);
|
|
171
|
+
const producedNode = returnArg ? (0, unpack_argument_1.unpackNonameArg)(returnArg) : undefined;
|
|
172
|
+
if (producedNode) {
|
|
173
|
+
information.graph.addEdge(rootId, producedNode.info.id, edge_1.EdgeType.Returns);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return information;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=built-in-purrr-formula.js.map
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
7
|
import type { ForceArguments } from '../common';
|
|
8
|
+
interface QuoteConfig extends ForceArguments {
|
|
9
|
+
quoteArgumentsWithIndex: number;
|
|
10
|
+
envArgIndex?: number;
|
|
11
|
+
}
|
|
8
12
|
/**
|
|
9
13
|
* Process a call to `quote` or similar nse/substitution functions.
|
|
10
14
|
*/
|
|
11
|
-
export declare function processQuote<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
12
|
-
|
|
13
|
-
} & ForceArguments): DataflowInformation;
|
|
15
|
+
export declare function processQuote<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: QuoteConfig): DataflowInformation;
|
|
16
|
+
export {};
|
|
@@ -2,14 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.processQuote = processQuote;
|
|
4
4
|
const known_call_handling_1 = require("../known-call-handling");
|
|
5
|
+
const node_id_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
6
|
+
const vertex_1 = require("../../../../../graph/vertex");
|
|
7
|
+
const logger_1 = require("../../../../../logger");
|
|
8
|
+
const df_helper_1 = require("../../../../../graph/df-helper");
|
|
5
9
|
const edge_1 = require("../../../../../graph/edge");
|
|
6
10
|
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
11
|
+
const graph_1 = require("../../../../../graph/graph");
|
|
7
12
|
/**
|
|
8
13
|
* Process a call to `quote` or similar nse/substitution functions.
|
|
9
14
|
*/
|
|
10
15
|
function processQuote(name, args, rootId, data, config) {
|
|
11
16
|
const startEnv = data.environment;
|
|
12
|
-
|
|
17
|
+
let lastEnv = startEnv;
|
|
18
|
+
const { information, processedArguments, fnRef } = (0, known_call_handling_1.processKnownFunctionCall)({
|
|
19
|
+
name, args, rootId, data, forceArgs: config.forceArgs, origin: built_in_proc_name_1.BuiltInProcName.Quote,
|
|
20
|
+
patchData(data, index) {
|
|
21
|
+
if (index === config.quoteArgumentsWithIndex) {
|
|
22
|
+
lastEnv = data.environment;
|
|
23
|
+
return { ...data, environment: data.ctx.env.makeCleanEnv() };
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return { ...data, environment: lastEnv };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
13
30
|
let inRefs = [fnRef];
|
|
14
31
|
let outRefs = [];
|
|
15
32
|
let unknownRefs = [];
|
|
@@ -28,6 +45,50 @@ function processQuote(name, args, rootId, data, config) {
|
|
|
28
45
|
}
|
|
29
46
|
}
|
|
30
47
|
}
|
|
48
|
+
if (config?.envArgIndex !== undefined) {
|
|
49
|
+
const envProcessed = processedArguments[config.envArgIndex];
|
|
50
|
+
const exprProcessed = processedArguments[config.quoteArgumentsWithIndex];
|
|
51
|
+
if (envProcessed && exprProcessed) {
|
|
52
|
+
try {
|
|
53
|
+
// traverse the env processed DFG to find list calls (prefix-aware handling)
|
|
54
|
+
df_helper_1.Dataflow.visitDfg(envProcessed.graph, envProcessed.entryPoint, (vtx) => {
|
|
55
|
+
if (vtx.tag !== vertex_1.VertexType.FunctionCall) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!vtx.origin.includes(built_in_proc_name_1.BuiltInProcName.List)) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
const useMap = new Map();
|
|
62
|
+
for (const vType of [vertex_1.VertexType.Use, vertex_1.VertexType.FunctionCall]) {
|
|
63
|
+
for (const [useId] of exprProcessed.graph.verticesOfType(vType)) {
|
|
64
|
+
const rn = (0, node_id_1.recoverName)(useId, exprProcessed.graph.idMap);
|
|
65
|
+
if (rn) {
|
|
66
|
+
const arr = useMap.get(rn) ?? [];
|
|
67
|
+
arr.push(useId);
|
|
68
|
+
useMap.set(rn, arr);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (useMap.size === 0) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
const listFields = vtx.args.filter(graph_1.FunctionArgument.isNamed);
|
|
76
|
+
for (const field of listFields) {
|
|
77
|
+
const uses = useMap.get(field.name);
|
|
78
|
+
if (uses) {
|
|
79
|
+
for (const useId of uses) {
|
|
80
|
+
information.graph.addEdge(useId, field.nodeId, edge_1.EdgeType.Reads);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
logger_1.dataflowLogger.warn('Failed to apply substitute-style env list replacement in quote-like call', { error: e });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
31
92
|
return {
|
|
32
93
|
...information,
|
|
33
94
|
environment: startEnv,
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type
|
|
4
|
+
import { type PotentiallyEmptyRArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
interface RecallConfig {
|
|
8
|
+
/** whether to not handle as a recall function but rather as an unknown side effect if the argument is non-constant non-zero */
|
|
9
|
+
unknownOnNonZeroArg?: boolean;
|
|
10
|
+
}
|
|
7
11
|
/**
|
|
8
12
|
* Processes a built-in 'Recall' function call, linking
|
|
9
13
|
* the recall to the enveloping function closure.
|
|
10
14
|
*/
|
|
11
|
-
export declare function processRecall<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly
|
|
15
|
+
export declare function processRecall<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly PotentiallyEmptyRArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: RecallConfig): DataflowInformation;
|
|
16
|
+
export {};
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.processRecall = processRecall;
|
|
4
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 type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
7
|
+
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
5
8
|
const log_1 = require("../../../../../../util/log");
|
|
6
9
|
const edge_1 = require("../../../../../graph/edge");
|
|
7
10
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
@@ -12,7 +15,7 @@ const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-
|
|
|
12
15
|
* Processes a built-in 'Recall' function call, linking
|
|
13
16
|
* the recall to the enveloping function closure.
|
|
14
17
|
*/
|
|
15
|
-
function processRecall(name, args, rootId, data) {
|
|
18
|
+
function processRecall(name, args, rootId, data, config) {
|
|
16
19
|
const { information } = (0, known_call_handling_1.processKnownFunctionCall)({
|
|
17
20
|
name,
|
|
18
21
|
args,
|
|
@@ -20,6 +23,17 @@ function processRecall(name, args, rootId, data) {
|
|
|
20
23
|
data,
|
|
21
24
|
origin: built_in_proc_name_1.BuiltInProcName.Recall
|
|
22
25
|
});
|
|
26
|
+
// If requested, treat Recall as an unknown side effect when a single argument is provided and it is not the numeric literal 0.
|
|
27
|
+
if (config?.unknownOnNonZeroArg) {
|
|
28
|
+
if (args.length === 1 && args[0] !== r_function_call_1.EmptyArgument && args[0].value) {
|
|
29
|
+
const v = args[0].value;
|
|
30
|
+
// only allow the normal recall handling if the single arg is the literal 0
|
|
31
|
+
if (!(v.type === type_1.RType.Number && v.content.num === 0)) {
|
|
32
|
+
(0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
|
|
33
|
+
return information;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
23
37
|
let cur = data.environment.current;
|
|
24
38
|
let closure;
|
|
25
39
|
while (cur) {
|