@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.
Files changed (66) hide show
  1. package/README.md +15 -5
  2. package/cli/repl/commands/commands.js +3 -1
  3. package/cli/repl/commands/lineage.d.ts +15 -0
  4. package/cli/repl/commands/lineage.js +66 -0
  5. package/cli/repl/server/connection.d.ts +1 -0
  6. package/cli/repl/server/connection.js +34 -0
  7. package/cli/repl/server/messages/lineage.d.ts +16 -0
  8. package/cli/repl/server/messages/lineage.js +17 -0
  9. package/cli/repl/server/messages/messages.d.ts +2 -1
  10. package/dataflow/environments/built-in.js +18 -8
  11. package/dataflow/environments/environment.js +4 -3
  12. package/dataflow/environments/resolve-by-name.d.ts +1 -1
  13. package/dataflow/environments/resolve-by-name.js +4 -4
  14. package/dataflow/graph/diff.js +1 -0
  15. package/dataflow/graph/graph.d.ts +18 -19
  16. package/dataflow/graph/graph.js +41 -24
  17. package/dataflow/graph/vertex.d.ts +6 -1
  18. package/dataflow/graph/vertex.js +21 -0
  19. package/dataflow/info.d.ts +1 -1
  20. package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +2 -1
  21. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +3 -3
  22. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -1
  23. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -4
  24. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +1 -1
  25. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +10 -1
  26. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -4
  27. package/dataflow/internal/process/functions/call/built-in/built-in-library.js +1 -0
  28. package/dataflow/internal/process/functions/call/built-in/built-in-quote.d.ts +3 -2
  29. package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +1 -1
  30. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +3 -2
  31. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +2 -1
  32. package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +2 -2
  33. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +18 -7
  34. package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.d.ts → built-in-special-bin-op.d.ts} +2 -1
  35. package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.js → built-in-special-bin-op.js} +3 -3
  36. package/dataflow/internal/process/functions/call/common.d.ts +6 -2
  37. package/dataflow/internal/process/functions/call/common.js +36 -1
  38. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +3 -2
  39. package/dataflow/internal/process/functions/call/known-call-handling.js +2 -2
  40. package/dataflow/internal/process/functions/call/named-call-handling.js +3 -1
  41. package/dataflow/internal/process/functions/call/unnamed-call-handling.js +1 -0
  42. package/dataflow/internal/process/functions/process-argument.js +0 -28
  43. package/package.json +3 -2
  44. package/r-bridge/data/data.d.ts +5 -0
  45. package/r-bridge/data/data.js +6 -0
  46. package/reconstruct/reconstruct.js +3 -3
  47. package/slicing/criterion/parse.d.ts +3 -4
  48. package/slicing/criterion/parse.js +3 -3
  49. package/slicing/static/slice-call.js +35 -13
  50. package/slicing/static/static-slicer.d.ts +1 -1
  51. package/slicing/static/static-slicer.js +10 -4
  52. package/statistics/statistics.js +1 -1
  53. package/util/json.d.ts +1 -1
  54. package/util/json.js +3 -3
  55. package/util/logic.d.ts +5 -1
  56. package/util/version.js +1 -1
  57. package/abstract-interpretation/domain.d.ts +0 -57
  58. package/abstract-interpretation/domain.js +0 -176
  59. package/abstract-interpretation/handler/binop/binop.d.ts +0 -15
  60. package/abstract-interpretation/handler/binop/binop.js +0 -42
  61. package/abstract-interpretation/handler/binop/operators.d.ts +0 -2
  62. package/abstract-interpretation/handler/binop/operators.js +0 -28
  63. package/abstract-interpretation/handler/handler.d.ts +0 -6
  64. package/abstract-interpretation/handler/handler.js +0 -3
  65. package/abstract-interpretation/processor.d.ts +0 -11
  66. package/abstract-interpretation/processor.js +0 -84
