@eagleoutice/flowr 2.1.9 → 2.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -0
  2. package/cli/flowr.js +8 -0
  3. package/cli/repl/commands/repl-query.js +13 -2
  4. package/config.d.ts +21 -0
  5. package/config.js +19 -2
  6. package/dataflow/environments/built-in.d.ts +2 -0
  7. package/dataflow/environments/built-in.js +2 -0
  8. package/dataflow/environments/default-builtin-config.js +3 -2
  9. package/dataflow/environments/define.js +78 -0
  10. package/dataflow/environments/identifier.d.ts +11 -3
  11. package/dataflow/environments/resolve-by-name.d.ts +12 -6
  12. package/dataflow/environments/resolve-by-name.js +105 -6
  13. package/dataflow/graph/vertex.d.ts +56 -1
  14. package/dataflow/graph/vertex.js +4 -0
  15. package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +11 -0
  16. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +144 -49
  17. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +7 -5
  18. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +47 -16
  19. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +3 -3
  20. package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +15 -0
  21. package/dataflow/internal/process/functions/call/built-in/built-in-list.js +50 -0
  22. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
  23. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +30 -1
  24. package/dataflow/internal/process/functions/call/common.js +15 -1
  25. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -1
  26. package/dataflow/internal/process/functions/call/known-call-handling.js +3 -2
  27. package/documentation/print-interface-wiki.js +13 -3
  28. package/documentation/print-query-wiki.js +13 -0
  29. package/package.json +1 -1
  30. package/queries/catalog/config-query/config-query-executor.d.ts +3 -0
  31. package/queries/catalog/config-query/config-query-executor.js +18 -0
  32. package/queries/catalog/config-query/config-query-format.d.ts +16 -0
  33. package/queries/catalog/config-query/config-query-format.js +24 -0
  34. package/queries/catalog/location-map-query/location-map-query-format.js +1 -1
  35. package/queries/query.d.ts +7 -1
  36. package/queries/query.js +2 -0
  37. package/util/list-access.d.ts +48 -0
  38. package/util/list-access.js +115 -0
  39. package/util/version.js +1 -1
@@ -11,10 +11,24 @@ 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");
16
+ const config_1 = require("../../../../../../config");
14
17
  function tableAssignmentProcessor(name, args, rootId, data, outInfo) {
15
18
  outInfo.definitionRootNodes.push(rootId);
16
19
  return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
17
20
  }
