@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.
- package/README.md +43 -39
- package/abstract-interpretation/data-frame/absint-visitor.js +3 -2
- package/benchmark/slicer.js +1 -1
- package/benchmark/summarizer/first-phase/process.js +1 -1
- package/cli/repl/commands/repl-query.js +11 -2
- package/cli/repl/core.d.ts +2 -2
- package/cli/repl/core.js +26 -7
- package/cli/repl/server/connection.js +3 -1
- package/cli/repl/server/messages/message-slice.d.ts +3 -0
- package/cli/repl/server/messages/message-slice.js +2 -0
- package/control-flow/extract-cfg.d.ts +3 -3
- package/control-flow/extract-cfg.js +4 -4
- package/control-flow/useless-loop.js +30 -21
- package/dataflow/environments/built-in.d.ts +1 -1
- package/dataflow/environments/default-builtin-config.d.ts +9 -0
- package/dataflow/environments/default-builtin-config.js +21 -21
- package/dataflow/environments/environment.js +18 -9
- package/dataflow/environments/overwrite.js +2 -2
- package/dataflow/extractor.js +1 -1
- package/dataflow/graph/diff-dataflow-graph.js +4 -4
- package/dataflow/graph/graph.d.ts +3 -3
- package/dataflow/graph/graph.js +4 -1
- package/dataflow/graph/quads.js +4 -4
- package/dataflow/info.js +1 -1
- package/dataflow/internal/linker.d.ts +2 -0
- package/dataflow/internal/linker.js +18 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +68 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -18
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +4 -5
- package/dataflow/internal/process/functions/call/common.js +4 -3
- package/documentation/doc-util/doc-query.js +6 -2
- package/documentation/doc-util/doc-types.d.ts +7 -2
- package/documentation/doc-util/doc-types.js +20 -4
- package/documentation/print-core-wiki.js +5 -1
- package/documentation/print-dataflow-graph-wiki.js +21 -12
- package/documentation/print-faq-wiki.js +5 -0
- package/documentation/print-interface-wiki.js +2 -0
- package/documentation/print-linter-wiki.js +2 -3
- package/documentation/print-query-wiki.js +22 -7
- package/linter/linter-executor.js +25 -17
- package/linter/linter-format.d.ts +10 -1
- package/linter/linter-format.js +8 -0
- package/linter/linter-rules.d.ts +1 -0
- package/linter/rules/absolute-path.js +8 -8
- package/linter/rules/dataframe-access-validation.js +1 -1
- package/linter/rules/file-path-validity.js +8 -11
- package/linter/rules/naming-convention.d.ts +5 -1
- package/linter/rules/naming-convention.js +24 -8
- package/linter/rules/seeded-randomness.js +2 -2
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +17 -15
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +5 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +14 -12
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +6 -5
- package/queries/catalog/call-context-query/call-context-query-format.js +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
- package/queries/catalog/config-query/config-query-executor.js +7 -1
- package/queries/catalog/config-query/config-query-format.d.ts +7 -0
- package/queries/catalog/config-query/config-query-format.js +72 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +50 -75
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +50 -26
- package/queries/catalog/dependencies-query/dependencies-query-format.js +75 -20
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +2 -2
- package/queries/catalog/dependencies-query/function-info/visualize-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/visualize-functions.js +13 -0
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +1 -1
- package/queries/catalog/linter-query/linter-query-format.js +4 -0
- package/queries/query-print.d.ts +2 -2
- package/queries/query-print.js +3 -2
- package/queries/query.d.ts +28 -21
- package/search/flowr-search-builder.d.ts +1 -1
- package/search/flowr-search-builder.js +1 -1
- package/search/flowr-search-filters.d.ts +20 -10
- package/search/flowr-search-filters.js +19 -3
- package/search/search-executor/search-enrichers.d.ts +1 -1
- package/search/search-executor/search-enrichers.js +3 -2
- package/search/search-executor/search-generators.js +1 -1
- package/search/search-executor/search-transformer.js +1 -1
- package/util/objects.d.ts +11 -0
- package/util/objects.js +26 -0
- 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.
|
|
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: [;1mlinter[0m (
|
|
36
|
+
Query: [;1mlinter[0m (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":
|
|
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":
|
|
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
|
-
[;3mAll queries together required ≈
|
|
59
|
+
[;3mAll queries together required ≈3 ms (1ms accuracy, total 9 ms)[0m[0m
|
|
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** (
|
|
81
|
+
Query: **linter** (14 ms)\
|
|
82
82
|
╰ **Deprecated Functions** (deprecated-functions):\
|
|
83
83
|
╰ _Metadata_: <code>{"totalDeprecatedCalls":0,"totalDeprecatedFunctionDefinitions":0,"searchTimeMs":2,"processTimeMs":0}</code>\
|
|
84
84
|
╰ **File Path Validity** (file-path-validity):\
|
|
@@ -86,13 +86,13 @@ It offers a wide variety of features, for example:
|
|
|
86
86
|
╰ Path `/root/x.txt` at 1.1-23\
|
|
87
87
|
╰ _Metadata_: <code>{"totalReads":1,"totalUnknown":0,"totalWritesBeforeAlways":0,"totalValid":0,"searchTimeMs":4,"processTimeMs":1}</code>\
|
|
88
88
|
╰ **Seeded Randomness** (seeded-randomness):\
|
|
89
|
-
╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":0,"processTimeMs":
|
|
89
|
+
╰ _Metadata_: <code>{"consumerCalls":0,"callsWithFunctionProducers":0,"callsWithAssignmentProducers":0,"callsWithNonConstantProducers":0,"searchTimeMs":0,"processTimeMs":1}</code>\
|
|
90
90
|
╰ **Absolute Paths** (absolute-file-paths):\
|
|
91
91
|
╰ certain:\
|
|
92
92
|
╰ Path `/root/x.txt` at 1.1-23\
|
|
93
|
-
╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":
|
|
93
|
+
╰ _Metadata_: <code>{"totalConsidered":1,"totalUnknown":0,"searchTimeMs":1,"processTimeMs":1}</code>\
|
|
94
94
|
╰ **Unused Definitions** (unused-definitions):\
|
|
95
|
-
╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":
|
|
95
|
+
╰ _Metadata_: <code>{"totalConsidered":0,"searchTimeMs":0,"processTimeMs":0}</code>\
|
|
96
96
|
╰ **Naming Convention** (naming-convention):\
|
|
97
97
|
╰ _Metadata_: <code>{"numMatches":0,"numBreak":0,"searchTimeMs":0,"processTimeMs":0}</code>\
|
|
98
98
|
╰ **Dataframe Access Validation** (dataframe-access-validation):\
|
|
@@ -100,12 +100,12 @@ It offers a wide variety of features, for example:
|
|
|
100
100
|
╰ **Dead Code** (dead-code):\
|
|
101
101
|
╰ _Metadata_: <code>{"consideredNodes":5,"searchTimeMs":1,"processTimeMs":0}</code>\
|
|
102
102
|
╰ **Useless Loops** (useless-loop):\
|
|
103
|
-
╰ _Metadata_: <code>{"numOfUselessLoops":0,"searchTimeMs":0,"processTimeMs":
|
|
104
|
-
_All queries together required ≈
|
|
103
|
+
╰ _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
|
|
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":
|
|
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":
|
|
179
|
-
"processTimeMs":
|
|
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":
|
|
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":
|
|
222
|
+
"processTimeMs": 1
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
},
|
|
226
226
|
".meta": {
|
|
227
|
-
"timing":
|
|
227
|
+
"timing": 14
|
|
228
228
|
}
|
|
229
229
|
},
|
|
230
230
|
".meta": {
|
|
231
|
-
"timing":
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
630
|
+
linkStyle 50 stroke:gray;
|
|
629
631
|
29 -->|"CD-True"| 36
|
|
630
|
-
linkStyle
|
|
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
|
|
636
|
+
linkStyle 54 stroke:gray,color:gray;
|
|
635
637
|
32 -->|"reads"| 12
|
|
636
638
|
32 -->|"CD-True"| 36
|
|
637
|
-
linkStyle
|
|
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
|
|
643
|
+
linkStyle 59 stroke:gray;
|
|
642
644
|
33 -->|"CD-True"| 36
|
|
643
|
-
linkStyle
|
|
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
|
|
653
|
+
linkStyle 66 stroke:gray;
|
|
650
654
|
34 -->|"CD-True"| 36
|
|
651
|
-
linkStyle
|
|
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
|
|
659
|
+
linkStyle 70 stroke:gray;
|
|
656
660
|
35 -->|"CD-True"| 36
|
|
657
|
-
linkStyle
|
|
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
|
|
666
|
+
linkStyle 75 stroke:gray;
|
|
663
667
|
40 -->|"reads"| 0
|
|
664
668
|
40 -->|"reads"| 23
|
|
665
669
|
40 -.->|"reads"| built-in:sum
|
|
666
|
-
linkStyle
|
|
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
|
|
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
|
|
682
|
+
linkStyle 88 stroke:gray;
|
|
679
683
|
```
|
|
680
684
|
|
|
681
685
|
|
|
682
|
-
(The analysis required _14.
|
|
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
|
|
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;
|
package/benchmark/slicer.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
};
|
package/cli/repl/core.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
*
|
|
70
|
+
* A version of {@link extractCfg} that is much quicker and does not apply any simplifciations or dataflow information.
|
|
71
71
|
*/
|
|
72
|
-
function
|
|
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
|
|
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 =
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(data.call.cds
|
|
101
|
-
return
|
|
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
|
-
|
|
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
|
|
115
|
-
|
|
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
|