@eagleoutice/flowr 2.4.7 → 2.5.0

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 (101) hide show
  1. package/README.md +48 -38
  2. package/abstract-interpretation/data-frame/absint-visitor.js +3 -2
  3. package/benchmark/slicer.js +2 -2
  4. package/benchmark/summarizer/first-phase/process.js +1 -1
  5. package/benchmark/summarizer/second-phase/graph.js +2 -2
  6. package/cli/repl/commands/repl-query.js +11 -2
  7. package/cli/repl/core.d.ts +2 -2
  8. package/cli/repl/core.js +26 -7
  9. package/cli/repl/server/connection.js +3 -1
  10. package/cli/repl/server/messages/message-slice.d.ts +3 -0
  11. package/cli/repl/server/messages/message-slice.js +2 -0
  12. package/cli/slicer-app.js +7 -2
  13. package/control-flow/extract-cfg.d.ts +3 -3
  14. package/control-flow/extract-cfg.js +4 -4
  15. package/control-flow/useless-loop.js +30 -21
  16. package/dataflow/environments/built-in.d.ts +1 -1
  17. package/dataflow/environments/default-builtin-config.d.ts +9 -0
  18. package/dataflow/environments/default-builtin-config.js +21 -21
  19. package/dataflow/environments/environment.js +18 -9
  20. package/dataflow/environments/overwrite.js +2 -2
  21. package/dataflow/extractor.js +1 -1
  22. package/dataflow/graph/diff-dataflow-graph.js +4 -4
  23. package/dataflow/graph/graph.d.ts +3 -3
  24. package/dataflow/graph/graph.js +4 -1
  25. package/dataflow/graph/quads.js +4 -4
  26. package/dataflow/info.js +1 -1
  27. package/dataflow/internal/linker.d.ts +2 -0
  28. package/dataflow/internal/linker.js +18 -1
  29. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
  30. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +68 -21
  31. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -2
  32. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +4 -4
  33. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -18
  34. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
  35. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +4 -5
  36. package/dataflow/internal/process/functions/call/common.js +4 -3
  37. package/documentation/doc-util/doc-query.js +6 -2
  38. package/documentation/doc-util/doc-types.d.ts +7 -2
  39. package/documentation/doc-util/doc-types.js +20 -4
  40. package/documentation/print-core-wiki.js +5 -1
  41. package/documentation/print-dataflow-graph-wiki.js +21 -12
  42. package/documentation/print-faq-wiki.js +5 -0
  43. package/documentation/print-interface-wiki.js +2 -0
  44. package/documentation/print-linter-wiki.js +2 -3
  45. package/documentation/print-linting-and-testing-wiki.js +4 -0
  46. package/documentation/print-query-wiki.js +22 -7
  47. package/documentation/print-readme.js +6 -0
  48. package/linter/linter-executor.js +25 -17
  49. package/linter/linter-format.d.ts +10 -1
  50. package/linter/linter-format.js +8 -0
  51. package/linter/linter-rules.d.ts +1 -0
  52. package/linter/rules/absolute-path.js +8 -8
  53. package/linter/rules/dataframe-access-validation.js +1 -1
  54. package/linter/rules/file-path-validity.js +8 -11
  55. package/linter/rules/naming-convention.d.ts +5 -1
  56. package/linter/rules/naming-convention.js +24 -8
  57. package/linter/rules/seeded-randomness.js +2 -2
  58. package/linter/rules/unused-definition.js +1 -1
  59. package/package.json +20 -15
  60. package/queries/catalog/call-context-query/call-context-query-executor.d.ts +5 -1
  61. package/queries/catalog/call-context-query/call-context-query-executor.js +14 -12
  62. package/queries/catalog/call-context-query/call-context-query-format.d.ts +6 -5
  63. package/queries/catalog/call-context-query/call-context-query-format.js +1 -1
  64. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -1
  65. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
  66. package/queries/catalog/config-query/config-query-executor.js +7 -1
  67. package/queries/catalog/config-query/config-query-format.d.ts +7 -0
  68. package/queries/catalog/config-query/config-query-format.js +72 -1
  69. package/queries/catalog/dependencies-query/dependencies-query-executor.js +50 -75
  70. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +50 -26
  71. package/queries/catalog/dependencies-query/dependencies-query-format.js +75 -20
  72. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +2 -2
  73. package/queries/catalog/dependencies-query/function-info/visualize-functions.d.ts +2 -0
  74. package/queries/catalog/dependencies-query/function-info/visualize-functions.js +13 -0
  75. package/queries/catalog/happens-before-query/happens-before-query-executor.js +1 -1
  76. package/queries/catalog/linter-query/linter-query-format.js +4 -0
  77. package/queries/query-print.d.ts +2 -2
  78. package/queries/query-print.js +3 -2
  79. package/queries/query.d.ts +28 -21
  80. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +1 -1
  81. package/r-bridge/retriever.d.ts +14 -2
  82. package/r-bridge/retriever.js +10 -4
  83. package/search/flowr-search-builder.d.ts +1 -1
  84. package/search/flowr-search-builder.js +1 -1
  85. package/search/flowr-search-filters.d.ts +20 -10
  86. package/search/flowr-search-filters.js +19 -3
  87. package/search/search-executor/search-enrichers.d.ts +1 -1
  88. package/search/search-executor/search-enrichers.js +3 -2
  89. package/search/search-executor/search-generators.js +1 -1
  90. package/search/search-executor/search-transformer.js +1 -1
  91. package/util/formats/adapter-format.d.ts +6 -0
  92. package/util/formats/adapter-format.js +3 -0
  93. package/util/formats/adapter.d.ts +16 -0
  94. package/util/formats/adapter.js +42 -0
  95. package/util/formats/adapters/r-adapter.d.ts +4 -0
  96. package/util/formats/adapters/r-adapter.js +7 -0
  97. package/util/formats/adapters/rmd-adapter.d.ts +26 -0
  98. package/util/formats/adapters/rmd-adapter.js +91 -0
  99. package/util/objects.d.ts +11 -0
  100. package/util/objects.js +26 -0
  101. 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.8, 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,34 +78,34 @@ 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** (15 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):\
