@eagleoutice/flowr 2.2.16 → 2.4.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 (147) hide show
  1. package/README.md +48 -20
  2. package/abstract-interpretation/data-frame/absint-info.d.ts +109 -0
  3. package/abstract-interpretation/data-frame/absint-info.js +31 -0
  4. package/abstract-interpretation/data-frame/absint-visitor.d.ts +58 -0
  5. package/abstract-interpretation/data-frame/absint-visitor.js +171 -0
  6. package/abstract-interpretation/data-frame/domain.d.ts +107 -0
  7. package/abstract-interpretation/data-frame/domain.js +315 -0
  8. package/abstract-interpretation/data-frame/mappers/access-mapper.d.ts +17 -0
  9. package/abstract-interpretation/data-frame/mappers/access-mapper.js +166 -0
  10. package/abstract-interpretation/data-frame/mappers/arguments.d.ts +117 -0
  11. package/abstract-interpretation/data-frame/mappers/arguments.js +188 -0
  12. package/abstract-interpretation/data-frame/mappers/assignment-mapper.d.ts +20 -0
  13. package/abstract-interpretation/data-frame/mappers/assignment-mapper.js +34 -0
  14. package/abstract-interpretation/data-frame/mappers/function-mapper.d.ts +261 -0
  15. package/abstract-interpretation/data-frame/mappers/function-mapper.js +1219 -0
  16. package/abstract-interpretation/data-frame/mappers/replacement-mapper.d.ts +12 -0
  17. package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +206 -0
  18. package/abstract-interpretation/data-frame/resolve-args.d.ts +42 -0
  19. package/abstract-interpretation/data-frame/resolve-args.js +118 -0
  20. package/abstract-interpretation/data-frame/semantics.d.ts +213 -0
  21. package/abstract-interpretation/data-frame/semantics.js +363 -0
  22. package/abstract-interpretation/data-frame/shape-inference.d.ts +38 -0
  23. package/abstract-interpretation/data-frame/shape-inference.js +111 -0
  24. package/benchmark/slicer.d.ts +15 -1
  25. package/benchmark/slicer.js +137 -0
  26. package/benchmark/stats/print.js +123 -45
  27. package/benchmark/stats/size-of.d.ts +7 -0
  28. package/benchmark/stats/size-of.js +1 -0
  29. package/benchmark/stats/stats.d.ts +30 -1
  30. package/benchmark/stats/stats.js +4 -2
  31. package/benchmark/summarizer/data.d.ts +33 -2
  32. package/benchmark/summarizer/first-phase/input.js +5 -1
  33. package/benchmark/summarizer/first-phase/process.js +47 -1
  34. package/benchmark/summarizer/second-phase/graph.js +1 -1
  35. package/benchmark/summarizer/second-phase/process.js +102 -4
  36. package/cli/benchmark-app.d.ts +2 -0
  37. package/cli/benchmark-app.js +2 -0
  38. package/cli/benchmark-helper-app.d.ts +2 -0
  39. package/cli/benchmark-helper-app.js +10 -3
  40. package/cli/common/options.js +4 -0
  41. package/cli/repl/commands/repl-query.js +1 -1
  42. package/cli/repl/server/connection.js +14 -5
  43. package/config.d.ts +31 -0
  44. package/config.js +21 -1
  45. package/control-flow/basic-cfg-guided-visitor.d.ts +1 -2
  46. package/control-flow/basic-cfg-guided-visitor.js +0 -6
  47. package/control-flow/cfg-simplification.d.ts +6 -0
  48. package/control-flow/cfg-simplification.js +18 -9
  49. package/control-flow/control-flow-graph.d.ts +3 -8
  50. package/control-flow/control-flow-graph.js +5 -6
  51. package/control-flow/dfg-cfg-guided-visitor.js +1 -1
  52. package/control-flow/extract-cfg.d.ts +2 -2
  53. package/control-flow/extract-cfg.js +52 -63
  54. package/control-flow/semantic-cfg-guided-visitor.d.ts +1 -1
  55. package/control-flow/semantic-cfg-guided-visitor.js +1 -1
  56. package/core/steps/all/static-slicing/00-slice.d.ts +7 -1
  57. package/core/steps/all/static-slicing/00-slice.js +9 -3
  58. package/core/steps/pipeline/default-pipelines.d.ts +74 -74
  59. package/dataflow/environments/built-in.d.ts +7 -5
  60. package/dataflow/environments/built-in.js +16 -13
  61. package/dataflow/eval/resolve/alias-tracking.js +2 -2
  62. package/dataflow/eval/resolve/resolve.d.ts +53 -9
  63. package/dataflow/eval/resolve/resolve.js +132 -38
  64. package/dataflow/graph/dataflowgraph-builder.js +2 -2
  65. package/dataflow/graph/graph.js +1 -1
  66. package/dataflow/graph/invert-dfg.d.ts +2 -0
  67. package/dataflow/graph/invert-dfg.js +17 -0
  68. package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +1 -0
  69. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +4 -0
  70. package/documentation/doc-util/doc-query.js +11 -1
  71. package/documentation/doc-util/doc-search.js +2 -2
  72. package/documentation/print-cfg-wiki.js +3 -4
  73. package/documentation/print-core-wiki.js +2 -2
  74. package/documentation/print-dataflow-graph-wiki.js +7 -0
  75. package/documentation/print-faq-wiki.js +4 -0
  76. package/documentation/print-interface-wiki.js +11 -0
  77. package/documentation/print-linter-wiki.js +36 -4
  78. package/documentation/print-linting-and-testing-wiki.js +13 -1
  79. package/documentation/print-onboarding-wiki.js +4 -0
  80. package/documentation/print-query-wiki.js +29 -3
  81. package/linter/linter-executor.js +1 -2
  82. package/linter/linter-format.d.ts +26 -4
  83. package/linter/linter-format.js +25 -6
  84. package/linter/linter-rules.d.ts +63 -12
  85. package/linter/linter-rules.js +5 -1
  86. package/linter/rules/absolute-path.d.ts +4 -7
  87. package/linter/rules/absolute-path.js +9 -6
  88. package/linter/rules/dataframe-access-validation.d.ts +55 -0
  89. package/linter/rules/dataframe-access-validation.js +118 -0
  90. package/linter/rules/dead-code.d.ts +43 -0
  91. package/linter/rules/dead-code.js +50 -0
  92. package/linter/rules/deprecated-functions.d.ts +3 -2
  93. package/linter/rules/deprecated-functions.js +3 -1
  94. package/linter/rules/file-path-validity.d.ts +4 -4
  95. package/linter/rules/file-path-validity.js +8 -6
  96. package/linter/rules/naming-convention.d.ts +5 -4
  97. package/linter/rules/naming-convention.js +8 -2
  98. package/linter/rules/seeded-randomness.d.ts +4 -3
  99. package/linter/rules/seeded-randomness.js +3 -1
  100. package/linter/rules/unused-definition.d.ts +2 -0
  101. package/linter/rules/unused-definition.js +3 -1
  102. package/package.json +2 -2
  103. package/queries/catalog/dependencies-query/dependencies-query-executor.js +6 -1
  104. package/queries/catalog/dependencies-query/function-info/read-functions.js +1 -0
  105. package/queries/catalog/dependencies-query/function-info/write-functions.js +1 -0
  106. package/queries/catalog/df-shape-query/df-shape-query-executor.d.ts +3 -0
  107. package/queries/catalog/df-shape-query/df-shape-query-executor.js +46 -0
  108. package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +72 -0
  109. package/queries/catalog/df-shape-query/df-shape-query-format.js +31 -0
  110. package/queries/catalog/linter-query/linter-query-format.js +1 -1
  111. package/queries/catalog/location-map-query/location-map-query-executor.js +7 -5
  112. package/queries/catalog/location-map-query/location-map-query-format.d.ts +3 -0
  113. package/queries/catalog/location-map-query/location-map-query-format.js +1 -0
  114. package/queries/catalog/search-query/search-query-executor.js +1 -1
  115. package/queries/catalog/static-slice-query/static-slice-query-executor.js +2 -1
  116. package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +3 -0
  117. package/queries/catalog/static-slice-query/static-slice-query-format.js +3 -1
  118. package/queries/query-print.d.ts +1 -1
  119. package/queries/query-print.js +0 -1
  120. package/queries/query.d.ts +77 -6
  121. package/queries/query.js +26 -11
  122. package/search/flowr-search-builder.d.ts +6 -6
  123. package/search/flowr-search-executor.d.ts +2 -2
  124. package/search/flowr-search-executor.js +1 -1
  125. package/search/flowr-search.d.ts +13 -8
  126. package/search/flowr-search.js +21 -0
  127. package/search/search-executor/search-enrichers.d.ts +87 -20
  128. package/search/search-executor/search-enrichers.js +44 -5
  129. package/search/search-executor/search-generators.d.ts +4 -4
  130. package/search/search-executor/search-generators.js +12 -7
  131. package/search/search-executor/search-mappers.js +3 -2
  132. package/search/search-executor/search-transformer.d.ts +3 -3
  133. package/search/search-executor/search-transformer.js +2 -2
  134. package/slicing/static/static-slicer.d.ts +4 -2
  135. package/slicing/static/static-slicer.js +10 -4
  136. package/util/collections/arrays.d.ts +2 -0
  137. package/util/collections/arrays.js +9 -0
  138. package/util/files.d.ts +8 -2
  139. package/util/files.js +22 -4
  140. package/util/mermaid/dfg.js +4 -2
  141. package/util/r-value.d.ts +23 -0
  142. package/util/r-value.js +113 -0
  143. package/util/range.d.ts +1 -0
  144. package/util/range.js +5 -1
  145. package/util/version.js +1 -1
  146. package/util/cfg/cfg.d.ts +0 -0
  147. package/util/cfg/cfg.js +0 -2