21
+ /**
22
+ * Processes different types of access operations.
23
+ *
24
+ * Example:
25
+ * ```r
26
+ * a[i]
27
+ * a$foo
28
+ * a[[i]]
29
+ * a@foo
30
+ * ```
31
+ */
18
32
  function processAccess(name, args, rootId, data, config) {
19
33
  if (args.length < 2) {
20
34
  logger_1.dataflowLogger.warn(`Access ${name.content} has less than 2 arguments, skipping`);
@@ -26,47 +40,10 @@ function processAccess(name, args, rootId, data, config) {
26
40
  if (!config.treatIndicesAsString) {
27
41
  /* 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
42
  // do we have a local definition that needs to be recovered?
29
- const existing = data.environment.current.memory.get(':=');
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
- }
43
+ fnCall = processNumberBasedAccess(data, name, args, rootId, config, head);
47
44
  }
48
45
  else {
49
- const newArgs = [...args];
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 });
46
+ fnCall = processStringBasedAccess(args, data, name, rootId, config);
70
47
  }
71
48
  const info = fnCall.information;
72
49
  info.graph.addEdge(name.info.id, fnCall.processedArguments[0]?.entryPoint ?? head.info.id, edge_1.EdgeType.Returns);
@@ -80,16 +57,16 @@ function processAccess(name, args, rootId, data, config) {
80
57
  return {
81
58
  ...info,
82
59
  /*
83
- * Keep active nodes in case of assignments etc.
84
- * We make them maybe as a kind of hack.
85
- * This way when using
86
- * ```ts
87
- * a[[1]] <- 3
88
- * a[[2]] <- 4
89
- * a
90
- * ```
91
- * the read for a will use both accesses as potential definitions and not just the last one!
92
- */
60
+ * Keep active nodes in case of assignments etc.
61
+ * We make them maybe as a kind of hack.
62
+ * This way when using
63
+ * ```ts
64
+ * a[[1]] <- 3
65
+ * a[[2]] <- 4
66
+ * a
67
+ * ```
68
+ * the read for a will use both accesses as potential definitions and not just the last one!
69
+ */
93
70
  unknownReferences: (0, environment_1.makeAllMaybe)(info.unknownReferences, info.graph, info.environment, false),
94
71
  entryPoint: rootId,
95
72
  /** it is, to be precise, the accessed element we want to map to maybe */
@@ -103,4 +80,122 @@ function processAccess(name, args, rootId, data, config) {
103
80
  })
104
81
  };
105
82
  }
83
+ /**
84
+ * Processes different types of number-based access operations.
85
+ *
86
+ * Example:
87
+ * ```r
88
+ * a[i]
89
+ * a[[i]]
90
+ * ```
91
+ */
92
+ function processNumberBasedAccess(data, name, args, rootId, config, head) {
93
+ const existing = data.environment.current.memory.get(':=');
94
+ const outInfo = { definitionRootNodes: [] };
95
+ data.environment.current.memory.set(':=', [{
96
+ type: identifier_1.ReferenceType.BuiltInFunction,
97
+ definedAt: built_in_1.BuiltIn,
98
+ controlDependencies: undefined,
99
+ processor: (name, args, rootId, data) => tableAssignmentProcessor(name, args, rootId, data, outInfo),
100
+ name: ':=',
101
+ nodeId: built_in_1.BuiltIn,
102
+ }]);
103
+ const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
104
+ /* recover the environment */
105
+ if (existing !== undefined) {
106
+ data.environment.current.memory.set(':=', existing);
107
+ }
108
+ if (head.value && outInfo.definitionRootNodes.length > 0) {
109
+ (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);
110
+ }
111
+ return fnCall;
112
+ }
113
+ /**
114
+ * Processes different types of string-based access operations.
115
+ *
116
+ * Example:
117
+ * ```r
118
+ * a$foo
119
+ * a@foo
120
+ * ```
121
+ */
122
+ function processStringBasedAccess(args, data, name, rootId, config) {
123
+ const newArgs = [...args];
124
+ // if the argument is a symbol, we convert it to a string for this perspective
125
+ for (let i = 1; i < newArgs.length; i++) {
126
+ const arg = newArgs[i];
127
+ if (arg !== r_function_call_1.EmptyArgument && arg.value?.type === type_1.RType.Symbol) {
128
+ newArgs[i] = {
129
+ ...arg,
130
+ value: {
131
+ type: type_1.RType.String,
132
+ info: arg.value.info,
133
+ lexeme: arg.value.lexeme,
134
+ location: arg.value.location,
135
+ content: {
136
+ quotes: 'none',
137
+ str: arg.value.lexeme
138
+ }
139
+ }
140
+ };
141
+ }
142
+ }
143
+ const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: newArgs, rootId, data, forceArgs: config.forceArgs });
144
+ // Resolve access on the way up the fold
145
+ const nonEmptyArgs = newArgs.filter(arg => arg !== r_function_call_1.EmptyArgument);
146
+ const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */);
147
+ const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */);
148
+ if (accessedArg === undefined || accessArg === undefined) {
149
+ return fnCall;
150
+ }
151
+ if ((0, config_1.getConfig)().solver.pointerTracking) {
152
+ let accessedIndicesCollection;
153
+ // If the accessedArg is a symbol, it's either a simple access or the base case of a nested access
154
+ if (accessedArg.value?.type === type_1.RType.Symbol) {
155
+ accessedIndicesCollection = (0, list_access_1.resolveSingleIndex)(accessedArg, accessArg, data.environment);
156
+ }
157
+ else {
158
+ // Higher access call
159
+ const underlyingAccessId = accessedArg.value?.info.id ?? -1;
160
+ const vertex = fnCall.information.graph.getVertex(underlyingAccessId);
161
+ const subIndices = vertex?.indicesCollection
162
+ ?.flatMap(indices => indices.indices)
163
+ ?.flatMap(index => index?.subIndices ?? []);
164
+ if (subIndices) {
165
+ accessedIndicesCollection = (0, list_access_1.filterIndices)(subIndices, accessArg);
166
+ }
167
+ }
168
+ // Add indices to vertex afterward
169
+ if (accessedIndicesCollection) {
170
+ const vertex = fnCall.information.graph.getVertex(rootId);
171
+ if (vertex) {
172
+ vertex.indicesCollection = accessedIndicesCollection;
173
+ }
174
+ // When access has no access as parent, it's the top most
175
+ const rootNode = data.completeAst.idMap.get(rootId);
176
+ const parentNode = data.completeAst.idMap.get(rootNode?.info.parent ?? -1);
177
+ if (parentNode?.type !== type_1.RType.Access) {
178
+ // Only reference indices in top most access
179
+ referenceIndices(accessedIndicesCollection, fnCall, name.info.id);
180
+ }
181
+ }
182
+ }
183
+ return fnCall;
184
+ }
185
+ /**
186
+ * Creates edges of type {@link EdgeType.Reads} to the accessed Indices and their sub-indices starting from
187
+ * the node with {@link parentNodeId}.
188
+ *
189
+ * @param accessedIndicesCollection - All indices that were accessed by the access operation
190
+ * @param fnCall - The {@link ProcessKnownFunctionCallResult} of the access operation
191
+ * @param parentNodeId - {@link NodeId} of the parent from which the edge starts
192
+ */
193
+ function referenceIndices(accessedIndicesCollection, fnCall, parentNodeId) {
194
+ const accessedIndices = accessedIndicesCollection?.flatMap(indices => indices.indices);
195
+ for (const accessedIndex of accessedIndices ?? []) {
196
+ fnCall.information.graph.addEdge(parentNodeId, accessedIndex.nodeId, edge_1.EdgeType.Reads);
197
+ const accessedSubIndices = (0, vertex_1.isParentContainerIndex)(accessedIndex) ? accessedIndex.subIndices : undefined;
198
+ referenceIndices(accessedSubIndices, fnCall, accessedIndex.nodeId);
199
+ }
200
+ }
106
201
  //# sourceMappingURL=built-in-access.js.map