85
85
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ certain:\
86
86
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ Path `/root/x.txt` at 1.1-23\
87
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":4,"processTimeMs":1}</code>\
87
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":5,"processTimeMs":0}</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":1,"processTimeMs":0}</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
93
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":2,"processTimeMs":0}</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):\
99
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":2}</code>\
99
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>{"numOperations":0,"numAccesses":0,"totalAccessed":0,"searchTimeMs":0,"processTimeMs":4}</code>\
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
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)_
104
+ _All queries together required ≈16 ms (1ms accuracy, total 209 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 _209.2 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.
@@ -144,8 +144,8 @@ It offers a wide variety of features, for example:
144
144
  "totalUnknown": 0,
145
145
  "totalWritesBeforeAlways": 0,
146
146
  "totalValid": 0,
147
- "searchTimeMs": 4,
148
- "processTimeMs": 1
147
+ "searchTimeMs": 5,
148
+ "processTimeMs": 0
149
149
  }
150
150
  },
151
151
  "seeded-randomness": {
@@ -155,7 +155,7 @@ It offers a wide variety of features, for example:
155
155
  "callsWithFunctionProducers": 0,
156
156
  "callsWithAssignmentProducers": 0,
157
157
  "callsWithNonConstantProducers": 0,
158
- "searchTimeMs": 0,
158
+ "searchTimeMs": 1,
159
159
  "processTimeMs": 0
160
160
  }
161
161
  },
@@ -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": {
@@ -203,7 +203,7 @@ It offers a wide variety of features, for example:
203
203
  "numAccesses": 0,
204
204
  "totalAccessed": 0,
205
205
  "searchTimeMs": 0,
206
- "processTimeMs": 2
206
+ "processTimeMs": 4
207
207
  }
208
208
  },
209
209
  "dead-code": {
@@ -224,11 +224,11 @@ It offers a wide variety of features, for example:
224
224
  }
225
225
  },
226
226
  ".meta": {
227
- "timing": 13
227
+ "timing": 15
228
228
  }
229
229
  },
