@eagleoutice/flowr 2.9.6 → 2.9.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 (62) hide show
  1. package/README.md +28 -26
  2. package/abstract-interpretation/absint-visitor.d.ts +5 -4
  3. package/abstract-interpretation/absint-visitor.js +12 -11
  4. package/abstract-interpretation/data-frame/dataframe-domain.js +1 -2
  5. package/benchmark/slicer.d.ts +0 -1
  6. package/benchmark/slicer.js +3 -9
  7. package/benchmark/stats/print.js +1 -0
  8. package/benchmark/summarizer/data.d.ts +2 -0
  9. package/benchmark/summarizer/first-phase/process.js +3 -1
  10. package/benchmark/summarizer/second-phase/process.js +4 -0
  11. package/cli/repl/commands/repl-commands.d.ts +1 -0
  12. package/cli/repl/commands/repl-commands.js +1 -0
  13. package/cli/repl/commands/repl-normalize.d.ts +1 -0
  14. package/cli/repl/commands/repl-normalize.js +28 -1
  15. package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
  16. package/control-flow/basic-cfg-guided-visitor.js +8 -9
  17. package/control-flow/cfg-dead-code.js +16 -15
  18. package/control-flow/cfg-properties.d.ts +2 -2
  19. package/control-flow/cfg-properties.js +3 -2
  20. package/control-flow/cfg-to-basic-blocks.js +9 -12
  21. package/control-flow/control-flow-graph.d.ts +384 -78
  22. package/control-flow/control-flow-graph.js +607 -115
  23. package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
  24. package/control-flow/dfg-cfg-guided-visitor.js +3 -3
  25. package/control-flow/diff-cfg.js +35 -29
  26. package/control-flow/extract-cfg.d.ts +5 -4
  27. package/control-flow/extract-cfg.js +156 -127
  28. package/control-flow/happens-before.js +2 -1
  29. package/control-flow/semantic-cfg-guided-visitor.js +2 -1
  30. package/control-flow/simple-visitor.d.ts +1 -2
  31. package/control-flow/simple-visitor.js +20 -15
  32. package/control-flow/syntax-cfg-guided-visitor.js +2 -1
  33. package/control-flow/useless-loop.js +2 -1
  34. package/documentation/doc-readme.js +11 -9
  35. package/documentation/wiki-absint.js +4 -3
  36. package/documentation/wiki-cfg.js +21 -9
  37. package/documentation/wiki-mk/doc-context.d.ts +3 -0
  38. package/documentation/wiki-mk/doc-context.js +4 -1
  39. package/documentation/wiki-mk/doc-maker.js +1 -1
  40. package/linter/linter-rules.d.ts +2 -2
  41. package/linter/rules/dataframe-access-validation.d.ts +2 -2
  42. package/linter/rules/dataframe-access-validation.js +3 -3
  43. package/package.json +1 -1
  44. package/project/cache/flowr-analyzer-controlflow-cache.js +3 -0
  45. package/project/cfg-kind.d.ts +5 -1
  46. package/project/cfg-kind.js +5 -1
  47. package/project/plugins/file-plugins/files/flowr-namespace-file.js +3 -2
  48. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +10 -2
  49. package/queries/catalog/control-flow-query/control-flow-query-format.js +1 -1
  50. package/queries/catalog/df-shape-query/df-shape-query-executor.js +12 -5
  51. package/r-bridge/lang-4.x/convert-values.js +1 -1
  52. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.d.ts +2 -1
  53. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +83 -53
  54. package/search/search-executor/search-generators.js +2 -2
  55. package/util/assert.d.ts +3 -3
  56. package/util/mermaid/cfg.d.ts +1 -7
  57. package/util/mermaid/cfg.js +37 -44
  58. package/util/r-regex.d.ts +4 -0
  59. package/util/r-regex.js +35 -3
  60. package/util/version.js +1 -1
  61. package/control-flow/invert-cfg.d.ts +0 -5
  62. package/control-flow/invert-cfg.js +0 -20
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.9.5, R grammar v14 (tree-sitter engine)
27
+ flowR repl using flowR v2.9.7, R grammar v14 (tree-sitter engine)
28
28
  R> :query @linter "read.csv(\"/root/x.txt\")"
29
29
  ```
30
30
 
@@ -33,15 +33,15 @@ It offers a wide variety of features, for example:
33
33
 
34
34
 
35
35
  ```text
36
- Query: linter (3 ms)
36
+ Query: linter (2 ms)
37
37
  ╰ Deprecated Functions (deprecated-functions):
38
- ╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 1, processTimeMs: 0
38
+ ╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0
39
39
  ╰ File Path Validity (file-path-validity):
40
40
  ╰ certain:
41
41
  ╰ Path `/root/x.txt` at 1.1-23
42
- ╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs: 0
42
+ ╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 1, processTimeMs: 0
43
43
  ╰ Seeded Randomness (seeded-randomness):
