@eagleoutice/flowr 2.9.9 → 2.9.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.
Files changed (55) hide show
  1. package/README.md +34 -29
  2. package/abstract-interpretation/absint-visitor.d.ts +16 -14
  3. package/abstract-interpretation/absint-visitor.js +91 -46
  4. package/abstract-interpretation/data-frame/shape-inference.d.ts +2 -5
  5. package/abstract-interpretation/data-frame/shape-inference.js +4 -5
  6. package/abstract-interpretation/domains/abstract-domain.d.ts +4 -4
  7. package/abstract-interpretation/domains/abstract-domain.js +8 -8
  8. package/abstract-interpretation/domains/mapped-abstract-domain.d.ts +12 -5
  9. package/abstract-interpretation/domains/mapped-abstract-domain.js +47 -23
  10. package/abstract-interpretation/domains/state-abstract-domain.d.ts +30 -1
  11. package/abstract-interpretation/domains/state-abstract-domain.js +130 -4
  12. package/control-flow/cfg-simplification.d.ts +1 -0
  13. package/control-flow/cfg-simplification.js +1 -0
  14. package/control-flow/extract-cfg.js +33 -15
  15. package/control-flow/semantic-cfg-guided-visitor.js +1 -0
  16. package/dataflow/environments/built-in.d.ts +4 -0
  17. package/dataflow/environments/built-in.js +17 -5
  18. package/dataflow/environments/default-builtin-config.d.ts +4 -8
  19. package/dataflow/environments/default-builtin-config.js +8 -5
  20. package/dataflow/environments/reference-to-maybe.d.ts +8 -0
  21. package/dataflow/environments/reference-to-maybe.js +46 -3
  22. package/dataflow/eval/resolve/alias-tracking.d.ts +1 -1
  23. package/dataflow/eval/resolve/alias-tracking.js +4 -5
  24. package/dataflow/eval/resolve/resolve.js +8 -7
  25. package/dataflow/graph/graph.d.ts +1 -1
  26. package/dataflow/graph/graph.js +9 -10
  27. package/dataflow/graph/unknown-side-effect.js +3 -1
  28. package/dataflow/info.d.ts +4 -0
  29. package/dataflow/info.js +2 -2
  30. package/dataflow/internal/linker.d.ts +2 -2
  31. package/dataflow/internal/linker.js +52 -27
  32. package/dataflow/internal/process/functions/call/argument/make-argument.js +2 -1
  33. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +15 -6
  34. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +2 -2
  35. package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +4 -4
  36. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -11
  37. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +22 -19
  38. package/dataflow/internal/process/functions/call/known-call-handling.js +0 -2
  39. package/documentation/wiki-absint.js +7 -8
  40. package/linter/rules/dead-code.js +1 -1
  41. package/linter/rules/seeded-randomness.js +1 -1
  42. package/linter/rules/unused-definition.js +1 -1
  43. package/package.json +7 -7
  44. package/project/plugins/file-plugins/files/flowr-description-file.d.ts +4 -0
  45. package/project/plugins/file-plugins/files/flowr-description-file.js +4 -0
  46. package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
  47. package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +1 -1
  48. package/queries/catalog/df-shape-query/df-shape-query-format.js +3 -3
  49. package/r-bridge/lang-4.x/ast/model/processing/decorate.js +23 -17
  50. package/r-bridge/lang-4.x/ast/model/processing/role.d.ts +18 -17
  51. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +31 -13
  52. package/statistics/features/supported/data-access/data-access.js +2 -2
  53. package/util/mermaid/ast.js +1 -1
  54. package/util/mermaid/dfg.js +6 -5
  55. package/util/version.js +1 -1
@@ -112,8 +112,8 @@ exports.DefaultBuiltinConfig = [
112
112
  'pdf', 'jpeg', 'png', 'windows', 'postscript', 'xfig', 'bitmap', 'pictex', 'cairo_pdf', 'svg', 'bmp', 'tiff', 'X11', 'quartz',
113
113
  'jitter'
114
114
  ],
115
- processor: built_in_1.BuiltInProcName.Default,
116
- config: { readAllArguments: true },
115
+ processor: built_in_1.BuiltInProcName.DefaultReadAllArgs,
116
+ config: {},
117
117
  assumePrimitive: true
118
118
  },
