@eagleoutice/flowr 2.4.7 → 2.4.8

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 (86) hide show
  1. package/README.md +43 -39
  2. package/abstract-interpretation/data-frame/absint-visitor.js +3 -2
  3. package/benchmark/slicer.js +1 -1
  4. package/benchmark/summarizer/first-phase/process.js +1 -1
  5. package/cli/repl/commands/repl-query.js +11 -2
  6. package/cli/repl/core.d.ts +2 -2
  7. package/cli/repl/core.js +26 -7
  8. package/cli/repl/server/connection.js +3 -1
  9. package/cli/repl/server/messages/message-slice.d.ts +3 -0
  10. package/cli/repl/server/messages/message-slice.js +2 -0
  11. package/control-flow/extract-cfg.d.ts +3 -3
  12. package/control-flow/extract-cfg.js +4 -4
  13. package/control-flow/useless-loop.js +30 -21
  14. package/dataflow/environments/built-in.d.ts +1 -1
  15. package/dataflow/environments/default-builtin-config.d.ts +9 -0
  16. package/dataflow/environments/default-builtin-config.js +21 -21
  17. package/dataflow/environments/environment.js +18 -9
  18. package/dataflow/environments/overwrite.js +2 -2
  19. package/dataflow/extractor.js +1 -1
  20. package/dataflow/graph/diff-dataflow-graph.js +4 -4
  21. package/dataflow/graph/graph.d.ts +3 -3
  22. package/dataflow/graph/graph.js +4 -1
  23. package/dataflow/graph/quads.js +4 -4
  24. package/dataflow/info.js +1 -1
  25. package/dataflow/internal/linker.d.ts +2 -0
  26. package/dataflow/internal/linker.js +18 -1
  27. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
  28. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +68 -21
  29. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -2
  30. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +4 -4
  31. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -18
  32. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
  33. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +4 -5
  34. package/dataflow/internal/process/functions/call/common.js +4 -3
  35. package/documentation/doc-util/doc-query.js +6 -2
  36. package/documentation/doc-util/doc-types.d.ts +7 -2
  37. package/documentation/doc-util/doc-types.js +20 -4
  38. package/documentation/print-core-wiki.js +5 -1
  39. package/documentation/print-dataflow-graph-wiki.js +21 -12
  40. package/documentation/print-faq-wiki.js +5 -0
  41. package/documentation/print-interface-wiki.js +2 -0
  42. package/documentation/print-linter-wiki.js +2 -3
  43. package/documentation/print-query-wiki.js +22 -7
  44. package/linter/linter-executor.js +25 -17
  45. package/linter/linter-format.d.ts +10 -1
  46. package/linter/linter-format.js +8 -0
  47. package/linter/linter-rules.d.ts +1 -0
  48. package/linter/rules/absolute-path.js +8 -8
  49. package/linter/rules/dataframe-access-validation.js +1 -1
  50. package/linter/rules/file-path-validity.js +8 -11
  51. package/linter/rules/naming-convention.d.ts +5 -1
  52. package/linter/rules/naming-convention.js +24 -8
  53. package/linter/rules/seeded-randomness.js +2 -2
  54. package/linter/rules/unused-definition.js +1 -1
  55. package/package.json +17 -15
  56. package/queries/catalog/call-context-query/call-context-query-executor.d.ts +5 -1
  57. package/queries/catalog/call-context-query/call-context-query-executor.js +14 -12
  58. package/queries/catalog/call-context-query/call-context-query-format.d.ts +6 -5
  59. package/queries/catalog/call-context-query/call-context-query-format.js +1 -1
  60. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -1
  61. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
  62. package/queries/catalog/config-query/config-query-executor.js +7 -1
  63. package/queries/catalog/config-query/config-query-format.d.ts +7 -0
  64. package/queries/catalog/config-query/config-query-format.js +72 -1
  65. package/queries/catalog/dependencies-query/dependencies-query-executor.js +50 -75
  66. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +50 -26
  67. package/queries/catalog/dependencies-query/dependencies-query-format.js +75 -20
  68. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +2 -2
  69. package/queries/catalog/dependencies-query/function-info/visualize-functions.d.ts +2 -0
  70. package/queries/catalog/dependencies-query/function-info/visualize-functions.js +13 -0
  71. package/queries/catalog/happens-before-query/happens-before-query-executor.js +1 -1
  72. package/queries/catalog/linter-query/linter-query-format.js +4 -0
  73. package/queries/query-print.d.ts +2 -2
  74. package/queries/query-print.js +3 -2
  75. package/queries/query.d.ts +28 -21
  76. package/search/flowr-search-builder.d.ts +1 -1
  77. package/search/flowr-search-builder.js +1 -1
  78. package/search/flowr-search-filters.d.ts +20 -10
  79. package/search/flowr-search-filters.js +19 -3
  80. package/search/search-executor/search-enrichers.d.ts +1 -1
  81. package/search/search-executor/search-enrichers.js +3 -2
  82. package/search/search-executor/search-generators.js +1 -1
  83. package/search/search-executor/search-transformer.js +1 -1
  84. package/util/objects.d.ts +11 -0
  85. package/util/objects.js +26 -0
  86. package/util/version.js +1 -1