@@ -9,6 +9,8 @@ const defaultmap_1 = require("../../../util/collections/defaultmap");
9
9
  const summarizer_1 = require("../../../util/summarizer");
10
10
  const assert_1 = require("../../../util/assert");
11
11
  const stats_1 = require("../../stats/stats");
12
+ const semantics_1 = require("../../../abstract-interpretation/data-frame/semantics");
13
+ const arrays_1 = require("../../../util/collections/arrays");
12
14
  function summarizeAllSummarizedStats(stats) {
13
15
  const commonMeasurements = new defaultmap_1.DefaultMap(() => []);
14
16
  const perSliceMeasurements = new defaultmap_1.DefaultMap(() => []);
@@ -19,11 +21,14 @@ function summarizeAllSummarizedStats(stats) {
19
21
  const normalizeTimesPerToken = [];
20
22
  const dataflowTimesPerToken = [];
21
23
  const totalCommonTimesPerToken = [];
24
+ const controlFlowTimePerToken = [];
25
+ const dataFrameShapeTimePerToken = [];
22
26
  const memory = new defaultmap_1.DefaultMap(() => []);
23
27
  const reductions = [];
24
28
  const reductionsNoFluff = [];
25
29
  const inputs = [];
26
30
  const dataflows = [];
31
+ const dataFrameShapes = [];
27
32
  let failedToRepParse = 0;
28
33
  let timesHitThreshold = 0;
29
34
  let totalSlices = 0;
@@ -41,6 +46,12 @@ function summarizeAllSummarizedStats(stats) {
41
46
  normalizeTimesPerToken.push(stat.normalizeTimePerToken);
42
47
  dataflowTimesPerToken.push(stat.dataflowTimePerToken);
43
48
  totalCommonTimesPerToken.push(stat.totalCommonTimePerToken);
49
+ if (stat.controlFlowTimePerToken !== undefined) {
50
+ controlFlowTimePerToken.push(stat.controlFlowTimePerToken);
51
+ }
52
+ if (stat.dataFrameShapeTimePerToken !== undefined) {
53
+ dataFrameShapeTimePerToken.push(stat.dataFrameShapeTimePerToken);
54
+ }
44
55
  for (const [k, v] of stat.memory) {
45
56
  memory.get(k).push(v);
46
57
  }
@@ -48,6 +59,9 @@ function summarizeAllSummarizedStats(stats) {
48
59
  reductionsNoFluff.push(stat.perSliceMeasurements.reductionNoFluff);
49
60
  inputs.push(stat.input);
50
61
  dataflows.push(stat.dataflow);
62
+ if (stat.dataFrameShape !== undefined) {
63
+ dataFrameShapes.push(stat.dataFrameShape);
64
+ }
51
65
  failedToRepParse += stat.perSliceMeasurements.failedToRepParse;
52
66
  totalSlices += stat.perSliceMeasurements.numberOfSlices;
53
67
  timesHitThreshold += stat.perSliceMeasurements.timesHitThreshold;
@@ -64,6 +78,8 @@ function summarizeAllSummarizedStats(stats) {
64
78
  normalizeTimePerToken: (0, process_1.summarizeTimePerToken)(normalizeTimesPerToken),
65
79
  dataflowTimePerToken: (0, process_1.summarizeTimePerToken)(dataflowTimesPerToken),
66
80
  totalCommonTimePerToken: (0, process_1.summarizeTimePerToken)(totalCommonTimesPerToken),
81
+ controlFlowTimePerToken: controlFlowTimePerToken.length > 0 ? (0, process_1.summarizeTimePerToken)(controlFlowTimePerToken) : undefined,
82
+ dataFrameShapeTimePerToken: dataFrameShapeTimePerToken.length > 0 ? (0, process_1.summarizeTimePerToken)(dataFrameShapeTimePerToken) : undefined,
67
83
  failedToRepParse,
68
84
  timesHitThreshold,
69
85
  reduction: (0, process_1.summarizeSummarizedReductions)(reductions),
@@ -89,7 +105,43 @@ function summarizeAllSummarizedStats(stats) {
89
105
  storedVertexIndices: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.storedVertexIndices)),
90
106
  storedEnvIndices: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.storedEnvIndices)),
91
107
  overwrittenIndices: (0, summarizer_1.summarizeMeasurement)(dataflows.map(d => d.overwrittenIndices)),
92
- }
108
+ },
109
+ dataFrameShape: stats.some(s => s.dataFrameShape !== undefined) ? {
110
+ numberOfDataFrameFiles: (0, arrays_1.arraySum)(stats.map(s => s.dataFrameShape?.numberOfDataFrameFiles).filter(assert_1.isNotUndefined)),
111
+ numberOfNonDataFrameFiles: (0, arrays_1.arraySum)(stats.map(s => s.dataFrameShape?.numberOfNonDataFrameFiles).filter(assert_1.isNotUndefined)),
112
+ numberOfResultConstraints: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultConstraints).filter(assert_1.isNotUndefined)),
113
+ numberOfResultingValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingValues).filter(assert_1.isNotUndefined)),
114
+ numberOfResultingTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(assert_1.isNotUndefined)),
115
+ numberOfResultingBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingBottom).filter(assert_1.isNotUndefined)),
116
+ numberOfEmptyNodes: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEmptyNodes).filter(assert_1.isNotUndefined)),
117
+ numberOfOperationNodes: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperationNodes).filter(assert_1.isNotUndefined)),
118
+ numberOfValueNodes: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfValueNodes).filter(assert_1.isNotUndefined)),
119
+ sizeOfInfo: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.sizeOfInfo).filter(assert_1.isNotUndefined)),
120
+ numberOfEntriesPerNode: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(assert_1.isNotUndefined)),
121
+ numberOfOperations: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(assert_1.isNotUndefined)),
122
+ numberOfTotalValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(assert_1.isNotUndefined)),
123
+ numberOfTotalTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(assert_1.isNotUndefined)),
124
+ numberOfTotalBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(assert_1.isNotUndefined)),
125
+ inferredColNames: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredColNames).filter(assert_1.isNotUndefined)),
126
+ numberOfColNamesValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesValues).filter(assert_1.isNotUndefined)),
127
+ numberOfColNamesTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(assert_1.isNotUndefined)),
128
+ numberOfColNamesBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesBottom).filter(assert_1.isNotUndefined)),
129
+ inferredColCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredColCount).filter(assert_1.isNotUndefined)),
130
+ numberOfColCountExact: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountExact).filter(assert_1.isNotUndefined)),
131
+ numberOfColCountValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountValues).filter(assert_1.isNotUndefined)),
132
+ numberOfColCountTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(assert_1.isNotUndefined)),
133
+ numberOfColCountInfinite: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(assert_1.isNotUndefined)),
134
+ numberOfColCountBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountBottom).filter(assert_1.isNotUndefined)),
135
+ approxRangeColCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(assert_1.isNotUndefined)),
136
+ inferredRowCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredRowCount).filter(assert_1.isNotUndefined)),
137
+ numberOfRowCountExact: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountExact).filter(assert_1.isNotUndefined)),
138
+ numberOfRowCountValues: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountValues).filter(assert_1.isNotUndefined)),
139
+ numberOfRowCountTop: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(assert_1.isNotUndefined)),
140
+ numberOfRowCountInfinite: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(assert_1.isNotUndefined)),
141
+ numberOfRowCountBottom: (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountBottom).filter(assert_1.isNotUndefined)),
142
+ approxRangeRowCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(assert_1.isNotUndefined)),
143
+ perOperationNumber: new Map(semantics_1.DataFrameOperationNames.map(n => [n, (0, summarizer_1.summarizeMeasurement)(stats.map(s => s.dataFrameShape?.perOperationNumber.get(n) ?? 0))]))
144
+ } : undefined
93
145
  };