119
119
  {
@@ -121,8 +121,8 @@ exports.DefaultBuiltinConfig = [
121
121
  names: [
122
122
  't', 'aperm' /* transpose function, permutation generation */
123
123
  ],
124
- processor: built_in_1.BuiltInProcName.Default,
125
- config: { readAllArguments: true },
124
+ processor: built_in_1.BuiltInProcName.DefaultReadAllArgs,
125
+ config: {},
126
126
  assumePrimitive: false
127
127
  },
128
128
  { type: 'function', names: ['rm'], processor: built_in_1.BuiltInProcName.Rm, config: {}, assumePrimitive: true },
@@ -371,6 +371,9 @@ function getDefaultProcessor(name) {
371
371
  }
372
372
  const fn = exports.DefaultBuiltinConfig.find(def => (def.names.includes(name) && def.type !== 'constant')
373
373
  || (def.type === 'replacement' && def.suffixes.flatMap(d => def.names.map(n => `${n}${d}`)).includes(name)));
374
- return fn?.type === 'replacement' ? built_in_1.BuiltInProcName.Replacement : fn?.processor;
374
+ if (fn?.type === 'replacement') {
375
+ return built_in_1.BuiltInProcName.Replacement;
376
+ }
377
+ return fn?.processor === built_in_1.BuiltInProcName.DefaultReadAllArgs ? built_in_1.BuiltInProcName.Default : fn?.processor;
375
378
  }
376
379
  //# sourceMappingURL=default-builtin-config.js.map