package/README.md CHANGED
@@ -24,7 +24,7 @@ It offers a wide variety of features, for example:
24
24
 
25
25
  ```shell
26
26
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
27
- flowR repl using flowR v2.4.6, R v4.5.0 (r-shell engine)
27
+ flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
28
28
  R> :query @linter "read.csv(\"/root/x.txt\")"
29
29
  ```
30
30
 
@@ -33,7 +33,7 @@ It offers a wide variety of features, for example:
33
33
 
34
34
 
35
35
  ```text
36
- Query: linter (2 ms)
36
+ Query: linter (3 ms)
37
37
  ╰ **Deprecated Functions** (deprecated-functions):
38
38
  ╰ _Metadata_: <code>{"totalDeprecatedCalls":0,"totalDeprecatedFunctionDefinitions":0,"searchTimeMs":0,"processTimeMs":0}</code>
39
39
  ╰ **File Path Validity** (file-path-validity):
@@ -45,18 +45,18 @@ It offers a wide variety of features, for example:
45
45
  ╰ **Absolute Paths** (absolute-file-paths):
46
46
  ╰ certain:
47
47
  ╰ Path `/root/x.txt` at 1.1-23
48
- ╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":0,"processTimeMs":0}</code>
48
+ ╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":1,"processTimeMs":0}</code>
49
49
  ╰ **Unused Definitions** (unused-definitions):
50
50
  ╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":0}</code>
51
51
  ╰ **Naming Convention** (naming-convention):
52
52
  ╰ _Metadata_: <code>{"numMatches":0,"numBreak":0,"searchTimeMs":0,"processTimeMs":0}</code>
53
53
  ╰ **Dataframe Access Validation** (dataframe-access-validation):
54
- ╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":1}</code>
54
+ ╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":0}</code>
55
55
  ╰ **Dead Code** (dead-code):
56
56
  ╰ _Metadata_: <code>{"consideredNodes":5,"searchTimeMs":0,"processTimeMs":0}</code>
57
57
  ╰ **Useless Loops** (useless-loop):
58
58
  ╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":0}</code>
59
- All queries together required ≈2 ms (1ms accuracy, total 8 ms)
59
+ All queries together required ≈3 ms (1ms accuracy, total 9 ms)
60
60
  ```
61
61
 
62
62
 
@@ -78,7 +78,7 @@ It offers a wide variety of features, for example:
78
78
 
79
79
  _Results (prettified and summarized):_
80
80
 
81
- Query: **linter** (13 ms)\
81
+ Query: **linter** (14 ms)\
82
82
  &nbsp;&nbsp;&nbsp;╰ **Deprecated Functions** (deprecated-functions):\
83
83
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalDeprecatedCalls":0,"totalDeprecatedFunctionDefinitions":0,"searchTimeMs":2,"processTimeMs":0}</code>\
84
84
  &nbsp;&nbsp;&nbsp;╰ **File Path Validity** (file-path-validity):\
@@ -86,13 +86,13 @@ It offers a wide variety of features, for example:
86
86
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
87
87
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":4,"processTimeMs":1}</code>\
88
88
  &nbsp;&nbsp;&nbsp;╰ **Seeded Randomness** (seeded-randomness):\
89
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":0,"processTimeMs":0}</code>\
89
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":0,"processTimeMs":1}</code>\
90
90
  &nbsp;&nbsp;&nbsp;╰ **Absolute Paths** (absolute-file-paths):\
91
91
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
92
92
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
93
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":2,"processTimeMs":0}</code>\
93
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":1,"processTimeMs":1}</code>\
94
94
  &nbsp;&nbsp;&nbsp;╰ **Unused Definitions** (unused-definitions):\
95
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":1}</code>\
95
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":0}</code>\
96
96
  &nbsp;&nbsp;&nbsp;╰ **Naming Convention** (naming-convention):\
97
97
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numMatches":0,"numBreak":0,"searchTimeMs":0,"processTimeMs":0}</code>\
98
98
  &nbsp;&nbsp;&nbsp;╰ **Dataframe Access Validation** (dataframe-access-validation):\
@@ -100,12 +100,12 @@ It offers a wide variety of features, for example:
100
100
  &nbsp;&nbsp;&nbsp;╰ **Dead Code** (dead-code):\
101
101
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"consideredNodes":5,"searchTimeMs":1,"processTimeMs":0}</code>\
102
102
  &nbsp;&nbsp;&nbsp;╰ **Useless Loops** (useless-loop):\
103
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":0}</code>\
104
- _All queries together required ≈13 ms (1ms accuracy, total 210 ms)_
103
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":1}</code>\
104
+ _All queries together required ≈14 ms (1ms accuracy, total 216 ms)_
105
105
 
106
106
  <details> <summary style="color:gray">Show Detailed Results as Json</summary>
107
107
 