package/README.md CHANGED
@@ -1,20 +1,30 @@
1
1
  [![flowR logo](https://raw.githubusercontent.com/wiki/flowr-analysis/flowr/img/flowR.png)](https://github.com/flowr-analysis/flowr/wiki)\
2
- [![QA (and potentially deploy)](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml/badge.svg)](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml) [![codecov](https://codecov.io/gh/flowr-analysis/flowr/graph/badge.svg)](https://codecov.io/gh/flowr-analysis/flowr) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/eagleoutice/flowr?logo=docker&logoColor=white&label=dockerhub)](https://hub.docker.com/r/eagleoutice/flowr) [![latest tag](https://badgen.net/github/tag/flowr-analysis/flowr?label=latest&color=purple)](https://github.com/flowr-analysis/flowr/releases/latest) [![Marketplace](https://badgen.net/vs-marketplace/v/code-inspect.vscode-flowr)](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) [![All Contributors](https://img.shields.io/github/all-contributors/flowr-analysis/flowr)](#contributors)
2
+ [![QA (and potentially deploy)](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml/badge.svg)](https://github.com/flowr-analysis/flowr/actions/workflows/qa.yaml) [![codecov](https://codecov.io/gh/flowr-analysis/flowr/graph/badge.svg)](https://codecov.io/gh/flowr-analysis/flowr) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/eagleoutice/flowr?logo=docker&logoColor=white&label=dockerhub)](https://hub.docker.com/r/eagleoutice/flowr) [![latest tag](https://badgen.net/github/tag/flowr-analysis/flowr?label=latest&color=purple)](https://github.com/flowr-analysis/flowr/releases/latest) [![Marketplace](https://badgen.net/vs-marketplace/v/code-inspect.vscode-flowr)](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) [![All Contributors](https://img.shields.io/github/all-contributors/flowr-analysis/flowr)](#contributors)
3
3
  [![DOI](https://zenodo.org/badge/624819038.svg)](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`). It is available as a [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) and as a [docker image](https://hub.docker.com/r/eagleoutice/flowr).
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. For Visual Studio Code, please see the [marketplace entry](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr). With docker 🐳️, the following line should be enough (and drop you directly into the REPL):
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
+ ![Example of a simple REPL session](wiki/gif/repl-demo.gif)
22
+
23
+ </details>
14
24
 
15
25
  ## 📜 More Information
16
26
 
17
- For more details, see the [wiki pages](https://github.com/flowr-analysis/flowr/wiki) and the deployed [code documentation](https://flowr-analysis.github.io/flowr/doc/).
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 built_in_logical_bin_op_1 = require("../internal/process/functions/call/built-in/built-in-logical-bin-op");
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', 'apply', 'lapply', 'sapply', 'tapply', 'mapply', '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');
105
- registerBuiltInFunctions(true, ['print', '('], defaultBuiltInProcessor, { returnsNthArgument: 0 });
106
- registerBuiltInFunctions(false, ['cat', 'switch'], defaultBuiltInProcessor, {}); /* returns null */
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, ['&&', '&'], built_in_logical_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: true });
124
- registerBuiltInFunctions(true, ['||', '|'], built_in_logical_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: false });
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
- if (node[0].controlDependencies && defaultCd && !node[0].controlDependencies.includes(defaultCd)) {
24
- node[0].controlDependencies.push(defaultCd);
23
+ const [fst] = node;
24
+ if (fst.controlDependencies && defaultCd && !fst.controlDependencies.includes(defaultCd)) {
25
+ fst.controlDependencies.push(defaultCd);
25
26
  }
26
27
  else {
27
- node[0].controlDependencies = defaultCd ? [defaultCd] : [];
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 type { Ternary } from '../../util/logic';
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 'never';
27
+ return 2 /* Ternary.Never */;
28
28
  }
29
29
  const definition = resolveByName(name, environment);
30
30
  if (definition === undefined) {
31
- return 'never';
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 'always';
44
+ return 0 /* Ternary.Always */;
45
45
  }
46
46
  else {
47
- return some ? 'maybe' : 'never';
47
+ return some ? 1 /* Ternary.Maybe */ : 2 /* Ternary.Never */;
48
48
  }
49
49
  }
50
50
  exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
@@ -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
- readonly functionCache: Map<NodeId, Set<DataflowGraphVertexInfo>>;
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
- private rootVertices;
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
- * @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
86
- * @returns the ids of all toplevel vertices in the graph together with their vertex information
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
- * Adds a new vertex to the graph, for ease of use, some arguments are optional and filled automatically.
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
- * @see DataflowGraphVertexInfo
117
- * @see DataflowGraphVertexArgument
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 {};
@@ -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
- // this should be linked separately
46
- functionCache = new Map();
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
- * @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
105
- * @returns the ids of all toplevel vertices in the graph together with their vertex information
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
- * Adds a new vertex to the graph, for ease of use, some arguments are optional and filled automatically.
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
- * @see DataflowGraphVertexInfo
153
- * @see DataflowGraphVertexArgument
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
- * Will insert a new edge into the graph,
174
- * if the direction of the edge is of no importance (`same-read-read` or `same-def-def`), source
175
- * and target will be sorted so that `from` has the lower, and `to` the higher id (default ordering).
176
- * Please note, that this will never make edges to {@link BuiltIn} as they are not part of the graph.
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) {