44
- ╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 1, processTimeMs: 0
44
+ ╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs: 0
45
45
  ╰ Absolute Paths (absolute-file-paths):
46
46
  ╰ certain:
47
47
  ╰ Path `/root/x.txt` at 1.1-23
@@ -53,12 +53,12 @@ It offers a wide variety of features, for example:
53
53
  ╰ Network Functions (network-functions):
54
54
  ╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0
55
55
  ╰ Dataframe Access Validation (dataframe-access-validation):
56
- ╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 1
56
+ ╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 1, processTimeMs: 0
57
57
  ╰ Dead Code (dead-code):
58
58
  ╰ Metadata: consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0
59
59
  ╰ Useless Loops (useless-loop):
60
60
  ╰ Metadata: numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0
61
- All queries together required ≈3 ms (1ms accuracy, total 3 ms)
61
+ All queries together required ≈2 ms (1ms accuracy, total 3 ms)
62
62
  ```
63
63
 
64
64
 
@@ -92,7 +92,7 @@ It offers a wide variety of features, for example:
92
92
     ╰ **Absolute Paths** (absolute-file-paths):\
93
93
         ╰ certain:\
94
94
             ╰ Path `/root/x.txt` at 1.1-23\
95
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 1, totalUnknown: 0, searchTimeMs: 0, processTimeMs: 0</code>\
95
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 1, totalUnknown: 0, searchTimeMs: 1, processTimeMs: 0</code>\
96
96
  &nbsp;&nbsp;&nbsp;╰ **Unused Definitions** (unused-definitions):\
97
97
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalConsidered: 0, searchTimeMs: 0, processTimeMs: 0</code>\
98
98
  &nbsp;&nbsp;&nbsp;╰ **Naming Convention** (naming-convention):\
@@ -100,16 +100,16 @@ It offers a wide variety of features, for example:
100
100
  &nbsp;&nbsp;&nbsp;╰ **Network Functions** (network-functions):\
101
101
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0</code>\
102
102
  &nbsp;&nbsp;&nbsp;╰ **Dataframe Access Validation** (dataframe-access-validation):\
103
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 0</code>\
103
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 1</code>\
104
104
  &nbsp;&nbsp;&nbsp;╰ **Dead Code** (dead-code):\
105
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consideredNodes: 5, searchTimeMs: 1, processTimeMs: 0</code>\
105
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0</code>\
106
106
  &nbsp;&nbsp;&nbsp;╰ **Useless Loops** (useless-loop):\
107
107
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;╰ _Metadata_: <code>numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0</code>\
108
108
  _All queries together required ≈3 ms (1ms accuracy, total 3 ms)_
109
109
 
110
110
  <details> <summary style="color:gray">Show Detailed Results as Json</summary>
111
111
 
112
- The analysis required _3.2 ms_ (including parsing and normalization and the query) within the generation environment.
112
+ The analysis required _3.3 ms_ (including parsing and normalization and the query) within the generation environment.
113
113
 
114
114
  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.
115
115
  Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
@@ -181,7 +181,7 @@ It offers a wide variety of features, for example:
181
181
  ".meta": {
182
182
  "totalConsidered": 1,
183
183
  "totalUnknown": 0,
184
- "searchTimeMs": 0,
184
+ "searchTimeMs": 1,
185
185
  "processTimeMs": 0
186
186
  }
187
187
  },
@@ -218,14 +218,14 @@ It offers a wide variety of features, for example:
218
218
  "numAccesses": 0,
219
219
  "totalAccessed": 0,
220
220
  "searchTimeMs": 0,
221
- "processTimeMs": 0
221
+ "processTimeMs": 1
222
222
  }
223
223
  },
224
224
  "dead-code": {
225
225
  "results": [],
226
226
  ".meta": {
227
227
  "consideredNodes": 5,
228
- "searchTimeMs": 1,
228
+ "searchTimeMs": 0,
229
229
  "processTimeMs": 0
230
230
  }
231
231
  },
@@ -308,7 +308,7 @@ It offers a wide variety of features, for example:
308
308
 
309
309
  ```shell
310
310
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
311
- flowR repl using flowR v2.9.5, R grammar v14 (tree-sitter engine)
311
+ flowR repl using flowR v2.9.7, R grammar v14 (tree-sitter engine)
312
312
  R> :query @static-slice (11@sum) file://test/testfiles/example.R
