@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.
- package/README.md +34 -29
- package/abstract-interpretation/absint-visitor.d.ts +16 -14
- package/abstract-interpretation/absint-visitor.js +91 -46
- package/abstract-interpretation/data-frame/shape-inference.d.ts +2 -5
- package/abstract-interpretation/data-frame/shape-inference.js +4 -5
- package/abstract-interpretation/domains/abstract-domain.d.ts +4 -4
- package/abstract-interpretation/domains/abstract-domain.js +8 -8
- package/abstract-interpretation/domains/mapped-abstract-domain.d.ts +12 -5
- package/abstract-interpretation/domains/mapped-abstract-domain.js +47 -23
- package/abstract-interpretation/domains/state-abstract-domain.d.ts +30 -1
- package/abstract-interpretation/domains/state-abstract-domain.js +130 -4
- package/control-flow/cfg-simplification.d.ts +1 -0
- package/control-flow/cfg-simplification.js +1 -0
- package/control-flow/extract-cfg.js +33 -15
- package/control-flow/semantic-cfg-guided-visitor.js +1 -0
- package/dataflow/environments/built-in.d.ts +4 -0
- package/dataflow/environments/built-in.js +17 -5
- package/dataflow/environments/default-builtin-config.d.ts +4 -8
- package/dataflow/environments/default-builtin-config.js +8 -5
- package/dataflow/environments/reference-to-maybe.d.ts +8 -0
- package/dataflow/environments/reference-to-maybe.js +46 -3
- package/dataflow/eval/resolve/alias-tracking.d.ts +1 -1
- package/dataflow/eval/resolve/alias-tracking.js +4 -5
- package/dataflow/eval/resolve/resolve.js +8 -7
- package/dataflow/graph/graph.d.ts +1 -1
- package/dataflow/graph/graph.js +9 -10
- package/dataflow/graph/unknown-side-effect.js +3 -1
- package/dataflow/info.d.ts +4 -0
- package/dataflow/info.js +2 -2
- package/dataflow/internal/linker.d.ts +2 -2
- package/dataflow/internal/linker.js +52 -27
- package/dataflow/internal/process/functions/call/argument/make-argument.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +15 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -11
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +22 -19
- package/dataflow/internal/process/functions/call/known-call-handling.js +0 -2
- package/documentation/wiki-absint.js +7 -8
- package/linter/rules/dead-code.js +1 -1
- package/linter/rules/seeded-randomness.js +1 -1
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +7 -7
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +4 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +4 -0
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.js +3 -3
- package/r-bridge/lang-4.x/ast/model/processing/decorate.js +23 -17
- package/r-bridge/lang-4.x/ast/model/processing/role.d.ts +18 -17
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +31 -13
- package/statistics/features/supported/data-access/data-access.js +2 -2
- package/util/mermaid/ast.js +1 -1
- package/util/mermaid/dfg.js +6 -5
- 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.
|
|
116
|
-
config: {
|
|
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.
|
|
125
|
-
config: {
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
40
|
+
else if (nt === type_1.RType.FunctionDefinition) {
|
|
40
41
|
return { type: 'function-definition' };
|
|
41
42
|
}
|
|
42
|
-
else if ((
|
|
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 (
|
|
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 (
|
|
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:
|
|
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}
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -267,25 +267,24 @@ class DataflowGraph {
|
|
|
267
267
|
* @see DataflowGraphVertexArgument
|
|
268
268
|
*/
|
|
269
269
|
addVertex(vertex, fallbackEnv, asRoot = true, overwrite = false) {
|
|
270
|
-
const
|
|
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
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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(
|
|
281
|
+
has.push(vid);
|
|
283
282
|
}
|
|
284
283
|
else {
|
|
285
|
-
this.types.set(vertex.tag, [
|
|
284
|
+
this.types.set(vertex.tag, [vid]);
|
|
286
285
|
}
|
|
287
286
|
if (asRoot) {
|
|
288
|
-
this.rootVertices.add(
|
|
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
|
-
|
|
19
|
+
for (const handler of handlers) {
|
|
20
|
+
handler(graph, env, id, target);
|
|
21
|
+
}
|
|
20
22
|
}
|
|
21
23
|
//# sourceMappingURL=unknown-side-effect.js.map
|
package/dataflow/info.d.ts
CHANGED
|
@@ -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(
|
|
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,
|
|
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,
|
|
36
|
-
const
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
-
|
|
477
|
-
|
|
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
|
|
507
|
+
const { id: cId } = cd;
|
|
508
|
+
let setVertex = false;
|
|
499
509
|
if (ref.cds) {
|
|
500
|
-
if (!ref.cds?.find(c => c.id === cId
|
|
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
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
158
|
+
if (!Array.isArray(filepath)) {
|
|
159
|
+
filepath = filepath ? [filepath] : undefined;
|
|
160
160
|
}
|
|
161
|
-
if (filepath !== undefined) {
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
|
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`);
|