@eagleoutice/flowr 2.1.8 → 2.1.10
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 +3 -0
- package/benchmark/summarizer/first-phase/process.js +6 -5
- package/cli/repl/commands/repl-dataflow.js +5 -2
- package/cli/repl/commands/repl-normalize.js +5 -2
- package/cli/repl/commands/repl-query.js +2 -2
- package/cli/repl/server/messages/message-query.js +1 -1
- package/config.d.ts +21 -0
- package/config.js +19 -2
- package/dataflow/environments/built-in.d.ts +2 -0
- package/dataflow/environments/built-in.js +2 -0
- package/dataflow/environments/default-builtin-config.js +48 -8
- package/dataflow/environments/define.js +78 -0
- package/dataflow/environments/environment.d.ts +46 -8
- package/dataflow/environments/environment.js +24 -1
- package/dataflow/environments/identifier.d.ts +60 -10
- package/dataflow/environments/identifier.js +11 -2
- package/dataflow/environments/resolve-by-name.d.ts +10 -5
- package/dataflow/environments/resolve-by-name.js +103 -5
- package/dataflow/extractor.js +5 -4
- package/dataflow/graph/dataflowgraph-builder.d.ts +6 -0
- package/dataflow/graph/dataflowgraph-builder.js +8 -0
- package/dataflow/graph/edge.d.ts +10 -4
- package/dataflow/graph/edge.js +12 -5
- package/dataflow/graph/graph.d.ts +41 -3
- package/dataflow/graph/graph.js +39 -34
- package/dataflow/graph/vertex.d.ts +122 -8
- package/dataflow/graph/vertex.js +19 -0
- package/dataflow/info.d.ts +79 -11
- package/dataflow/info.js +20 -0
- package/dataflow/internal/linker.d.ts +4 -2
- package/dataflow/internal/linker.js +12 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +11 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +141 -49
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +8 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +40 -11
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +16 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +83 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +15 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +50 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +29 -1
- package/dataflow/internal/process/functions/call/common.js +16 -2
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +3 -2
- package/documentation/doc-util/doc-dfg.d.ts +0 -1
- package/documentation/doc-util/doc-dfg.js +1 -14
- package/documentation/print-capabilities-markdown.js +1 -1
- package/documentation/print-dataflow-graph-wiki.js +26 -7
- package/documentation/print-interface-wiki.js +6 -1
- package/documentation/print-linting-and-testing-wiki.js +60 -26
- package/documentation/print-query-wiki.js +1 -1
- package/package.json +17 -3
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +13 -0
- package/queries/catalog/call-context-query/call-context-query-format.js +3 -1
- package/queries/catalog/call-context-query/cascade-action.d.ts +8 -0
- package/queries/catalog/call-context-query/cascade-action.js +13 -0
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +41 -4
- package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -0
- package/queries/query.d.ts +4 -4
- package/queries/query.js +17 -5
- package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +5 -1
- package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +6 -1
- package/r-bridge/lang-4.x/ast/model/processing/node-id.js +6 -1
- package/slicing/static/slice-call.d.ts +7 -2
- package/slicing/static/slice-call.js +33 -44
- package/slicing/static/static-slicer.d.ts +5 -1
- package/slicing/static/static-slicer.js +22 -8
- package/slicing/static/visiting-queue.d.ts +4 -4
- package/slicing/static/visiting-queue.js +5 -3
- package/statistics/output/print-stats.js +2 -1
- package/statistics/summarizer/post-process/histogram.js +2 -1
- package/statistics/summarizer/post-process/post-process-output.js +2 -1
- package/statistics/summarizer/second-phase/process.js +3 -3
- package/util/arrays.d.ts +1 -1
- package/util/arrays.js +3 -3
- package/util/cfg/cfg.js +4 -2
- package/util/list-access.d.ts +48 -0
- package/util/list-access.js +115 -0
- package/util/mermaid/cfg.js +1 -1
- package/util/summarizer.js +2 -2
- package/util/version.js +1 -1
|
@@ -11,10 +11,23 @@ const environment_1 = require("../../../../../environments/environment");
|
|
|
11
11
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
12
12
|
const built_in_assignment_1 = require("./built-in-assignment");
|
|
13
13
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
14
|
+
const vertex_1 = require("../../../../../graph/vertex");
|
|
15
|
+
const list_access_1 = require("../../../../../../util/list-access");
|
|
14
16
|
function tableAssignmentProcessor(name, args, rootId, data, outInfo) {
|
|
15
17
|
outInfo.definitionRootNodes.push(rootId);
|
|
16
18
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
|
|
17
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Processes different types of access operations.
|
|
22
|
+
*
|
|
23
|
+
* Example:
|
|
24
|
+
* ```r
|
|
25
|
+
* a[i]
|
|
26
|
+
* a$foo
|
|
27
|
+
* a[[i]]
|
|
28
|
+
* a@foo
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
18
31
|
function processAccess(name, args, rootId, data, config) {
|
|
19
32
|
if (args.length < 2) {
|
|
20
33
|
logger_1.dataflowLogger.warn(`Access ${name.content} has less than 2 arguments, skipping`);
|
|
@@ -26,47 +39,10 @@ function processAccess(name, args, rootId, data, config) {
|
|
|
26
39
|
if (!config.treatIndicesAsString) {
|
|
27
40
|
/* within an access operation which treats its fields, we redefine the table assignment ':=' as a trigger if this is to be treated as a definition */
|
|
28
41
|
// do we have a local definition that needs to be recovered?
|
|
29
|
-
|
|
30
|
-
const outInfo = { definitionRootNodes: [] };
|
|
31
|
-
data.environment.current.memory.set(':=', [{
|
|
32
|
-
type: identifier_1.ReferenceType.BuiltInFunction,
|
|
33
|
-
definedAt: built_in_1.BuiltIn,
|
|
34
|
-
controlDependencies: undefined,
|
|
35
|
-
processor: (name, args, rootId, data) => tableAssignmentProcessor(name, args, rootId, data, outInfo),
|
|
36
|
-
name: ':=',
|
|
37
|
-
nodeId: built_in_1.BuiltIn
|
|
38
|
-
}]);
|
|
39
|
-
fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
|
|
40
|
-
/* recover the environment */
|
|
41
|
-
if (existing !== undefined) {
|
|
42
|
-
data.environment.current.memory.set(':=', existing);
|
|
43
|
-
}
|
|
44
|
-
if (head.value && outInfo.definitionRootNodes.length > 0) {
|
|
45
|
-
(0, built_in_assignment_1.markAsAssignment)(fnCall.information, { type: identifier_1.ReferenceType.Variable, name: head.value.lexeme ?? '', nodeId: head.value.info.id, definedAt: rootId, controlDependencies: [] }, outInfo.definitionRootNodes, rootId);
|
|
46
|
-
}
|
|
42
|
+
fnCall = processNumberBasedAccess(data, name, args, rootId, config, head);
|
|
47
43
|
}
|
|
48
44
|
else {
|
|
49
|
-
|
|
50
|
-
// if the argument is a symbol, we convert it to a string for this perspective
|
|
51
|
-
for (let i = 1; i < newArgs.length; i++) {
|
|
52
|
-
const arg = newArgs[i];
|
|
53
|
-
if (arg !== r_function_call_1.EmptyArgument && arg.value?.type === type_1.RType.Symbol) {
|
|
54
|
-
newArgs[i] = {
|
|
55
|
-
...arg,
|
|
56
|
-
value: {
|
|
57
|
-
type: type_1.RType.String,
|
|
58
|
-
info: arg.value.info,
|
|
59
|
-
lexeme: arg.value.lexeme,
|
|
60
|
-
location: arg.value.location,
|
|
61
|
-
content: {
|
|
62
|
-
quotes: 'none',
|
|
63
|
-
str: arg.value.lexeme
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs });
|
|
45
|
+
fnCall = processStringBasedAccess(args, data, name, rootId, config);
|
|
70
46
|
}
|
|
71
47
|
const info = fnCall.information;
|
|
72
48
|
info.graph.addEdge(name.info.id, fnCall.processedArguments[0]?.entryPoint ?? head.info.id, edge_1.EdgeType.Returns);
|
|
@@ -80,16 +56,16 @@ function processAccess(name, args, rootId, data, config) {
|
|
|
80
56
|
return {
|
|
81
57
|
...info,
|
|
82
58
|
/*
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
59
|
+
* Keep active nodes in case of assignments etc.
|
|
60
|
+
* We make them maybe as a kind of hack.
|
|
61
|
+
* This way when using
|
|
62
|
+
* ```ts
|
|
63
|
+
* a[[1]] <- 3
|
|
64
|
+
* a[[2]] <- 4
|
|
65
|
+
* a
|
|
66
|
+
* ```
|
|
67
|
+
* the read for a will use both accesses as potential definitions and not just the last one!
|
|
68
|
+
*/
|
|
93
69
|
unknownReferences: (0, environment_1.makeAllMaybe)(info.unknownReferences, info.graph, info.environment, false),
|
|
94
70
|
entryPoint: rootId,
|
|
95
71
|
/** it is, to be precise, the accessed element we want to map to maybe */
|
|
@@ -103,4 +79,120 @@ function processAccess(name, args, rootId, data, config) {
|
|
|
103
79
|
})
|
|
104
80
|
};
|
|
105
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Processes different types of number-based access operations.
|
|
84
|
+
*
|
|
85
|
+
* Example:
|
|
86
|
+
* ```r
|
|
87
|
+
* a[i]
|
|
88
|
+
* a[[i]]
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
function processNumberBasedAccess(data, name, args, rootId, config, head) {
|
|
92
|
+
const existing = data.environment.current.memory.get(':=');
|
|
93
|
+
const outInfo = { definitionRootNodes: [] };
|
|
94
|
+
data.environment.current.memory.set(':=', [{
|
|
95
|
+
type: identifier_1.ReferenceType.BuiltInFunction,
|
|
96
|
+
definedAt: built_in_1.BuiltIn,
|
|
97
|
+
controlDependencies: undefined,
|
|
98
|
+
processor: (name, args, rootId, data) => tableAssignmentProcessor(name, args, rootId, data, outInfo),
|
|
99
|
+
name: ':=',
|
|
100
|
+
nodeId: built_in_1.BuiltIn,
|
|
101
|
+
}]);
|
|
102
|
+
const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
|
|
103
|
+
/* recover the environment */
|
|
104
|
+
if (existing !== undefined) {
|
|
105
|
+
data.environment.current.memory.set(':=', existing);
|
|
106
|
+
}
|
|
107
|
+
if (head.value && outInfo.definitionRootNodes.length > 0) {
|
|
108
|
+
(0, built_in_assignment_1.markAsAssignment)(fnCall.information, { type: identifier_1.ReferenceType.Variable, name: head.value.lexeme ?? '', nodeId: head.value.info.id, definedAt: rootId, controlDependencies: [] }, outInfo.definitionRootNodes, rootId);
|
|
109
|
+
}
|
|
110
|
+
return fnCall;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Processes different types of string-based access operations.
|
|
114
|
+
*
|
|
115
|
+
* Example:
|
|
116
|
+
* ```r
|
|
117
|
+
* a$foo
|
|
118
|
+
* a@foo
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
function processStringBasedAccess(args, data, name, rootId, config) {
|
|
122
|
+
const newArgs = [...args];
|
|
123
|
+
// if the argument is a symbol, we convert it to a string for this perspective
|
|
124
|
+
for (let i = 1; i < newArgs.length; i++) {
|
|
125
|
+
const arg = newArgs[i];
|
|
126
|
+
if (arg !== r_function_call_1.EmptyArgument && arg.value?.type === type_1.RType.Symbol) {
|
|
127
|
+
newArgs[i] = {
|
|
128
|
+
...arg,
|
|
129
|
+
value: {
|
|
130
|
+
type: type_1.RType.String,
|
|
131
|
+
info: arg.value.info,
|
|
132
|
+
lexeme: arg.value.lexeme,
|
|
133
|
+
location: arg.value.location,
|
|
134
|
+
content: {
|
|
135
|
+
quotes: 'none',
|
|
136
|
+
str: arg.value.lexeme
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs });
|
|
143
|
+
// Resolve access on the way up the fold
|
|
144
|
+
const nonEmptyArgs = newArgs.filter(arg => arg !== r_function_call_1.EmptyArgument);
|
|
145
|
+
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */);
|
|
146
|
+
const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */);
|
|
147
|
+
if (accessedArg === undefined || accessArg === undefined) {
|
|
148
|
+
return fnCall;
|
|
149
|
+
}
|
|
150
|
+
let accessedIndicesCollection;
|
|
151
|
+
// If the accessedArg is a symbol, it's either a simple access or the base case of a nested access
|
|
152
|
+
if (accessedArg.value?.type === type_1.RType.Symbol) {
|
|
153
|
+
accessedIndicesCollection = (0, list_access_1.resolveSingleIndex)(accessedArg, accessArg, data.environment);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Higher access call
|
|
157
|
+
const underlyingAccessId = accessedArg.value?.info.id ?? -1;
|
|
158
|
+
const vertex = fnCall.information.graph.getVertex(underlyingAccessId);
|
|
159
|
+
const subIndices = vertex?.indicesCollection
|
|
160
|
+
?.flatMap(indices => indices.indices)
|
|
161
|
+
?.flatMap(index => index?.subIndices ?? []);
|
|
162
|
+
if (subIndices) {
|
|
163
|
+
accessedIndicesCollection = (0, list_access_1.filterIndices)(subIndices, accessArg);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Add indices to vertex afterward
|
|
167
|
+
if (accessedIndicesCollection) {
|
|
168
|
+
const vertex = fnCall.information.graph.getVertex(rootId);
|
|
169
|
+
if (vertex) {
|
|
170
|
+
vertex.indicesCollection = accessedIndicesCollection;
|
|
171
|
+
}
|
|
172
|
+
// When access has no access as parent, it's the top most
|
|
173
|
+
const rootNode = data.completeAst.idMap.get(rootId);
|
|
174
|
+
const parentNode = data.completeAst.idMap.get(rootNode?.info.parent ?? -1);
|
|
175
|
+
if (parentNode?.type !== type_1.RType.Access) {
|
|
176
|
+
// Only reference indices in top most access
|
|
177
|
+
referenceIndices(accessedIndicesCollection, fnCall, name.info.id);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return fnCall;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Creates edges of type {@link EdgeType.Reads} to the accessed Indices and their sub-indices starting from
|
|
184
|
+
* the node with {@link parentNodeId}.
|
|
185
|
+
*
|
|
186
|
+
* @param accessedIndicesCollection - All indices that were accessed by the access operation
|
|
187
|
+
* @param fnCall - The {@link ProcessKnownFunctionCallResult} of the access operation
|
|
188
|
+
* @param parentNodeId - {@link NodeId} of the parent from which the edge starts
|
|
189
|
+
*/
|
|
190
|
+
function referenceIndices(accessedIndicesCollection, fnCall, parentNodeId) {
|
|
191
|
+
const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
|
|
192
|
+
for (const accessedIndex of accessedIndices ?? []) {
|
|
193
|
+
fnCall.information.graph.addEdge(parentNodeId, accessedIndex.nodeId, edge_1.EdgeType.Reads);
|
|
194
|
+
const accessedSubIndices = (0, vertex_1.isParentContainerIndex)(accessedIndex) ? accessedIndex.subIndices : undefined;
|
|
195
|
+
referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
106
198
|
//# sourceMappingURL=built-in-access.js.map
|
|
@@ -4,17 +4,22 @@ import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/
|
|
|
4
4
|
import type { RNode } from '../../../../../../r-bridge/lang-4.x/ast/model/model';
|
|
5
5
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
6
|
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
|
-
import type
|
|
8
|
-
import type {
|
|
7
|
+
import { type NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
|
+
import type { InGraphIdentifierDefinition } from '../../../../../environments/identifier';
|
|
9
|
+
import type { ContainerIndicesCollection } from '../../../../../graph/vertex';
|
|
9
10
|
import type { ForceArguments } from '../common';
|
|
10
11
|
import type { REnvironmentInformation } from '../../../../../environments/environment';
|
|
11
12
|
import type { DataflowGraph } from '../../../../../graph/graph';
|
|
12
13
|
export interface AssignmentConfiguration extends ForceArguments {
|
|
13
14
|
readonly superAssignment?: boolean;
|
|
14
15
|
readonly swapSourceAndTarget?: boolean;
|
|
16
|
+
/** Make maybe if assigned to symbol */
|
|
15
17
|
readonly makeMaybe?: boolean;
|
|
16
18
|
readonly quoteSource?: boolean;
|
|
17
19
|
readonly canBeReplacement?: boolean;
|
|
20
|
+
/** is the target a variable pointing at the actual name? */
|
|
21
|
+
readonly targetVariable?: boolean;
|
|
22
|
+
readonly indicesCollection?: ContainerIndicesCollection;
|
|
18
23
|
}
|
|
19
24
|
/**
|
|
20
25
|
* Processes an assignment, i.e., `<target> <- <source>`.
|
|
@@ -43,4 +48,4 @@ export interface AssignmentToSymbolParameters<OtherInfo> extends AssignmentConfi
|
|
|
43
48
|
export declare function markAsAssignment(information: {
|
|
44
49
|
environment: REnvironmentInformation;
|
|
45
50
|
graph: DataflowGraph;
|
|
46
|
-
}, nodeToDefine:
|
|
51
|
+
}, nodeToDefine: InGraphIdentifierDefinition, sourceIds: readonly NodeId[], rootIdOfAssignment: NodeId, config?: AssignmentConfiguration | undefined): void;
|
|
@@ -16,6 +16,8 @@ const retriever_1 = require("../../../../../../r-bridge/retriever");
|
|
|
16
16
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
17
17
|
const define_1 = require("../../../../../environments/define");
|
|
18
18
|
const edge_1 = require("../../../../../graph/edge");
|
|
19
|
+
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
20
|
+
const list_access_1 = require("../../../../../../util/list-access");
|
|
19
21
|
function toReplacementSymbol(target, prefix, superAssignment) {
|
|
20
22
|
return {
|
|
21
23
|
type: type_1.RType.Symbol,
|
|
@@ -57,7 +59,7 @@ args, rootId, data, config) {
|
|
|
57
59
|
const effectiveArgs = getEffectiveOrder(config, args);
|
|
58
60
|
const { target, source } = extractSourceAndTarget(effectiveArgs, name);
|
|
59
61
|
const { type, named } = target;
|
|
60
|
-
if (type === type_1.RType.Symbol) {
|
|
62
|
+
if (!config.targetVariable && type === type_1.RType.Symbol) {
|
|
61
63
|
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, reverseOrder: !config.swapSourceAndTarget, forceArgs: config.forceArgs });
|
|
62
64
|
return processAssignmentToSymbol({
|
|
63
65
|
...config,
|
|
@@ -107,8 +109,10 @@ args, rootId, data, config) {
|
|
|
107
109
|
else if (type === type_1.RType.String) {
|
|
108
110
|
return processAssignmentToString(target, args, name, rootId, data, config, source);
|
|
109
111
|
}
|
|
110
|
-
logger_1.dataflowLogger.warn(`Assignment ${name.content} has an unknown target type ${target.type}
|
|
111
|
-
|
|
112
|
+
logger_1.dataflowLogger.warn(`Assignment ${name.content} has an unknown target type ${target.type} => unknown impact`);
|
|
113
|
+
const info = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: effectiveArgs, rootId, data, forceArgs: config.forceArgs }).information;
|
|
114
|
+
info.graph.markIdForUnknownSideEffects(rootId);
|
|
115
|
+
return info;
|
|
112
116
|
}
|
|
113
117
|
function extractSourceAndTarget(args, name) {
|
|
114
118
|
const source = (0, unpack_argument_1.unpackArgument)(args[1], false);
|
|
@@ -117,12 +121,16 @@ function extractSourceAndTarget(args, name) {
|
|
|
117
121
|
(0, assert_1.guard)(target !== undefined, () => `Assignment ${name.content} has no target, impossible!`);
|
|
118
122
|
return { source, target };
|
|
119
123
|
}
|
|
120
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Promotes the ingoing/unknown references of target (an assignment) to definitions
|
|
126
|
+
*/
|
|
127
|
+
function produceWrittenNodes(rootId, target, referenceType, data, makeMaybe, value) {
|
|
121
128
|
return [...target.in, ...target.unknownReferences].map(ref => ({
|
|
122
129
|
...ref,
|
|
123
130
|
type: referenceType,
|
|
124
131
|
definedAt: rootId,
|
|
125
|
-
controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined)
|
|
132
|
+
controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined),
|
|
133
|
+
value: value
|
|
126
134
|
}));
|
|
127
135
|
}
|
|
128
136
|
function processAssignmentToString(target, args, name, rootId, data, config, source) {
|
|
@@ -179,10 +187,29 @@ function checkTargetReferenceType(source, sourceInfo) {
|
|
|
179
187
|
* @param quoteSource - whether to quote the source (i.e., define `x` without a direct reference to `v`)
|
|
180
188
|
* @param superAssignment - whether this is a super assignment (i.e., `<<-`)
|
|
181
189
|
*/
|
|
182
|
-
function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment,
|
|
183
|
-
|
|
190
|
+
function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment, config) {
|
|
191
|
+
let indicesCollection = undefined;
|
|
192
|
+
if (sourceIds.length === 1) {
|
|
193
|
+
// support for tracking indices
|
|
194
|
+
// Indices were defined for the vertex e.g. a <- list(c = 1) or a$b <- list(c = 1)
|
|
195
|
+
indicesCollection = information.graph.getVertex(sourceIds[0])?.indicesCollection;
|
|
196
|
+
}
|
|
197
|
+
// Indices defined by replacement operation e.g. $<-
|
|
198
|
+
if (config?.indicesCollection !== undefined) {
|
|
199
|
+
// If there were indices stored in the vertex, then a container was defined
|
|
200
|
+
// and assigned to the index of another container e.g. a$b <- list(c = 1)
|
|
201
|
+
if (indicesCollection) {
|
|
202
|
+
indicesCollection = (0, list_access_1.addSubIndicesToLeafIndices)(config.indicesCollection, indicesCollection);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// No indices were defined for the vertex e.g. a$b <- 2
|
|
206
|
+
indicesCollection = config.indicesCollection;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
nodeToDefine.indicesCollection ??= indicesCollection;
|
|
210
|
+
information.environment = (0, define_1.define)(nodeToDefine, config?.superAssignment, information.environment);
|
|
184
211
|
information.graph.setDefinitionOfVertex(nodeToDefine);
|
|
185
|
-
if (!quoteSource) {
|
|
212
|
+
if (!config?.quoteSource) {
|
|
186
213
|
for (const sourceId of sourceIds) {
|
|
187
214
|
information.graph.addEdge(nodeToDefine, sourceId, edge_1.EdgeType.DefinedBy);
|
|
188
215
|
}
|
|
@@ -200,9 +227,11 @@ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignme
|
|
|
200
227
|
/**
|
|
201
228
|
* Helper function whenever it is known that the _target_ of an assignment is a (single) symbol (i.e. `x <- ...`, but not `names(x) <- ...`).
|
|
202
229
|
*/
|
|
203
|
-
function processAssignmentToSymbol(
|
|
230
|
+
function processAssignmentToSymbol(config) {
|
|
231
|
+
const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, makeMaybe, quoteSource } = config;
|
|
204
232
|
const referenceType = checkTargetReferenceType(source, sourceArg);
|
|
205
|
-
const
|
|
233
|
+
const aliases = (0, resolve_by_name_1.getAliases)([source.info.id], information.graph, information.environment);
|
|
234
|
+
const writeNodes = produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false, aliases);
|
|
206
235
|
if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
|
|
207
236
|
log_1.log.warn(`Unexpected write number in assignment: ${JSON.stringify(writeNodes)}`);
|
|
208
237
|
}
|
|
@@ -215,7 +244,7 @@ function processAssignmentToSymbol({ nameOfAssignmentFunction, source, args: [ta
|
|
|
215
244
|
information.environment = (0, overwrite_1.overwriteEnvironment)(targetArg.environment, sourceArg.environment);
|
|
216
245
|
// install assigned variables in environment
|
|
217
246
|
for (const write of writeNodes) {
|
|
218
|
-
markAsAssignment(information, write, [source.info.id], rootId,
|
|
247
|
+
markAsAssignment(information, write, [source.info.id], rootId, config);
|
|
219
248
|
}
|
|
220
249
|
information.graph.addEdge(rootId, targetArg.entryPoint, edge_1.EdgeType.Returns);
|
|
221
250
|
if (quoteSource) {
|
|
@@ -4,4 +4,20 @@ import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/
|
|
|
4
4
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
5
5
|
import type { RFunctionArgument } 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
|
+
import { DataflowGraph } from '../../../../../graph/graph';
|
|
8
|
+
import type { REnvironmentInformation } from '../../../../../environments/environment';
|
|
7
9
|
export declare function processFunctionDefinition<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
10
|
+
export declare function retrieveActiveEnvironment(callerEnvironment: REnvironmentInformation | undefined, baseEnvironment: REnvironmentInformation): REnvironmentInformation;
|
|
11
|
+
/**
|
|
12
|
+
* Update the closure links of all nested function definitions
|
|
13
|
+
* @param graph - dataflow graph to collect the function definitions from and to update the closure links for
|
|
14
|
+
* @param outEnvironment - active environment on resolving closures (i.e., exit of the function definition)
|
|
15
|
+
* @param fnId - id of the function definition to update the closure links for
|
|
16
|
+
*/
|
|
17
|
+
export declare function updateNestedFunctionClosures(graph: DataflowGraph, outEnvironment: REnvironmentInformation, fnId: NodeId): void;
|
|
18
|
+
/**
|
|
19
|
+
* Update the closure links of all nested function calls, this is probably to be done once at the end of the script
|
|
20
|
+
* @param graph - dataflow graph to collect the function calls from and to update the closure links for
|
|
21
|
+
* @param outEnvironment - active environment on resolving closures (i.e., exit of the function definition)
|
|
22
|
+
*/
|
|
23
|
+
export declare function updateNestedFunctionCalls(graph: DataflowGraph, outEnvironment: REnvironmentInformation): void;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.processFunctionDefinition = processFunctionDefinition;
|
|
4
|
+
exports.retrieveActiveEnvironment = retrieveActiveEnvironment;
|
|
5
|
+
exports.updateNestedFunctionClosures = updateNestedFunctionClosures;
|
|
6
|
+
exports.updateNestedFunctionCalls = updateNestedFunctionCalls;
|
|
4
7
|
const processor_1 = require("../../../../../processor");
|
|
5
8
|
const linker_1 = require("../../../../linker");
|
|
6
9
|
const known_call_handling_1 = require("../known-call-handling");
|
|
@@ -77,7 +80,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
77
80
|
graph: new Set(subgraph.rootIds()),
|
|
78
81
|
environment: outEnvironment
|
|
79
82
|
};
|
|
80
|
-
updateNestedFunctionClosures(subgraph, outEnvironment, name);
|
|
83
|
+
updateNestedFunctionClosures(subgraph, outEnvironment, name.info.id);
|
|
81
84
|
const exitPoints = body.exitPoints;
|
|
82
85
|
const graph = new graph_1.DataflowGraph(data.completeAst.idMap).mergeWith(subgraph, false);
|
|
83
86
|
graph.addVertex({
|
|
@@ -99,10 +102,32 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
99
102
|
environment: originalEnvironment
|
|
100
103
|
};
|
|
101
104
|
}
|
|
102
|
-
|
|
105
|
+
// this is no longer necessary when we update environments to be back to front (e.g., with a list of environments)
|
|
106
|
+
// this favors the bigger environment
|
|
107
|
+
function retrieveActiveEnvironment(callerEnvironment, baseEnvironment) {
|
|
108
|
+
callerEnvironment ??= (0, environment_1.initializeCleanEnvironments)(true);
|
|
109
|
+
let level = callerEnvironment.level ?? 0;
|
|
110
|
+
if (baseEnvironment.level !== level) {
|
|
111
|
+
while (baseEnvironment.level < level) {
|
|
112
|
+
baseEnvironment = (0, scoping_1.pushLocalEnvironment)(baseEnvironment);
|
|
113
|
+
}
|
|
114
|
+
while (baseEnvironment.level > level) {
|
|
115
|
+
callerEnvironment = (0, scoping_1.pushLocalEnvironment)(callerEnvironment);
|
|
116
|
+
level = callerEnvironment.level;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return (0, overwrite_1.overwriteEnvironment)(baseEnvironment, callerEnvironment);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Update the closure links of all nested function definitions
|
|
123
|
+
* @param graph - dataflow graph to collect the function definitions from and to update the closure links for
|
|
124
|
+
* @param outEnvironment - active environment on resolving closures (i.e., exit of the function definition)
|
|
125
|
+
* @param fnId - id of the function definition to update the closure links for
|
|
126
|
+
*/
|
|
127
|
+
function updateNestedFunctionClosures(graph, outEnvironment, fnId) {
|
|
103
128
|
// track *all* function definitions - including those nested within the current graph,
|
|
104
129
|
// try to resolve their 'in' by only using the lowest scope which will be popped after this definition
|
|
105
|
-
for (const [id, { subflow, tag }] of
|
|
130
|
+
for (const [id, { subflow, tag }] of graph.vertices(true)) {
|
|
106
131
|
if (tag !== vertex_1.VertexType.FunctionDefinition) {
|
|
107
132
|
continue;
|
|
108
133
|
}
|
|
@@ -114,15 +139,67 @@ function updateNestedFunctionClosures(subgraph, outEnvironment, name) {
|
|
|
114
139
|
remainingIn.push(ingoing);
|
|
115
140
|
continue;
|
|
116
141
|
}
|
|
117
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Found ${resolved.length} references to open ref ${id} in closure of function definition ${
|
|
142
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Found ${resolved.length} references to open ref ${id} in closure of function definition ${fnId}`);
|
|
118
143
|
for (const ref of resolved) {
|
|
119
|
-
|
|
144
|
+
graph.addEdge(ingoing, ref, edge_1.EdgeType.Reads);
|
|
120
145
|
}
|
|
121
146
|
}
|
|
122
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Keeping ${remainingIn.length} references to open ref ${id} in closure of function definition ${
|
|
147
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Keeping ${remainingIn.length} references to open ref ${id} in closure of function definition ${fnId}`);
|
|
123
148
|
subflow.in = remainingIn;
|
|
124
149
|
}
|
|
125
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Update the closure links of all nested function calls, this is probably to be done once at the end of the script
|
|
153
|
+
* @param graph - dataflow graph to collect the function calls from and to update the closure links for
|
|
154
|
+
* @param outEnvironment - active environment on resolving closures (i.e., exit of the function definition)
|
|
155
|
+
*/
|
|
156
|
+
function updateNestedFunctionCalls(graph, outEnvironment) {
|
|
157
|
+
// track *all* function definitions - including those nested within the current graph,
|
|
158
|
+
// try to resolve their 'in' by only using the lowest scope which will be popped after this definition
|
|
159
|
+
for (const [id, { onlyBuiltin, tag, environment, name }] of graph.vertices(true)) {
|
|
160
|
+
if (tag !== vertex_1.VertexType.FunctionCall || !name || onlyBuiltin) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
// only the call environment counts!
|
|
164
|
+
if (environment) {
|
|
165
|
+
while (outEnvironment.level > environment.level) {
|
|
166
|
+
outEnvironment = (0, scoping_1.popLocalEnvironment)(outEnvironment);
|
|
167
|
+
}
|
|
168
|
+
while (outEnvironment.level < environment.level) {
|
|
169
|
+
outEnvironment = (0, scoping_1.pushLocalEnvironment)(outEnvironment);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const effectiveEnvironment = environment ? (0, overwrite_1.overwriteEnvironment)(outEnvironment, environment) : outEnvironment;
|
|
173
|
+
const targets = (0, linker_1.getAllFunctionCallTargets)(id, graph, effectiveEnvironment);
|
|
174
|
+
for (const target of targets) {
|
|
175
|
+
const targetVertex = graph.getVertex(target);
|
|
176
|
+
if (targetVertex?.tag !== vertex_1.VertexType.FunctionDefinition) {
|
|
177
|
+
// support reads on symbols
|
|
178
|
+
if (targetVertex?.tag === vertex_1.VertexType.Use) {
|
|
179
|
+
graph.addEdge(id, target, edge_1.EdgeType.Reads);
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
graph.addEdge(id, target, edge_1.EdgeType.Calls);
|
|
184
|
+
const ingoingRefs = targetVertex.subflow.in;
|
|
185
|
+
const remainingIn = [];
|
|
186
|
+
for (const ingoing of ingoingRefs) {
|
|
187
|
+
const resolved = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, effectiveEnvironment, ingoing.type) : undefined;
|
|
188
|
+
if (resolved === undefined) {
|
|
189
|
+
remainingIn.push(ingoing);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Found ${resolved.length} references to open ref ${id} in closure of function definition ${id}`);
|
|
193
|
+
for (const def of resolved) {
|
|
194
|
+
graph.addEdge(ingoing, def, edge_1.EdgeType.DefinedByOnCall);
|
|
195
|
+
graph.addEdge(id, def, edge_1.EdgeType.DefinesOnCall);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Keeping ${remainingIn.length} references to open ref ${id} in closure of function definition ${id}`);
|
|
199
|
+
targetVertex.subflow.in = remainingIn;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
126
203
|
function prepareFunctionEnvironment(data) {
|
|
127
204
|
let env = (0, environment_1.initializeCleanEnvironments)();
|
|
128
205
|
for (let i = 0; i < data.environment.level + 1 /* add another env */; i++) {
|
|
@@ -33,9 +33,9 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
33
33
|
let then;
|
|
34
34
|
let makeThenMaybe = false;
|
|
35
35
|
// we should defer this to the abstract interpretation
|
|
36
|
-
const
|
|
37
|
-
const conditionIsAlwaysFalse =
|
|
38
|
-
const conditionIsAlwaysTrue =
|
|
36
|
+
const values = (0, resolve_by_name_1.resolveValueOfVariable)(condArg?.lexeme, data.environment, cond.graph);
|
|
37
|
+
const conditionIsAlwaysFalse = values?.every(d => d === false) ?? false;
|
|
38
|
+
const conditionIsAlwaysTrue = values?.every(d => d === true) ?? false;
|
|
39
39
|
if (!conditionIsAlwaysFalse) {
|
|
40
40
|
then = (0, processor_1.processDataflowFor)(thenArg, data);
|
|
41
41
|
if (then.entryPoint) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
2
|
+
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
3
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
5
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
6
|
+
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
7
|
+
/**
|
|
8
|
+
* Process a list call.
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* ```r
|
|
12
|
+
* list(a = 1, b = 2)
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function processList<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processList = processList;
|
|
4
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
5
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
6
|
+
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
7
|
+
const known_call_handling_1 = require("../known-call-handling");
|
|
8
|
+
const config_1 = require("../../../../../../config");
|
|
9
|
+
/**
|
|
10
|
+
* Process a list call.
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* ```r
|
|
14
|
+
* list(a = 1, b = 2)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function processList(name, args, rootId, data) {
|
|
18
|
+
if (!(0, config_1.getConfig)().solver.pointerTracking) {
|
|
19
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
|
|
20
|
+
}
|
|
21
|
+
const namedArguments = [];
|
|
22
|
+
for (const arg of args) {
|
|
23
|
+
// Skip non named arguments
|
|
24
|
+
if (arg === r_function_call_1.EmptyArgument || arg.type !== type_1.RType.Argument || arg.name === undefined) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
let newIndex = {
|
|
28
|
+
lexeme: arg.name.content,
|
|
29
|
+
nodeId: arg.info.id,
|
|
30
|
+
};
|
|
31
|
+
// Check whether argument value is non-primitive
|
|
32
|
+
if (arg.value?.type === type_1.RType.Symbol) {
|
|
33
|
+
const defs = (0, resolve_by_name_1.resolveByName)(arg.value.lexeme, data.environment);
|
|
34
|
+
const indices = defs?.flatMap(index => index.indicesCollection ?? []);
|
|
35
|
+
if (indices) {
|
|
36
|
+
newIndex = {
|
|
37
|
+
...newIndex,
|
|
38
|
+
subIndices: indices,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
namedArguments.push(newIndex);
|
|
43
|
+
}
|
|
44
|
+
const indices = {
|
|
45
|
+
indices: namedArguments,
|
|
46
|
+
isContainer: true,
|
|
47
|
+
};
|
|
48
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }, [indices]).information;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=built-in-list.js.map
|
|
@@ -3,7 +3,7 @@ import type { DataflowInformation } from '../../../../../info';
|
|
|
3
3
|
import type { ForceArguments } from '../common';
|
|
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
|
-
import type
|
|
6
|
+
import { type RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
7
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
8
|
export declare function processReplacementFunction<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>,
|
|
9
9
|
/** The last one has to be the value */
|
|
@@ -7,11 +7,14 @@ const log_1 = require("../../../../../../util/log");
|
|
|
7
7
|
const built_in_assignment_1 = require("./built-in-assignment");
|
|
8
8
|
const common_1 = require("../common");
|
|
9
9
|
const assert_1 = require("../../../../../../util/assert");
|
|
10
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
10
11
|
const logger_1 = require("../../../../../logger");
|
|
11
12
|
const vertex_1 = require("../../../../../graph/vertex");
|
|
12
13
|
const graph_1 = require("../../../../../graph/graph");
|
|
13
14
|
const edge_1 = require("../../../../../graph/edge");
|
|
14
15
|
const dfg_1 = require("../../../../../../util/mermaid/dfg");
|
|
16
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
17
|
+
const list_access_1 = require("../../../../../../util/list-access");
|
|
15
18
|
function processReplacementFunction(name,
|
|
16
19
|
/** The last one has to be the value */
|
|
17
20
|
args, rootId, data, config) {
|
|
@@ -21,8 +24,33 @@ args, rootId, data, config) {
|
|
|
21
24
|
}
|
|
22
25
|
/* we only get here if <-, <<-, ... or whatever is part of the replacement is not overwritten */
|
|
23
26
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Replacement ${name.content} with ${JSON.stringify(args)}, processing`);
|
|
27
|
+
let indices = undefined;
|
|
28
|
+
if (name.content === '$<-') {
|
|
29
|
+
const nonEmptyArgs = args.filter(arg => arg !== r_function_call_1.EmptyArgument);
|
|
30
|
+
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */);
|
|
31
|
+
const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */);
|
|
32
|
+
if (accessArg !== undefined && accessedArg != undefined) {
|
|
33
|
+
const leafIndex = { lexeme: accessArg.lexeme, nodeId: accessedArg.info.parent ?? '' };
|
|
34
|
+
const accessIndices = {
|
|
35
|
+
indices: [leafIndex],
|
|
36
|
+
isContainer: false
|
|
37
|
+
};
|
|
38
|
+
// Check for nested access
|
|
39
|
+
if (accessedArg.value?.type === type_1.RType.Access) {
|
|
40
|
+
indices = (0, list_access_1.constructNestedAccess)(accessedArg.value, accessIndices);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// use access node as reference to get complete line in slice
|
|
44
|
+
indices = [accessIndices];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
24
48
|
/* we assign the first argument by the last for now and maybe mark as maybe!, we can keep the symbol as we now know we have an assignment */
|
|
25
|
-
const res = (0, built_in_assignment_1.processAssignment)(name, [args[0], args[args.length - 1]], rootId, data, {
|
|
49
|
+
const res = (0, built_in_assignment_1.processAssignment)(name, [args[0], args[args.length - 1]], rootId, data, {
|
|
50
|
+
superAssignment: config.assignmentOperator === '<<-',
|
|
51
|
+
makeMaybe: indices !== undefined ? false : config.makeMaybe,
|
|
52
|
+
indicesCollection: indices
|
|
53
|
+
});
|
|
26
54
|
/* now, we soft-inject other arguments, so that calls like `x[y] <- 3` are linked correctly */
|
|
27
55
|
const { callArgs } = (0, common_1.processAllArguments)({
|
|
28
56
|
functionName: (0, info_1.initializeCleanDataflowInformation)(rootId, data),
|