@@ -4,19 +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 { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
- import type { IdentifierDefinition } from '../../../../../environments/identifier';
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;
18
20
  /** is the target a variable pointing at the actual name? */
19
21
  readonly targetVariable?: boolean;
22
+ readonly indicesCollection?: ContainerIndicesCollection;
20
23
  }
21
24
  /**
22
25
  * Processes an assignment, i.e., `<target> <- <source>`.
@@ -39,10 +42,9 @@ export interface AssignmentToSymbolParameters<OtherInfo> extends AssignmentConfi
39
42
  * @param nodeToDefine - `x`
40
43
  * @param sourceIds - `v`
41
44
  * @param rootIdOfAssignment - `<-`
42
- * @param quoteSource - whether to quote the source (i.e., define `x` without a direct reference to `v`)
43
- * @param superAssignment - whether this is a super assignment (i.e., `<<-`)
45
+ * @param config - configuration for the assignment processing
44
46
  */
45
47
  export declare function markAsAssignment(information: {
46
48
  environment: REnvironmentInformation;
47
49
  graph: DataflowGraph;
48
- }, nodeToDefine: IdentifierDefinition, sourceIds: readonly NodeId[], rootIdOfAssignment: NodeId, quoteSource?: boolean, superAssignment?: boolean): void;
50
+ }, nodeToDefine: InGraphIdentifierDefinition, sourceIds: readonly NodeId[], rootIdOfAssignment: NodeId, config?: AssignmentConfiguration | undefined): void;
@@ -16,6 +16,9 @@ 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");
21
+ const config_1 = require("../../../../../../config");
19
22
  function toReplacementSymbol(target, prefix, superAssignment) {
20
23
  return {
21
24
  type: type_1.RType.Symbol,
@@ -119,12 +122,16 @@ function extractSourceAndTarget(args, name) {
119
122
  (0, assert_1.guard)(target !== undefined, () => `Assignment ${name.content} has no target, impossible!`);
120
123
  return { source, target };
121
124
  }
122
- function produceWrittenNodes(rootId, target, referenceType, data, makeMaybe) {
125
+ /**
126
+ * Promotes the ingoing/unknown references of target (an assignment) to definitions
127
+ */
128
+ function produceWrittenNodes(rootId, target, referenceType, data, makeMaybe, value) {
123
129
  return [...target.in, ...target.unknownReferences].map(ref => ({
124
130
  ...ref,
125
131
  type: referenceType,
126
132
  definedAt: rootId,
127
- controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined)
133
+ controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined),
134
+ value: value
128
135
  }));
129
136
  }
130
137
  function processAssignmentToString(target, args, name, rootId, data, config, source) {
@@ -178,33 +185,57 @@ function checkTargetReferenceType(source, sourceInfo) {
178
185
  * @param nodeToDefine - `x`
179
186
  * @param sourceIds - `v`
180
187
  * @param rootIdOfAssignment - `<-`
181
- * @param quoteSource - whether to quote the source (i.e., define `x` without a direct reference to `v`)
182
- * @param superAssignment - whether this is a super assignment (i.e., `<<-`)
188
+ * @param config - configuration for the assignment processing
183
189
  */
184
- function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment, quoteSource, superAssignment) {
185
- information.environment = (0, define_1.define)(nodeToDefine, superAssignment, information.environment);
190
+ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment, config) {
191
+ if ((0, config_1.getConfig)().solver.pointerTracking) {
192
+ let indicesCollection = undefined;
193
+ if (sourceIds.length === 1) {
194
+ // support for tracking indices
195
+ // Indices were defined for the vertex e.g. a <- list(c = 1) or a$b <- list(c = 1)
196
+ indicesCollection = information.graph.getVertex(sourceIds[0])?.indicesCollection;
197
+ }
198
+ // Indices defined by replacement operation e.g. $<-
199
+ if (config?.indicesCollection !== undefined) {
200
+ // If there were indices stored in the vertex, then a container was defined
201
+ // and assigned to the index of another container e.g. a$b <- list(c = 1)
202
+ if (indicesCollection) {
203
+ indicesCollection = (0, list_access_1.addSubIndicesToLeafIndices)(config.indicesCollection, indicesCollection);
204
+ }
205
+ else {
206
+ // No indices were defined for the vertex e.g. a$b <- 2
207
+ indicesCollection = config.indicesCollection;
208
+ }
209
+ }
210
+ nodeToDefine.indicesCollection ??= indicesCollection;
211
+ }
212
+ information.environment = (0, define_1.define)(nodeToDefine, config?.superAssignment, information.environment);
186
213
  information.graph.setDefinitionOfVertex(nodeToDefine);
187
- if (!quoteSource) {
214
+ if (!config?.quoteSource) {
188
215
  for (const sourceId of sourceIds) {
189
216
  information.graph.addEdge(nodeToDefine, sourceId, edge_1.EdgeType.DefinedBy);
190
217
  }
191
218
  }
192
219
  information.graph.addEdge(nodeToDefine, rootIdOfAssignment, edge_1.EdgeType.DefinedBy);
193
- // kinda dirty, but we have to remove existing read edges for the symbol, added by the child
194
- const out = information.graph.outgoingEdges(nodeToDefine.nodeId);
195
- for (const [id, edge] of (out ?? [])) {
196
- edge.types &= ~edge_1.EdgeType.Reads;
197
- if (edge.types == 0) {
198
- out?.delete(id);
220
+ if ((0, config_1.getConfig)().solver.pointerTracking) {
221
+ // kinda dirty, but we have to remove existing read edges for the symbol, added by the child
222
+ const out = information.graph.outgoingEdges(nodeToDefine.nodeId);
223
+ for (const [id, edge] of (out ?? [])) {
224
+ edge.types &= ~edge_1.EdgeType.Reads;
225
+ if (edge.types == 0) {
226
+ out?.delete(id);
227
+ }
199
228
  }
200
229
  }
201
230
  }
202
231
  /**
203
232
  * Helper function whenever it is known that the _target_ of an assignment is a (single) symbol (i.e. `x <- ...`, but not `names(x) <- ...`).
204
233
  */
205
- function processAssignmentToSymbol({ nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, superAssignment, makeMaybe, quoteSource }) {
234
+ function processAssignmentToSymbol(config) {
235
+ const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, makeMaybe, quoteSource } = config;
206
236
  const referenceType = checkTargetReferenceType(source, sourceArg);
207
- const writeNodes = produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false);
237
+ const aliases = (0, resolve_by_name_1.getAliases)([source.info.id], information.graph, information.environment);
238
+ const writeNodes = produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false, aliases);
208
239
  if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
209
240
  log_1.log.warn(`Unexpected write number in assignment: ${JSON.stringify(writeNodes)}`);
210
241
  }
@@ -217,7 +248,7 @@ function processAssignmentToSymbol({ nameOfAssignmentFunction, source, args: [ta
217
248
  information.environment = (0, overwrite_1.overwriteEnvironment)(targetArg.environment, sourceArg.environment);
218
249
  // install assigned variables in environment
219
250
  for (const write of writeNodes) {
220
- markAsAssignment(information, write, [source.info.id], rootId, quoteSource, superAssignment);
251
+ markAsAssignment(information, write, [source.info.id], rootId, config);
221
252
  }
222
253
  information.graph.addEdge(rootId, targetArg.entryPoint, edge_1.EdgeType.Returns);
223
254
  if (quoteSource) {
@@ -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 definitions = (0, resolve_by_name_1.resolveToConstants)(condArg?.lexeme, data.environment);
37
- const conditionIsAlwaysFalse = definitions?.every(d => d.value === false) ?? false;
38
- const conditionIsAlwaysTrue = definitions?.every(d => d.value === true) ?? false;
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 { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
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,15 @@ 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");
18
+ const config_1 = require("../../../../../../config");
15
19
  function processReplacementFunction(name,
16
20
  /** The last one has to be the value */
17
21
  args, rootId, data, config) {
@@ -21,8 +25,33 @@ args, rootId, data, config) {
21
25
  }
22
26
  /* we only get here if <-, <<-, ... or whatever is part of the replacement is not overwritten */
23
27
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Replacement ${name.content} with ${JSON.stringify(args)}, processing`);
28
+ let indices = undefined;
29
+ if (name.content === '$<-' && (0, config_1.getConfig)().solver.pointerTracking) {
30
+ const nonEmptyArgs = args.filter(arg => arg !== r_function_call_1.EmptyArgument);
31
+ const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */);
32
+ const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */);
33
+ if (accessArg !== undefined && accessedArg != undefined) {
34
+ const leafIndex = { lexeme: accessArg.lexeme, nodeId: accessedArg.info.parent ?? '' };
35
+ const accessIndices = {
36
+ indices: [leafIndex],
37
+ isContainer: false
38
+ };
39
+ // Check for nested access
40
+ if (accessedArg.value?.type === type_1.RType.Access) {
41
+ indices = (0, list_access_1.constructNestedAccess)(accessedArg.value, accessIndices);
42
+ }
43
+ else {
44
+ // use access node as reference to get complete line in slice
45
+ indices = [accessIndices];
46
+ }
47
+ }
48
+ }
24
49
  /* 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, { superAssignment: config.assignmentOperator === '<<-', makeMaybe: config.makeMaybe });
50
+ const res = (0, built_in_assignment_1.processAssignment)(name, [args[0], args[args.length - 1]], rootId, data, {
51
+ superAssignment: config.assignmentOperator === '<<-',
52
+ makeMaybe: indices !== undefined ? false : config.makeMaybe,
53
+ indicesCollection: indices
54
+ });
26
55
  /* now, we soft-inject other arguments, so that calls like `x[y] <- 3` are linked correctly */
27
56
  const { callArgs } = (0, common_1.processAllArguments)({
28
57
  functionName: (0, info_1.initializeCleanDataflowInformation)(rootId, data),
@@ -77,7 +77,12 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
77
77
  if ((0, info_1.happensInEveryBranch)(resolved.controlDependencies)) {
78
78
  assumeItMayHaveAHigherTarget = false;
79
79
  }
80
- finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, edge_1.EdgeType.Reads);
80
+ // When only a single index is referenced, we don't need to reference the whole object
81
+ const resolvedInGraphDef = resolved;
82
+ const isContainer = checkForContainer(resolvedInGraphDef?.indicesCollection);
83
+ if (isContainer || isContainer === undefined) {
84
+ finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, edge_1.EdgeType.Reads);
85
+ }
81
86
  }
82
87
  if (assumeItMayHaveAHigherTarget) {
83
88
  remainingReadInArgs.push(ingoing);
@@ -113,4 +118,13 @@ function patchFunctionCall({ nextGraph, rootId, name, data, argumentProcessResul
113
118
  }
114
119
  }
115
120
  }
121
+ /**
122
+ * Check whether passed {@link indices} are containers or whether their sub-indices are containers.
123
+ */
124
+ function checkForContainer(indices) {
125
+ return indices?.every((indices) => {
126
+ const areSubIndicesContainers = indices.indices.every(index => 'subIndices' in index && checkForContainer(index.subIndices));
127
+ return indices.isContainer || areSubIndicesContainers;
128
+ });
129
+ }
116
130
  //# sourceMappingURL=common.js.map
@@ -8,6 +8,7 @@ import type { NodeId } from '../../../../../r-bridge/lang-4.x/ast/model/processi
8
8
  import type { RNode } from '../../../../../r-bridge/lang-4.x/ast/model/model';
9
9
  import type { IdentifierReference } from '../../../../environments/identifier';
10
10
  import { DataflowGraph } from '../../../../graph/graph';
11
+ import type { ContainerIndicesCollection } from '../../../../graph/vertex';
11
12
  export interface ProcessKnownFunctionCallInput<OtherInfo> extends ForceArguments {
12
13
  readonly name: RSymbol<OtherInfo & ParentInformation>;
13
14
  readonly args: readonly (RNode<OtherInfo & ParentInformation> | RFunctionArgument<OtherInfo & ParentInformation>)[];
@@ -28,4 +29,4 @@ export interface ProcessKnownFunctionCallResult {
28
29
  readonly fnRef: IdentifierReference;
29
30
  }
30
31
  export declare function markNonStandardEvaluationEdges(markAsNSE: readonly number[], callArgs: readonly (DataflowInformation | undefined)[], finalGraph: DataflowGraph, rootId: NodeId): void;
31
- export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>): ProcessKnownFunctionCallResult;
32
+ export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>, indicesCollection?: ContainerIndicesCollection): ProcessKnownFunctionCallResult;
@@ -23,7 +23,7 @@ function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId)
23
23
  }
24
24
  }
25
25
  }
26
- function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }) {
26
+ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }, indicesCollection = undefined) {
27
27
  const functionName = (0, processor_1.processDataflowFor)(name, data);
28
28
  const finalGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
29
29
  const functionCallName = name.content;
@@ -41,7 +41,8 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
41
41
  /* will be overwritten accordingly */
42
42
  onlyBuiltin: false,
43
43
  controlDependencies: data.controlDependencies,
44
- args: reverseOrder ? [...callArgs].reverse() : callArgs
44
+ args: reverseOrder ? [...callArgs].reverse() : callArgs,
45
+ indicesCollection: indicesCollection,
45
46
  });
46
47
  if (hasUnknownSideEffect) {
47
48
  finalGraph.markIdForUnknownSideEffects(rootId);
@@ -162,6 +162,11 @@ function explainConfigFile() {
162
162
  When running _flowR_, you may want to specify some behaviors with a dedicated configuration file.
163
163
  By default, flowR looks for a file named \`${flowr_main_options_1.defaultConfigFile}\` in the current working directory (or any higher directory).
164
164
  You can also specify a different file with ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'config-file')} or pass the configuration inline using ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'config-json')}.
165
+ To inspect the current configuration, you can run flowr with the ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'verbose')} flag, or use the \`config\` [Query](${doc_files_1.FlowrWikiBaseRef}/Query%20API).
166
+ Within the REPL this works by running the following:
167
+
168
+ ${(0, doc_code_1.codeBlock)('shell', ':query @config')}
169
+
165
170
 
166
171
  The following summarizes the configuration options:
167
172
 
@@ -171,6 +176,7 @@ The following summarizes the configuration options:
171
176
  - \`semantics\`: allows to configure the way _flowR_ handles R, although we currently only support \`semantics/environment/overwriteBuiltIns\`.
172
177
  You may use this to overwrite _flowR_'s handling of built-in function and even completely clear the preset definitions shipped with flowR.
173
178
  See [Configure BuiltIn Semantics](#configure-builtin-semantics) for more information.
179
+ - \`solver\`: allows to configure how _flowR_ resolves variables and their values (currently we support: ${Object.values(config_1.VariableResolve).map(v => `\`${v}\``).join(', ')}), as well as if pointer analysis should be active.
174
180
 
175
181
  So you can configure _flowR_ by adding a file like the following:
176
182
 
@@ -189,6 +195,10 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
189
195
  ]
190
196
  }
191
197
  }
198
+ },
199
+ solver: {
200
+ variables: config_1.VariableResolve.Alias,
201
+ pointerTracking: true
192
202
  }
193
203
  }, null, 2))}