94
146
  }
95
147
  function summarizeAllUltimateStats(stats) {
@@ -100,7 +152,7 @@ function summarizeAllUltimateStats(stats) {
100
152
  failedToRepParse: Math.max(...stats.map(s => s.failedToRepParse)),
101
153
  timesHitThreshold: Math.max(...stats.map(s => s.timesHitThreshold)),
102
154
  // average out / summarize other measurements
103
- commonMeasurements: new Map(stats_1.CommonSlicerMeasurements.map(m => [m, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.commonMeasurements.get(m)))])),
155
+ commonMeasurements: new Map(stats_1.CommonSlicerMeasurements.filter(m => stats.some(s => s.commonMeasurements.has(m))).map(m => [m, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.commonMeasurements.get(m)))])),
104
156
  perSliceMeasurements: new Map(stats_1.PerSliceMeasurements.map(m => [m, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.perSliceMeasurements.get(m)))])),
105
157
  sliceTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.sliceTimePerToken)),
106
158
  reconstructTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.reconstructTimePerToken)),
@@ -109,6 +161,8 @@ function summarizeAllUltimateStats(stats) {
109
161
  normalizeTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.normalizeTimePerToken)),
110
162
  dataflowTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.dataflowTimePerToken)),
111
163
  totalCommonTimePerToken: (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.totalCommonTimePerToken)),