313
313
  ```
314
314
 
@@ -356,16 +356,16 @@ It offers a wide variety of features, for example:
356
356
 
357
357
 
358
358
  * 🚀 **fast call-graph, data-, and control-flow graphs**\
359
- Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">99.6 ms</span></i> (as of Feb 5, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
360
- _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,
361
- and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for more details on the dataflow graphs as well as call graphs.
359
+ Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">111.7 ms</span></i> (as of Feb 7, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
360
+ _flowR_ can analyze the data- and control-flow of the average real-world R&nbsp;script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
361
+ and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for more details on the [dataflow graphs](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) as well as [call graphs](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph#perspectives-cg).
362
362
 
363
363
 
364
364
  <details><summary>Example: Generating a dataflow graph with flowR</summary>
365
365
 
366
366
 
367
367
  You can investigate flowR's analyses using the [REPL](https://github.com/flowr-analysis/flowr/wiki/Interface#using-the-repl).
368
- Commands like <span title="Description (Repl Command, starred version): Returns the URL to mermaid.live; Base Command: Get mermaid code for the dataflow graph, start with 'file://' to indicate a file (aliases: :d*, :df*)">`:dataflow*`</span> allow you to view a dataflow graph for a given R script.
368
+ Commands like <span title="Description (Repl Command, starred version): Returns the URL to mermaid.live; Base Command: Get mermaid code for the dataflow graph, start with 'file://' to indicate a file (aliases: :d*, :df*)">`:dataflow*`</span> allow you to view a [dataflow graph](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for a given R script.
369
369
 
370
370
  Let's have a look at the following example:
371
371
 
@@ -386,13 +386,13 @@ It offers a wide variety of features, for example:
386
386
  ```
387
387
 
388
388
 
