@eagleoutice/flowr 2.0.1 → 2.0.2
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/benchmark/slicer.js +30 -5
- package/benchmark/stats/print.js +28 -9
- package/benchmark/stats/stats.d.ts +5 -0
- package/benchmark/summarizer/data.d.ts +10 -1
- package/benchmark/summarizer/first-phase/process.d.ts +1 -1
- package/benchmark/summarizer/first-phase/process.js +83 -30
- package/benchmark/summarizer/second-phase/process.js +20 -4
- package/cli/repl/commands/commands.js +19 -1
- package/cli/slicer-app.js +1 -1
- package/dataflow/environments/append.js +1 -2
- package/dataflow/environments/built-in.js +2 -1
- package/dataflow/environments/clone.js +1 -1
- package/dataflow/environments/diff.d.ts +1 -1
- package/dataflow/environments/diff.js +16 -18
- package/dataflow/environments/environment.d.ts +4 -7
- package/dataflow/environments/environment.js +5 -8
- package/dataflow/environments/identifier.d.ts +2 -1
- package/dataflow/environments/overwrite.js +1 -2
- package/dataflow/environments/scoping.js +1 -1
- package/dataflow/graph/diff.js +11 -6
- package/dataflow/graph/graph.d.ts +6 -2
- package/dataflow/graph/graph.js +13 -7
- package/dataflow/graph/vertex.d.ts +2 -1
- package/dataflow/info.d.ts +10 -1
- package/dataflow/info.js +54 -2
- package/dataflow/internal/linker.d.ts +1 -1
- package/dataflow/internal/linker.js +1 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +21 -25
- package/dataflow/internal/process/functions/call/built-in/built-in-get.js +6 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +10 -8
- package/dataflow/internal/process/functions/call/built-in/built-in-logical-bin-op.d.ts +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-logical-bin-op.js +1 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +1 -1
- package/dataflow/internal/process/functions/call/default-call-handling.js +1 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +1 -1
- package/dataflow/processor.d.ts +2 -3
- package/package.json +4 -2
- package/r-bridge/data/data.d.ts +1 -1
- package/r-bridge/data/data.js +1 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/model/operators.js +1 -1
- package/r-bridge/lang-4.x/ast/model/processing/decorate.js +1 -1
- package/r-bridge/lang-4.x/ast/model/processing/stateful-fold.js +1 -1
- package/r-bridge/lang-4.x/ast/model/processing/visitor.js +2 -2
- package/r-bridge/lang-4.x/ast/parser/xml/internal/functions/normalize-call.js +2 -2
- package/r-bridge/lang-4.x/ast/parser/xml/internal/operators/normalize-binary.js +1 -1
- package/r-bridge/retriever.d.ts +1 -1
- package/r-bridge/retriever.js +3 -2
- package/r-bridge/shell.js +2 -1
- package/reconstruct/reconstruct.d.ts +3 -3
- package/reconstruct/reconstruct.js +40 -41
- package/slicing/criterion/filters/all-variables.js +1 -1
- package/slicing/static/static-slicer.js +2 -2
- package/statistics/features/common-syntax-probability.js +1 -1
- package/statistics/features/supported/control-flow/control-flow.js +1 -1
- package/statistics/features/supported/defined-functions/defined-functions.js +1 -1
- package/statistics/features/supported/loops/loops.js +1 -1
- package/statistics/features/supported/used-functions/used-functions.js +1 -1
- package/util/assert.d.ts +1 -1
- package/util/mermaid/ast.js +4 -0
- package/util/mermaid/dfg.js +15 -5
- package/util/mermaid/mermaid.js +21 -1
- package/util/version.js +1 -1
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.diffEnvironmentInformation = exports.diffEnvironment = exports.diffIdentifierReferences = void 0;
|
|
4
4
|
const diff_1 = require("../../util/diff");
|
|
5
5
|
const json_1 = require("../../util/json");
|
|
6
|
-
const
|
|
6
|
+
const info_1 = require("../info");
|
|
7
7
|
function diffIdentifierReferences(a, b, info) {
|
|
8
8
|
if (a === undefined || b === undefined) {
|
|
9
9
|
if (a !== b) {
|
|
@@ -17,9 +17,7 @@ function diffIdentifierReferences(a, b, info) {
|
|
|
17
17
|
if (a.nodeId !== b.nodeId) {
|
|
18
18
|
info.report.addComment(`${info.position}Different nodeIds: ${info.leftname}: ${a.nodeId} vs. ${info.rightname}: ${b.nodeId}`);
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
info.report.addComment(`${info.position}Different control dependency: ${info.leftname}: ${JSON.stringify(a.controlDependencies)} vs. ${info.rightname}: ${JSON.stringify(b.controlDependencies)}`);
|
|
22
|
-
}
|
|
20
|
+
(0, info_1.diffControlDependencies)(a.controlDependencies, b.controlDependencies, info);
|
|
23
21
|
}
|
|
24
22
|
exports.diffIdentifierReferences = diffIdentifierReferences;
|
|
25
23
|
function diffMemory(a, b, info) {
|
|
@@ -41,9 +39,7 @@ function diffMemory(a, b, info) {
|
|
|
41
39
|
if (aVal.nodeId !== bVal.nodeId) {
|
|
42
40
|
info.report.addComment(`${info.position}Different ids for ${key}. ${info.leftname}: ${aVal.nodeId} vs. ${info.rightname}: ${bVal.nodeId}`);
|
|
43
41
|
}
|
|
44
|
-
|
|
45
|
-
info.report.addComment(`${info.position}Different controlDependency for ${key} (${aVal.nodeId}). ${info.leftname}: ${JSON.stringify(aVal.controlDependencies)} vs. ${info.rightname}: ${JSON.stringify(bVal.controlDependencies)}`);
|
|
46
|
-
}
|
|
42
|
+
(0, info_1.diffControlDependencies)(aVal.controlDependencies, bVal.controlDependencies, { ...info, position: `${info.position} For ${key}. ` });
|
|
47
43
|
if (aVal.definedAt !== bVal.definedAt) {
|
|
48
44
|
info.report.addComment(`${info.position}Different definition ids (definedAt) for ${key} (${aVal.nodeId}). ${info.leftname}: ${aVal.definedAt} vs. ${info.rightname}: ${bVal.definedAt}`);
|
|
49
45
|
}
|
|
@@ -53,33 +49,35 @@ function diffMemory(a, b, info) {
|
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
|
-
function diffEnvironment(a, b, info) {
|
|
52
|
+
function diffEnvironment(a, b, info, depth) {
|
|
57
53
|
if (a === undefined || b === undefined) {
|
|
58
54
|
if (a !== b) {
|
|
59
|
-
info.report.addComment(`${info.position}Different environments. ${info.leftname}: ${a !== undefined ? 'present' : 'undefined'} vs. ${info.rightname}: ${b !== undefined ? 'present' : 'undefined'}`);
|
|
55
|
+
info.report.addComment(`${info.position}[at level: ${depth}] Different environments. ${info.leftname}: ${a !== undefined ? 'present' : 'undefined'} vs. ${info.rightname}: ${b !== undefined ? 'present' : 'undefined'}`);
|
|
60
56
|
}
|
|
61
57
|
return;
|
|
62
58
|
}
|
|
63
|
-
if (a.name !== b.name) {
|
|
64
|
-
info.report.addComment(`${info.position}Different environment names. ${info.leftname}: ${a.name} vs. ${info.rightname}: ${b.name}`);
|
|
65
|
-
}
|
|
66
59
|
if (a.memory.size !== b.memory.size) {
|
|
67
|
-
info.report.addComment(`${info.position}Different environment
|
|
60
|
+
info.report.addComment(`${info.position}[at level: ${depth}] Different number of definitions in environment. ${info.leftname}: ${a.memory.size} vs. ${info.rightname}: ${b.memory.size}`);
|
|
68
61
|
(0, diff_1.setDifference)(new Set([...a.memory.keys()]), new Set([...b.memory.keys()]), {
|
|
69
62
|
...info,
|
|
70
|
-
position: `${info.position}Key comparison. `
|
|
63
|
+
position: `${info.position}[at level: ${depth}] Key comparison. `
|
|
71
64
|
});
|
|
72
65
|
}
|
|
73
|
-
diffMemory(a, b, info);
|
|
74
|
-
diffEnvironment(a.parent, b.parent, { ...info, position: `${info.position}Parents of ${a.id} & ${b.id}. ` });
|
|
66
|
+
diffMemory(a, b, { ...info, position: `${info.position}[at level: ${depth}] ` });
|
|
67
|
+
diffEnvironment(a.parent, b.parent, { ...info, position: `${info.position}Parents of ${a.id} & ${b.id}. ` }, depth--);
|
|
75
68
|
}
|
|
76
69
|
exports.diffEnvironment = diffEnvironment;
|
|
77
70
|
function diffEnvironmentInformation(a, b, info) {
|
|
78
71
|
if (a === undefined || b === undefined) {
|
|
79
|
-
|
|
72
|
+
if (a !== b) {
|
|
73
|
+
info.report.addComment(`${info.position}Different environments: ${JSON.stringify(a, json_1.jsonReplacer)} vs. ${JSON.stringify(b, json_1.jsonReplacer)}`);
|
|
74
|
+
}
|
|
80
75
|
return;
|
|
81
76
|
}
|
|
82
|
-
|
|
77
|
+
if (a.level !== b.level) {
|
|
78
|
+
info.report.addComment(`${info.position}Different environment levels: ${info.leftname}: ${a.level} vs. ${info.rightname}: ${b.level}. Using max to report level for further errors.`);
|
|
79
|
+
}
|
|
80
|
+
diffEnvironment(a.current, b.current, info, Math.max(a.level, b.level));
|
|
83
81
|
}
|
|
84
82
|
exports.diffEnvironmentInformation = diffEnvironmentInformation;
|
|
85
83
|
//# sourceMappingURL=diff.js.map
|
|
@@ -6,13 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Identifier, IdentifierDefinition, IdentifierReference } from './identifier';
|
|
8
8
|
import type { DataflowGraph } from '../graph/graph';
|
|
9
|
-
import type {
|
|
10
|
-
export declare function makeReferenceMaybe(ref: IdentifierReference, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?:
|
|
11
|
-
export declare function makeAllMaybe(references: readonly IdentifierReference[] | undefined, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?:
|
|
9
|
+
import type { ControlDependency } from '../info';
|
|
10
|
+
export declare function makeReferenceMaybe(ref: IdentifierReference, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference;
|
|
11
|
+
export declare function makeAllMaybe(references: readonly IdentifierReference[] | undefined, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference[];
|
|
12
12
|
export interface IEnvironment {
|
|
13
13
|
/** unique and internally generated identifier -- will not be used for comparison but assists debugging for tracking identities */
|
|
14
14
|
readonly id: string;
|
|
15
|
-
readonly name: string;
|
|
16
15
|
/** Lexical parent of the environment, if any (can be manipulated by R code) */
|
|
17
16
|
parent: IEnvironment;
|
|
18
17
|
/**
|
|
@@ -21,11 +20,10 @@ export interface IEnvironment {
|
|
|
21
20
|
memory: Map<Identifier, IdentifierDefinition[]>;
|
|
22
21
|
}
|
|
23
22
|
export declare class Environment implements IEnvironment {
|
|
24
|
-
readonly name: string;
|
|
25
23
|
readonly id: string;
|
|
26
24
|
parent: IEnvironment;
|
|
27
25
|
memory: Map<Identifier, IdentifierDefinition[]>;
|
|
28
|
-
constructor(
|
|
26
|
+
constructor(parent: IEnvironment);
|
|
29
27
|
}
|
|
30
28
|
/**
|
|
31
29
|
* First of all, yes, R stores its environments differently, potentially even with a different differentiation between
|
|
@@ -41,5 +39,4 @@ export interface REnvironmentInformation {
|
|
|
41
39
|
readonly level: number;
|
|
42
40
|
}
|
|
43
41
|
export declare const BuiltInEnvironment: Environment;
|
|
44
|
-
export declare const GLOBAL_ENV_NAME = "global";
|
|
45
42
|
export declare function initializeCleanEnvironments(): REnvironmentInformation;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.initializeCleanEnvironments = exports.
|
|
3
|
+
exports.initializeCleanEnvironments = exports.BuiltInEnvironment = exports.Environment = exports.makeAllMaybe = exports.makeReferenceMaybe = void 0;
|
|
4
4
|
const built_in_1 = require("./built-in");
|
|
5
5
|
const resolve_by_name_1 = require("./resolve-by-name");
|
|
6
6
|
function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = undefined) {
|
|
@@ -9,7 +9,7 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
|
|
|
9
9
|
const definitions = ref.name ? (0, resolve_by_name_1.resolveByName)(ref.name, environments) : undefined;
|
|
10
10
|
for (const definition of definitions ?? []) {
|
|
11
11
|
if (definition.kind !== 'built-in-function' && definition.kind !== 'built-in-value') {
|
|
12
|
-
if (definition.controlDependencies && defaultCd && !definition.controlDependencies.
|
|
12
|
+
if (definition.controlDependencies && defaultCd && !definition.controlDependencies.find(c => c.id === defaultCd.id)) {
|
|
13
13
|
definition.controlDependencies.push(defaultCd);
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
@@ -38,24 +38,21 @@ function makeAllMaybe(references, graph, environments, includeDefs, defaultCd =
|
|
|
38
38
|
exports.makeAllMaybe = makeAllMaybe;
|
|
39
39
|
let environmentIdCounter = 0;
|
|
40
40
|
class Environment {
|
|
41
|
-
name;
|
|
42
41
|
id = `${environmentIdCounter++}`;
|
|
43
42
|
parent;
|
|
44
43
|
memory;
|
|
45
|
-
constructor(
|
|
46
|
-
this.name = name;
|
|
44
|
+
constructor(parent) {
|
|
47
45
|
this.parent = parent;
|
|
48
46
|
this.memory = new Map();
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
49
|
exports.Environment = Environment;
|
|
52
50
|
/* the built-in environment is the root of all environments */
|
|
53
|
-
exports.BuiltInEnvironment = new Environment(
|
|
51
|
+
exports.BuiltInEnvironment = new Environment(undefined);
|
|
54
52
|
exports.BuiltInEnvironment.memory = built_in_1.BuiltInMemory;
|
|
55
|
-
exports.GLOBAL_ENV_NAME = 'global';
|
|
56
53
|
function initializeCleanEnvironments() {
|
|
57
54
|
return {
|
|
58
|
-
current: new Environment(exports.
|
|
55
|
+
current: new Environment(exports.BuiltInEnvironment),
|
|
59
56
|
level: 0
|
|
60
57
|
};
|
|
61
58
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BuiltInIdentifierConstant, BuiltInIdentifierDefinition } from './built-in';
|
|
2
2
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
|
+
import type { ControlDependency } from '../info';
|
|
3
4
|
export type Identifier = string & {
|
|
4
5
|
__brand?: 'identifier';
|
|
5
6
|
};
|
|
@@ -26,6 +27,6 @@ export interface IdentifierReference {
|
|
|
26
27
|
* If the reference is only effective if, e.g. an if-then-else condition is true, this references the root of the `if`.
|
|
27
28
|
* As a hackey intermediate solution (until we have pointer-analysis), an empty array may indicate a `maybe` which is due to pointer access (e.g., in `a[x] <- 3`).
|
|
28
29
|
*/
|
|
29
|
-
controlDependencies:
|
|
30
|
+
controlDependencies: ControlDependency[] | undefined;
|
|
30
31
|
}
|
|
31
32
|
export {};
|
|
@@ -16,7 +16,6 @@ function anyIsMaybeOrEmpty(values) {
|
|
|
16
16
|
}
|
|
17
17
|
function overwriteIEnvironmentWith(base, next, includeParent = true) {
|
|
18
18
|
(0, assert_1.guard)(base !== undefined && next !== undefined, 'can not overwrite environments with undefined');
|
|
19
|
-
(0, assert_1.guard)(base.name === next.name, 'cannot overwrite environments with different names');
|
|
20
19
|
const map = new Map(base.memory);
|
|
21
20
|
for (const [key, values] of next.memory) {
|
|
22
21
|
const hasMaybe = anyIsMaybeOrEmpty(values);
|
|
@@ -43,7 +42,7 @@ function overwriteIEnvironmentWith(base, next, includeParent = true) {
|
|
|
43
42
|
else {
|
|
44
43
|
parent = base.parent;
|
|
45
44
|
}
|
|
46
|
-
const out = new environment_1.Environment(
|
|
45
|
+
const out = new environment_1.Environment(parent);
|
|
47
46
|
out.memory = map;
|
|
48
47
|
return out;
|
|
49
48
|
}
|
|
@@ -6,7 +6,7 @@ const assert_1 = require("../../util/assert");
|
|
|
6
6
|
/** Add a new local environment scope to the stack, returns the modified variant - sharing the original environments in the stack (no deep-clone) */
|
|
7
7
|
function pushLocalEnvironment(base) {
|
|
8
8
|
return {
|
|
9
|
-
current: new environment_1.Environment(
|
|
9
|
+
current: new environment_1.Environment(base.current),
|
|
10
10
|
level: base.level + 1
|
|
11
11
|
};
|
|
12
12
|
}
|
package/dataflow/graph/diff.js
CHANGED
|
@@ -9,6 +9,7 @@ const edge_1 = require("./edge");
|
|
|
9
9
|
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
10
10
|
const diff_2 = require("../environments/diff");
|
|
11
11
|
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
12
|
+
const info_1 = require("../info");
|
|
12
13
|
class DataflowDifferenceReport {
|
|
13
14
|
_comments = undefined;
|
|
14
15
|
_problematic = undefined;
|
|
@@ -62,10 +63,18 @@ function diffOutgoingEdges(ctx) {
|
|
|
62
63
|
ctx.report.addComment(`Detected different number of edges! ${ctx.leftname} has ${lEdges.size} (${JSON.stringify(lEdges, json_1.jsonReplacer)}). ${ctx.rightname} has ${rEdges.size} ${JSON.stringify(rEdges, json_1.jsonReplacer)}`);
|
|
63
64
|
}
|
|
64
65
|
for (const [id, edge] of lEdges) {
|
|
66
|
+
if (!ctx.left.hasVertex(id)) {
|
|
67
|
+
ctx.report.addComment(`The source ${id} of edges ${JSON.stringify(edge, json_1.jsonReplacer)} is not present in ${ctx.leftname}. This means that the graph contains an edge but not the corresponding vertex.`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
65
70
|
diffEdges(ctx, id, edge, rEdges.get(id));
|
|
66
71
|
}
|
|
67
72
|
// just to make it both ways in case the length differs
|
|
68
73
|
for (const [id, edge] of rEdges) {
|
|
74
|
+
if (!ctx.right.hasVertex(id)) {
|
|
75
|
+
ctx.report.addComment(`The source ${id} of edges ${JSON.stringify(edge, json_1.jsonReplacer)} is not present in ${ctx.rightname}. This means that the graph contains an edge but not the corresponding vertex.`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
69
78
|
if (!lEdges.has(id)) {
|
|
70
79
|
diffEdges(ctx, id, undefined, edge);
|
|
71
80
|
}
|
|
@@ -137,9 +146,7 @@ function diffFunctionArguments(fn, a, b, ctx) {
|
|
|
137
146
|
if (aArg.name !== bArg.name) {
|
|
138
147
|
ctx.report.addComment(`${ctx.position}In argument #${i} (of ${ctx.leftname}, unnamed) the name differs: ${aArg.name} vs ${bArg.name}.`);
|
|
139
148
|
}
|
|
140
|
-
|
|
141
|
-
ctx.report.addComment(`${ctx.position}In argument #${i} (of ${ctx.leftname}, unnamed) the control dependency differs: ${JSON.stringify(aArg.controlDependencies)} vs ${JSON.stringify(bArg.controlDependencies)}.`, { tag: 'vertex', id: fn });
|
|
142
|
-
}
|
|
149
|
+
(0, info_1.diffControlDependencies)(aArg.controlDependencies, bArg.controlDependencies, { ...ctx, position: `${ctx.position}In argument #${i} (of ${ctx.leftname}, unnamed) the control dependency differs: ${JSON.stringify(aArg.controlDependencies)} vs ${JSON.stringify(bArg.controlDependencies)}.` });
|
|
143
150
|
}
|
|
144
151
|
}
|
|
145
152
|
}
|
|
@@ -173,9 +180,7 @@ function diffVertices(ctx) {
|
|
|
173
180
|
});
|
|
174
181
|
}
|
|
175
182
|
}
|
|
176
|
-
|
|
177
|
-
ctx.report.addComment(`Vertex ${id} differs in controlDependency. ${ctx.leftname}: ${JSON.stringify(lInfo.controlDependencies)} vs ${ctx.rightname}: ${JSON.stringify(rInfo.controlDependencies)}`, { tag: 'vertex', id });
|
|
178
|
-
}
|
|
183
|
+
(0, info_1.diffControlDependencies)(lInfo.controlDependencies, rInfo.controlDependencies, { ...ctx, position: `Vertex ${id} differs in controlDependencies. ` });
|
|
179
184
|
(0, diff_2.diffEnvironmentInformation)(lInfo.environment, rInfo.environment, { ...ctx, position: `${ctx.position}Vertex ${id} differs in environment. ` });
|
|
180
185
|
if (lInfo.tag === "function-call" /* VertexType.FunctionCall */) {
|
|
181
186
|
if (rInfo.tag !== "function-call" /* VertexType.FunctionCall */) {
|
|
@@ -46,7 +46,7 @@ type EdgeData<Edge extends DataflowGraphEdge> = Omit<Edge, 'from' | 'to' | 'type
|
|
|
46
46
|
*/
|
|
47
47
|
export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo, Edge extends DataflowGraphEdge = DataflowGraphEdge> {
|
|
48
48
|
private static DEFAULT_ENVIRONMENT;
|
|
49
|
-
|
|
49
|
+
private _idMap;
|
|
50
50
|
constructor(idMap: AstIdMap | undefined);
|
|
51
51
|
/** Contains the vertices of the root level graph (i.e., included those vertices from the complete graph, that are nested within function definitions) */
|
|
52
52
|
private rootVertices;
|
|
@@ -76,6 +76,10 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
76
76
|
getVertex(id: NodeId, includeDefinedFunctions?: boolean): Vertex | undefined;
|
|
77
77
|
outgoingEdges(id: NodeId): OutgoingEdges | undefined;
|
|
78
78
|
ingoingEdges(id: NodeId): IngoingEdges | undefined;
|
|
79
|
+
/** Retrieves the id-map to the normalized AST attached to the dataflow graph */
|
|
80
|
+
get idMap(): AstIdMap | undefined;
|
|
81
|
+
/** Allows setting the id-map explicitly (which should only be used when, e.g., you plan to compare two dataflow graphs on the same AST-basis) */
|
|
82
|
+
setIdMap(idMap: AstIdMap): void;
|
|
79
83
|
/**
|
|
80
84
|
* @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
|
|
81
85
|
* @returns the ids of all toplevel vertices in the graph together with their vertex information
|
|
@@ -95,7 +99,7 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
95
99
|
* @param id - The id to check for
|
|
96
100
|
* @param includeDefinedFunctions - If true this will check function definitions as well and not just the toplevel
|
|
97
101
|
*/
|
|
98
|
-
hasVertex(id: NodeId, includeDefinedFunctions
|
|
102
|
+
hasVertex(id: NodeId, includeDefinedFunctions?: boolean): boolean;
|
|
99
103
|
/**
|
|
100
104
|
* Returns true if the root level of the graph contains a node with the given id.
|
|
101
105
|
*/
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -40,10 +40,10 @@ function extractEdgeIds(from, to) {
|
|
|
40
40
|
*/
|
|
41
41
|
class DataflowGraph {
|
|
42
42
|
static DEFAULT_ENVIRONMENT = undefined;
|
|
43
|
-
|
|
43
|
+
_idMap;
|
|
44
44
|
constructor(idMap) {
|
|
45
45
|
DataflowGraph.DEFAULT_ENVIRONMENT ??= (0, environment_1.initializeCleanEnvironments)();
|
|
46
|
-
this.
|
|
46
|
+
this._idMap = idMap;
|
|
47
47
|
}
|
|
48
48
|
/** Contains the vertices of the root level graph (i.e., included those vertices from the complete graph, that are nested within function definitions) */
|
|
49
49
|
rootVertices = new Set();
|
|
@@ -89,6 +89,14 @@ class DataflowGraph {
|
|
|
89
89
|
}
|
|
90
90
|
return edges;
|
|
91
91
|
}
|
|
92
|
+
/** Retrieves the id-map to the normalized AST attached to the dataflow graph */
|
|
93
|
+
get idMap() {
|
|
94
|
+
return this._idMap;
|
|
95
|
+
}
|
|
96
|
+
/** Allows setting the id-map explicitly (which should only be used when, e.g., you plan to compare two dataflow graphs on the same AST-basis) */
|
|
97
|
+
setIdMap(idMap) {
|
|
98
|
+
this._idMap = idMap;
|
|
99
|
+
}
|
|
92
100
|
/**
|
|
93
101
|
* @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
|
|
94
102
|
* @returns the ids of all toplevel vertices in the graph together with their vertex information
|
|
@@ -119,7 +127,7 @@ class DataflowGraph {
|
|
|
119
127
|
* @param id - The id to check for
|
|
120
128
|
* @param includeDefinedFunctions - If true this will check function definitions as well and not just the toplevel
|
|
121
129
|
*/
|
|
122
|
-
hasVertex(id, includeDefinedFunctions) {
|
|
130
|
+
hasVertex(id, includeDefinedFunctions = true) {
|
|
123
131
|
return includeDefinedFunctions ? this.vertexInformation.has(id) : this.rootVertices.has(id);
|
|
124
132
|
}
|
|
125
133
|
/**
|
|
@@ -146,8 +154,9 @@ class DataflowGraph {
|
|
|
146
154
|
if (oldVertex !== undefined) {
|
|
147
155
|
return this;
|
|
148
156
|
}
|
|
157
|
+
const fallback = vertex.tag === "variable-definition" /* VertexType.VariableDefinition */ || vertex.tag === "use" /* VertexType.Use */ || vertex.tag === "value" /* VertexType.Value */ ? undefined : DataflowGraph.DEFAULT_ENVIRONMENT;
|
|
149
158
|
// keep a clone of the original environment
|
|
150
|
-
const environment = vertex.environment === undefined ?
|
|
159
|
+
const environment = vertex.environment === undefined ? fallback : (0, clone_1.cloneEnvironmentInformation)(vertex.environment);
|
|
151
160
|
this.vertexInformation.set(vertex.id, {
|
|
152
161
|
...vertex,
|
|
153
162
|
when: vertex.controlDependencies ?? 'always',
|
|
@@ -263,9 +272,6 @@ class DataflowGraph {
|
|
|
263
272
|
const vertex = this.getVertex(reference.nodeId, true);
|
|
264
273
|
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${JSON.stringify(reference)} to set reference`);
|
|
265
274
|
if (vertex.tag === "function-definition" /* VertexType.FunctionDefinition */ || vertex.tag === "variable-definition" /* VertexType.VariableDefinition */) {
|
|
266
|
-
(0, assert_1.guard)(vertex.controlDependencies !== undefined
|
|
267
|
-
|| reference.controlDependencies !== undefined
|
|
268
|
-
|| (0, arrays_1.arrayEqual)(vertex.controlDependencies, reference.controlDependencies), () => `node ${JSON.stringify(vertex)} must not be previously defined at position or have same scope for ${JSON.stringify(reference)}`);
|
|
269
275
|
vertex.controlDependencies = reference.controlDependencies;
|
|
270
276
|
}
|
|
271
277
|
else {
|
|
@@ -2,6 +2,7 @@ import type { MergeableRecord } from '../../util/objects';
|
|
|
2
2
|
import type { DataflowFunctionFlowInformation, FunctionArgument } from './graph';
|
|
3
3
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
4
|
import type { REnvironmentInformation } from '../environments/environment';
|
|
5
|
+
import type { ControlDependency } from '../info';
|
|
5
6
|
export type DataflowGraphVertices<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo> = Map<NodeId, Vertex>;
|
|
6
7
|
export declare const enum VertexType {
|
|
7
8
|
Value = "value",
|
|
@@ -33,7 +34,7 @@ interface DataflowGraphVertexBase extends MergeableRecord {
|
|
|
33
34
|
/**
|
|
34
35
|
* See {@link IdentifierReference}
|
|
35
36
|
*/
|
|
36
|
-
controlDependencies:
|
|
37
|
+
controlDependencies: ControlDependency[] | undefined;
|
|
37
38
|
}
|
|
38
39
|
export interface DataflowGraphValue extends DataflowGraphVertexBase {
|
|
39
40
|
readonly tag: VertexType.Value;
|
package/dataflow/info.d.ts
CHANGED
|
@@ -3,16 +3,22 @@ import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
|
3
3
|
import type { IdentifierReference } from './environments/identifier';
|
|
4
4
|
import type { REnvironmentInformation } from './environments/environment';
|
|
5
5
|
import { DataflowGraph } from './graph/graph';
|
|
6
|
+
import type { GenericDifferenceInformation, WriteableDifferenceReport } from '../util/diff';
|
|
6
7
|
export declare const enum ExitPointType {
|
|
7
8
|
Default = 0,
|
|
8
9
|
Return = 1,
|
|
9
10
|
Break = 2,
|
|
10
11
|
Next = 3
|
|
11
12
|
}
|
|
13
|
+
export interface ControlDependency {
|
|
14
|
+
readonly id: NodeId;
|
|
15
|
+
/** when does this control dependency trigger (if the condition is true or false)? */
|
|
16
|
+
readonly when?: boolean;
|
|
17
|
+
}
|
|
12
18
|
export interface ExitPoint {
|
|
13
19
|
readonly type: ExitPointType;
|
|
14
20
|
readonly nodeId: NodeId;
|
|
15
|
-
readonly controlDependencies:
|
|
21
|
+
readonly controlDependencies: ControlDependency[] | undefined;
|
|
16
22
|
}
|
|
17
23
|
export declare function addNonDefaultExitPoints(existing: ExitPoint[], add: readonly ExitPoint[]): void;
|
|
18
24
|
/**
|
|
@@ -45,5 +51,8 @@ export interface DataflowInformation extends DataflowCfgInformation {
|
|
|
45
51
|
graph: DataflowGraph;
|
|
46
52
|
}
|
|
47
53
|
export declare function initializeCleanDataflowInformation<T>(entryPoint: NodeId, data: Pick<DataflowProcessorInformation<T>, 'environment' | 'completeAst'>): DataflowInformation;
|
|
54
|
+
export declare function happensInEveryBranch(controlDependencies: ControlDependency[] | undefined): boolean;
|
|
48
55
|
export declare function alwaysExits(data: DataflowInformation): boolean;
|
|
49
56
|
export declare function filterOutLoopExitPoints(exitPoints: readonly ExitPoint[]): readonly ExitPoint[];
|
|
57
|
+
export declare function diffControlDependency<Report extends WriteableDifferenceReport>(a: ControlDependency | undefined, b: ControlDependency | undefined, info: GenericDifferenceInformation<Report>): void;
|
|
58
|
+
export declare function diffControlDependencies<Report extends WriteableDifferenceReport>(a: ControlDependency[] | undefined, b: ControlDependency[] | undefined, info: GenericDifferenceInformation<Report>): void;
|
package/dataflow/info.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.filterOutLoopExitPoints = exports.alwaysExits = exports.initializeCleanDataflowInformation = exports.addNonDefaultExitPoints = void 0;
|
|
3
|
+
exports.diffControlDependencies = exports.diffControlDependency = exports.filterOutLoopExitPoints = exports.alwaysExits = exports.happensInEveryBranch = exports.initializeCleanDataflowInformation = exports.addNonDefaultExitPoints = void 0;
|
|
4
4
|
const graph_1 = require("./graph/graph");
|
|
5
5
|
function addNonDefaultExitPoints(existing, add) {
|
|
6
6
|
existing.push(...add.filter(({ type }) => type !== 0 /* ExitPointType.Default */));
|
|
@@ -18,12 +18,64 @@ function initializeCleanDataflowInformation(entryPoint, data) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
exports.initializeCleanDataflowInformation = initializeCleanDataflowInformation;
|
|
21
|
+
function happensInEveryBranch(controlDependencies) {
|
|
22
|
+
if (controlDependencies === undefined) {
|
|
23
|
+
/* the cds are unconstrained */
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
else if (controlDependencies.length === 0) {
|
|
27
|
+
/* this happens only when we have no idea and require more analysis */
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const trues = [];
|
|
31
|
+
const falseSet = new Set();
|
|
32
|
+
for (const { id, when } of controlDependencies) {
|
|
33
|
+
if (when) {
|
|
34
|
+
trues.push(id);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
falseSet.add(id);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return trues.every(id => falseSet.has(id));
|
|
41
|
+
}
|
|
42
|
+
exports.happensInEveryBranch = happensInEveryBranch;
|
|
21
43
|
function alwaysExits(data) {
|
|
22
|
-
return data.exitPoints?.some(e => e.type !== 0 /* ExitPointType.Default */ && e.controlDependencies
|
|
44
|
+
return data.exitPoints?.some(e => e.type !== 0 /* ExitPointType.Default */ && happensInEveryBranch(e.controlDependencies)) ?? false;
|
|
23
45
|
}
|
|
24
46
|
exports.alwaysExits = alwaysExits;
|
|
25
47
|
function filterOutLoopExitPoints(exitPoints) {
|
|
26
48
|
return exitPoints.filter(({ type }) => type === 1 /* ExitPointType.Return */ || type === 0 /* ExitPointType.Default */);
|
|
27
49
|
}
|
|
28
50
|
exports.filterOutLoopExitPoints = filterOutLoopExitPoints;
|
|
51
|
+
function diffControlDependency(a, b, info) {
|
|
52
|
+
if (a === undefined || b === undefined) {
|
|
53
|
+
if (a !== b) {
|
|
54
|
+
info.report.addComment(`${info.position}Different control dependencies. ${info.leftname}: ${JSON.stringify(a)} vs. ${info.rightname}: ${JSON.stringify(b)}`);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (a.id !== b.id) {
|
|
59
|
+
info.report.addComment(`${info.position}Different control dependency ids. ${info.leftname}: ${a.id} vs. ${info.rightname}: ${b.id}`);
|
|
60
|
+
}
|
|
61
|
+
if (a.when !== b.when) {
|
|
62
|
+
info.report.addComment(`${info.position}Different control dependency when. ${info.leftname}: ${a.when} vs. ${info.rightname}: ${b.when}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.diffControlDependency = diffControlDependency;
|
|
66
|
+
function diffControlDependencies(a, b, info) {
|
|
67
|
+
if (a === undefined || b === undefined) {
|
|
68
|
+
if (a !== b) {
|
|
69
|
+
info.report.addComment(`${info.position}Different control dependencies: ${JSON.stringify(a)} vs. ${JSON.stringify(b)}`);
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (a.length !== b.length) {
|
|
74
|
+
info.report.addComment(`${info.position}Different control dependency lengths: ${a.length} vs. ${b.length}`);
|
|
75
|
+
}
|
|
76
|
+
for (let i = 0; i < a.length; ++i) {
|
|
77
|
+
diffControlDependency(a[i], b[i], { ...info, position: `${info.position}Control dependency at index: ${i}: ` });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.diffControlDependencies = diffControlDependencies;
|
|
29
81
|
//# sourceMappingURL=info.js.map
|
|
@@ -17,7 +17,7 @@ export declare function linkFunctionCalls(graph: DataflowGraph, idMap: AstIdMap,
|
|
|
17
17
|
functionCall: NodeId;
|
|
18
18
|
called: readonly DataflowGraphVertexInfo[];
|
|
19
19
|
}[];
|
|
20
|
-
export declare function getAllLinkedFunctionDefinitions(functionDefinitionReadIds:
|
|
20
|
+
export declare function getAllLinkedFunctionDefinitions(functionDefinitionReadIds: ReadonlySet<NodeId>, dataflowGraph: DataflowGraph): Map<NodeId, DataflowGraphVertexInfo>;
|
|
21
21
|
/**
|
|
22
22
|
* This method links a set of read variables to definitions in an environment.
|
|
23
23
|
*
|
|
@@ -136,9 +136,8 @@ function getAllLinkedFunctionDefinitions(functionDefinitionReadIds, dataflowGrap
|
|
|
136
136
|
const result = new Map();
|
|
137
137
|
while (potential.length > 0) {
|
|
138
138
|
const currentId = potential.pop();
|
|
139
|
+
// do not traverse builtins
|
|
139
140
|
if (currentId === built_in_1.BuiltIn) {
|
|
140
|
-
// do not traverse builtins
|
|
141
|
-
static_slicer_1.slicerLogger.trace('skipping builtin function definition during collection');
|
|
142
141
|
continue;
|
|
143
142
|
}
|
|
144
143
|
const currentInfo = dataflowGraph.get(currentId, true);
|
|
@@ -39,7 +39,7 @@ args, rootId, data, config) {
|
|
|
39
39
|
}
|
|
40
40
|
const effectiveArgs = getEffectiveOrder(config, args);
|
|
41
41
|
const { target, source } = extractSourceAndTarget(effectiveArgs, name);
|
|
42
|
-
const { type,
|
|
42
|
+
const { type, named } = target;
|
|
43
43
|
if (type === "RSymbol" /* RType.Symbol */) {
|
|
44
44
|
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, reverseOrder: !config.swapSourceAndTarget });
|
|
45
45
|
return processAssignmentToSymbol({
|
|
@@ -53,7 +53,7 @@ args, rootId, data, config) {
|
|
|
53
53
|
information: res.information,
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
-
else if (config.canBeReplacement && type === "RFunctionCall" /* RType.FunctionCall */ &&
|
|
56
|
+
else if (config.canBeReplacement && type === "RFunctionCall" /* RType.FunctionCall */ && named) {
|
|
57
57
|
/* as replacement functions take precedence over the lhs fn-call (i.e., `names(x) <- ...` is independent from the definition of `names`), we do not have to process the call */
|
|
58
58
|
logger_1.dataflowLogger.debug(`Assignment ${name.content} has a function call as target => replacement function ${target.lexeme}`);
|
|
59
59
|
const replacement = toReplacementSymbol(target, target.functionName.content, config.superAssignment ?? false);
|
|
@@ -132,7 +132,7 @@ function processAssignmentToSymbol({ name, source, args: [targetArg, sourceArg],
|
|
|
132
132
|
}
|
|
133
133
|
// we drop the first arg which we use to pass along arguments :D
|
|
134
134
|
const readFromSourceWritten = sourceArg.out.slice(1);
|
|
135
|
-
const readTargets = [{ nodeId:
|
|
135
|
+
const readTargets = [{ nodeId: rootId, name: name.content, controlDependencies: data.controlDependencies }, ...sourceArg.unknownReferences, ...sourceArg.in, ...targetArg.in.filter(i => i.nodeId !== target.info.id), ...readFromSourceWritten];
|
|
136
136
|
const writeTargets = [...writeNodes, ...writeNodes, ...readFromSourceWritten];
|
|
137
137
|
information.environment = (0, overwrite_1.overwriteEnvironment)(targetArg.environment, sourceArg.environment);
|
|
138
138
|
// install assigned variables in environment
|
|
@@ -152,14 +152,14 @@ function processAssignmentToSymbol({ name, source, args: [targetArg, sourceArg],
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
information.graph.addEdge(
|
|
155
|
+
information.graph.addEdge(rootId, targetArg.entryPoint, { type: 8 /* EdgeType.Returns */ });
|
|
156
156
|
if (quoteSource) {
|
|
157
157
|
information.graph.addEdge(rootId, source.info.id, { type: 256 /* EdgeType.NonStandardEvaluation */ });
|
|
158
158
|
}
|
|
159
159
|
return {
|
|
160
160
|
...information,
|
|
161
161
|
unknownReferences: [],
|
|
162
|
-
entryPoint:
|
|
162
|
+
entryPoint: rootId,
|
|
163
163
|
in: readTargets,
|
|
164
164
|
out: writeTargets
|
|
165
165
|
};
|
|
@@ -29,7 +29,7 @@ function processForLoop(name, args, rootId, data) {
|
|
|
29
29
|
const variable = (0, processor_1.processDataflowFor)(variableArg, data);
|
|
30
30
|
// this should not be able to exit always!
|
|
31
31
|
const originalDependency = data.controlDependencies;
|
|
32
|
-
data = { ...data, controlDependencies: [...data.controlDependencies ?? [], name.info.id] };
|
|
32
|
+
data = { ...data, controlDependencies: [...data.controlDependencies ?? [], { id: name.info.id, when: true }] };
|
|
33
33
|
let headEnvironments = (0, overwrite_1.overwriteEnvironment)(vector.environment, variable.environment);
|
|
34
34
|
const headGraph = variable.graph.mergeWith(vector.graph);
|
|
35
35
|
const writtenVariable = [...variable.unknownReferences, ...variable.in];
|
|
@@ -13,6 +13,7 @@ const overwrite_1 = require("../../../../../environments/overwrite");
|
|
|
13
13
|
const scoping_1 = require("../../../../../environments/scoping");
|
|
14
14
|
const environment_1 = require("../../../../../environments/environment");
|
|
15
15
|
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
16
|
+
const log_1 = require("../../../../../../util/log");
|
|
16
17
|
function processFunctionDefinition(name, args, rootId, data) {
|
|
17
18
|
if (args.length < 1) {
|
|
18
19
|
logger_1.dataflowLogger.warn(`Function Definition ${name.content} does not have an argument, skipping`);
|
|
@@ -53,7 +54,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
53
54
|
tag: "use" /* VertexType.Use */,
|
|
54
55
|
id: read.nodeId,
|
|
55
56
|
environment: undefined,
|
|
56
|
-
controlDependencies:
|
|
57
|
+
controlDependencies: undefined
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -65,8 +66,8 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
65
66
|
graph: new Set(subgraph.rootIds()),
|
|
66
67
|
environment: outEnvironment
|
|
67
68
|
};
|
|
69
|
+
updateNestedFunctionClosures(subgraph, outEnvironment, name);
|
|
68
70
|
const exitPoints = body.exitPoints;
|
|
69
|
-
updateNestedFunctionClosures(exitPoints, subgraph, outEnvironment, name);
|
|
70
71
|
const graph = new graph_1.DataflowGraph(data.completeAst.idMap).mergeWith(subgraph, false);
|
|
71
72
|
graph.addVertex({
|
|
72
73
|
tag: "function-definition" /* VertexType.FunctionDefinition */,
|
|
@@ -88,33 +89,28 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
91
|
exports.processFunctionDefinition = processFunctionDefinition;
|
|
91
|
-
function updateNestedFunctionClosures(
|
|
92
|
-
// track *all* function definitions - including those nested within the current graph
|
|
92
|
+
function updateNestedFunctionClosures(subgraph, outEnvironment, name) {
|
|
93
|
+
// track *all* function definitions - including those nested within the current graph,
|
|
93
94
|
// try to resolve their 'in' by only using the lowest scope which will be popped after this definition
|
|
94
|
-
for (const [id,
|
|
95
|
-
if (
|
|
95
|
+
for (const [id, { subflow, tag }] of subgraph.vertices(true)) {
|
|
96
|
+
if (tag !== "function-definition" /* VertexType.FunctionDefinition */) {
|
|
96
97
|
continue;
|
|
97
98
|
}
|
|
98
|
-
const ingoingRefs =
|
|
99
|
-
const remainingIn =
|
|
99
|
+
const ingoingRefs = subflow.in;
|
|
100
|
+
const remainingIn = [];
|
|
100
101
|
for (const ingoing of ingoingRefs) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
logger_1.dataflowLogger.trace(`Found ${resolved.length} references to open ref ${id} in closure of function definition ${name.info.id}`);
|
|
111
|
-
for (const ref of resolved) {
|
|
112
|
-
subgraph.addEdge(ingoing, ref, { type: 1 /* EdgeType.Reads */ });
|
|
113
|
-
}
|
|
102
|
+
const resolved = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, outEnvironment) : undefined;
|
|
103
|
+
if (resolved === undefined) {
|
|
104
|
+
remainingIn.push(ingoing);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Found ${resolved.length} references to open ref ${id} in closure of function definition ${name.info.id}`);
|
|
108
|
+
for (const ref of resolved) {
|
|
109
|
+
subgraph.addEdge(ingoing, ref, { type: 1 /* EdgeType.Reads */ });
|
|
114
110
|
}
|
|
115
111
|
}
|
|
116
|
-
logger_1.dataflowLogger
|
|
117
|
-
|
|
112
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Keeping ${remainingIn.length} references to open ref ${id} in closure of function definition ${name.info.id}`);
|
|
113
|
+
subflow.in = remainingIn;
|
|
118
114
|
}
|
|
119
115
|
}
|
|
120
116
|
function prepareFunctionEnvironment(data) {
|
|
@@ -127,11 +123,11 @@ function prepareFunctionEnvironment(data) {
|
|
|
127
123
|
/**
|
|
128
124
|
* Within something like `f <- function(a=b, m=3) { b <- 1; a; b <- 5; a + 1 }`
|
|
129
125
|
* `a` will be defined by `b` and `b`will be a promise object bound by the first definition of b it can find.
|
|
130
|
-
* This means
|
|
126
|
+
* This means that this function returns `2` due to the first `b <- 1` definition.
|
|
131
127
|
* If the code is `f <- function(a=b, m=3) { if(m > 3) { b <- 1; }; a; b <- 5; a + 1 }`, we need a link to `b <- 1` and `b <- 6`
|
|
132
128
|
* as `b` can be defined by either one of them.
|
|
133
129
|
* <p>
|
|
134
|
-
* <b>Currently we may be unable to narrow down every definition within the body as we have not implemented ways to track what covers
|
|
130
|
+
* <b>Currently we may be unable to narrow down every definition within the body as we have not implemented ways to track what covers the first definitions precisely</b>
|
|
135
131
|
*/
|
|
136
132
|
function findPromiseLinkagesForParameters(parameters, readInParameters, parameterEnvs, body) {
|
|
137
133
|
// first, we try to bind again within parameters - if we have it, fine
|