164
+ controlFlowTimePerToken: stats.some(s => s.controlFlowTimePerToken !== undefined) ? (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.controlFlowTimePerToken).filter(assert_1.isNotUndefined)) : undefined,
165
+ dataFrameShapeTimePerToken: stats.some(s => s.dataFrameShapeTimePerToken !== undefined) ? (0, process_1.summarizeSummarizedTimePerToken)(stats.map(s => s.dataFrameShapeTimePerToken).filter(assert_1.isNotUndefined)) : undefined,
112
166
  reduction: (0, process_1.summarizeSummarizedReductions)(stats.map(s => s.reduction)),
113
167
  reductionNoFluff: (0, process_1.summarizeSummarizedReductions)(stats.map(s => s.reductionNoFluff)),
114
168
  input: {
@@ -132,7 +186,43 @@ function summarizeAllUltimateStats(stats) {
132
186
  storedVertexIndices: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.storedVertexIndices)),
133
187
  storedEnvIndices: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.storedEnvIndices)),
134
188
  overwrittenIndices: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataflow.overwrittenIndices)),
135
- }
189
+ },
190
+ dataFrameShape: stats.some(s => s.dataFrameShape !== undefined) ? {
191
+ numberOfDataFrameFiles: (0, arrays_1.arraySum)(stats.map(s => s.dataFrameShape?.numberOfDataFrameFiles).filter(assert_1.isNotUndefined)),
192
+ numberOfNonDataFrameFiles: (0, arrays_1.arraySum)(stats.map(s => s.dataFrameShape?.numberOfNonDataFrameFiles).filter(assert_1.isNotUndefined)),
193
+ numberOfResultConstraints: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultConstraints).filter(assert_1.isNotUndefined)),
194
+ numberOfResultingValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingValues).filter(assert_1.isNotUndefined)),
195
+ numberOfResultingTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingTop).filter(assert_1.isNotUndefined)),
196
+ numberOfResultingBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfResultingBottom).filter(assert_1.isNotUndefined)),
197
+ numberOfEmptyNodes: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEmptyNodes).filter(assert_1.isNotUndefined)),
198
+ numberOfOperationNodes: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperationNodes).filter(assert_1.isNotUndefined)),
199
+ numberOfValueNodes: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfValueNodes).filter(assert_1.isNotUndefined)),
200
+ sizeOfInfo: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.sizeOfInfo).filter(assert_1.isNotUndefined)),
201
+ numberOfEntriesPerNode: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfEntriesPerNode).filter(assert_1.isNotUndefined)),
202
+ numberOfOperations: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfOperations).filter(assert_1.isNotUndefined)),
203
+ numberOfTotalValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalValues).filter(assert_1.isNotUndefined)),
204
+ numberOfTotalTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalTop).filter(assert_1.isNotUndefined)),
205
+ numberOfTotalBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfTotalBottom).filter(assert_1.isNotUndefined)),
206
+ inferredColNames: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredColNames).filter(assert_1.isNotUndefined)),
207
+ numberOfColNamesValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesValues).filter(assert_1.isNotUndefined)),
208
+ numberOfColNamesTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesTop).filter(assert_1.isNotUndefined)),
209
+ numberOfColNamesBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColNamesBottom).filter(assert_1.isNotUndefined)),
210
+ inferredColCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredColCount).filter(assert_1.isNotUndefined)),
211
+ numberOfColCountExact: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountExact).filter(assert_1.isNotUndefined)),
212
+ numberOfColCountValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountValues).filter(assert_1.isNotUndefined)),
213
+ numberOfColCountTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountTop).filter(assert_1.isNotUndefined)),
214
+ numberOfColCountInfinite: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountInfinite).filter(assert_1.isNotUndefined)),
215
+ numberOfColCountBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfColCountBottom).filter(assert_1.isNotUndefined)),
216
+ approxRangeColCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.approxRangeColCount).filter(assert_1.isNotUndefined)),
217
+ inferredRowCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.inferredRowCount).filter(assert_1.isNotUndefined)),
218
+ numberOfRowCountExact: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountExact).filter(assert_1.isNotUndefined)),
219
+ numberOfRowCountValues: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountValues).filter(assert_1.isNotUndefined)),
220
+ numberOfRowCountTop: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountTop).filter(assert_1.isNotUndefined)),
221
+ numberOfRowCountInfinite: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountInfinite).filter(assert_1.isNotUndefined)),
222
+ numberOfRowCountBottom: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.numberOfRowCountBottom).filter(assert_1.isNotUndefined)),
223
+ approxRangeRowCount: (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.approxRangeRowCount).filter(assert_1.isNotUndefined)),
224
+ perOperationNumber: new Map(semantics_1.DataFrameOperationNames.map(n => [n, (0, process_1.summarizeSummarizedMeasurement)(stats.map(s => s.dataFrameShape?.perOperationNumber.get(n)).filter(assert_1.isNotUndefined))]))
225
+ } : undefined
136
226
  };
137
227
  }
138
228
  function processNextSummary(line, allSummarized) {
@@ -152,7 +242,11 @@ function processNextSummary(line, allSummarized) {
152
242
  ...got.summarize.perSliceMeasurements,
153
243
  // restore maps
154
244
  measurements: new Map(got.summarize.perSliceMeasurements.measurements),
155
- }
245
+ },
246
+ dataFrameShape: got.summarize.dataFrameShape !== undefined ? {
247
+ ...got.summarize.dataFrameShape,
248
+ perOperationNumber: new Map(got.summarize.dataFrameShape.perOperationNumber)
249
+ } : undefined
156
250
  }
157
251
  };
158
252
  allSummarized.push(got.summarize);
@@ -164,6 +258,10 @@ function processNextUltimateSummary(line, allSummarized) {
164
258
  // restore maps
165
259
  commonMeasurements: new Map(got.commonMeasurements),
166
260
  perSliceMeasurements: new Map(got.perSliceMeasurements),
261
+ dataFrameShape: got.dataFrameShape !== undefined ? {
262
+ ...got.dataFrameShape,
263
+ perOperationNumber: new Map(got.dataFrameShape.perOperationNumber)
264
+ } : undefined
167
265
  };