389
- To get the dataflow graph for this script, you can use the following command:
389
+ To get the [dataflow graph](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for this script, you can use the following command:
390
390
 
391
391
 
392
392
 
393
393
  ```shell
394
394
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
395
- flowR repl using flowR v2.9.5, R grammar v14 (tree-sitter engine)
395
+ flowR repl using flowR v2.9.7, R grammar v14 (tree-sitter engine)
396
396
  R> :dataflow* test/testfiles/example.R
397
397
  ```
398
398
 
@@ -697,7 +697,7 @@ It offers a wide variety of features, for example:
697
697
  ```
698
698
 
699
699
 
700
- (The analysis required _4.3 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
700
+ (The analysis required _1.8 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
701
701
 
702
702
 
703
703
 
@@ -724,8 +724,8 @@ If you are already using flowR and want to give feedback, please consider fillin
724
724
 
725
725
  ## ⭐ Getting Started
726
726
 
727
- To get started with _flowR_ and its features, please check out the [Overview](https://github.com/flowr-analysis/flowr/wiki/Overview) wiki page.
728
- The [Setup](https://github.com/flowr-analysis/flowr/wiki/Setup) wiki page explains how you can download and setup _flowR_ on your system.
727
+ To get started with _flowR_ and its features, please check out the [Overview](https://github.com/flowr-analysis/flowr/wiki/wiki/overview) wiki page.
728
+ The [Setup](https://github.com/flowr-analysis/flowr/wiki/wiki/setup) wiki page explains how you can download and setup _flowR_ on your system.
729
729
  With docker&nbsp;🐳️, the following line should be enough (and drop you directly into the read-eval-print loop):
730
730
 
731
731
 
@@ -753,7 +753,9 @@ If you want to use the same commands:
753
753
  ## 📜 More Information
754
754
 
755
755
  For more details on how to use _flowR_ please refer to the [wiki pages](https://github.com/flowr-analysis/flowr/wiki),
756
- as well as the deployed [code documentation](https://flowr-analysis.github.io/flowr/doc/).
756
+ as well as the deployed [code documentation](https://flowr-analysis.github.io/flowr/docs).
757
+ To cite flowR, please check out the publications below. To specifically refer to the source code,
758
+ please check out flowR's [Zenodo archive](https://zenodo.org/doi/10.5281/zenodo.13319290).
757
759
 
758
760
  ## 📃 Publications on flowR
759
761
 
@@ -860,7 +862,7 @@ please check out the following publications (if you find that a paper is missing
860
862
 
861
863
  ## 🚀 Contributing
862
864
 
863
- We welcome every contribution! Please check out the [developer onboarding](https://github.com/flowr-analysis/flowr/wiki/Onboarding) section in the wiki for all the information you will need.
865
+ We welcome every contribution! Please check out the [developer onboarding](https://github.com/flowr-analysis/flowr/wiki/wiki/onboarding) section in the wiki for all the information you will need.
864
866
 
865
867
  ### Contributors
866
868
 
@@ -1,4 +1,5 @@
1
- import type { CfgSimpleVertex, ControlFlowInformation } from '../control-flow/control-flow-graph';
1
+ import type { ControlFlowInformation } from '../control-flow/control-flow-graph';
2
+ import { CfgVertex } from '../control-flow/control-flow-graph';
2
3
  import type { SemanticCfgGuidedVisitorConfiguration } from '../control-flow/semantic-cfg-guided-visitor';
3
4
  import { SemanticCfgGuidedVisitor } from '../control-flow/semantic-cfg-guided-visitor';
4
5
  import { BuiltInProcName } from '../dataflow/environments/built-in';
@@ -98,15 +99,15 @@ export declare abstract class AbstractInterpretationVisitor<Domain extends AnyAb
98
99
  * Checks whether to continue visiting the control flow graph after a widening point.
99
100
  * By default, we only continue visiting if the widening point is visited for the first time or the abstract state at the widening point changed.
100
101
  */
101
- protected shouldContinueVisiting(wideningPoint: CfgSimpleVertex, oldState: StateAbstractDomain<Domain>): boolean;
102
+ protected shouldContinueVisiting(wideningPoint: CfgVertex, oldState: StateAbstractDomain<Domain>): boolean;
102
103
  /**
103
104
  * Checks whether a control flow graph vertex should be skipped during visitation.
104
105
  * By default, we only process vertices of leaf nodes and exit vertices (no entry nodes of complex nodes).
105
106
  */
106
- protected shouldSkipVertex(vertex: CfgSimpleVertex): boolean;
107
+ protected shouldSkipVertex(vertex: CfgVertex): boolean;
107
108
  /**
108
109
  * Whether widening should be performed at a widening point.
109
110
  * By default, we perform widening when the number of visitation of the widening point reaches the widening threshold of the config.
110
111
  */
111
- protected shouldWiden(wideningPoint: CfgSimpleVertex): boolean;
112
+ protected shouldWiden(wideningPoint: CfgVertex): boolean;
112
113
  }
@@ -100,7 +100,7 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
100
100
  */
101
101
  getEndState() {
102
102
  const exitPoints = this.config.controlFlow.exitPoints.map(id => this.getCfgVertex(id)).filter(assert_1.isNotUndefined);
103
- const exitNodes = exitPoints.map(vertex => (0, control_flow_graph_1.getVertexRootId)(vertex)).filter(assert_1.isNotUndefined);
103
+ const exitNodes = exitPoints.map(vertex => control_flow_graph_1.CfgVertex.getRootId(vertex)).filter(assert_1.isNotUndefined);
104
104
  const states = exitNodes.map(node => this.getAbstractState(node)).filter(assert_1.isNotUndefined);
105
105
  return this.config.domain.bottom().joinAll(states);
106
106
  }
@@ -121,14 +121,14 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
121
121
  if (vertex === undefined) {
122
122
  return true;
123
123
  }
124
- const nodeId = (0, control_flow_graph_1.getVertexRootId)(vertex);
124
+ const nodeId = control_flow_graph_1.CfgVertex.getRootId(vertex);
125
125
  if (this.isWideningPoint(nodeId)) {
126
126
  // only check widening points at the entry vertex
127
- if (vertex.type === control_flow_graph_1.CfgVertexType.EndMarker) {
127
+ if (control_flow_graph_1.CfgVertex.isMarker(vertex)) {
128
128
  return true;
129
129
  }
130
130
  const oldState = this.getAbstractState(nodeId) ?? this.config.domain.bottom();
131
- const predecessorDomains = this.getPredecessorNodes(vertex.id).map(pred => this.getAbstractState(pred)).filter(assert_1.isNotUndefined);
131
+ const predecessorDomains = this.getPredecessorNodes(control_flow_graph_1.CfgVertex.getId(vertex)).map(pred => this.getAbstractState(pred)).filter(assert_1.isNotUndefined);
132
132
  this.currentState = this.config.domain.bottom().joinAll(predecessorDomains);
133
133
  if (this.shouldWiden(vertex)) {
134
134
  this.currentState = oldState.widen(this.currentState);
@@ -139,7 +139,7 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
139
139
  else if (this.shouldSkipVertex(vertex)) {
140
140
  return true;
141
141
  }
142
- const predecessorDomains = this.getPredecessorNodes(vertex.id).map(pred => this.getAbstractState(pred)).filter(assert_1.isNotUndefined);
142
+ const predecessorDomains = this.getPredecessorNodes(control_flow_graph_1.CfgVertex.getId(vertex)).map(pred => this.getAbstractState(pred)).filter(assert_1.isNotUndefined);
143
143
  this.currentState = this.config.domain.bottom().joinAll(predecessorDomains);
144
144
  this.onVisitNode(vertexId);
145
145
  // discard the inferred abstract state when encountering functions with unknown side effects (e.g. `eval`)
@@ -211,10 +211,10 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
211
211
  return [];
212
212
  }
213
213
  else if (this.shouldSkipVertex(vertex)) {
214
- return this.getPredecessorNodes(vertex.id);
214
+ return this.getPredecessorNodes(control_flow_graph_1.CfgVertex.getId(vertex));
215
215
  }
216
216
  else {
217
- return [(0, control_flow_graph_1.getVertexRootId)(vertex)];
217
+ return [control_flow_graph_1.CfgVertex.getRootId(vertex)];
218
218
  }
219
219
  })
220
220
  .toArray() ?? [];
@@ -248,8 +248,9 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
248
248
  * By default, we only continue visiting if the widening point is visited for the first time or the abstract state at the widening point changed.
249
249
  */
250
250
  shouldContinueVisiting(wideningPoint, oldState) {
251
- const visitedCount = this.visited.get(wideningPoint.id) ?? 0;
252
- this.visited.set(wideningPoint.id, visitedCount + 1);
251
+ const wid = control_flow_graph_1.CfgVertex.getId(wideningPoint);
252
+ const visitedCount = this.visited.get(wid) ?? 0;
253
+ this.visited.set(wid, visitedCount + 1);
253
254
  return visitedCount === 0 || !oldState.equals(this.currentState);
254
255
  }
255
256
  /**
@@ -257,14 +258,14 @@ class AbstractInterpretationVisitor extends semantic_cfg_guided_visitor_1.Semant
257
258
  * By default, we only process vertices of leaf nodes and exit vertices (no entry nodes of complex nodes).
258
259
  */
259
260
  shouldSkipVertex(vertex) {
260
- return vertex.type !== control_flow_graph_1.CfgVertexType.EndMarker && vertex.end !== undefined;
261
+ return !control_flow_graph_1.CfgVertex.isMarker(vertex) && !control_flow_graph_1.CfgVertex.isBlock(vertex) && control_flow_graph_1.CfgVertex.getEnd(vertex) !== undefined;
261
262
  }
262
263
  /**
263
264
  * Whether widening should be performed at a widening point.
264
265
  * By default, we perform widening when the number of visitation of the widening point reaches the widening threshold of the config.
265
266
  */
266
267
  shouldWiden(wideningPoint) {
267
- return (this.visited.get(wideningPoint.id) ?? 0) >= this.config.ctx.config.abstractInterpretation.wideningThreshold;
268
+ return (this.visited.get(control_flow_graph_1.CfgVertex.getId(wideningPoint)) ?? 0) >= this.config.ctx.config.abstractInterpretation.wideningThreshold;
268
269
  }
269
270
  }
270
271
  exports.AbstractInterpretationVisitor = AbstractInterpretationVisitor;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DataFrameDomain = void 0;
4
- const lattice_1 = require("../domains/lattice");
5
4
  const positive_interval_domain_1 = require("../domains/positive-interval-domain");
6
5
  const product_domain_1 = require("../domains/product-domain");
7
6
  const set_range_domain_1 = require("../domains/set-range-domain");
@@ -53,7 +52,7 @@ class DataFrameDomain extends product_domain_1.ProductDomain {
53
52
  }
54
53
  static refine(value) {
55
54
  if (value.colnames.isValue() && value.cols.isValue()) {
56
- if (value.colnames.value.range === lattice_1.Top && value.colnames.value.min.size >= value.cols.value[1]) {
55
+ if (value.colnames.value.min.size >= value.cols.value[1]) {
57
56
  value.colnames = value.colnames.meet({ min: new Set(), range: value.colnames.value.min });
58
57
  }
59
58
  if (value.colnames.isValue()) {
@@ -57,7 +57,6 @@ export declare class BenchmarkSlicer {
57
57
  private readonly perSliceMeasurements;
58
58
  private readonly deltas;
59
59
  private readonly parserName;
60
- private config;
61
60
  private context;
62
61
  private stats;
63
62
  private loadedXml;
@@ -41,7 +41,6 @@ class BenchmarkSlicer {
41
41
  perSliceMeasurements = new Map();
42
42
  deltas = new Map();
43
43
  parserName;
44
- config;
45
44
  context;
46
45
  stats;
47
46
  loadedXml;
@@ -63,7 +62,6 @@ class BenchmarkSlicer {
63
62
  */
64
63
  async init(request, config, autoSelectIf, threshold) {
65
64
  (0, assert_1.guard)(this.stats === undefined, 'cannot initialize the slicer twice');
66
- this.config = config;
67
65
  // we know these are in sync so we just cast to one of them
68
66
  this.parser = await this.commonMeasurements.measure('initialize R session', async () => {
69
67
  if (this.parserName === 'r-shell') {
@@ -227,11 +225,8 @@ class BenchmarkSlicer {
227
225
  exports.benchmarkLogger.trace('try to extract the control flow graph');
228
226
  this.guardActive();
229
227
  (0, assert_1.guard)(this.normalizedAst !== undefined, 'normalizedAst should be defined for control flow extraction');
230
- (0, assert_1.guard)(this.dataflow !== undefined, 'dataflow should be defined for control flow extraction');
231
- (0, assert_1.guard)(this.config !== undefined, 'config should be defined for control flow extraction');
232
228
  const ast = this.normalizedAst;
233
- const dfg = this.dataflow.graph;
234
- this.controlFlow = this.measureSimpleStep('extract control flow graph', () => (0, extract_cfg_1.extractCfg)(ast, this.context, dfg));
229
+ this.controlFlow = this.measureSimpleStep('extract control flow graph', () => (0, extract_cfg_1.extractCfg)(ast, this.context, undefined, undefined, true));
235
230
  }
236
231
  /**
237
232
  * Infer the shape of data frames using abstract interpretation with {@link inferDataFrameShapes}
@@ -264,6 +259,7 @@ class BenchmarkSlicer {
264
259
  this.measureSimpleStep('infer data frame shapes', () => inference.start());
265
260
  const result = inference.getEndState();
266
261
  stats.numberOfResultConstraints = result.value.size;
262
+ stats.sizeOfInfo = (0, size_of_1.safeSizeOf)([inference.getAbstractTrace()]);
267
263
  for (const value of result.value.values()) {
268
264
  if (value.isTop()) {
269
265
  stats.numberOfResultingTop++;
@@ -283,10 +279,8 @@ class BenchmarkSlicer {
283
279
  stats.numberOfEmptyNodes++;
284
280
  return;
285
281
  }
286
- const state = inference.getAbstractState(node.info.id);
287
- stats.sizeOfInfo += (0, size_of_1.safeSizeOf)([state]);
288
282
  const nodeStats = {
289
- numberOfEntries: state?.value.size ?? 0
283
+ numberOfEntries: inference.getAbstractState(node.info.id)?.value.size ?? 0
290
284
  };
291
285
  if (operations !== undefined) {
292
286
  nodeStats.mappedOperations = operations.map(op => op.operation);
@@ -268,6 +268,7 @@ Dataframe shape inference:
268
268
  Number of abstract value nodes: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfValueNodes)}
269
269
  Number of entries per node: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfEntriesPerNode)}
270
270
  Number of operations: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfOperations)}
271
+ Number of total exact: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfTotalExact)}
271
272
  Number of total values: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfTotalValues)}
272
273
  Number of total top: ${formatSummarizedMeasure(stats.dataFrameShape.numberOfTotalTop)}
273
274
  Inferred column names per node: ${formatSummarizedMeasure(stats.dataFrameShape.inferredColNames)}
@@ -83,6 +83,8 @@ export interface UltimateSlicerStats {
83
83
  export interface SummarizedDfShapeStats<T = number> extends Omit<SlicerStatsDfShape<T>, 'perNodeStats'> {
84
84
  numberOfEntriesPerNode: SummarizedMeasurement;
85
85
  numberOfOperations: T;
86
+ numberOfTotalConstraints: T;
87
+ numberOfTotalExact: T;
86
88
  numberOfTotalValues: T;
87
89
  numberOfTotalBottom: T;
88
90
  numberOfTotalTop: T;
@@ -265,8 +265,10 @@ function summarizeDfShapeStats({ perNodeStats, ...stats }) {
265
265
  ...stats,
266
266
  numberOfEntriesPerNode: (0, summarizer_1.summarizeMeasurement)(nodeStats.map(s => s.numberOfEntries)),
267
267
  numberOfOperations: (0, arrays_1.arraySum)(nodeStats.map(s => s.mappedOperations?.length).filter(assert_1.isNotUndefined)),
268
+ numberOfTotalConstraints: nodeStats.filter(s => s.inferredColNames !== undefined && s.inferredColCount !== undefined && s.inferredRowCount !== undefined).length,
269
+ numberOfTotalExact: nodeStats.filter(s => s.approxRangeColNames === 0 && s.approxRangeColCount === 0 && s.approxRangeRowCount === 0).length,
268
270
  numberOfTotalValues: nodeStats.filter(s => isValue(s.inferredColNames) && isValue(s.inferredColCount) && isValue(s.inferredRowCount)).length,
269
- numberOfTotalBottom: nodeStats.filter(s => s.inferredColNames === 0 && isBottom(s.inferredColCount) && isBottom(s.inferredRowCount)).length,
271
+ numberOfTotalBottom: nodeStats.filter(s => isBottom(s.inferredColCount) && isBottom(s.inferredColCount) && isBottom(s.inferredRowCount)).length,
270
272
  numberOfTotalTop: nodeStats.filter(s => isTop(s.inferredColNames) && isTop(s.inferredColCount) && isTop(s.inferredRowCount)).length,
271
273
  inferredColNames: (0, summarizer_1.summarizeMeasurement)(nodeStats.map(s => s.inferredColNames).filter(isValue)),
272
274
  approxRangeColNames: (0, summarizer_1.summarizeMeasurement)(nodeStats.map(s => s.approxRangeColNames).filter(assert_1.isNotUndefined).filter(isFinite)),
@@ -119,6 +119,8 @@ function summarizeAllSummarizedStats(stats) {
119
119
  sizeOfInfo: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.sizeOfInfo).filter(assert_1.isNotUndefined)),
120
120
  numberOfEntriesPerNode: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(assert_1.isNotUndefined)),
121
121
  numberOfOperations: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(assert_1.isNotUndefined)),
122
+ numberOfTotalConstraints: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalConstraints).filter(assert_1.isNotUndefined)),
123
+ numberOfTotalExact: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalExact).filter(assert_1.isNotUndefined)),
122
124
  numberOfTotalValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(assert_1.isNotUndefined)),
123
125
  numberOfTotalBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(assert_1.isNotUndefined)),
124
126
  numberOfTotalTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(assert_1.isNotUndefined)),
@@ -203,6 +205,8 @@ function summarizeAllUltimateStats(stats) {
203
205
  sizeOfInfo: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.sizeOfInfo).filter(assert_1.isNotUndefined)),
204
206
  numberOfEntriesPerNode: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(assert_1.isNotUndefined)),
205
207
  numberOfOperations: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(assert_1.isNotUndefined)),
208
+ numberOfTotalConstraints: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalConstraints).filter(assert_1.isNotUndefined)),
209
+ numberOfTotalExact: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalExact).filter(assert_1.isNotUndefined)),
206
210
  numberOfTotalValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(assert_1.isNotUndefined)),
207
211
  numberOfTotalBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(assert_1.isNotUndefined)),
208
212
  numberOfTotalTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(assert_1.isNotUndefined)),
@@ -12,6 +12,7 @@ declare const _commands: {
12
12
  readonly parse: ReplCodeCommand;
13
13
  readonly normalize: ReplCodeCommand;
14
14
  readonly 'normalize*': ReplCodeCommand;
15
+ readonly 'normalize#': ReplCodeCommand;
15
16
  readonly dataflow: ReplCodeCommand;
16
17
  readonly 'dataflow*': ReplCodeCommand;
17
18
  readonly dataflowsimple: ReplCodeCommand;
@@ -79,6 +79,7 @@ const _commands = {
79
79
  'parse': repl_parse_1.parseCommand,
80
80
  'normalize': repl_normalize_1.normalizeCommand,
81
81
  'normalize*': repl_normalize_1.normalizeStarCommand,
82
+ 'normalize#': repl_normalize_1.normalizeHashCommand,
82
83
  'dataflow': repl_dataflow_1.dataflowCommand,
83
84
  'dataflow*': repl_dataflow_1.dataflowStarCommand,
84
85
  'dataflowsimple': repl_dataflow_1.dataflowSimplifiedCommand,
@@ -1,3 +1,4 @@
1
1
  import type { ReplCodeCommand } from './repl-main';
2
2
  export declare const normalizeCommand: ReplCodeCommand;
3
3
  export declare const normalizeStarCommand: ReplCodeCommand;
4
+ export declare const normalizeHashCommand: ReplCodeCommand;
@@ -33,11 +33,13 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.normalizeStarCommand = exports.normalizeCommand = void 0;
36
+ exports.normalizeHashCommand = exports.normalizeStarCommand = exports.normalizeCommand = void 0;
37
37
  const retriever_1 = require("../../../r-bridge/retriever");
38
38
  const ast_1 = require("../../../util/mermaid/ast");
39
39
  const ansi_1 = require("../../../util/text/ansi");
40
40
  const core_1 = require("../core");
41
+ const defaultmap_1 = require("../../../util/collections/defaultmap");
42
+ const visitor_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/visitor");
41
43
  function formatInfo(out, type, meta) {
42
44
  return out.formatter.format(`Copied ${type} to clipboard (normalize: ${meta['.meta'].timing + 'ms'}).`, { color: 7 /* Colors.White */, effect: ansi_1.ColorEffect.Foreground, style: 3 /* FontStyles.Italic */ });
43
45
  }
@@ -79,4 +81,29 @@ exports.normalizeStarCommand = {
79
81
  catch { /* do nothing this is a service thing */ }
80
82
  }
81
83
  };
84
+ exports.normalizeHashCommand = {
85
+ description: 'Returns summarization stats for the normalized AST',
86
+ isCodeCommand: true,
87
+ usageExample: ':normalize#',
88
+ aliases: ['n#'],
89
+ script: false,
90
+ argsParser: (args) => (0, core_1.handleString)(args),
91
+ fn: async ({ output, analyzer }) => {
92
+ const result = await analyzer.normalize();
93
+ const counts = new defaultmap_1.DefaultMap(() => 0);
94
+ let total = 0;
95
+ const files = result.ast.files.length;
96
+ (0, visitor_1.visitAst)(result.ast.files.map(f => f.root), n => {
97
+ counts.set(n.type, counts.get(n.type) + 1);
98
+ total++;
99
+ });
100
+ const num = (s, pad = 0) => output.formatter.format(s.toString().padStart(pad, ' '), { color: 6 /* Colors.Cyan */, effect: ansi_1.ColorEffect.Foreground });
101
+ output.stdout(output.formatter.format('Calculated in ' + result['.meta'].timing + 'ms', { color: 7 /* Colors.White */, effect: ansi_1.ColorEffect.Foreground, style: 3 /* FontStyles.Italic */ }));
102
+ output.stdout(`${num(total)} nodes total over ${num(files)} file(s)`);
103
+ const longestType = counts.keys().map(p => p.toString().length).reduce((a, b) => Math.max(a, b), 0);
104
+ for (const [type, count] of counts.entries().toArray().sort((a, b) => b[1] - a[1])) {
105
+ output.stdout(` ${(type + ':').padEnd(longestType + 1, ' ')} ${num(count, 7)}`);
106
+ }
107
+ }
108
+ };
82
109
  //# sourceMappingURL=repl-normalize.js.map
@@ -1,4 +1,4 @@
1
- import { type CfgBasicBlockVertex, type CfgEndMarkerVertex, type CfgExpressionVertex, type CfgSimpleVertex, type CfgStatementVertex, type ControlFlowInformation } from './control-flow-graph';
1
+ import { type CfgBasicBlockVertex, type CfgMarkerVertex, type CfgExpressionVertex, CfgVertex, type CfgStatementVertex, type ControlFlowInformation } from './control-flow-graph';
2
2
  import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
3
3
  export interface BasicCfgGuidedVisitorConfiguration<ControlFlow extends ControlFlowInformation = ControlFlowInformation> {
4
4
  readonly controlFlow: ControlFlow;
@@ -28,10 +28,10 @@ export declare class BasicCfgGuidedVisitor<ControlFlow extends ControlFlowInform
28
28
  /**
29
29
  * Get the control flow vertex for the given node id or fail if it does not exist.
30
30
  */
31
- protected getCfgVertex(id: NodeId): CfgSimpleVertex | undefined;
31
+ protected getCfgVertex(id: NodeId): CfgVertex | undefined;
32
32
  protected onVisitNode(node: NodeId): void;
33
33
  protected onBasicBlockNode(node: CfgBasicBlockVertex): void;
34
34
  protected onStatementNode(_node: CfgStatementVertex): void;
35
35
  protected onExpressionNode(_node: CfgExpressionVertex): void;
36
- protected onEndMarkerNode(_node: CfgEndMarkerVertex): void;
36
+ protected onEndMarkerNode(_node: CfgMarkerVertex): void;
37
37
  }
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BasicCfgGuidedVisitor = void 0;
4
4
  const control_flow_graph_1 = require("./control-flow-graph");
5
5
  const assert_1 = require("../util/assert");
6
- const invert_cfg_1 = require("./invert-cfg");
7
6
  /**
8
7
  * In contrast to {@link visitCfgInOrder} and {@link visitCfgInReverseOrder}, this visitor is not a simple visitor
9
8
  * and serves as the basis for a variety of more complicated visiting orders of the control flow graph.
@@ -34,8 +33,7 @@ class BasicCfgGuidedVisitor {
34
33
  const graph = this.config.controlFlow.graph;
35
34
  let getNext;
36
35
  if (this.config.defaultVisitingOrder === 'forward') {
37
- const inverseGraph = (0, invert_cfg_1.invertCfg)(graph);
38
- getNext = (node) => inverseGraph.outgoingEdges(node)?.keys().toArray().reverse();
36
+ getNext = (node) => graph.ingoingEdges(node)?.keys().toArray().reverse();
39
37
  }
40
38
  else {
41
39
  getNext = (node) => graph.outgoingEdges(node)?.keys();
@@ -68,7 +66,7 @@ class BasicCfgGuidedVisitor {
68
66
  if (vertex === undefined) {
69
67
  return;
70
68
  }
71
- const type = vertex.type;
69
+ const type = control_flow_graph_1.CfgVertex.getType(vertex);
72
70
  switch (type) {
73
71
  case control_flow_graph_1.CfgVertexType.Statement:
74
72
  this.onStatementNode(vertex);
@@ -76,7 +74,7 @@ class BasicCfgGuidedVisitor {
76
74
  case control_flow_graph_1.CfgVertexType.Expression:
77
75
  this.onExpressionNode(vertex);
78
76
  break;
79
- case control_flow_graph_1.CfgVertexType.EndMarker:
77
+ case control_flow_graph_1.CfgVertexType.Marker:
80
78
  this.onEndMarkerNode(vertex);
81
79
  break;
82
80
  case control_flow_graph_1.CfgVertexType.Block:
@@ -87,14 +85,15 @@ class BasicCfgGuidedVisitor {
87
85
  }
88
86
  }
89
87
  onBasicBlockNode(node) {
88
+ const elems = control_flow_graph_1.CfgVertex.getBasicBlockElements(node);
90
89
  if (this.config.defaultVisitingOrder === 'forward') {
91
- for (const elem of node.elems.toReversed()) {
92
- this.visitNode(elem.id);
90
+ for (const elem of elems.toReversed()) {
91
+ this.visitNode(control_flow_graph_1.CfgVertex.getId(elem));
93
92
  }
94
93
  }
95
94
  else {
96
- for (const elem of node.elems) {
97
- this.visitNode(elem.id);
95
+ for (const elem of elems) {
96
+ this.visitNode(control_flow_graph_1.CfgVertex.getId(elem));
98
97
  }
99
98
  }
100
99
  }