108
- The analysis required _210.1 ms_ (including parsing and normalization and the query) within the generation environment.
108
+ The analysis required _215.9 ms_ (including parsing and normalization and the query) within the generation environment.
109
109
 
110
110
  In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
111
111
  Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
@@ -156,7 +156,7 @@ It offers a wide variety of features, for example:
156
156
  "callsWithAssignmentProducers": 0,
157
157
  "callsWithNonConstantProducers": 0,
158
158
  "searchTimeMs": 0,
159
- "processTimeMs": 0
159
+ "processTimeMs": 1
160
160
  }
161
161
  },
162
162
  "absolute-file-paths": {
@@ -175,8 +175,8 @@ It offers a wide variety of features, for example:
175
175
  ".meta": {
176
176
  "totalConsidered": 1,
177
177
  "totalUnknown": 0,
178
- "searchTimeMs": 2,
179
- "processTimeMs": 0
178
+ "searchTimeMs": 1,
179
+ "processTimeMs": 1
180
180
  }
181
181
  },
182
182
  "unused-definitions": {
@@ -184,7 +184,7 @@ It offers a wide variety of features, for example:
184
184
  ".meta": {
185
185
  "totalConsidered": 0,
186
186
  "searchTimeMs": 0,
187
- "processTimeMs": 1
187
+ "processTimeMs": 0
188
188
  }
189
189
  },
190
190
  "naming-convention": {
@@ -219,16 +219,16 @@ It offers a wide variety of features, for example:
219
219
  ".meta": {
220
220
  "numOfUselessLoops": 0,
221
221
  "searchTimeMs": 0,
222
- "processTimeMs": 0
222
+ "processTimeMs": 1
223
223
  }
224
224
  }
225
225
  },
226
226
  ".meta": {
227
- "timing": 13
227
+ "timing": 14
228
228
  }
229
229
  },
230
230
  ".meta": {
231
- "timing": 13
231
+ "timing": 14
232
232
  }
233
233
  }
234
234
  ```
@@ -295,7 +295,7 @@ It offers a wide variety of features, for example:
295
295
 
296
296
  ```shell
297
297
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
298
- flowR repl using flowR v2.4.6, R v4.5.0 (r-shell engine)
298
+ flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
299
299
  R> :slicer test/testfiles/example.R --criterion "11@sum"
300
300
  ```
301
301
 
@@ -342,7 +342,7 @@ It offers a wide variety of features, for example:
342
342
 
343
343
 
344
344
  * 🚀 **fast data- and control-flow graphs**\
345
- Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">135.6 ms</span></i> (as of Aug 20, 2025),
345
+ Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">135.1 ms</span></i> (as of Aug 20, 2025),
346
346
  _flowR_ can analyze the data- and control-flow of the average real-world R script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
347
347
  and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/Dataflow-Graph) for more details on the dataflow graph.
348
348
 
@@ -378,7 +378,7 @@ It offers a wide variety of features, for example:
378
378
 
379
379
  ```shell
380
380
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
381
- flowR repl using flowR v2.4.6, R v4.5.0 (r-shell engine)
381
+ flowR repl using flowR v2.4.7, R v4.5.0 (r-shell engine)
382
382
  R> :dataflow* test/testfiles/example.R
383
383
  ```
384
384
 
@@ -493,7 +493,7 @@ It offers a wide variety of features, for example:
493
493
  *7.10-20*
494
494
  (26, 27)`"]]