168
266
  allSummarized.push(got);
169
267
  }
@@ -10,9 +10,11 @@ export interface BenchmarkCliOptions {
10
10
  runs?: number;
11
11
  seed?: string;
12
12
  parser: KnownParserName;
13
+ 'dataframe-shape-inference': boolean;
13
14
  'enable-pointer-tracking': boolean;
14
15
  'max-file-slices': number;
15
16
  threshold?: number;
16
17
  'per-file-time-limit'?: number;
17
18
  'sampling-strategy': string;
19
+ cfg?: boolean;
18
20
  }
@@ -69,11 +69,13 @@ async function benchmark() {
69
69
  '--output', path_1.default.join(options.output, path_1.default.relative(f.baseDir, `${f.request.content}.json`)),
70
70
  '--slice', options.slice, ...verboseAdd,
71
71
  '--parser', options.parser,
72
+ ...(options['dataframe-shape-inference'] ? ['--dataframe-shape-inference'] : []),
72
73
  ...(options['enable-pointer-tracking'] ? ['--enable-pointer-tracking'] : []),
73
74
  '--max-slices', `${options['max-file-slices']}`,
74
75
  ...(options.threshold ? ['--threshold', `${options.threshold}`] : []),
75
76
  '--sampling-strategy', options['sampling-strategy'],
76
77
  ...(options.seed ? ['--seed', options.seed] : []),
78
+ ...(options.cfg ? ['--cfg'] : []),
77
79
  ]);
78
80
  const runs = options.runs ?? 1;