230
230
  ".meta": {
231
- "timing": 13
231
+ "timing": 16
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.8, 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.8, 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,60 +622,64 @@ 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
 
@@ -724,6 +728,12 @@ You can enter <span title="Description (Repl Command): Show help information (al
724
728
 
725
729
  ![Example of a simple REPL session](wiki/gif/repl-demo-opt.gif)
726
730
 
731
+ If you want to use the same commands:
732
+
733
+ 1. First this runs `docker run -it --rm eagleoutice/flowr` in a terminal to start the REPL.
734
+ 2. In the REPL, it runs `:slicer -c '11@prod' demo.R --diff` to slice the example file `demo.R` for the print statement in line 11.
735
+ Please note that the `11` refers to the 11th line number to slice for!
736
+
727
737
  </details>
728
738
 
729
739
  ## 📜 More Information
@@ -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;
@@ -9,7 +9,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.BenchmarkSlicer = exports.benchmarkLogger = void 0;
11
11
  const stopwatch_1 = require("./stopwatch");
12
- const fs_1 = __importDefault(require("fs"));
13
12
  const seedrandom_1 = __importDefault(require("seedrandom"));
14
13
  const log_1 = require("../util/log");
15
14
  const assert_1 = require("../util/assert");
@@ -30,6 +29,7 @@ const extract_cfg_1 = require("../control-flow/extract-cfg");
30
29
  const absint_info_1 = require("../abstract-interpretation/data-frame/absint-info");
31
30
  const domain_1 = require("../abstract-interpretation/data-frame/domain");
32
31
  const shape_inference_1 = require("../abstract-interpretation/data-frame/shape-inference");
32
+ const fs_1 = __importDefault(require("fs"));
33
33
  /**
34
34
  * The logger to be used for benchmarking as a global object.
35
35
  */
@@ -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';
@@ -19,7 +19,7 @@ function writeGraphOutput(ultimate, outputGraphPath) {
19
19
  name: pointName[0].toUpperCase() + pointName.slice(1),
20
20
  unit: 'ms',
21
21
  value: Number(measurement.mean / 1e6),
22
- range: Number(measurement.std / 1e6),
22
+ range: String(Number(measurement.std / 1e6)),
23
23
  extra: `median: ${(measurement.median / 1e6).toFixed(2)}ms`
24
24
  });
25
25
  }
@@ -51,7 +51,7 @@ function writeGraphOutput(ultimate, outputGraphPath) {
51
51
  name: 'memory (df-graph)',
52
52
  unit: 'KiB',
53
53
  value: ultimate.dataflow.sizeOfObject.mean / 1024,
54
- range: ultimate.dataflow.sizeOfObject.std / 1024,
54
+ range: String(ultimate.dataflow.sizeOfObject.std / 1024),
55
55
  extra: `median: ${(ultimate.dataflow.sizeOfObject.median / 1024).toFixed(2)}`
56
56
  });
57
57
  // write the output file
@@ -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 = {
package/cli/slicer-app.js CHANGED
@@ -15,6 +15,7 @@ const print_1 = require("../benchmark/stats/print");
15
15
  const magic_comments_1 = require("../reconstruct/auto-select/magic-comments");
16
16
  const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
17
17
  const config_1 = require("../config");
18
+ const adapter_1 = require("../util/formats/adapter");
18
19
  const options = (0, script_1.processCommandLineArgs)('slicer', ['input', 'criterion'], {
19
20
  subtitle: 'Slice R code based on a given slicing criterion',
20
21
  examples: [
@@ -32,7 +33,7 @@ async function getSlice() {
32
33
  const config = (0, config_1.getConfig)();
33
34
  await slicer.init(options['input-is-text']
34
35
  ? { request: 'text', content: options.input.replaceAll('\\n', '\n') }
35
- : { request: 'file', content: options.input }, config, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
36
+ : (0, adapter_1.requestFromFile)(options.input), config, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
36
37
  let mappedSlices = [];
37
38
  let reconstruct = undefined;
38
39
  const doSlicing = options.criterion.trim() !== '';
@@ -74,7 +75,11 @@ async function getSlice() {
74
75
  }
75
76
  else {
76
77
  if (doSlicing && options.diff) {
77
- const originalCode = options['input-is-text'] ? options.input : fs_1.default.readFileSync(options.input).toString();
78
+ let originalCode = options.input;
79
+ if (!options['input-is-text']) {
80
+ const request = (0, adapter_1.requestFromFile)(options.input);
81
+ originalCode = request.request === 'text' ? request.content : fs_1.default.readFileSync(request.content).toString();
82
+ }
78
83
  console.log((0, slice_diff_ansi_1.sliceDiffAnsi)(slice.result, normalize, new Set(mappedSlices.map(({ id }) => id)), originalCode));
79
84
  }
80
85
  if (options.stats) {
@@ -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) {