495
495
  23["`#91;RSymbol#93; sum
496
- (23, :may:)
496
+ (23, :may:36+)
497
497
  *7.3-5*`"]
498
498
  29[["`#91;RBinaryOp#93; #60;#45;
499
499
  (29, :may:36+)
@@ -510,7 +510,7 @@ It offers a wide variety of features, for example:
510
510
  *8.14-24*
511
511
  (31, 32)`"]]
512
512
  30["`#91;RSymbol#93; product
513
- (30, :may:)
513
+ (30, :may:36+)
514
514
  *8.3-9*`"]
515
515
  34[["`#91;RBinaryOp#93; #60;#45;
516
516
  (34, :may:36+)
@@ -622,64 +622,68 @@ It offers a wide variety of features, for example:
622
622
  linkStyle 44 stroke:gray,color:gray;
623
623
  23 -->|"defined-by"| 28
624
624
  23 -->|"defined-by"| 29
625
+ 23 -->|"CD-True"| 36
626
+ linkStyle 47 stroke:gray,color:gray;
625
627
  29 -->|"argument"| 28
626
628
  29 -->|"returns, argument"| 23
627
629
  29 -.->|"reads, calls"| built-in:_-
628
- linkStyle 49 stroke:gray;
630
+ linkStyle 50 stroke:gray;
629
631
  29 -->|"CD-True"| 36
630
- linkStyle 50 stroke:gray,color:gray;
632
+ linkStyle 51 stroke:gray,color:gray;
631
633
  31 -->|"reads"| 3
632
634
  31 -->|"reads"| 30
633
635
  31 -->|"CD-True"| 36
634
- linkStyle 53 stroke:gray,color:gray;
636
+ linkStyle 54 stroke:gray,color:gray;
635
637
  32 -->|"reads"| 12
636
638
  32 -->|"CD-True"| 36
637
- linkStyle 55 stroke:gray,color:gray;
639
+ linkStyle 56 stroke:gray,color:gray;
638
640
  33 -->|"reads, argument"| 31
639
641
  33 -->|"reads, argument"| 32
640
642
  33 -.->|"reads, calls"| built-in:_
641
- linkStyle 58 stroke:gray;
643
+ linkStyle 59 stroke:gray;
642
644
  33 -->|"CD-True"| 36
643
- linkStyle 59 stroke:gray,color:gray;
645
+ linkStyle 60 stroke:gray,color:gray;
644
646
  30 -->|"defined-by"| 33
645
647
  30 -->|"defined-by"| 34
648
+ 30 -->|"CD-True"| 36
649
+ linkStyle 63 stroke:gray,color:gray;
646
650
  34 -->|"argument"| 33
647
651
  34 -->|"returns, argument"| 30
648
652
  34 -.->|"reads, calls"| built-in:_-
649
- linkStyle 64 stroke:gray;
653
+ linkStyle 66 stroke:gray;
650
654
  34 -->|"CD-True"| 36
651
- linkStyle 65 stroke:gray,color:gray;
655
+ linkStyle 67 stroke:gray,color:gray;
652
656
  35 -->|"argument"| 29
653
657
  35 -->|"returns, argument"| 34
654
658
  35 -.->|"reads, calls"| built-in:_
655
- linkStyle 68 stroke:gray;
659
+ linkStyle 70 stroke:gray;
656
660
  35 -->|"CD-True"| 36
657
- linkStyle 69 stroke:gray,color:gray;
661
+ linkStyle 71 stroke:gray,color:gray;
658
662
  36 -->|"argument"| 12
659
663
  36 -->|"reads, argument"| 20
660
664
  36 -->|"argument, non-standard-evaluation"| 35
661
665
  36 -.->|"reads, calls"| built-in:for
662
- linkStyle 73 stroke:gray;
666
+ linkStyle 75 stroke:gray;
663
667
  40 -->|"reads"| 0
664
668
  40 -->|"reads"| 23
665
669
  40 -.->|"reads"| built-in:sum
666
- linkStyle 76 stroke:gray;
670
+ linkStyle 78 stroke:gray;
667
671
  44 -->|"argument"| 38
668
672
  44 -->|"reads, argument"| 40
669
673
  44 -->|"argument"| 42
670
674
  44 -.->|"reads, calls"| built-in:cat
671
- linkStyle 80 stroke:gray;
675
+ linkStyle 82 stroke:gray;
672
676
  48 -->|"reads"| 3
673
677
  48 -->|"reads"| 30
674
678
  52 -->|"argument"| 46
675
679
  52 -->|"reads, argument"| 48
676
680
  52 -->|"argument"| 50
677
681
  52 -.->|"reads, calls"| built-in:cat
678
- linkStyle 86 stroke:gray;
682
+ linkStyle 88 stroke:gray;
679
683
  ```
680
684
 
681
685
 
682
- (The analysis required _14.2 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
686
+ (The analysis required _14.9 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
683
687
 
684
688
 
685
689
 
@@ -137,7 +137,7 @@ class DataFrameShapeInferenceVisitor extends semantic_cfg_guided_visitor_1.Seman
137
137
  }
138
138
  /** Get all AST nodes for the predecessor vertices that are leaf nodes and exit vertices */
139
139
  getPredecessorNodes(vertexId) {
140
- return [...this.config.controlFlow.graph.outgoingEdges(vertexId)?.keys() ?? []] // outgoing dependency edges are incoming CFG edges
140
+ return this.config.controlFlow.graph.outgoingEdges(vertexId)?.keys() // outgoing dependency edges are incoming CFG edges
141
141
  .map(id => this.getCfgVertex(id))
142
142
  .flatMap(vertex => {
143
143
  if (vertex === undefined) {
@@ -150,7 +150,8 @@ class DataFrameShapeInferenceVisitor extends semantic_cfg_guided_visitor_1.Seman
150
150
  return [this.getNormalizedAst((0, control_flow_graph_1.getVertexRootId)(vertex))];
151
151
  }
152
152
  })
153
- .filter(assert_1.isNotUndefined);
153
+ .filter(assert_1.isNotUndefined)
154
+ .toArray() ?? [];
154
155
  }
155
156
  shouldWiden(vertex) {
156
157
  return (this.visited.get(vertex.id) ?? 0) >= this.config.flowrConfig.abstractInterpretation.dataFrame.wideningThreshold;
@@ -108,7 +108,7 @@ class BenchmarkSlicer {
108
108
  (0, assert_1.guard)(this.normalizedAst !== undefined, 'normalizedAst should be defined after initialization');
109
109
  (0, assert_1.guard)(this.dataflow !== undefined, 'dataflow should be defined after initialization');
110
110
  // collect dataflow graph size
111
- const vertices = [...this.dataflow.graph.vertices(true)];
111
+ const vertices = this.dataflow.graph.vertices(true);
112
112
  let numberOfEdges = 0;
113
113
  let numberOfCalls = 0;
114
114
  let numberOfDefinitions = 0;
@@ -256,7 +256,7 @@ async function summarizeSlicerStats(stats, report = () => {
256
256
  };
257
257
  }
258
258
  function summarizeDfShapeStats({ perNodeStats, ...stats }) {
259
- const nodeStats = [...perNodeStats.values()];
259
+ const nodeStats = perNodeStats.values().toArray();
260
260
  const isTop = (value) => value === 'top';
261
261
  const isInfinite = (value) => value === 'infinite';
262
262
  const isBottom = (value) => value === 'bottom';
@@ -37,7 +37,15 @@ async function processQueryArgs(line, parser, output, config) {
37
37
  }
38
38
  let parsedQuery = [];
39
39
  if (query.startsWith('@')) {
40
- parsedQuery = [{ type: query.slice(1) }];
40
+ const queryName = query.slice(1);
41
+ const queryObj = query_1.SupportedQueries[queryName];
42
+ if (queryObj?.fromLine) {
43
+ const q = queryObj.fromLine(args, config);
44
+ parsedQuery = q ? (Array.isArray(q) ? q : [q]) : [];
45
+ }
46
+ else {
47
+ parsedQuery = [{ type: query.slice(1) }];
48
+ }
41
49
  const validationResult = (0, query_1.QueriesSchema)().validate(parsedQuery);
42
50
  if (validationResult.error) {
43
51
  output.stderr(`Invalid query: ${validationResult.error.message}`);
@@ -59,6 +67,7 @@ async function processQueryArgs(line, parser, output, config) {
59
67
  }
60
68
  const processed = await getDataflow(config, parser, args.join(' '));
61
69
  return {
70
+ parsedQuery,
62
71
  query: await Promise.resolve((0, query_1.executeQueries)({ dataflow: processed.dataflow, ast: processed.normalize, config }, parsedQuery)),
63
72
  processed
64
73
  };
@@ -73,7 +82,7 @@ exports.queryCommand = {
73
82
  const results = await processQueryArgs(remainingLine, parser, output, config);
74
83
  const totalEnd = Date.now();
75
84
  if (results) {
76
- output.stdout((0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.ansiFormatter, totalEnd - totalStart, results.query, results.processed));
85
+ output.stdout((0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.ansiFormatter, totalEnd - totalStart, results.query, results.processed, results.parsedQuery));
77
86
  }
78
87
  }
79
88
  };
@@ -6,8 +6,8 @@ import type { FlowrConfigOptions } from '../../config';
6
6
  /**
7
7
  * Used by the repl to provide automatic completions for a given (partial) input line
8
8
  */
9
- export declare function replCompleter(line: string): [string[], string];
10
- export declare function makeDefaultReplReadline(): readline.ReadLineOptions;
9
+ export declare function replCompleter(line: string, config: FlowrConfigOptions): [string[], string];
10
+ export declare function makeDefaultReplReadline(config: FlowrConfigOptions): readline.ReadLineOptions;
11
11
  /**
12
12
  * This function interprets the given `expr` as a REPL command (see {@link repl} for more on the semantics).
13
13
  *
package/cli/repl/core.js CHANGED
@@ -60,6 +60,7 @@ const repl_main_1 = require("./commands/repl-main");
60
60
  const shell_1 = require("../../r-bridge/shell");
61
61
  const log_1 = require("../../util/log");
62
62
  const config_1 = require("../../config");
63
+ const query_1 = require("../../queries/query");
63
64
  let _replCompleterKeywords = undefined;
64
65
  function replCompleterKeywords() {
65
66
  if (_replCompleterKeywords === undefined) {
@@ -71,7 +72,7 @@ const defaultHistoryFile = path_1.default.join(os_1.default.tmpdir(), '.flowrhis
71
72
  /**
72
73
  * Used by the repl to provide automatic completions for a given (partial) input line
73
74
  */
74
- function replCompleter(line) {
75
+ function replCompleter(line, config) {
75
76
  const splitLine = (0, args_1.splitAtEscapeSensitive)(line);
76
77
  // did we just type a space (and are starting a new arg right now)?
77
78
  const startingNewArg = line.endsWith(' ');
@@ -81,17 +82,19 @@ function replCompleter(line) {
81
82
  if (commandNameColon) {
82
83
  const completions = [];
83
84
  const commandName = commandNameColon.slice(1);
84
- if ((0, repl_commands_1.getCommand)(commandName)?.script === true) {
85
+ const cmd = (0, repl_commands_1.getCommand)(commandName);
86
+ if (cmd?.script === true) {
85
87
  // autocomplete script arguments
86
88
  const options = scripts_info_1.scripts[commandName].options;
87
89
  completions.push(...(0, scripts_info_1.getValidOptionsForCompletion)(options, splitLine).map(o => `${o} `));
88
90
  }
91
+ else if (commandName.startsWith('query')) {
92
+ completions.push(...replQueryCompleter(splitLine, config));
93
+ }
89
94
  else {
90
95
  // autocomplete command arguments (specifically, autocomplete the file:// protocol)
91
96
  completions.push(retriever_1.fileProtocol);
92
97
  }
93
- // add an empty option so that it doesn't autocomplete the only defined option immediately
94
- completions.push(' ');
95
98
  const currentArg = startingNewArg ? '' : splitLine[splitLine.length - 1];
96
99
  return [completions.filter(a => a.startsWith(currentArg)), currentArg];
97
100
  }
@@ -99,7 +102,23 @@ function replCompleter(line) {
99
102
  // if no command is already typed, just return all commands that match
100
103
  return [replCompleterKeywords().filter(k => k.startsWith(line)).map(k => `${k} `), line];
101
104
  }
102
- function makeDefaultReplReadline() {
105
+ function replQueryCompleter(splitLine, config) {
106
+ const nonEmpty = splitLine.slice(1).map(s => s.trim()).filter(s => s.length > 0);
107
+ const queryShorts = Object.keys(query_1.SupportedQueries).map(q => `@${q}`).concat(['help']);
108
+ let candidates = [];
109
+ if (nonEmpty.length == 0 || (nonEmpty.length == 1 && queryShorts.some(q => q.startsWith(nonEmpty[0]) && nonEmpty[0] !== q))) {
110
+ candidates = candidates.concat(queryShorts.map(q => `${q} `));
111
+ }
112
+ else {
113
+ const q = nonEmpty[0].slice(1);
114
+ const queryElement = query_1.SupportedQueries[q];
115
+ if (queryElement?.completer) {
116
+ candidates = candidates.concat(queryElement.completer(nonEmpty.slice(1), config));
117
+ }
118
+ }
119
+ return candidates;
120
+ }
121
+ function makeDefaultReplReadline(config) {
103
122
  return {
104
123
  input: process.stdin,
105
124
  output: process.stdout,
@@ -107,7 +126,7 @@ function makeDefaultReplReadline() {
107
126
  terminal: true,
108
127
  history: loadReplHistory(defaultHistoryFile),
109
128
  removeHistoryDuplicates: true,
110
- completer: replCompleter
129
+ completer: (c) => replCompleter(c, config)
111
130
  };
112
131
  }
113
132
  async function replProcessStatement(output, statement, parser, allowRSessionAccess, config) {
@@ -162,7 +181,7 @@ async function replProcessAnswer(config, output, expr, parser, allowRSessionAcce
162
181
  * For the execution, this function makes use of {@link replProcessAnswer}.
163
182
  *
164
183
  */
165
- async function repl(config, { parser = new shell_1.RShell((0, config_1.getEngineConfig)(config, 'r-shell'), { revive: 2 /* RShellReviveOptions.Always */ }), rl = readline.createInterface(makeDefaultReplReadline()), output = repl_main_1.standardReplOutput, historyFile = defaultHistoryFile, allowRSessionAccess = false }) {
184
+ async function repl(config, { parser = new shell_1.RShell((0, config_1.getEngineConfig)(config, 'r-shell'), { revive: 2 /* RShellReviveOptions.Always */ }), rl = readline.createInterface(makeDefaultReplReadline(config)), output = repl_main_1.standardReplOutput, historyFile = defaultHistoryFile, allowRSessionAccess = false }) {
166
185
  if (historyFile) {
167
186
  rl.on('history', h => fs_1.default.writeFileSync(historyFile, h.join('\n'), { encoding: 'utf-8' }));
168
187
  }
@@ -61,6 +61,7 @@ const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-se
61
61
  const message_query_1 = require("./messages/message-query");
62
62
  const query_1 = require("../../../queries/query");
63
63
  const compact_1 = require("./compact");
64
+ const _00_slice_1 = require("../../../core/steps/all/static-slicing/00-slice");
64
65
  /**
65
66
  * Each connection handles a single client, answering to its requests.
66
67
  * There is no need to construct this class manually, {@link FlowRServer} will do it for you.
@@ -241,7 +242,7 @@ class FlowRServerConnection {
241
242
  return;
242
243
  }
243
244
  const request = requestResult.message;
244
- this.logger.info(`[${request.filetoken}] Received slice request with criteria ${JSON.stringify(request.criterion)}`);
245
+ this.logger.info(`[${request.filetoken}] Received ${request.direction ?? _00_slice_1.SliceDirection.Backward} slice request with criteria ${JSON.stringify(request.criterion)}`);
245
246
  const fileInformation = this.fileMap.get(request.filetoken);
246
247
  if (!fileInformation) {
247
248
  (0, send_1.sendMessage)(this.socket, {
@@ -254,6 +255,7 @@ class FlowRServerConnection {
254
255
  }
255
256
  fileInformation.pipeline.updateRequest({
256
257
  criterion: request.criterion,
258
+ direction: request.direction,
257
259
  autoSelectIf: request.noMagicComments ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect)
258
260
  });
259
261
  void fileInformation.pipeline.allRemainingSteps(true).then(results => {
@@ -2,6 +2,7 @@ import type { IdMessageBase, MessageDefinition } from './all-messages';
2
2
  import type { SlicingCriteria } from '../../../../slicing/criterion/parse';
3
3
  import type { PipelineOutput } from '../../../../core/steps/pipeline/pipeline';
4
4
  import type { DEFAULT_DATAFLOW_PIPELINE, DEFAULT_SLICING_PIPELINE } from '../../../../core/steps/pipeline/default-pipelines';
5
+ import { SliceDirection } from '../../../../core/steps/all/static-slicing/00-slice';
5
6
  /**
6
7
  * Can only be sent after you have sent the {@link FileAnalysisRequestMessage}.
7
8
  * Using the same `filetoken` as in the {@link FileAnalysisRequestMessage} you
@@ -13,6 +14,8 @@ export interface SliceRequestMessage extends IdMessageBase {
13
14
  filetoken: string;
14
15
  /** The slicing criteria to use */
15
16
  criterion: SlicingCriteria;
17
+ /** The direction to slice in. Defaults to backward slicing if unset. */
18
+ direction?: SliceDirection;
16
19
  /**
17
20
  * Should the magic comments (force-including lines within the slice) be ignord?
18
21
  */
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.responseSliceMessage = exports.requestSliceMessage = void 0;
37
37
  const Joi = __importStar(require("joi"));
38
+ const _00_slice_1 = require("../../../../core/steps/all/static-slicing/00-slice");
38
39
  exports.requestSliceMessage = {
39
40
  type: 'request-slice',
40
41
  schema: Joi.object({
@@ -42,6 +43,7 @@ exports.requestSliceMessage = {
42
43
  id: Joi.string().optional().description('The id of the message, if you passed one in the request.'),
43
44
  filetoken: Joi.string().required().description('The filetoken of the file to slice must be the same as with the analysis request.'),
44
45
  criterion: Joi.array().items(Joi.string()).min(0).required().required().description('The slicing criteria to use.'),
46
+ direction: Joi.string().valid(...Object.values(_00_slice_1.SliceDirection)).description('The direction to slice in. Defaults to backward slicing if unset.')
45
47
  })
46
48
  };
47
49
  exports.responseSliceMessage = {
@@ -14,13 +14,13 @@ import type { FlowrConfigOptions } from '../config';
14
14
  * @param graph - additional dataflow facts to consider by the control flow extraction
15
15
  * @param simplifications - a list of simplification passes to apply to the control flow graph
16
16
  *
17
- * @see {@link extractSimpleCfg} - for a simplified version of this function
17
+ * @see {@link extractCfgQuick} - for a simplified version of this function
18
18
  */
19
19
  export declare function extractCfg<Info = ParentInformation>(ast: NormalizedAst<Info & ParentInformation>, config: FlowrConfigOptions, graph?: DataflowGraph, simplifications?: readonly CfgSimplificationPassName[]): ControlFlowInformation;
20
20
  /**
21
- * Simplified version of {@link extractCfg} that is much quicker, but much simpler!
21
+ * A version of {@link extractCfg} that is much quicker and does not apply any simplifciations or dataflow information.
22
22
  */
23
- export declare function extractSimpleCfg<Info = ParentInformation>(ast: NormalizedAst<Info>): ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>;
23
+ export declare function extractCfgQuick<Info = ParentInformation>(ast: NormalizedAst<Info>): ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>;
24
24
  export declare const ResolvedCallSuffix = "-resolved-call-exit";
25
25
  /**
26
26
  * Convert a cfg to RDF quads.
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResolvedCallSuffix = void 0;
4
4
  exports.extractCfg = extractCfg;
5
- exports.extractSimpleCfg = extractSimpleCfg;
5
+ exports.extractCfgQuick = extractCfgQuick;
6
6
  exports.cfg2quads = cfg2quads;
7
7
  const quads_1 = require("../util/quads");
8
8
  const fold_1 = require("../r-bridge/lang-4.x/ast/model/processing/fold");
@@ -61,15 +61,15 @@ function dataflowCfgFolds(dataflowGraph) {
61
61
  * @param graph - additional dataflow facts to consider by the control flow extraction
62
62
  * @param simplifications - a list of simplification passes to apply to the control flow graph
63
63
  *
64
- * @see {@link extractSimpleCfg} - for a simplified version of this function
64
+ * @see {@link extractCfgQuick} - for a simplified version of this function
65
65
  */
66
66
  function extractCfg(ast, config, graph, simplifications) {
67
67
  return (0, cfg_simplification_1.simplifyControlFlowInformation)((0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds), { ast, dfg: graph, config }, simplifications);
68
68
  }
69
69
  /**
70
- * Simplified version of {@link extractCfg} that is much quicker, but much simpler!
70
+ * A version of {@link extractCfg} that is much quicker and does not apply any simplifciations or dataflow information.
71
71
  */
72
- function extractSimpleCfg(ast) {
72
+ function extractCfgQuick(ast) {
73
73
  return (0, fold_1.foldAst)(ast.ast, cfgFolds);
74
74
  }
75
75
  function cfgLeaf(type) {
@@ -58,6 +58,8 @@ function onlyLoopsOnce(loop, dataflow, controlflow, ast, config) {
58
58
  return visitor.loopsOnlyOnce();
59
59
  }
60
60
  class CfgSingleIterationLoopDetector extends semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor {
61
+ loopCds = undefined;
62
+ encounteredLoopBreaker = false;
61
63
  onlyLoopyOnce = false;
62
64
  loopToCheck;
63
65
  constructor(loop, config) {
@@ -76,7 +78,7 @@ class CfgSingleIterationLoopDetector extends semantic_cfg_guided_visitor_1.Seman
76
78
  }
77
79
  startVisitor(_) {
78
80
  const g = this.config.controlFlow.graph;
79
- const n = (i) => g.ingoingEdges(i);
81
+ const ingoing = (i) => g.ingoingEdges(i);
80
82
  const exits = new Set(g.getVertex(this.loopToCheck)?.end ?? []);
81
83
  (0, assert_1.guard)(exits.size !== 0, "Can't find end of loop");
82
84
  const stack = [this.loopToCheck];
@@ -86,38 +88,45 @@ class CfgSingleIterationLoopDetector extends semantic_cfg_guided_visitor_1.Seman
86
88
  continue;
87
89
  }
88
90
  if (!exits.has(current)) {
89
- const next = n(current) ?? [];
91
+ const next = ingoing(current) ?? [];
90
92
  for (const [to] of next) {
91
93
  stack.unshift(to);
92
94
  }
93
95
  }
96
+ this.onlyLoopyOnce ||= this.encounteredLoopBreaker && (0, info_1.happensInEveryBranch)(this.loopCds);
97
+ }
98
+ this.onlyLoopyOnce ||= this.encounteredLoopBreaker && (0, info_1.happensInEveryBranch)(this.loopCds);
99
+ }
100
+ app(cds) {
101
+ if (cds === undefined) {
102
+ return;
103
+ }
104
+ const filtered = cds.filter(c => c.id !== this.loopToCheck);
105
+ if (filtered.length > 0) {
106
+ if (this.loopCds === undefined) {
107
+ this.loopCds = filtered;
108
+ }
109
+ else {
110
+ this.loopCds = this.loopCds.concat(filtered);
111
+ }
94
112
  }
95
113
  }
96
114
  onDefaultFunctionCall(data) {
97
- let stopsLoop = false;
98
- const alwaysHappens = () => {
99
- if (!data.call.cds ||
100
- (data.call.cds.length === 1 && data.call.cds[0].id === this.loopToCheck)) {
101
- return true;
115
+ for (const origin of data.call.origin) {
116
+ if (origin === 'builtin:stop' || origin === 'builtin:return' || origin === 'builtin:break') {
117
+ this.encounteredLoopBreaker = true;
118
+ this.app(data.call.cds);
119
+ return;
102
120
  }
103
- const cds = data.call.cds.filter(d => d.id !== this.loopToCheck);
104
- return (0, info_1.happensInEveryBranch)(cds);
105
- };
106
- switch (data.call.origin[0]) {
107
- case 'builtin:return':
108
- case 'builtin:stop':
109
- case 'builtin:break':
110
- stopsLoop = alwaysHappens();
111
- break;
112
- case 'builtin:stopifnot': {
121
+ else if (origin === 'builtin:stopifnot') {
113
122
  const arg = this.getBoolArgValue(data);
114
- if (arg !== undefined) {
115
- stopsLoop = !arg && alwaysHappens();
123
+ if (arg === false) {
124
+ this.encounteredLoopBreaker = true;
125
+ this.app(data.call.cds);
126
+ return;
116
127
  }
117
- break;
118
128
  }
119
129
  }
120
- this.onlyLoopyOnce = this.onlyLoopyOnce || stopsLoop;
121
130
  }
122
131
  loopsOnlyOnce() {
123
132
  this.startVisitor([]);
@@ -55,7 +55,7 @@ export interface DefaultBuiltInProcessorConfiguration extends ForceArguments {
55
55
  readonly returnsNthArgument?: number | 'last';
56
56
  readonly cfg?: ExitPointType;
57
57
  readonly readAllArguments?: boolean;
58
- readonly hasUnknownSideEffects?: boolean | LinkTo;
58
+ readonly hasUnknownSideEffects?: boolean | LinkTo<RegExp | string>;
59
59
  /** record mapping the actual function name called to the arguments that should be treated as function calls */
60
60
  readonly treatAsFnCall?: Record<string, readonly string[]>;
61
61
  /** Name that should be used for the origin (useful when needing to differentiate between