79
81
  for (let i = 1; i <= runs; i++) {
@@ -8,8 +8,10 @@ export interface SingleBenchmarkCliOptions {
8
8
  slice: string;
9
9
  output?: string;
10
10
  parser: KnownParserName;
11
+ 'dataframe-shape-inference': boolean;
11
12
  'enable-pointer-tracking': boolean;
12
13
  'max-slices': number;
14
+ 'cfg': boolean;
13
15
  threshold?: number;
14
16
  'sampling-strategy': string;
15
17
  seed?: string;
@@ -34,13 +34,12 @@ async function benchmark() {
34
34
  const prefix = `[${options.input}${options['file-id'] !== undefined ? ` (file ${options['file-id']}, run ${options['run-num']})` : ''}]`;
35
35
  console.log(`${prefix} Appending output to ${options.output}`);
36
36
  const directory = path_1.default.parse(options.output).dir;
37
- // ensure the directory exists if path contains one
37
+ // ensure the directory exists if the path contains one
38
38
  if (directory !== '') {
39
39
  fs_1.default.mkdirSync(directory, { recursive: true });
40
40
  }
41
41
  // Enable pointer analysis if requested, otherwise disable it
42
- const config = (0, config_1.getConfig)();
43
- (0, config_1.amendConfig)(config, c => {
42
+ const config = (0, config_1.amendConfig)((0, config_1.getConfig)(), c => {
44
43
  c.solver.pointerTracking = options['enable-pointer-tracking'];
45
44
  return c;
46
45
  });
@@ -70,6 +69,14 @@ async function benchmark() {
70
69
  (0, assert_1.guard)(count >= 0, `Number of slices exceeded limit of ${maxSlices} with ${-count} slices, skipping in count`);
71
70
  (0, assert_1.guard)(count > 0, `No possible slices found for ${options.input}, skipping in count`);
72
71
  }
72
+ if (options['cfg'] || options['dataframe-shape-inference']) {
73
+ slicer.extractCFG();
74
+ }
75
+ if (options['dataframe-shape-inference']) {
76
+ console.log(`${prefix} Performing shape inference for data frames`);
77
+ slicer.inferDataFrameShapes();
78
+ console.log(`${prefix} Completed data frame shape inference`);
79
+ }
73
80
  const { stats } = slicer.finish();
74
81
  const output = {
75
82
  filename: options.input,
@@ -22,11 +22,13 @@ exports.benchmarkOptions = [
22
22
  { name: 'slice', alias: 's', type: String, description: 'Automatically slice for *all* variables (default) or *no* slicing and only parsing/dataflow construction. Numbers will indicate: sample X random slices from all.', defaultValue: 'all', typeLabel: '{underline all/no}' },
23
23
  { name: 'output', alias: 'o', type: String, description: `Folder to write all the measurements to in a per-file-basis (defaults to {italic benchmark-${StartTimeString}})`, defaultValue: `benchmark-${StartTimeString}`, typeLabel: '{underline folder}' },
24
24
  { name: 'parser', type: String, description: 'The parser to use for the benchmark', defaultValue: 'r-shell', typeLabel: '{underline parser}' },
25
+ { name: 'dataframe-shape-inference', type: Boolean, description: 'Infer the shape of data frames using abstract interpretation (includes control flow graph extraction)', defaultValue: false },
25
26
  { name: 'enable-pointer-tracking', type: Boolean, description: 'Run dataflow analysis with pointer tracking', defaultValue: false },
26
27
  { name: 'max-file-slices', type: Number, description: 'If file has more than passed number of slices, the file is not processed', defaultValue: -1, typeLabel: '{underline number}' },
27
28
  { name: 'threshold', alias: 't', type: Number, description: 'How many re-visits of the same node are ok?', defaultValue: undefined, typeLabel: '{underline number}' },
28
29
  { name: 'per-file-time-limit', type: Number, description: 'Time limit in milliseconds to process single file (disabled by default)', defaultValue: undefined, typeLabel: '{underline number}' },
29
30
  { name: 'sampling-strategy', type: String, description: 'Which strategy to use, when sampling is enabled', defaultValue: 'random', typeLabel: '{underline random/equidistant}' },
31
+ { name: 'cfg', alias: 'c', type: Boolean, description: 'Extract the control flow graph of the file (benchmark it too)' }
30
32
  ];
31
33
  exports.benchmarkHelperOptions = [
32
34
  { name: 'verbose', alias: 'v', type: Boolean, description: 'Run with verbose logging [do not use for the real benchmark as this affects the time measurements, but only to find errors]' },
@@ -35,8 +37,10 @@ exports.benchmarkHelperOptions = [
35
37
  { name: 'file-id', alias: 'd', type: Number, description: 'A numeric file id that can be used to match an input and run-num to a file' },
36
38
  { name: 'run-num', alias: 'r', type: Number, description: 'The n-th time that the file with the given file-id is being benchmarked' },
37
39
  { name: 'slice', alias: 's', type: String, description: 'Automatically slice for *all* variables (default) or *no* slicing and only parsing/dataflow construction. Numbers will indicate: sample X random slices from all.', defaultValue: 'all', typeLabel: '{underline all/no}' },
40
+ { name: 'cfg', alias: 'c', type: Boolean, description: 'Extract the control flow graph of the file (benchmark it too)' },
38
41
  { name: 'output', alias: 'o', type: String, description: 'File to write the measurements to (appends a single line in JSON format)', typeLabel: '{underline file}' },
39
42
  { name: 'parser', type: String, description: 'The parser to use for the benchmark', defaultValue: 'r-shell', typeLabel: '{underline parser}' },
43
+ { name: 'dataframe-shape-inference', type: Boolean, description: 'Infer the shape of data frames using abstract interpretation (includes control flow graph extraction)', defaultValue: false },
40
44
  { name: 'enable-pointer-tracking', type: Boolean, description: 'Run dataflow analysis with pointer tracking', defaultValue: false },
41
45
  { name: 'max-slices', type: Number, description: 'If file has more than passed number of slices, the file is not processed', defaultValue: -1, typeLabel: '{underline number}' },
42
46
  { name: 'threshold', alias: 't', type: Number, description: 'How many re-visits of the same node are ok?', defaultValue: undefined, typeLabel: '{underline number}' },
@@ -59,7 +59,7 @@ async function processQueryArgs(line, parser, output, config) {
59
59
  }
60
60
  const processed = await getDataflow(config, parser, args.join(' '));
61
61
  return {
62
- query: (0, query_1.executeQueries)({ dataflow: processed.dataflow, ast: processed.normalize, config: config }, parsedQuery),
62
+ query: await Promise.resolve((0, query_1.executeQueries)({ dataflow: processed.dataflow, ast: processed.normalize, config: config }, parsedQuery)),
63
63
  processed
64
64
  };
65
65
  }
@@ -348,11 +348,20 @@ class FlowRServerConnection {
348
348
  const { dataflow: dfg, normalize: ast } = fileInformation.pipeline.getResults(true);
349
349
  (0, assert_1.guard)(dfg !== undefined, `Dataflow graph must be present (request: ${request.filetoken})`);
350
350
  (0, assert_1.guard)(ast !== undefined, `AST must be present (request: ${request.filetoken})`);
351
- const results = (0, query_1.executeQueries)({ dataflow: dfg, ast, config: this.config }, request.query);
352
- (0, send_1.sendMessage)(this.socket, {
353
- type: 'response-query',
354
- id: request.id,
355
- results
351
+ void Promise.resolve((0, query_1.executeQueries)({ dataflow: dfg, ast, config: this.config }, request.query)).then(results => {
352
+ (0, send_1.sendMessage)(this.socket, {
353
+ type: 'response-query',
354
+ id: request.id,
355
+ results
356
+ });
357
+ }).catch(e => {
358
+ this.logger.error(`[${this.name}] Error while executing query: ${String(e)}`);
359
+ (0, send_1.sendMessage)(this.socket, {
360
+ id: request.id,
361
+ type: 'error',
362
+ fatal: false,
363
+ reason: `Error while executing query: ${String(e)}`
364
+ });
356
365
  });
357
366
  }
358
367
  }
package/config.d.ts CHANGED
@@ -145,6 +145,37 @@ export interface FlowrConfigOptions extends MergeableRecord {
145
145
  readonly threshold?: number;
146
146
  };
147
147
  };
148
+ /**
149
+ * Configuration options for abstract interpretation
150
+ */
151
+ readonly abstractInterpretation: {
152
+ /**
153
+ * The configuration of the shape inference for data frames
154
+ */
155
+ readonly dataFrame: {
156
+ /**
157
+ * The maximum number of columns names to infer for data frames before over-approximating the column names to top
158
+ */
159
+ readonly maxColNames: number;
160
+ /**
161
+ * The threshold for the number of visitations of a node at which widening should be performed to ensure the termination of the fixpoint iteration
162
+ */
163
+ readonly wideningThreshold: number;
164
+ /**
165
+ * Configuration options for reading data frame shapes from loaded external data files, such as CSV files
166
+ */
167
+ readonly readLoadedData: {
168
+ /**
169
+ * Whether data frame shapes should be extracted from loaded external data files, such as CSV files
170
+ */
171
+ readonly readExternalFiles: boolean;
172
+ /**
173
+ * The maximum number of lines to read when extracting data frame shapes from loaded files, such as CSV files
174
+ */
175
+ readonly maxReadLines: number;
176
+ };
177
+ };
178
+ };
148
179
  }
149
180
  export interface TreeSitterEngineConfig extends MergeableRecord {
150
181
  readonly type: 'tree-sitter';
package/config.js CHANGED
@@ -81,6 +81,16 @@ exports.defaultConfigOptions = {
81
81
  slicer: {
82
82
  threshold: 50
83
83
  }
84
+ },
85
+ abstractInterpretation: {
86
+ dataFrame: {
87
+ maxColNames: 50,
88
+ wideningThreshold: 4,
89
+ readLoadedData: {
90
+ readExternalFiles: true,
91
+ maxReadLines: 1e6
92
+ }
93
+ }
84
94
  }
85
95
  };
86
96
  exports.flowrConfigFileSchema = joi_1.default.object({
@@ -120,7 +130,17 @@ exports.flowrConfigFileSchema = joi_1.default.object({
120
130
  slicer: joi_1.default.object({
121
131
  threshold: joi_1.default.number().optional().description('The maximum number of iterations to perform on a single function call during slicing.')
122
132
  }).optional().description('The configuration for the slicer.')
123
- }).description('How to resolve constants, constraints, cells, ...')
133
+ }).description('How to resolve constants, constraints, cells, ...'),
134
+ abstractInterpretation: joi_1.default.object({
135
+ dataFrame: joi_1.default.object({
136
+ maxColNames: joi_1.default.number().min(0).description('The maximum number of columns names to infer for data frames before over-approximating the column names to top.'),
137
+ wideningThreshold: joi_1.default.number().min(1).description('The threshold for the number of visitations of a node at which widening should be performed to ensure the termination of the fixpoint iteration.'),
138
+ readLoadedData: joi_1.default.object({
139
+ readExternalFiles: joi_1.default.boolean().description('Whether data frame shapes should be extracted from loaded external files, such as CSV files.'),
140
+ maxReadLines: joi_1.default.number().min(1).description('The maximum number of lines to read when extracting data frame shapes from loaded files, such as CSV files.')
141
+ }).description('Configuration options for reading data frame shapes from loaded external data files, such as CSV files.')
142
+ }).description('The configuration of the shape inference for data frames.')
143
+ }).description('The configuration options for abstract interpretation.')
124
144
  }).description('The configuration file format for flowR.');
125
145
  function parseConfig(jsonString) {
126
146
  try {
@@ -1,4 +1,4 @@
1
- import type { CfgBasicBlockVertex, CfgEndMarkerVertex, CfgExpressionVertex, CfgMidMarkerVertex, CfgSimpleVertex, CfgStatementVertex, ControlFlowInformation } from './control-flow-graph';
1
+ import type { CfgBasicBlockVertex, CfgEndMarkerVertex, CfgExpressionVertex, CfgSimpleVertex, CfgStatementVertex, 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;
@@ -34,6 +34,5 @@ export declare class BasicCfgGuidedVisitor<ControlFlow extends ControlFlowInform
34
34
  protected onBasicBlockNode(node: CfgBasicBlockVertex): void;
35
35
  protected onStatementNode(_node: CfgStatementVertex): void;
36
36
  protected onExpressionNode(_node: CfgExpressionVertex): void;
37
- protected onMidMarkerNode(_node: CfgMidMarkerVertex): void;
38
37
  protected onEndMarkerNode(_node: CfgEndMarkerVertex): void;
39
38
  }
@@ -72,9 +72,6 @@ class BasicCfgGuidedVisitor {
72
72
  case control_flow_graph_1.CfgVertexType.Expression:
73
73
  this.onExpressionNode(vertex);
74
74
  break;
75
- case control_flow_graph_1.CfgVertexType.MidMarker:
76
- this.onMidMarkerNode(vertex);
77
- break;
78
75
  case control_flow_graph_1.CfgVertexType.EndMarker:
79
76
  this.onEndMarkerNode(vertex);
80
77
  break;
@@ -103,9 +100,6 @@ class BasicCfgGuidedVisitor {
103
100
  onExpressionNode(_node) {
104
101
  /* does nothing by default */
105
102
  }
106
- onMidMarkerNode(_node) {
107
- /* does nothing by default */
108
- }
109
103
  onEndMarkerNode(_node) {
110
104
  /* does nothing by default */
111
105
  }
@@ -1,6 +1,7 @@
1
1
  import type { ControlFlowInformation } from './control-flow-graph';
2
2
  import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
3
3
  import type { DataflowGraph } from '../dataflow/graph/graph';
4
+ import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
4
5
  import { cfgAnalyzeDeadCode } from './cfg-dead-code';
5
6
  import type { FlowrConfigOptions } from '../config';
6
7
  export interface CfgPassInfo {
@@ -28,4 +29,9 @@ export declare function simplifyControlFlowInformation(cfg: ControlFlowInformati
28
29
  declare function cfgRemoveDeadCode(cfg: ControlFlowInformation, _info?: CfgPassInfo): ControlFlowInformation;
29
30
  declare function uniqueControlFlowSets(cfg: ControlFlowInformation, _info?: CfgPassInfo): ControlFlowInformation;
30
31
  declare function toBasicBlocks(cfg: ControlFlowInformation, _info?: CfgPassInfo): ControlFlowInformation;
32
+ /**
33
+ * Uses {@link visitCfgInOrder} to find all nodes that are reachable from the control flow graph's {@link ControlFlowInformation.entryPoints} and returns them as a set.
34
+ * @param cfg - The control flow graph whose reachable nodes to find.
35
+ */
36
+ export declare function cfgFindAllReachable(cfg: ControlFlowInformation): Set<NodeId>;
31
37
  export {};
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DefaultCfgSimplificationOrder = exports.CfgSimplificationPasses = void 0;
4
4
  exports.simplifyControlFlowInformation = simplifyControlFlowInformation;
5
+ exports.cfgFindAllReachable = cfgFindAllReachable;
5
6
  const cfg_to_basic_blocks_1 = require("./cfg-to-basic-blocks");
6
7
  const simple_visitor_1 = require("./simple-visitor");
7
8
  const cfg_dead_code_1 = require("./cfg-dead-code");
@@ -32,10 +33,7 @@ function simplifyControlFlowInformation(cfg, info, passes = exports.DefaultCfgSi
32
33
  */
33
34
  function cfgRemoveDeadCode(cfg, _info) {
34
35
  // remove every root level node and accompanying vertices that can not be reached from the entry points
35
- const reachable = new Set();
36
- (0, simple_visitor_1.visitCfgInOrder)(cfg.graph, cfg.entryPoints, node => {
37
- reachable.add(node);
38
- });
36
+ const reachable = cfgFindAllReachable(cfg);
39
37
  for (const id of cfg.graph.rootIds()) {
40
38
  if (!reachable.has(id)) {
41
39
  cfg.graph.removeVertex(id);
@@ -45,15 +43,26 @@ function cfgRemoveDeadCode(cfg, _info) {
45
43
  }
46
44
  function uniqueControlFlowSets(cfg, _info) {
47
45
  return {
48
- returns: [...new Set(cfg.returns)],
49
- entryPoints: [...new Set(cfg.entryPoints)],
50
- exitPoints: [...new Set(cfg.exitPoints)],
51
- breaks: [...new Set(cfg.breaks)],
52
- nexts: [...new Set(cfg.nexts)],
46
+ returns: Array.from(new Set(cfg.returns)),
47
+ entryPoints: Array.from(new Set(cfg.entryPoints)),
48
+ exitPoints: Array.from(new Set(cfg.exitPoints)),
49
+ breaks: Array.from(new Set(cfg.breaks)),
50
+ nexts: Array.from(new Set(cfg.nexts)),
53
51
  graph: cfg.graph
54
52
  };
55
53
  }
56
54
  function toBasicBlocks(cfg, _info) {
57
55
  return (0, cfg_to_basic_blocks_1.convertCfgToBasicBlocks)(cfg);
58
56
  }
57
+ /**
58
+ * Uses {@link visitCfgInOrder} to find all nodes that are reachable from the control flow graph's {@link ControlFlowInformation.entryPoints} and returns them as a set.
59
+ * @param cfg - The control flow graph whose reachable nodes to find.
60
+ */
61
+ function cfgFindAllReachable(cfg) {
62
+ const reachable = new Set();
63
+ (0, simple_visitor_1.visitCfgInOrder)(cfg.graph, cfg.entryPoints, node => {
64
+ reachable.add(node);
65
+ });
66
+ return reachable;
67
+ }
59
68
  //# sourceMappingURL=cfg-simplification.js.map
@@ -2,8 +2,6 @@ import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
2
2
  import type { MergeableRecord } from '../util/objects';
3
3
  import type { RFalse, RTrue } from '../r-bridge/lang-4.x/convert-values';
4
4
  export declare enum CfgVertexType {
5
- /** Marks a break point in a construct (e.g., between the name and the value of an argument, or the formals and the body of a function) */
6
- MidMarker = "mid",
7
5
  /** The explicit exit-nodes to ensure the hammock property */
8
6
  EndMarker = "end",
9
7
  /** something like an if, assignment, ... even though in the classical sense of R they are still expressions */
@@ -50,10 +48,6 @@ export interface CfgWithRoot extends CfgBaseVertex {
50
48
  /** the vertex for which this is a marker */
51
49
  root: NodeId;
52
50
  }
53
- export interface CfgMidMarkerVertex extends CfgWithRoot {
54
- type: CfgVertexType.MidMarker;
55
- kind: string;
56
- }
57
51
  export interface CfgEndMarkerVertex extends CfgWithRoot {
58
52
  type: CfgVertexType.EndMarker;
59
53
  }
@@ -65,9 +59,10 @@ export interface CfgBasicBlockVertex extends CfgBaseVertex {
65
59
  /**
66
60
  * A vertex in the {@link ControlFlowGraph}.
67
61
  */
68
- export type CfgSimpleVertex = CfgStatementVertex | CfgExpressionVertex | CfgBasicBlockVertex | CfgMidMarkerVertex | CfgEndMarkerVertex;
62
+ export type CfgSimpleVertex = CfgStatementVertex | CfgExpressionVertex | CfgBasicBlockVertex | CfgEndMarkerVertex;
69
63
  export declare function equalVertex(a: CfgSimpleVertex, b: CfgSimpleVertex): boolean;
70
- export declare function isMarkerVertex(vertex: CfgSimpleVertex): vertex is CfgMidMarkerVertex | CfgEndMarkerVertex;
64
+ export declare function isMarkerVertex(vertex: CfgSimpleVertex): vertex is CfgEndMarkerVertex;
65
+ export declare function getVertexRootId(vertex: CfgSimpleVertex): NodeId;
71
66
  interface CfgFlowDependencyEdge extends MergeableRecord {
72
67
  label: CfgEdgeType.Fd;
73
68
  }
@@ -4,12 +4,11 @@ exports.ControlFlowGraph = exports.CfgVertexType = void 0;
4
4
  exports.edgeTypeToString = edgeTypeToString;
5
5
  exports.equalVertex = equalVertex;
6
6
  exports.isMarkerVertex = isMarkerVertex;
7
+ exports.getVertexRootId = getVertexRootId;
7
8
  exports.emptyControlFlowInformation = emptyControlFlowInformation;
8
9
  const assert_1 = require("../util/assert");
9
10
  var CfgVertexType;
10
11
  (function (CfgVertexType) {
11
- /** Marks a break point in a construct (e.g., between the name and the value of an argument, or the formals and the body of a function) */
12
- CfgVertexType["MidMarker"] = "mid";
13
12
  /** The explicit exit-nodes to ensure the hammock property */
14
13
  CfgVertexType["EndMarker"] = "end";
15
14
  /** something like an if, assignment, ... even though in the classical sense of R they are still expressions */
@@ -36,16 +35,16 @@ function equalVertex(a, b) {
36
35
  else if (a.type === CfgVertexType.Block && b.type === CfgVertexType.Block) {
37
36
  return a.elems.length === b.elems.length && a.elems.every((e, i) => e.id === b.elems[i].id);
38
37
  }
39
- else if (a.type === CfgVertexType.MidMarker && b.type === CfgVertexType.MidMarker) {
40
- return a.kind === b.kind && a.root === b.root;
41
- }
42
38
  else if (a.type === CfgVertexType.EndMarker && b.type === CfgVertexType.EndMarker) {
43
39
  return a.root === b.root;
44
40
  }
45
41
  return true;
46
42
  }
47
43
  function isMarkerVertex(vertex) {
48
- return vertex.type === CfgVertexType.MidMarker || vertex.type === CfgVertexType.EndMarker;
44
+ return vertex.type === CfgVertexType.EndMarker;
45
+ }
46
+ function getVertexRootId(vertex) {
47
+ return isMarkerVertex(vertex) ? vertex.root : vertex.id;
49
48
  }
50
49
  /**
51
50
  * This class represents the control flow graph of an R program.
@@ -36,7 +36,7 @@ class DataflowAwareCfgGuidedVisitor extends basic_cfg_guided_visitor_1.BasicCfgG
36
36
  }
37
37
  }
38
38
  visitDataflowNode(node) {
39
- const dfgVertex = this.getDataflowGraph((0, control_flow_graph_1.isMarkerVertex)(node) ? node.root : node.id);
39
+ const dfgVertex = this.getDataflowGraph((0, control_flow_graph_1.getVertexRootId)(node));
40
40
  if (!dfgVertex) {
41
41
  this.visitUnknown(node);
42
42
  return;
@@ -5,12 +5,12 @@ import type { ControlFlowInformation } from './control-flow-graph';
5
5
  import type { CfgSimplificationPassName } from './cfg-simplification';
6
6
  import type { FlowrConfigOptions } from '../config';
7
7
  /**
8
- * Given a normalized AST this approximates the control flow graph of the program.
8
+ * Given a normalized AST, this approximates the control flow graph of the program.
9
9
  * This view is different from the computation of the dataflow graph and may differ,
10
10
  * especially because it focuses on intra-procedural analysis.
11
11
  *
12
12
  * @param ast - the normalized AST
13
- * @param config - the Flowr config
13
+ * @param config - the flowR 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
  *