@@ -11,3 +11,11 @@ export declare function makeReferenceMaybe(ref: IdentifierReference, graph: Data
11
11
  * @see {@link makeReferenceMaybe}
12
12
  */
13
13
  export declare function makeAllMaybe(references: readonly IdentifierReference[] | undefined, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, applyCds?: ControlDependency[] | undefined): IdentifierReference[];
14
+ /**
15
+ * apply the given cds to all elements in the graph and also transform the given references similar to {@link makeAllMaybe}.
16
+ */
17
+ export declare function applyCdsToAllInGraphButConstants(graph: DataflowGraph, references: readonly IdentifierReference[], cds: readonly ControlDependency[]): void;
18
+ /**
19
+ * apply the given cds to all given references, but not to the graph. This is useful if we want to mark the references as maybe without marking all other nodes in the graph as maybe.
20
+ */
21
+ export declare function applyCdToReferences(references: readonly IdentifierReference[], cds: readonly ControlDependency[]): void;
@@ -2,16 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeReferenceMaybe = makeReferenceMaybe;
4
4
  exports.makeAllMaybe = makeAllMaybe;
5
+ exports.applyCdsToAllInGraphButConstants = applyCdsToAllInGraphButConstants;
6
+ exports.applyCdToReferences = applyCdToReferences;
5
7
  const identifier_1 = require("./identifier");
6
8
  const resolve_by_name_1 = require("./resolve-by-name");
9
+ const vertex_1 = require("../graph/vertex");
7
10
  function appToCdsUnique(target, toAdd) {
8
11
  if (toAdd) {
9
- target.push(...toAdd.filter(c => !target.find(tc => tc.id === c.id && tc.when === c.when)));
12
+ target.push(...toAdd.filter(c => !target.some(tc => tc.id === c.id && tc.when === c.when)));
10
13
  }
11
14
  }
12
15
  function concatCdsUnique(target, toAdd) {
13
16
  if (toAdd) {
14
- return target.concat(toAdd.filter(c => !target.find(tc => tc.id === c.id && tc.when === c.when)));
17
+ return target.concat(toAdd.filter(c => !target.some(tc => tc.id === c.id && tc.when === c.when)));
15
18
  }
16
19
  else {
17
20
  return target;
@@ -58,6 +61,46 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
58
61
  * @see {@link makeReferenceMaybe}
59
62
  */
60
63
  function makeAllMaybe(references, graph, environments, includeDefs, applyCds = undefined) {
61
- return references?.map(ref => makeReferenceMaybe(ref, graph, environments, includeDefs, applyCds)) ?? [];
64
+ if (references === undefined || references.length === 0) {
65
+ return [];
66
+ }
67
+ return references.map(ref => makeReferenceMaybe(ref, graph, environments, includeDefs, applyCds));
68
+ }
69
+ /**
70
+ * apply the given cds to all elements in the graph and also transform the given references similar to {@link makeAllMaybe}.
71
+ */
72
+ function applyCdsToAllInGraphButConstants(graph, references, cds) {
73
+ for (const [, v] of graph.vertices(true)) {
74
+ if (v.tag === vertex_1.VertexType.Value) {
75
+ continue;
76
+ }
77
+ if (v.cds) {
78
+ appToCdsUnique(v.cds, cds);
79
+ }
80
+ else {
81
+ v.cds = Array.from(cds);
82
+ }
83
+ }
84
+ for (const ref of references) {
85
+ if (ref.cds) {
86
+ appToCdsUnique(ref.cds, cds);
87
+ }
88
+ else {
89
+ ref.cds = Array.from(cds);
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * apply the given cds to all given references, but not to the graph. This is useful if we want to mark the references as maybe without marking all other nodes in the graph as maybe.
95
+ */
96
+ function applyCdToReferences(references, cds) {
97
+ for (const ref of references) {
98
+ if (ref.cds) {
99
+ appToCdsUnique(ref.cds, cds);
100
+ }
101
+ else {
102
+ ref.cds = Array.from(cds);
103
+ }
104
+ }
62
105
  }
63
106
  //# sourceMappingURL=reference-to-maybe.js.map
@@ -58,7 +58,7 @@ export declare function getAliases(sourceIds: readonly NodeId[], dataflow: Dataf
58
58
  * @param ctx - Context used for clean environment
59
59
  * @param blocked - If set, the ids that should not be considered during resolution (=>top)
60
60
  */
61
- export declare function resolveIdToValue(id: NodeId | RNodeWithParent | undefined, { environment, graph, idMap, full, resolve, ctx, blocked }: ResolveInfo): ResolveResult;
61
+ export declare function resolveIdToValue(id: NodeId | RNodeWithParent | undefined, { environment, graph, idMap, full, ctx, resolve, blocked }: ResolveInfo): ResolveResult;
62
62
  /**
63
63
  * Please use {@link resolveIdToValue}
64
64
  *
@@ -119,8 +119,7 @@ function getAliases(sourceIds, dataflow, environment) {
119
119
  * @param ctx - Context used for clean environment
120
120
  * @param blocked - If set, the ids that should not be considered during resolution (=>top)
121
121
  */
122
- function resolveIdToValue(id, { environment, graph, idMap, full = true, resolve, ctx, blocked }) {
123
- const variableResolve = resolve ?? ctx.config.solver.variables;
122
+ function resolveIdToValue(id, { environment, graph, idMap, full = true, ctx, resolve = ctx.config.solver.variables, blocked }) {
124
123
  blocked ??= new Set();
125
124
  if (id === undefined) {
126
125
  return r_value_1.Top;
@@ -134,13 +133,13 @@ function resolveIdToValue(id, { environment, graph, idMap, full = true, resolve,
134
133
  switch (node.type) {
135
134
  case type_1.RType.Argument:
136
135
  if (node.value) {
137
- return resolveIdToValue(node.value.info.id, { environment, graph, idMap, full, resolve: variableResolve, ctx, blocked });
136
+ return resolveIdToValue(node.value.info.id, { environment, graph, idMap, full, resolve, ctx, blocked });
138
137
  }
139
138
  // eslint-disable-next-line no-fallthrough
140
139
  case type_1.RType.Symbol:
141
140
  if (full) {
142
141
  if (environment) {
143
- return trackAliasInEnvironments(identifier_1.Identifier.toString(node.content), environment, { idMap, resolve: variableResolve, ctx, graph, blocked });
142
+ return trackAliasInEnvironments(identifier_1.Identifier.toString(node.content), environment, { idMap, resolve, ctx, graph, blocked });
144
143
  }
145
144
  else if (graph && resolve === config_1.VariableResolve.Alias) {
146
145
  return trackAliasesInGraph(node.info.id, graph, ctx, idMap);
@@ -153,7 +152,7 @@ function resolveIdToValue(id, { environment, graph, idMap, full = true, resolve,
153
152
  case type_1.RType.BinaryOp:
154
153
  case type_1.RType.UnaryOp:
155
154
  return (0, set_constants_1.setFrom)((0, resolve_1.resolveNode)({
156
- resolve: variableResolve, node, ctx, environment, graph, idMap, blocked
155
+ resolve, node, ctx, environment, graph, idMap, blocked
157
156
  }));
158
157
  case type_1.RType.String:
159
158
  case type_1.RType.Number:
@@ -27,19 +27,20 @@ const identifier_1 = require("../../environments/identifier");
27
27
  * @returns resolved value or top/bottom
28
28
  */
29
29
  function resolveNode({ resolve, node, ctx, blocked, environment, graph, idMap }) {
30
- if (node.type === type_1.RType.String) {
30
+ const nt = node.type;
31
+ if (nt === type_1.RType.String) {
31
32
  return (0, string_constants_1.stringFrom)(node.content.str);
32
33
  }
33
- else if (node.type === type_1.RType.Number) {
34
+ else if (nt === type_1.RType.Number) {
34
35
  return (0, interval_constants_1.intervalFrom)(node.content.num, node.content.num);
35
36
  }
36
- else if (node.type === type_1.RType.Logical) {
37
+ else if (nt === type_1.RType.Logical) {
37
38
  return node.content.valueOf() ? logical_constants_1.ValueLogicalTrue : logical_constants_1.ValueLogicalFalse;
38
39
  }
39
- else if (node.type === type_1.RType.FunctionDefinition) {
40
+ else if (nt === type_1.RType.FunctionDefinition) {
40
41
  return { type: 'function-definition' };
41
42
  }
42
- else if ((node.type === type_1.RType.FunctionCall || node.type === type_1.RType.BinaryOp || node.type === type_1.RType.UnaryOp) && graph) {
43
+ else if ((nt === type_1.RType.FunctionCall || nt === type_1.RType.BinaryOp || nt === type_1.RType.UnaryOp) && graph) {
43
44
  const origin = (0, dfg_get_origin_1.getOriginInDfg)(graph, node.info.id)?.[0];
44
45
  if (origin === undefined || origin.type !== 3 /* OriginType.BuiltInFunctionOrigin */) {
45
46
  return r_value_2.Top;
@@ -48,10 +49,10 @@ function resolveNode({ resolve, node, ctx, blocked, environment, graph, idMap })
48
49
  if ((0, built_in_1.isBuiltIn)(origin.proc)) {
49
50
  builtInName = origin.proc;
50
51
  }
51
- else if (node.type === type_1.RType.FunctionCall && node.named) {
52
+ else if (nt === type_1.RType.FunctionCall && node.named) {
52
53
  builtInName = (0, built_in_1.builtInId)(identifier_1.Identifier.getName(node.functionName.content));
53
54
  }
54
- else if (node.type === type_1.RType.BinaryOp || node.type === type_1.RType.UnaryOp) {
55
+ else if (nt === type_1.RType.BinaryOp || nt === type_1.RType.UnaryOp) {
55
56
  builtInName = (0, built_in_1.builtInId)(node.operator);
56
57
  }
57
58
  else {
@@ -88,7 +88,7 @@ export declare const FunctionArgument: {
88
88
  * ```
89
89
  * @see {@link isNotEmpty}
90
90
  */
91
- readonly isEmpty: (this: void, arg: FunctionArgument) => arg is typeof EmptyArgument;
91
+ readonly isEmpty: (this: void, arg: unknown) => arg is typeof EmptyArgument;
92
92
  /**
93
93
  * Checks whether the given argument is not an empty argument.
94
94
  * @see {@link isEmpty}
@@ -267,25 +267,24 @@ class DataflowGraph {
267
267
  * @see DataflowGraphVertexArgument
268
268
  */
269
269
  addVertex(vertex, fallbackEnv, asRoot = true, overwrite = false) {
270
- const oldVertex = this.vertexInformation.get(vertex.id);
270
+ const vid = vertex.id;
271
+ const oldVertex = this.vertexInformation.get(vid);
271
272
  if (oldVertex !== undefined && !overwrite) {
272
273
  return this;
273
274
  }
274
- const fallback = vertex.tag === vertex_1.VertexType.FunctionDefinition || (vertex.tag === vertex_1.VertexType.FunctionCall && !vertex.onlyBuiltin) ? fallbackEnv : undefined;
275
- this.vertexInformation.set(vertex.id, {
276
- ...vertex,
277
- // keep a clone of the original environment
278
- environment: vertex.environment ? (0, clone_1.cloneEnvironmentInformation)(vertex.environment) : fallback
279
- });
275
+ const vtag = vertex.tag;
276
+ // keep a clone of the original environment
277
+ vertex.environment = vertex.environment ? (0, clone_1.cloneEnvironmentInformation)(vertex.environment) : (vtag === vertex_1.VertexType.FunctionDefinition || (vtag === vertex_1.VertexType.FunctionCall && !vertex.onlyBuiltin) ? fallbackEnv : undefined);
278
+ this.vertexInformation.set(vid, vertex);
280
279
  const has = this.types.get(vertex.tag);
281
280
  if (has) {
282
- has.push(vertex.id);
281
+ has.push(vid);
283
282
  }
284
283
  else {
285
- this.types.set(vertex.tag, [vertex.id]);
284
+ this.types.set(vertex.tag, [vid]);
286
285
  }
287
286
  if (asRoot) {
288
- this.rootVertices.add(vertex.id);
287
+ this.rootVertices.add(vid);
289
288
  }
290
289
  return this;
291
290
  }
@@ -16,6 +16,8 @@ function onUnknownSideEffect(handler) {
16
16
  */
17
17
  function handleUnknownSideEffect(graph, env, id, target) {
18
18
  graph.markIdForUnknownSideEffects(id, target);
19
- handlers.forEach(handler => handler(graph, env, id, target));
19
+ for (const handler of handlers) {
20
+ handler(graph, env, id, target);
21
+ }
20
22
  }
21
23
  //# sourceMappingURL=unknown-side-effect.js.map
@@ -19,6 +19,10 @@ export interface ControlDependency {
19
19
  readonly when?: boolean;
20
20
  /** whether this control dependency was created due to iteration (e.g., a loop) */
21
21
  readonly byIteration?: boolean;
22
+ /**
23
+ * any file-exist assumptions made
24
+ */
25
+ readonly file?: string;
22
26
  }
23
27
  /**
24
28
  * Negates the given control dependency (i.e., flips the `when` flag).
package/dataflow/info.js CHANGED
@@ -66,7 +66,7 @@ function initializeCleanDataflowInformation(entryPoint, data) {
66
66
  in: [],
67
67
  out: [],
68
68
  environment: data.environment,
69
- graph: new graph_1.DataflowGraph(data.completeAst.idMap),
69
+ graph: new graph_1.DataflowGraph(undefined),
70
70
  entryPoint,
71
71
  exitPoints: [{ nodeId: entryPoint, type: 0 /* ExitPointType.Default */ }],
72
72
  hooks: []
@@ -138,7 +138,7 @@ function diffControlDependency(a, b, info) {
138
138
  info.report.addComment(`${info.position}Different control dependency ids. ${info.leftname}: ${JSON.stringify(a.id)} vs. ${info.rightname}: ${JSON.stringify(b.id)}`);
139
139
  }
140
140
  if (a.when !== b.when) {
141
- info.report.addComment(`${info.position}Different control dependency when. ${info.leftname}: ${a.when} vs. ${info.rightname}: ${b.when}`);
141
+ info.report.addComment(`${info.position}Different control dependency when (id: ${JSON.stringify(a.id)}). ${info.leftname}: ${a.when} vs. ${info.rightname}: ${b.when}`);
142
142
  }
143
143
  }
144
144
  /**
@@ -12,7 +12,7 @@ export type NameIdMap = DefaultMap<Identifier, IdentifierReference[]>;
12
12
  /**
13
13
  * Find all reads within the graph that do not reference a local definition in the graph.
14
14
  */
15
- export declare function findNonLocalReads(graph: DataflowGraph, ignore: readonly IdentifierReference[]): IdentifierReference[];
15
+ export declare function findNonLocalReads(graph: DataflowGraph, ignores?: ReadonlySet<NodeId>): IdentifierReference[];
16
16
  /**
17
17
  * Produces a map from names to all identifier references sharing that name.
18
18
  */
@@ -101,4 +101,4 @@ export declare function linkCircularRedefinitionsWithinALoop(graph: DataflowGrap
101
101
  /**
102
102
  * Reapplies the loop exit points' control dependencies to the given identifier references.
103
103
  */
104
- export declare function reapplyLoopExitPoints(exits: readonly ExitPoint[], references: readonly IdentifierReference[]): void;
104
+ export declare function reapplyLoopExitPoints(exits: readonly ExitPoint[], references: readonly IdentifierReference[], graph: DataflowGraph): void;
@@ -32,27 +32,29 @@ const unnamed_call_handling_1 = require("./process/functions/call/unnamed-call-h
32
32
  /**
33
33
  * Find all reads within the graph that do not reference a local definition in the graph.
34
34
  */
35
- function findNonLocalReads(graph, ignore) {
36
- const ignores = new Set(ignore.map(i => i.nodeId));
37
- const ids = new Set(graph.vertexIdsOfType(vertex_1.VertexType.Use).concat(graph.vertexIdsOfType(vertex_1.VertexType.FunctionCall)));
35
+ function findNonLocalReads(graph, ignores = new Set()) {
36
+ const defs = new Set(graph.vertexIdsOfType(vertex_1.VertexType.VariableDefinition).concat(graph.vertexIdsOfType(vertex_1.VertexType.FunctionDefinition)));
38
37
  /* find all variable use ids which do not link to a given id */
39
38
  const nonLocalReads = [];
40
- for (const nodeId of ids) {
41
- if (ignores.has(nodeId)) {
42
- continue;
43
- }
44
- const outgoing = graph.outgoingEdges(nodeId);
45
- const name = (0, node_id_1.recoverName)(nodeId, graph.idMap);
46
- const origin = graph.getVertex(nodeId);
47
- const type = origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable;
48
- if (outgoing === undefined) {
49
- nonLocalReads.push({ name, nodeId, type });
50
- continue;
51
- }
52
- for (const [target, e] of outgoing) {
53
- if (edge_1.DfEdge.includesType(e, edge_1.EdgeType.Reads) && !ids.has(target)) {
54
- nonLocalReads.push({ name, nodeId, type });
55
- break;
39
+ for (const ids of [graph.vertexIdsOfType(vertex_1.VertexType.Use), graph.vertexIdsOfType(vertex_1.VertexType.FunctionCall)]) {
40
+ for (const nodeId of ids) {
41
+ if (ignores.has(nodeId)) {
42
+ continue;
43
+ }
44
+ const outgoing = graph.outgoingEdges(nodeId);
45
+ const origin = graph.getVertex(nodeId);
46
+ const name = (0, node_id_1.recoverName)(nodeId, graph.idMap);
47
+ const type = origin?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Variable;
48
+ const identifierRef = { nodeId, name, type };
49
+ if (outgoing === undefined) {
50
+ nonLocalReads.push(identifierRef);
51
+ continue;
52
+ }
53
+ for (const [target, e] of outgoing) {
54
+ if (edge_1.DfEdge.includesType(e, edge_1.EdgeType.Reads) && !defs.has(target)) {
55
+ nonLocalReads.push(identifierRef);
56
+ break;
57
+ }
56
58
  }
57
59
  }
58
60
  }
@@ -64,8 +66,9 @@ function findNonLocalReads(graph, ignore) {
64
66
  function produceNameSharedIdMap(references) {
65
67
  const nameIdShares = new defaultmap_1.DefaultMap(() => []);
66
68
  for (const reference of references) {
67
- if (reference.name) {
68
- nameIdShares.get(reference.name).push(reference);
69
+ const rn = reference.name;
70
+ if (rn) {
71
+ nameIdShares.get(rn).push(reference);
69
72
  }
70
73
  }
71
74
  return nameIdShares;
@@ -473,8 +476,9 @@ function linkCircularRedefinitionsWithinALoop(graph, openIns, outgoing) {
473
476
  // this implicitly assumes that the outgoing references are ordered
474
477
  const lastOutgoing = new Map();
475
478
  for (const out of outgoing) {
476
- if (out.name) {
477
- lastOutgoing.set(out.name, out);
479
+ const on = out.name;
480
+ if (on) {
481
+ lastOutgoing.set(on, out);
478
482
  }
479
483
  }
480
484
  for (const [name, targets] of openIns.entries()) {
@@ -490,19 +494,40 @@ function linkCircularRedefinitionsWithinALoop(graph, openIns, outgoing) {
490
494
  /**
491
495
  * Reapplies the loop exit points' control dependencies to the given identifier references.
492
496
  */
493
- function reapplyLoopExitPoints(exits, references) {
497
+ function reapplyLoopExitPoints(exits, references, graph) {
494
498
  // just apply the cds of all exit points not already present
495
- const exitCds = new Set(exits.flatMap(e => e.cds).filter(assert_1.isNotUndefined));
499
+ const exitCds = new Set(exits.flatMap(e => e.cds?.map(info_1.negateControlDependency)).filter(assert_1.isNotUndefined));
500
+ const seenRefs = new Set();
496
501
  for (const ref of references) {
502
+ if (seenRefs.has(ref.nodeId)) {
503
+ continue;
504
+ }
505
+ seenRefs.add(ref.nodeId);
497
506
  for (const cd of exitCds) {
498
- const { id: cId, when: cWhen } = cd;
507
+ const { id: cId } = cd;
508
+ let setVertex = false;
499
509
  if (ref.cds) {
500
- if (!ref.cds?.find(c => c.id === cId && c.when === cWhen)) {
510
+ if (!ref.cds?.find(c => c.id === cId)) {
501
511
  ref.cds.push({ ...cd, byIteration: true });
512
+ setVertex = true;
502
513
  }
503
514
  }
504
515
  else {
505
516
  ref.cds = [{ ...cd, byIteration: true }];
517
+ setVertex = true;
518
+ }
519
+ if (setVertex) {
520
+ const vertex = graph.getVertex(ref.nodeId);
521
+ if (vertex) {
522
+ if (vertex.cds) {
523
+ if (!vertex.cds?.find(c => c.id === cId)) {
524
+ vertex.cds.push({ ...cd, byIteration: true });
525
+ }
526
+ }
527
+ else {
528
+ vertex.cds = [{ ...cd, byIteration: true }];
529
+ }
530
+ }
506
531
  }
507
532
  }
508
533
  }
@@ -5,6 +5,7 @@ exports.wrapArgumentsUnnamed = wrapArgumentsUnnamed;
5
5
  const range_1 = require("../../../../../../util/range");
6
6
  const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
7
7
  const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
8
+ const graph_1 = require("../../../../../graph/graph");
8
9
  /**
9
10
  * Converts a normalized node into an unnamed argument (wraps it with an argument node).
10
11
  */
@@ -30,6 +31,6 @@ function toUnnamedArgument(node, idMap) {
30
31
  * Wraps the given nodes as unnamed arguments where necessary.
31
32
  */
32
33
  function wrapArgumentsUnnamed(nodes, idMap) {
33
- return nodes.map(n => n === r_function_call_1.EmptyArgument || n?.type === type_1.RType.Argument ? n : toUnnamedArgument(n, idMap));
34
+ return nodes.map(n => graph_1.FunctionArgument.isEmpty(n) || n?.type === type_1.RType.Argument ? n : toUnnamedArgument(n, idMap));
34
35
  }
35
36
  //# sourceMappingURL=make-argument.js.map
@@ -29,6 +29,8 @@ function processForLoop(name, args, rootId, data) {
29
29
  return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
30
30
  }
31
31
  const [variableArg, vectorArg, bodyArg] = args.map(e => (0, unpack_argument_1.unpackNonameArg)(e));
32
+ // we store the original environment here, as we merge it back lter in case the for-loop never executes
33
+ const origEnv = data.environment;
32
34
  (0, assert_1.guard)(variableArg !== undefined && vectorArg !== undefined && bodyArg !== undefined, () => `For-Loop ${JSON.stringify(args)} has missing arguments! Bad!`);
33
35
  const vector = (0, processor_1.processDataflowFor)(vectorArg, data);
34
36
  if ((0, info_1.alwaysExits)(vector)) {
@@ -41,23 +43,29 @@ function processForLoop(name, args, rootId, data) {
41
43
  let headEnvironments = (0, overwrite_1.overwriteEnvironment)(vector.environment, variable.environment);
42
44
  const headGraph = variable.graph.mergeWith(vector.graph);
43
45
  const writtenVariable = variable.unknownReferences.concat(variable.in);
46
+ const writtenIds = new Set();
44
47
  for (const write of writtenVariable) {
48
+ writtenIds.add(write.nodeId);
45
49
  headEnvironments = (0, define_1.define)({ ...write, definedAt: name.info.id, type: identifier_1.ReferenceType.Variable }, false, headEnvironments);
46
50
  }
47
- data = { ...data, cds: [...data.cds ?? [], { id: name.info.id, when: true }], environment: headEnvironments };
51
+ data.environment = headEnvironments;
48
52
  const body = (0, processor_1.processDataflowFor)(bodyArg, data);
49
- const nextGraph = headGraph.mergeWith(body.graph);
50
53
  const outEnvironment = (0, append_1.appendEnvironment)(headEnvironments, body.environment);
54
+ const cd = [{ id: name.info.id, when: true }];
55
+ const bodyRefs = body.in.concat(body.unknownReferences);
56
+ (0, reference_to_maybe_1.applyCdsToAllInGraphButConstants)(body.graph, bodyRefs, cd);
57
+ const nextGraph = headGraph.mergeWith(body.graph);
51
58
  // now we have to identify all reads that may be effected by a circular redefinition
52
59
  // for this, we search for all reads with a non-local read resolve!
53
- const nameIdShares = (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(nextGraph, writtenVariable));
60
+ const nameIdShares = (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(nextGraph, writtenIds));
54
61
  for (const write of writtenVariable) {
55
62
  nextGraph.addEdge(write.nodeId, vector.entryPoint, edge_1.EdgeType.DefinedBy);
56
63
  nextGraph.setDefinitionOfVertex(write);
57
64
  }
58
- const outgoing = variable.out.concat(writtenVariable, (0, reference_to_maybe_1.makeAllMaybe)(body.out, nextGraph, outEnvironment, true));
65
+ (0, reference_to_maybe_1.applyCdToReferences)(body.out, cd);
66
+ const outgoing = variable.out.concat(writtenVariable, body.out);
59
67
  (0, linker_1.linkCircularRedefinitionsWithinALoop)(nextGraph, nameIdShares, body.out);
60
- (0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
68
+ (0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences), nextGraph);
61
69
  (0, common_1.patchFunctionCall)({
62
70
  nextGraph,
63
71
  rootId,
@@ -78,7 +86,8 @@ function processForLoop(name, args, rootId, data) {
78
86
  graph: nextGraph,
79
87
  entryPoint: name.info.id,
80
88
  exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
81
- environment: outEnvironment,
89
+ // if we can not be sure that the for-loop runs once, we have to merge back the original environment, as the body may never execute
90
+ environment: (0, append_1.appendEnvironment)(origEnv, outEnvironment),
82
91
  hooks: variable.hooks.concat(vector.hooks, body.hooks),
83
92
  };
84
93
  }
@@ -41,8 +41,8 @@ function processRepeatLoop(name, args, rootId, data) {
41
41
  });
42
42
  const body = processedArguments[0];
43
43
  (0, assert_1.guard)(body !== undefined, () => `Repeat-Loop ${identifier_1.Identifier.toString(name.content)} has no body, impossible!`);
44
- (0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph, [])), body.out);
45
- (0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
44
+ (0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph)), body.out);
45
+ (0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences), information.graph);
46
46
  information.exitPoints = (0, info_1.filterOutLoopExitPoints)(information.exitPoints);
47
47
  return information;
48
48
  }
@@ -80,7 +80,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
80
80
  info: {
81
81
  id: argNameId,
82
82
  nesting: name.info.nesting,
83
- role: "arg-name" /* RoleInParent.ArgumentName */,
83
+ role: "arg-n" /* RoleInParent.ArgumentName */,
84
84
  fullRange: r,
85
85
  adToks: undefined,
86
86
  file: name.info.file,
@@ -117,7 +117,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
117
117
  info: {
118
118
  id: rootId + '-s7-new-generic-fun-body',
119
119
  nesting: name.info.nesting,
120
- role: "fun-body" /* RoleInParent.FunctionDefinitionBody */,
120
+ role: "fun-b" /* RoleInParent.FunctionDefinitionBody */,
121
121
  fullRange: r,
122
122
  adToks: undefined,
123
123
  file: name.info.file,
@@ -132,7 +132,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
132
132
  file: name.info.file,
133
133
  id: fdefId,
134
134
  nesting: name.info.nesting,
135
- role: "arg-value" /* RoleInParent.ArgumentValue */,
135
+ role: "arg-v" /* RoleInParent.ArgumentValue */,
136
136
  parent: rootId,
137
137
  index: args + 1,
138
138
  adToks: undefined,
@@ -150,7 +150,7 @@ function makeS7DispatchFDef(name, names, rootId, args, idMap) {
150
150
  info: {
151
151
  id: paramNameId,
152
152
  nesting: name.info.nesting,
153
- role: "param-name" /* RoleInParent.ParameterName */,
153
+ role: "param-n" /* RoleInParent.ParameterName */,
154
154
  fullRange: r,
155
155
  adToks: undefined,
156
156
  file: name.info.file,
@@ -155,19 +155,30 @@ function processSourceCall(name, args, rootId, data, config) {
155
155
  if (sourceFile?.length === 1) {
156
156
  const path = (0, retriever_1.removeRQuotes)(sourceFile[0]);
157
157
  let filepath = path ? findSource(data.ctx.config.solver.resolveSource, path, data) : path;
158
- if (Array.isArray(filepath)) {
159
- filepath = filepath?.[0];
158
+ if (!Array.isArray(filepath)) {
159
+ filepath = filepath ? [filepath] : undefined;
160
160
  }
161
- if (filepath !== undefined) {
162
- // check if the sourced file has already been dataflow analyzed, and if so, skip it
163
- const limit = data.ctx.config.solver.resolveSource?.repeatedSourceLimit ?? 0;
164
- const findCount = data.referenceChain.filter(e => e !== undefined && filepath === e).length;
165
- if (findCount > limit) {
166
- logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(filepath)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
167
- (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
168
- return information;
161
+ if (filepath !== undefined && filepath.length > 0) {
162
+ let result = information;
163
+ const origCds = data.cds?.slice() ?? [];
164
+ for (const f of filepath) {
165
+ // check if the sourced file has already been dataflow analyzed, and if so, skip it
166
+ const limit = data.ctx.config.solver.resolveSource?.repeatedSourceLimit ?? 0;
167
+ const findCount = data.referenceChain.filter(e => e !== undefined && f === e).length;
168
+ if (findCount > limit) {
169
+ logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(filepath)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
170
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(result.graph, result.environment, rootId);
171
+ continue;
172
+ }
173
+ if (filepath.length > 1) {
174
+ data = { ...data, cds: [...origCds, { id: rootId, when: true, file: f }] };
175
+ }
176
+ result = sourceRequest(rootId, {
177
+ request: 'file',
178
+ content: f
179
+ }, data, result, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + f, name.location));
169
180
  }
170
- return sourceRequest(rootId, { request: 'file', content: filepath }, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + path, name.location));
181
+ return result;
171
182
  }
172
183
  }
173
184
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);