@eagleoutice/flowr 2.0.15 → 2.0.17
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 +15 -5
- package/cli/repl/commands/commands.js +3 -1
- package/cli/repl/commands/lineage.d.ts +15 -0
- package/cli/repl/commands/lineage.js +66 -0
- package/cli/repl/server/connection.d.ts +1 -0
- package/cli/repl/server/connection.js +34 -0
- package/cli/repl/server/messages/lineage.d.ts +16 -0
- package/cli/repl/server/messages/lineage.js +17 -0
- package/cli/repl/server/messages/messages.d.ts +2 -1
- package/dataflow/environments/built-in.js +18 -8
- package/dataflow/environments/environment.js +4 -3
- package/dataflow/environments/resolve-by-name.d.ts +1 -1
- package/dataflow/environments/resolve-by-name.js +4 -4
- package/dataflow/graph/diff.js +1 -0
- package/dataflow/graph/graph.d.ts +18 -19
- package/dataflow/graph/graph.js +41 -24
- package/dataflow/graph/vertex.d.ts +6 -1
- package/dataflow/graph/vertex.js +21 -0
- package/dataflow/info.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -4
- 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 +10 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-library.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.d.ts +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +18 -7
- package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.d.ts → built-in-special-bin-op.d.ts} +2 -1
- package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.js → built-in-special-bin-op.js} +3 -3
- package/dataflow/internal/process/functions/call/common.d.ts +6 -2
- package/dataflow/internal/process/functions/call/common.js +36 -1
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +3 -2
- package/dataflow/internal/process/functions/call/known-call-handling.js +2 -2
- package/dataflow/internal/process/functions/call/named-call-handling.js +3 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +1 -0
- package/dataflow/internal/process/functions/process-argument.js +0 -28
- package/package.json +3 -2
- package/r-bridge/data/data.d.ts +5 -0
- package/r-bridge/data/data.js +6 -0
- package/reconstruct/reconstruct.js +3 -3
- package/slicing/criterion/parse.d.ts +3 -4
- package/slicing/criterion/parse.js +3 -3
- package/slicing/static/slice-call.js +35 -13
- package/slicing/static/static-slicer.d.ts +1 -1
- package/slicing/static/static-slicer.js +10 -4
- package/statistics/statistics.js +1 -1
- package/util/json.d.ts +1 -1
- package/util/json.js +3 -3
- package/util/logic.d.ts +5 -1
- package/util/version.js +1 -1
- package/abstract-interpretation/domain.d.ts +0 -57
- package/abstract-interpretation/domain.js +0 -176
- package/abstract-interpretation/handler/binop/binop.d.ts +0 -15
- package/abstract-interpretation/handler/binop/binop.js +0 -42
- package/abstract-interpretation/handler/binop/operators.d.ts +0 -2
- package/abstract-interpretation/handler/binop/operators.js +0 -28
- package/abstract-interpretation/handler/handler.d.ts +0 -6
- package/abstract-interpretation/handler/handler.js +0 -3
- package/abstract-interpretation/processor.d.ts +0 -11
- package/abstract-interpretation/processor.js +0 -84
package/README.md
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
[](https://github.com/flowr-analysis/flowr/wiki)\
|
|
2
|
-
[](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml) [](https://codecov.io/gh/flowr-analysis/flowr) [](https://hub.docker.com/r/eagleoutice/flowr) [](https://github.com/flowr-analysis/flowr/releases/latest) [](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) [](#contributors)
|
|
2
|
+
[](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml) [](https://codecov.io/gh/flowr-analysis/flowr) [](https://hub.docker.com/r/eagleoutice/flowr) [](https://github.com/flowr-analysis/flowr/releases/latest) [](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) [](#contributors)
|
|
3
3
|
[](https://zenodo.org/doi/10.5281/zenodo.13319290)
|
|
4
4
|
|
|
5
|
-
_flowR_ is a static [dataflow analyzer](https://en.wikipedia.org/wiki/Data-flow_analysis) and [program slicer](https://github.com/flowr-analysis/flowr/wiki/Terminology#program-slice) for the [_R_](https://www.r-project.org/) programming language (currently tested for versions `4.x` and `3.6.x`).
|
|
5
|
+
_flowR_ is a static [dataflow analyzer](https://en.wikipedia.org/wiki/Data-flow_analysis) and [program slicer](https://github.com/flowr-analysis/flowr/wiki/Terminology#program-slice) for the [_R_](https://www.r-project.org/) programming language (currently tested for versions `4.x` and `3.6.x`). You can get and use _flowR_ as a [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr), [RStudio Addin](https://github.com/flowr-analysis/rstudio-addin-flowr), [R package](https://github.com/flowr-analysis/flowr-r-adapter), and as a [Docker image](https://hub.docker.com/r/eagleoutice/flowr).
|
|
6
6
|
|
|
7
7
|
## ⭐ Getting Started
|
|
8
8
|
|
|
9
|
-
To get started with _flowR_, please check out the [Overview](https://github.com/flowr-analysis/flowr/wiki/Overview). The [Setup](https://github.com/flowr-analysis/flowr/wiki/Setup) wiki page explains how you can download and setup _flowR_ on your system.
|
|
9
|
+
To get started with _flowR_ and its features, please check out the [Overview](https://github.com/flowr-analysis/flowr/wiki/Overview) page. The [Setup](https://github.com/flowr-analysis/flowr/wiki/Setup) wiki page explains how you can download and setup _flowR_ on your system. With docker 🐳️, the following line should be enough (and drop you directly into the read-eval-print loop):
|
|
10
10
|
|
|
11
11
|
```shell
|
|
12
12
|
docker run -it --rm eagleoutice/flowr
|
|
13
|
-
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
You can enter `:help` to gain more information on its capabilities.
|
|
16
|
+
|
|
17
|
+
<details>
|
|
18
|
+
|
|
19
|
+
<summary>Example REPL session</summary>
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
</details>
|
|
14
24
|
|
|
15
25
|
## 📜 More Information
|
|
16
26
|
|
|
17
|
-
For more details
|
|
27
|
+
For more details on how to use _flowR_ please refer to the the [wiki pages](https://github.com/flowr-analysis/flowr/wiki), as well as the deployed [code documentation](https://flowr-analysis.github.io/flowr/doc/).
|
|
18
28
|
|
|
19
29
|
## 🚀 Contributing
|
|
20
30
|
|
|
@@ -14,6 +14,7 @@ const ansi_1 = require("../../../util/ansi");
|
|
|
14
14
|
const args_1 = require("../../../util/args");
|
|
15
15
|
const assert_1 = require("../../../util/assert");
|
|
16
16
|
const scripts_info_1 = require("../../common/scripts-info");
|
|
17
|
+
const lineage_1 = require("./lineage");
|
|
17
18
|
function printHelpForScript(script, f) {
|
|
18
19
|
const base = ` ${(0, ansi_1.bold)(padCmd(':' + script[0]), f)}${script[1].description}`;
|
|
19
20
|
if (script[1].aliases.length === 0) {
|
|
@@ -58,7 +59,8 @@ const _commands = {
|
|
|
58
59
|
'dataflow': dataflow_1.dataflowCommand,
|
|
59
60
|
'dataflow*': dataflow_1.dataflowStarCommand,
|
|
60
61
|
'controlflow': cfg_1.controlflowCommand,
|
|
61
|
-
'controlflow*': cfg_1.controlflowStarCommand
|
|
62
|
+
'controlflow*': cfg_1.controlflowStarCommand,
|
|
63
|
+
'lineage': lineage_1.getLineageCommand
|
|
62
64
|
};
|
|
63
65
|
let commandsInitialized = false;
|
|
64
66
|
function hasModule(path) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReplCommand } from './main';
|
|
2
|
+
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
3
|
+
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
|
+
import type { DataflowInformation } from '../../../dataflow/info';
|
|
5
|
+
import type { NormalizedAst } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
|
+
/**
|
|
7
|
+
* Get the lineage of a node in the dataflow graph
|
|
8
|
+
*
|
|
9
|
+
* @param criterion - The criterion to get the lineage of
|
|
10
|
+
* @param ast - The normalized AST
|
|
11
|
+
* @param dfg - The dataflow graph
|
|
12
|
+
* @returns The lineage of the node represented as a set of node ids
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLineage(criterion: SingleSlicingCriterion, { idMap }: NormalizedAst, dfg: DataflowInformation): Set<NodeId>;
|
|
15
|
+
export declare const getLineageCommand: ReplCommand;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLineageCommand = exports.getLineage = void 0;
|
|
4
|
+
const pipeline_executor_1 = require("../../../core/pipeline-executor");
|
|
5
|
+
const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipelines");
|
|
6
|
+
const retriever_1 = require("../../../r-bridge/retriever");
|
|
7
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
8
|
+
const edge_1 = require("../../../dataflow/graph/edge");
|
|
9
|
+
const assert_1 = require("../../../util/assert");
|
|
10
|
+
function splitAt(str, idx) {
|
|
11
|
+
return [str.slice(0, idx), str.slice(idx)];
|
|
12
|
+
}
|
|
13
|
+
async function getDfg(shell, remainingLine) {
|
|
14
|
+
return await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
|
|
15
|
+
shell,
|
|
16
|
+
request: (0, retriever_1.requestFromInput)(remainingLine.trim())
|
|
17
|
+
}).allRemainingSteps();
|
|
18
|
+
}
|
|
19
|
+
function filterRelevantEdges(edge) {
|
|
20
|
+
return (0, edge_1.edgeIncludesType)(2 /* EdgeType.DefinedBy */ | 32 /* EdgeType.DefinedByOnCall */ | 8 /* EdgeType.Returns */ | 1 /* EdgeType.Reads */, edge.types);
|
|
21
|
+
}
|
|
22
|
+
function pushRelevantEdges(queue, outgoingEdges) {
|
|
23
|
+
queue.push(...[...outgoingEdges].filter(([_, edge]) => filterRelevantEdges(edge)));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the lineage of a node in the dataflow graph
|
|
27
|
+
*
|
|
28
|
+
* @param criterion - The criterion to get the lineage of
|
|
29
|
+
* @param ast - The normalized AST
|
|
30
|
+
* @param dfg - The dataflow graph
|
|
31
|
+
* @returns The lineage of the node represented as a set of node ids
|
|
32
|
+
*/
|
|
33
|
+
function getLineage(criterion, { idMap }, dfg) {
|
|
34
|
+
const src = dfg.graph.get((0, parse_1.slicingCriterionToId)(criterion, idMap));
|
|
35
|
+
(0, assert_1.guard)(src !== undefined, 'The ID pointed to by the criterion does not exist in the dataflow graph');
|
|
36
|
+
const [vertex, outgoingEdges] = src;
|
|
37
|
+
const result = new Set([vertex.id]);
|
|
38
|
+
const edgeQueue = [];
|
|
39
|
+
pushRelevantEdges(edgeQueue, outgoingEdges);
|
|
40
|
+
while (edgeQueue.length > 0) {
|
|
41
|
+
const [target] = edgeQueue.shift();
|
|
42
|
+
if (result.has(target)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
result.add(target);
|
|
46
|
+
const outgoingEdges = dfg.graph.outgoingEdges(target);
|
|
47
|
+
if (outgoingEdges !== undefined) {
|
|
48
|
+
pushRelevantEdges(edgeQueue, outgoingEdges);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
exports.getLineage = getLineage;
|
|
54
|
+
exports.getLineageCommand = {
|
|
55
|
+
description: 'Get the lineage of an R object',
|
|
56
|
+
usageExample: ':lineage',
|
|
57
|
+
aliases: ['lin'],
|
|
58
|
+
script: false,
|
|
59
|
+
fn: async (output, shell, remainingLine) => {
|
|
60
|
+
const [criterion, rest] = splitAt(remainingLine, remainingLine.indexOf(' '));
|
|
61
|
+
const { dataflow: dfg, normalize: ast } = await getDfg(shell, rest);
|
|
62
|
+
const lineageIds = getLineage(criterion, ast, dfg);
|
|
63
|
+
output.stdout([...lineageIds].join('\n'));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=lineage.js.map
|
|
@@ -22,5 +22,6 @@ export declare class FlowRServerConnection {
|
|
|
22
22
|
private createPipelineExecutorForRequest;
|
|
23
23
|
private handleSliceRequest;
|
|
24
24
|
private handleRepl;
|
|
25
|
+
private handleLineageRequest;
|
|
25
26
|
}
|
|
26
27
|
export declare function sanitizeAnalysisResults(results: Partial<PipelineOutput<typeof DEFAULT_SLICING_PIPELINE>>): DeepPartial<PipelineOutput<typeof DEFAULT_SLICING_PIPELINE>>;
|
|
@@ -48,6 +48,9 @@ const tmp = __importStar(require("tmp"));
|
|
|
48
48
|
const fs_1 = __importDefault(require("fs"));
|
|
49
49
|
const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
|
|
50
50
|
const magic_comments_1 = require("../../../reconstruct/auto-select/magic-comments");
|
|
51
|
+
const lineage_1 = require("./messages/lineage");
|
|
52
|
+
const lineage_2 = require("../commands/lineage");
|
|
53
|
+
const assert_1 = require("../../../util/assert");
|
|
51
54
|
/**
|
|
52
55
|
* Each connection handles a single client, answering to its requests.
|
|
53
56
|
* There is no need to construct this class manually, {@link FlowRServer} will do it for you.
|
|
@@ -97,6 +100,9 @@ class FlowRServerConnection {
|
|
|
97
100
|
case 'request-repl-execution':
|
|
98
101
|
this.handleRepl(request.message);
|
|
99
102
|
break;
|
|
103
|
+
case 'request-lineage':
|
|
104
|
+
this.handleLineageRequest(request.message);
|
|
105
|
+
break;
|
|
100
106
|
default:
|
|
101
107
|
(0, send_1.sendMessage)(this.socket, {
|
|
102
108
|
id: request.message.id,
|
|
@@ -260,6 +266,34 @@ class FlowRServerConnection {
|
|
|
260
266
|
});
|
|
261
267
|
});
|
|
262
268
|
}
|
|
269
|
+
handleLineageRequest(base) {
|
|
270
|
+
const requestResult = (0, validate_1.validateMessage)(base, lineage_1.requestLineageMessage);
|
|
271
|
+
if (requestResult.type === 'error') {
|
|
272
|
+
(0, validate_1.answerForValidationError)(this.socket, requestResult, base.id);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const request = requestResult.message;
|
|
276
|
+
this.logger.info(`[${this.name}] Received lineage request for criterion ${request.criterion}`);
|
|
277
|
+
const fileInformation = this.fileMap.get(request.filetoken);
|
|
278
|
+
if (!fileInformation) {
|
|
279
|
+
(0, send_1.sendMessage)(this.socket, {
|
|
280
|
+
id: request.id,
|
|
281
|
+
type: 'error',
|
|
282
|
+
fatal: false,
|
|
283
|
+
reason: `The file token ${request.filetoken} has never been analyzed.`
|
|
284
|
+
});
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const { dataflow: dfg, normalize: ast } = fileInformation.pipeline.getResults(true);
|
|
288
|
+
(0, assert_1.guard)(dfg !== undefined, `Dataflow graph must be present (request: ${request.filetoken})`);
|
|
289
|
+
(0, assert_1.guard)(ast !== undefined, `AST must be present (request: ${request.filetoken})`);
|
|
290
|
+
const lineageIds = (0, lineage_2.getLineage)(request.criterion, ast, dfg);
|
|
291
|
+
(0, send_1.sendMessage)(this.socket, {
|
|
292
|
+
type: 'response-lineage',
|
|
293
|
+
id: request.id,
|
|
294
|
+
lineage: [...lineageIds]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
263
297
|
}
|
|
264
298
|
exports.FlowRServerConnection = FlowRServerConnection;
|
|
265
299
|
function sanitizeAnalysisResults(results) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SingleSlicingCriterion } from '../../../../slicing/criterion/parse';
|
|
2
|
+
import type { IdMessageBase, MessageDefinition } from './messages';
|
|
3
|
+
import type { NodeId } from '../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
|
+
export interface LineageRequestMessage extends IdMessageBase {
|
|
5
|
+
type: 'request-lineage';
|
|
6
|
+
/** The {@link FileAnalysisRequestMessage#filetoken} of the file/data */
|
|
7
|
+
filetoken: string;
|
|
8
|
+
/** The criterion to start the lineage from */
|
|
9
|
+
criterion: SingleSlicingCriterion;
|
|
10
|
+
}
|
|
11
|
+
export declare const requestLineageMessage: MessageDefinition<LineageRequestMessage>;
|
|
12
|
+
export interface LineageResponseMessage extends IdMessageBase {
|
|
13
|
+
type: 'response-lineage';
|
|
14
|
+
/** The lineage of the given criterion. With this being the representation of a set, there is no guarantee about order. */
|
|
15
|
+
lineage: NodeId[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.requestLineageMessage = void 0;
|
|
7
|
+
const joi_1 = __importDefault(require("joi"));
|
|
8
|
+
exports.requestLineageMessage = {
|
|
9
|
+
type: 'request-lineage',
|
|
10
|
+
schema: joi_1.default.object({
|
|
11
|
+
type: joi_1.default.string().valid('request-lineage').required(),
|
|
12
|
+
id: joi_1.default.string().optional(),
|
|
13
|
+
filetoken: joi_1.default.string().required(),
|
|
14
|
+
criterion: joi_1.default.string().required()
|
|
15
|
+
})
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=lineage.js.map
|
|
@@ -9,6 +9,7 @@ import type { FileAnalysisRequestMessage, FileAnalysisResponseMessageJson } from
|
|
|
9
9
|
import type { ExecuteEndMessage, ExecuteIntermediateResponseMessage, ExecuteRequestMessage } from './repl';
|
|
10
10
|
import type { SliceRequestMessage, SliceResponseMessage } from './slice';
|
|
11
11
|
import type { FlowrErrorMessage } from './error';
|
|
12
|
+
import type { LineageRequestMessage, LineageResponseMessage } from './lineage';
|
|
12
13
|
/**
|
|
13
14
|
* If you send a message it must *not* contain a newline but the message must be terminated by a newline.
|
|
14
15
|
*/
|
|
@@ -32,4 +33,4 @@ export declare const baseMessage: MessageDefinition<IdMessageBase>;
|
|
|
32
33
|
/**
|
|
33
34
|
* This is the main message type that should be used to represent a message in *flowR*
|
|
34
35
|
*/
|
|
35
|
-
export type FlowrMessage = FlowrHelloResponseMessage | FileAnalysisRequestMessage | FileAnalysisResponseMessageJson | ExecuteRequestMessage | ExecuteIntermediateResponseMessage | ExecuteEndMessage | SliceRequestMessage | SliceResponseMessage | FlowrErrorMessage;
|
|
36
|
+
export type FlowrMessage = FlowrHelloResponseMessage | FileAnalysisRequestMessage | FileAnalysisResponseMessageJson | ExecuteRequestMessage | ExecuteIntermediateResponseMessage | ExecuteEndMessage | SliceRequestMessage | SliceResponseMessage | LineageRequestMessage | LineageResponseMessage | FlowrErrorMessage;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EmptyBuiltInMemory = exports.BuiltInMemory = exports.registerReplacementFunctions = exports.registerBuiltInFunctions = exports.BuiltIn = void 0;
|
|
4
4
|
const known_call_handling_1 = require("../internal/process/functions/call/known-call-handling");
|
|
5
|
-
const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
|
|
6
5
|
const built_in_access_1 = require("../internal/process/functions/call/built-in/built-in-access");
|
|
7
6
|
const built_in_if_then_else_1 = require("../internal/process/functions/call/built-in/built-in-if-then-else");
|
|
8
7
|
const built_in_assignment_1 = require("../internal/process/functions/call/built-in/built-in-assignment");
|
|
9
|
-
const
|
|
8
|
+
const built_in_special_bin_op_1 = require("../internal/process/functions/call/built-in/built-in-special-bin-op");
|
|
10
9
|
const built_in_pipe_1 = require("../internal/process/functions/call/built-in/built-in-pipe");
|
|
11
10
|
const built_in_for_loop_1 = require("../internal/process/functions/call/built-in/built-in-for-loop");
|
|
12
11
|
const built_in_repeat_loop_1 = require("../internal/process/functions/call/built-in/built-in-repeat-loop");
|
|
@@ -18,9 +17,10 @@ const built_in_function_definition_1 = require("../internal/process/functions/ca
|
|
|
18
17
|
const built_in_expression_list_1 = require("../internal/process/functions/call/built-in/built-in-expression-list");
|
|
19
18
|
const built_in_get_1 = require("../internal/process/functions/call/built-in/built-in-get");
|
|
20
19
|
const built_in_library_1 = require("../internal/process/functions/call/built-in/built-in-library");
|
|
20
|
+
const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
|
|
21
21
|
exports.BuiltIn = 'built-in';
|
|
22
22
|
function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
23
|
-
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
|
|
23
|
+
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
|
|
24
24
|
if (config.returnsNthArgument !== undefined) {
|
|
25
25
|
const arg = config.returnsNthArgument === 'last' ? processedArguments[args.length - 1] : processedArguments[config.returnsNthArgument];
|
|
26
26
|
if (arg !== undefined) {
|
|
@@ -34,6 +34,9 @@ function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
if (config.hasUnknownSideEffects) {
|
|
38
|
+
res.graph.markIdForUnknownSideEffects(rootId);
|
|
39
|
+
}
|
|
37
40
|
if (config.cfg !== undefined) {
|
|
38
41
|
res.exitPoints = [...res.exitPoints, { type: config.cfg, nodeId: rootId, controlDependencies: data.controlDependencies }];
|
|
39
42
|
}
|
|
@@ -41,6 +44,7 @@ function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
|
41
44
|
}
|
|
42
45
|
function registerBuiltInFunctions(both, names, processor, config) {
|
|
43
46
|
for (const name of names) {
|
|
47
|
+
(0, assert_1.guard)(processor !== undefined, `Processor for ${name} is undefined, maybe you have an import loop? You may run 'npm run detect-circular-deps' - although by far not all are bad`);
|
|
44
48
|
(0, assert_1.guard)(!exports.BuiltInMemory.has(name), `Built-in ${name} already defined`);
|
|
45
49
|
const d = [{
|
|
46
50
|
kind: 'built-in-function',
|
|
@@ -101,9 +105,13 @@ registerBuiltInConstant(true, 'TRUE', true);
|
|
|
101
105
|
registerBuiltInConstant(true, 'T', true);
|
|
102
106
|
registerBuiltInConstant(true, 'FALSE', false);
|
|
103
107
|
registerBuiltInConstant(true, 'F', false);
|
|
104
|
-
registerSimpleFunctions('~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':', 'list', 'c', 'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max', 'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean', 'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'plot', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix', '
|
|
105
|
-
registerBuiltInFunctions(true, ['
|
|
106
|
-
registerBuiltInFunctions(
|
|
108
|
+
registerSimpleFunctions('~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':', 'list', 'c', 'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max', 'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean', 'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'plot', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix', 'do.call', 'rbind', 'nrow', 'ncol', 'tryCatch', 'expression', 'factor', 'missing', 'as.data.frame', 'data.frame', 'na.omit', 'rownames', 'names', 'order', 'length', 'any', 'dim', 'matrix', 'cbind', 'nchar', 't');
|
|
109
|
+
registerBuiltInFunctions(true, ['apply', 'lapply', 'sapply', 'tapply', 'mapply'], defaultBuiltInProcessor, { forceArgs: [false, true] });
|
|
110
|
+
registerBuiltInFunctions(true, ['print'], defaultBuiltInProcessor, { returnsNthArgument: 0, forceArgs: 'all' });
|
|
111
|
+
registerBuiltInFunctions(true, ['('], defaultBuiltInProcessor, { returnsNthArgument: 0 });
|
|
112
|
+
registerBuiltInFunctions(true, ['load', 'load_all', 'setwd', 'set.seed'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: [true] });
|
|
113
|
+
registerBuiltInFunctions(false, ['cat'], defaultBuiltInProcessor, { forceArgs: 'all' }); /* returns null */
|
|
114
|
+
registerBuiltInFunctions(false, ['switch'], defaultBuiltInProcessor, {}); /* returns null */
|
|
107
115
|
registerBuiltInFunctions(true, ['return'], defaultBuiltInProcessor, { returnsNthArgument: 0, cfg: 1 /* ExitPointType.Return */ });
|
|
108
116
|
registerBuiltInFunctions(true, ['break'], defaultBuiltInProcessor, { cfg: 2 /* ExitPointType.Break */ });
|
|
109
117
|
registerBuiltInFunctions(true, ['next'], defaultBuiltInProcessor, { cfg: 3 /* ExitPointType.Next */ });
|
|
@@ -120,14 +128,16 @@ registerBuiltInFunctions(true, ['delayedAssign'], built_in_assignment_1.processA
|
|
|
120
128
|
registerBuiltInFunctions(true, ['<<-'], built_in_assignment_1.processAssignment, { superAssignment: true, canBeReplacement: true });
|
|
121
129
|
registerBuiltInFunctions(true, ['->'], built_in_assignment_1.processAssignment, { swapSourceAndTarget: true, canBeReplacement: true });
|
|
122
130
|
registerBuiltInFunctions(true, ['->>'], built_in_assignment_1.processAssignment, { superAssignment: true, swapSourceAndTarget: true, canBeReplacement: true });
|
|
123
|
-
registerBuiltInFunctions(true, ['&&', '&'],
|
|
124
|
-
registerBuiltInFunctions(true, ['||', '|'],
|
|
131
|
+
registerBuiltInFunctions(true, ['&&', '&'], built_in_special_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: true });
|
|
132
|
+
registerBuiltInFunctions(true, ['||', '|'], built_in_special_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: false });
|
|
125
133
|
registerBuiltInFunctions(true, ['|>', '%>%'], built_in_pipe_1.processPipe, {});
|
|
126
134
|
registerBuiltInFunctions(true, ['function', '\\'], built_in_function_definition_1.processFunctionDefinition, {});
|
|
127
135
|
registerBuiltInFunctions(true, ['quote', 'substitute', 'bquote'], built_in_quote_1.processQuote, { quoteArgumentsWithIndex: 0 });
|
|
128
136
|
registerBuiltInFunctions(true, ['for'], built_in_for_loop_1.processForLoop, {});
|
|
129
137
|
registerBuiltInFunctions(true, ['repeat'], built_in_repeat_loop_1.processRepeatLoop, {});
|
|
130
138
|
registerBuiltInFunctions(true, ['while'], built_in_while_loop_1.processWhileLoop, {});
|
|
139
|
+
registerBuiltInFunctions(true, ['options'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: 'all' });
|
|
140
|
+
registerBuiltInFunctions(true, ['on.exit', 'sys.on.exit'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
|
|
131
141
|
/* they are all mapped to `<-` but we separate super assignments */
|
|
132
142
|
registerReplacementFunctions({ makeMaybe: true }, ['<-', '<<-'], '[', '[[', '$', '@', 'names', 'dimnames', 'attributes', 'attr', 'class', 'levels', 'rownames', 'colnames');
|
|
133
143
|
//# sourceMappingURL=built-in.js.map
|
|
@@ -20,11 +20,12 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
if (node) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const [fst] = node;
|
|
24
|
+
if (fst.controlDependencies && defaultCd && !fst.controlDependencies.includes(defaultCd)) {
|
|
25
|
+
fst.controlDependencies.push(defaultCd);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
|
-
|
|
28
|
+
fst.controlDependencies = defaultCd ? [defaultCd] : [];
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
return { ...ref, controlDependencies: [...ref.controlDependencies ?? [], ...(defaultCd ? [defaultCd] : [])] };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { REnvironmentInformation } from './environment';
|
|
2
|
-
import
|
|
2
|
+
import { Ternary } from '../../util/logic';
|
|
3
3
|
import type { Identifier, IdentifierDefinition } from './identifier';
|
|
4
4
|
/**
|
|
5
5
|
* Resolves a given identifier name to a list of its possible definition location using R scoping and resolving rules.
|
|
@@ -24,11 +24,11 @@ function resolveByName(name, environment) {
|
|
|
24
24
|
exports.resolveByName = resolveByName;
|
|
25
25
|
function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
26
26
|
if (name === undefined) {
|
|
27
|
-
return
|
|
27
|
+
return 2 /* Ternary.Never */;
|
|
28
28
|
}
|
|
29
29
|
const definition = resolveByName(name, environment);
|
|
30
30
|
if (definition === undefined) {
|
|
31
|
-
return
|
|
31
|
+
return 2 /* Ternary.Never */;
|
|
32
32
|
}
|
|
33
33
|
let all = true;
|
|
34
34
|
let some = false;
|
|
@@ -41,10 +41,10 @@ function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
if (all) {
|
|
44
|
-
return
|
|
44
|
+
return 0 /* Ternary.Always */;
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
|
-
return some ?
|
|
47
|
+
return some ? 1 /* Ternary.Maybe */ : 2 /* Ternary.Never */;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
|
package/dataflow/graph/diff.js
CHANGED
|
@@ -94,6 +94,7 @@ function diffOutgoingEdges(ctx) {
|
|
|
94
94
|
}
|
|
95
95
|
function diffRootVertices(ctx) {
|
|
96
96
|
(0, diff_1.setDifference)(ctx.left.rootIds(), ctx.right.rootIds(), { ...ctx, position: `${ctx.position}Root vertices differ in graphs. ` });
|
|
97
|
+
(0, diff_1.setDifference)(ctx.left.unknownSideEffects, ctx.right.unknownSideEffects, { ...ctx, position: `${ctx.position}Unknown side effects differ in graphs. ` });
|
|
97
98
|
}
|
|
98
99
|
function diffOfDataflowGraphs(left, right, config) {
|
|
99
100
|
if (left.graph === right.graph) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { DataflowGraphEdge } from './edge';
|
|
2
2
|
import { EdgeType } from './edge';
|
|
3
3
|
import type { DataflowInformation } from '../info';
|
|
4
|
-
import type { DataflowDifferenceReport } from './diff';
|
|
5
4
|
import type { DataflowGraphVertexArgument, DataflowGraphVertexInfo } from './vertex';
|
|
6
5
|
import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
6
|
import type { IdentifierDefinition, IdentifierReference } from '../environments/identifier';
|
|
@@ -47,10 +46,10 @@ type EdgeData<Edge extends DataflowGraphEdge> = Omit<Edge, 'from' | 'to' | 'type
|
|
|
47
46
|
export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo, Edge extends DataflowGraphEdge = DataflowGraphEdge> {
|
|
48
47
|
private static DEFAULT_ENVIRONMENT;
|
|
49
48
|
private _idMap;
|
|
50
|
-
|
|
49
|
+
private _unknownSideEffects;
|
|
51
50
|
constructor(idMap: AstIdMap | undefined);
|
|
52
51
|
/** Contains the vertices of the root level graph (i.e., included those vertices from the complete graph, that are nested within function definitions) */
|
|
53
|
-
|
|
52
|
+
protected rootVertices: Set<NodeId>;
|
|
54
53
|
/** All vertices in the complete graph (including those nested in function definition) */
|
|
55
54
|
private vertexInformation;
|
|
56
55
|
/** All edges in the complete graph (including those nested in function definition) */
|
|
@@ -79,14 +78,18 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
79
78
|
ingoingEdges(id: NodeId): IngoingEdges | undefined;
|
|
80
79
|
/** Retrieves the id-map to the normalized AST attached to the dataflow graph */
|
|
81
80
|
get idMap(): AstIdMap | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Retrieves the set of vertices which have side effects that we do not know anything about.
|
|
83
|
+
*/
|
|
84
|
+
get unknownSideEffects(): ReadonlySet<NodeId>;
|
|
82
85
|
/** 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) */
|
|
83
86
|
setIdMap(idMap: AstIdMap): void;
|
|
84
87
|
/**
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
* @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
|
|
89
|
+
* @returns the ids of all toplevel vertices in the graph together with their vertex information
|
|
87
90
|
*
|
|
88
91
|
* @see #edges
|
|
89
|
-
|
|
92
|
+
*/
|
|
90
93
|
vertices(includeDefinedFunctions: boolean): IterableIterator<[NodeId, Vertex]>;
|
|
91
94
|
/**
|
|
92
95
|
* @returns the ids of all edges in the graph together with their edge information
|
|
@@ -107,15 +110,15 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
107
110
|
isRoot(id: NodeId): boolean;
|
|
108
111
|
rootIds(): ReadonlySet<NodeId>;
|
|
109
112
|
/**
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
* Adds a new vertex to the graph, for ease of use, some arguments are optional and filled automatically.
|
|
114
|
+
*
|
|
112
115
|
* @param vertex - The vertex to add
|
|
113
116
|
* @param asRoot - If false, this will only add the vertex but do not add it to the {@link rootIds|root vertices} of the graph.
|
|
114
117
|
* This is probably only of use, when you construct dataflow graphs for tests.
|
|
115
118
|
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
* @see DataflowGraphVertexInfo
|
|
120
|
+
* @see DataflowGraphVertexArgument
|
|
121
|
+
*/
|
|
119
122
|
addVertex(vertex: DataflowGraphVertexArgument & Omit<Vertex, keyof DataflowGraphVertexArgument>, asRoot?: boolean): this;
|
|
120
123
|
/** {@inheritDoc} */
|
|
121
124
|
addEdge(from: NodeId, to: NodeId, edgeInfo: EdgeData<Edge>): this;
|
|
@@ -133,18 +136,14 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
133
136
|
*/
|
|
134
137
|
mergeWith(otherGraph: DataflowGraph<Vertex, Edge> | undefined, mergeRootVertices?: boolean): this;
|
|
135
138
|
private mergeEdges;
|
|
136
|
-
equals(other: DataflowGraph<Vertex, Edge>, diff: true, names?: {
|
|
137
|
-
left: string;
|
|
138
|
-
right: string;
|
|
139
|
-
}): DataflowDifferenceReport;
|
|
140
|
-
equals(other: DataflowGraph<Vertex, Edge>, diff?: false, names?: {
|
|
141
|
-
left: string;
|
|
142
|
-
right: string;
|
|
143
|
-
}): boolean;
|
|
144
139
|
/**
|
|
145
140
|
* Marks a vertex in the graph to be a definition
|
|
146
141
|
* @param reference - The reference to the vertex to mark as definition
|
|
147
142
|
*/
|
|
148
143
|
setDefinitionOfVertex(reference: IdentifierReference): void;
|
|
144
|
+
/** If you do not pass the `to` node, this will just mark the node as maybe */
|
|
145
|
+
addControlDependency(from: NodeId, to?: NodeId, when?: boolean): this;
|
|
146
|
+
/** Marks the given node as having unknown side effects */
|
|
147
|
+
markIdForUnknownSideEffects(id: NodeId): this;
|
|
149
148
|
}
|
|
150
149
|
export {};
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -5,6 +5,7 @@ const assert_1 = require("../../util/assert");
|
|
|
5
5
|
const diff_1 = require("./diff");
|
|
6
6
|
const arrays_1 = require("../../util/arrays");
|
|
7
7
|
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
8
|
+
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
8
9
|
const environment_1 = require("../environments/environment");
|
|
9
10
|
const clone_1 = require("../environments/clone");
|
|
10
11
|
const built_in_1 = require("../environments/built-in");
|
|
@@ -42,8 +43,8 @@ function extractEdgeIds(from, to) {
|
|
|
42
43
|
class DataflowGraph {
|
|
43
44
|
static DEFAULT_ENVIRONMENT = undefined;
|
|
44
45
|
_idMap;
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
/* Set of vertices which have sideEffects that we do not know anything about */
|
|
47
|
+
_unknownSideEffects = new Set();
|
|
47
48
|
constructor(idMap) {
|
|
48
49
|
DataflowGraph.DEFAULT_ENVIRONMENT ??= (0, environment_1.initializeCleanEnvironments)();
|
|
49
50
|
this._idMap = idMap;
|
|
@@ -96,16 +97,22 @@ class DataflowGraph {
|
|
|
96
97
|
get idMap() {
|
|
97
98
|
return this._idMap;
|
|
98
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Retrieves the set of vertices which have side effects that we do not know anything about.
|
|
102
|
+
*/
|
|
103
|
+
get unknownSideEffects() {
|
|
104
|
+
return this._unknownSideEffects;
|
|
105
|
+
}
|
|
99
106
|
/** 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) */
|
|
100
107
|
setIdMap(idMap) {
|
|
101
108
|
this._idMap = idMap;
|
|
102
109
|
}
|
|
103
110
|
/**
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
* @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
|
|
112
|
+
* @returns the ids of all toplevel vertices in the graph together with their vertex information
|
|
106
113
|
*
|
|
107
114
|
* @see #edges
|
|
108
|
-
|
|
115
|
+
*/
|
|
109
116
|
*vertices(includeDefinedFunctions) {
|
|
110
117
|
if (includeDefinedFunctions) {
|
|
111
118
|
yield* this.vertexInformation.entries();
|
|
@@ -143,15 +150,15 @@ class DataflowGraph {
|
|
|
143
150
|
return this.rootVertices;
|
|
144
151
|
}
|
|
145
152
|
/**
|
|
146
|
-
|
|
147
|
-
|
|
153
|
+
* Adds a new vertex to the graph, for ease of use, some arguments are optional and filled automatically.
|
|
154
|
+
*
|
|
148
155
|
* @param vertex - The vertex to add
|
|
149
156
|
* @param asRoot - If false, this will only add the vertex but do not add it to the {@link rootIds|root vertices} of the graph.
|
|
150
157
|
* This is probably only of use, when you construct dataflow graphs for tests.
|
|
151
158
|
*
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
* @see DataflowGraphVertexInfo
|
|
160
|
+
* @see DataflowGraphVertexArgument
|
|
161
|
+
*/
|
|
155
162
|
addVertex(vertex, asRoot = true) {
|
|
156
163
|
const oldVertex = this.vertexInformation.get(vertex.id);
|
|
157
164
|
if (oldVertex !== undefined) {
|
|
@@ -170,11 +177,11 @@ class DataflowGraph {
|
|
|
170
177
|
return this;
|
|
171
178
|
}
|
|
172
179
|
/**
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
* Will insert a new edge into the graph,
|
|
181
|
+
* if the direction of the edge is of no importance (`same-read-read` or `same-def-def`), source
|
|
182
|
+
* and target will be sorted so that `from` has the lower, and `to` the higher id (default ordering).
|
|
183
|
+
* Please note that this will never make edges to {@link BuiltIn} as they are not part of the graph.
|
|
184
|
+
*/
|
|
178
185
|
addEdge(from, to, edgeInfo) {
|
|
179
186
|
const { fromId, toId } = extractEdgeIds(from, to);
|
|
180
187
|
const { type, ...rest } = edgeInfo;
|
|
@@ -232,6 +239,9 @@ class DataflowGraph {
|
|
|
232
239
|
this.rootVertices.add(root);
|
|
233
240
|
}
|
|
234
241
|
}
|
|
242
|
+
for (const unknown of otherGraph.unknownSideEffects) {
|
|
243
|
+
this._unknownSideEffects.add(unknown);
|
|
244
|
+
}
|
|
235
245
|
for (const [id, info] of otherGraph.vertexInformation) {
|
|
236
246
|
const currentInfo = this.vertexInformation.get(id);
|
|
237
247
|
this.vertexInformation.set(id, currentInfo === undefined ? info : mergeNodeInfos(currentInfo, info));
|
|
@@ -258,15 +268,6 @@ class DataflowGraph {
|
|
|
258
268
|
}
|
|
259
269
|
}
|
|
260
270
|
}
|
|
261
|
-
equals(other, diff = false, names = { left: 'left', right: 'right' }) {
|
|
262
|
-
const report = (0, diff_1.diffOfDataflowGraphs)({ name: names.left, graph: this }, { name: names.right, graph: other });
|
|
263
|
-
if (diff) {
|
|
264
|
-
return report;
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
return report.isEqual();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
271
|
/**
|
|
271
272
|
* Marks a vertex in the graph to be a definition
|
|
272
273
|
* @param reference - The reference to the vertex to mark as definition
|
|
@@ -281,6 +282,22 @@ class DataflowGraph {
|
|
|
281
282
|
this.vertexInformation.set(reference.nodeId, { ...vertex, tag: 'variable-definition' });
|
|
282
283
|
}
|
|
283
284
|
}
|
|
285
|
+
/** If you do not pass the `to` node, this will just mark the node as maybe */
|
|
286
|
+
addControlDependency(from, to, when) {
|
|
287
|
+
to = to ? (0, node_id_1.normalizeIdToNumberIfPossible)(to) : undefined;
|
|
288
|
+
const vertex = this.getVertex(from, true);
|
|
289
|
+
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${from} to add control dependency`);
|
|
290
|
+
vertex.controlDependencies ??= [];
|
|
291
|
+
if (to && vertex.controlDependencies.every(({ id, when: cond }) => id !== to && when !== cond)) {
|
|
292
|
+
vertex.controlDependencies.push({ id: to, when });
|
|
293
|
+
}
|
|
294
|
+
return this;
|
|
295
|
+
}
|
|
296
|
+
/** Marks the given node as having unknown side effects */
|
|
297
|
+
markIdForUnknownSideEffects(id) {
|
|
298
|
+
this._unknownSideEffects.add((0, node_id_1.normalizeIdToNumberIfPossible)(id));
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
284
301
|
}
|
|
285
302
|
exports.DataflowGraph = DataflowGraph;
|
|
286
303
|
function mergeNodeInfos(current, next) {
|