194
204
 
@@ -204,8 +214,8 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
204
214
  - \`loadDefaults\` (boolean, initially \`true\`): If set to \`true\`, the default built-in definitions are loaded before applying the custom definitions. Setting this flag to \`false\` explicitly disables the loading of the default definitions.
205
215
  - \`definitions\` (array, initially empty): Allows to overwrite or define new built-in elements. Each object within must have a \`type\` which is one of the below. Furthermore, they may define a string array of \`names\` which specifies the identifiers to bind the definitions to. You may use \`assumePrimitive\` to specify whether _flowR_ should assume that this is a primitive non-library definition (so you probably just do not want to specify the key).
206
216
 
207
- | Type | Description | Example |
208
- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
217
+ | Type | Description | Example |
218
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
209
219
  | \`constant\` | Additionally allows for a \`value\` this should resolve to. | \`{ type: 'constant', names: ['NULL', 'NA'], value: null }\` |
210
220
  | \`function\` | Is a rather flexible way to define and bind built-in functions. For the time, we do not have extensive documentation to cover all the cases, so please either consult the sources with the \`default-builtin-config.ts\` or open a [new issue](${doc_issue_1.NewIssueUrl}). | \`{ type: 'function', names: ['next'], processor: 'builtin:default', config: { cfg: ExitPointType.Next } }\` |
211
221
  | \`replacement\` | A comfortable way to specify replacement functions like \`$<-\` or \`names<-\`. \`suffixes\` describes the... suffixes to attach automatically. | \`{ type: 'replacement', suffixes: ['<-', '<<-'], names: ['[', '[['] }\` |
@@ -233,7 +243,7 @@ _flowR_ can be used as a [module](${doc_files_1.FlowrNpmRef}) and offers several
233
243
  ### Using the \`${shell_1.RShell.name}\` to Interact with R
234
244
 
235
245
  The \`${shell_1.RShell.name}\` class allows to interface with the \`R\`&nbsp;ecosystem installed on the host system.
236
- For now there are no (real) alternatives, although we plan on providing more flexible drop-in replacements.
246
+ For now, there are no (real) alternatives, although we plan on providing more flexible drop-in replacements.
237
247
 
238
248
  > [!IMPORTANT]
239
249
  > Each \`${shell_1.RShell.name}\` controls a new instance of the R&nbsp;interpreter, make sure to call \`${shell_1.RShell.name}::${shell.close.name}()\` when you’re done.