@eagleoutice/flowr 2.2.11 → 2.2.13

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 (301) hide show
  1. package/README.md +82 -20
  2. package/benchmark/slicer.d.ts +49 -22
  3. package/benchmark/slicer.js +89 -29
  4. package/benchmark/stats/print.js +16 -10
  5. package/benchmark/stats/size-of.js +18 -1
  6. package/benchmark/stats/stats.d.ts +3 -0
  7. package/benchmark/summarizer/first-phase/input.js +1 -1
  8. package/benchmark/summarizer/first-phase/process.js +3 -3
  9. package/benchmark/summarizer/second-phase/process.js +9 -3
  10. package/benchmark/summarizer/summarizer.js +1 -1
  11. package/cli/benchmark-app.d.ts +5 -0
  12. package/cli/benchmark-app.js +49 -6
  13. package/cli/benchmark-helper-app.d.ts +4 -0
  14. package/cli/benchmark-helper-app.js +20 -4
  15. package/cli/common/options.js +15 -6
  16. package/cli/common/script.js +1 -1
  17. package/cli/flowr.js +1 -1
  18. package/cli/repl/commands/repl-cfg.d.ts +2 -0
  19. package/cli/repl/commands/repl-cfg.js +38 -24
  20. package/cli/repl/commands/repl-commands.js +6 -2
  21. package/cli/repl/commands/repl-dataflow.d.ts +2 -0
  22. package/cli/repl/commands/repl-dataflow.js +37 -3
  23. package/cli/repl/commands/repl-execute.js +1 -1
  24. package/cli/repl/commands/repl-main.d.ts +1 -1
  25. package/cli/repl/commands/repl-main.js +1 -1
  26. package/cli/repl/commands/repl-normalize.js +1 -1
  27. package/cli/repl/commands/repl-query.js +2 -2
  28. package/cli/repl/core.js +1 -1
  29. package/cli/repl/prompt.js +1 -1
  30. package/cli/repl/server/connection.js +4 -4
  31. package/cli/repl/server/messages/message-analysis.d.ts +1 -1
  32. package/cli/script-core/statistics-core.js +1 -1
  33. package/cli/script-core/statistics-helper-core.js +4 -4
  34. package/config.d.ts +60 -21
  35. package/config.js +24 -4
  36. package/control-flow/basic-cfg-guided-visitor.d.ts +39 -0
  37. package/control-flow/basic-cfg-guided-visitor.js +114 -0
  38. package/control-flow/cfg-properties.d.ts +26 -0
  39. package/control-flow/cfg-properties.js +100 -0
  40. package/control-flow/cfg-simplification.d.ts +18 -0
  41. package/control-flow/cfg-simplification.js +55 -0
  42. package/control-flow/cfg-to-basic-blocks.d.ts +5 -0
  43. package/control-flow/cfg-to-basic-blocks.js +81 -0
  44. package/control-flow/control-flow-graph.d.ts +247 -0
  45. package/control-flow/control-flow-graph.js +290 -0
  46. package/control-flow/dfg-cfg-guided-visitor.d.ts +32 -0
  47. package/control-flow/dfg-cfg-guided-visitor.js +71 -0
  48. package/control-flow/diff-cfg.d.ts +11 -0
  49. package/control-flow/diff-cfg.js +161 -0
  50. package/control-flow/extract-cfg.d.ts +30 -0
  51. package/control-flow/extract-cfg.js +475 -0
  52. package/control-flow/happens-before.d.ts +7 -0
  53. package/{util/cfg → control-flow}/happens-before.js +3 -3
  54. package/control-flow/semantic-cfg-guided-visitor.d.ts +452 -0
  55. package/control-flow/semantic-cfg-guided-visitor.js +492 -0
  56. package/control-flow/simple-visitor.d.ts +25 -0
  57. package/control-flow/simple-visitor.js +80 -0
  58. package/control-flow/syntax-cfg-guided-visitor.d.ts +128 -0
  59. package/control-flow/syntax-cfg-guided-visitor.js +166 -0
  60. package/core/print/print.d.ts +1 -1
  61. package/core/print/slice-diff-ansi.js +1 -1
  62. package/core/steps/pipeline/create-pipeline.js +1 -1
  63. package/dataflow/environments/built-in-config.d.ts +5 -2
  64. package/dataflow/environments/built-in-config.js +17 -8
  65. package/dataflow/environments/built-in.d.ts +16 -5
  66. package/dataflow/environments/built-in.js +55 -6
  67. package/dataflow/environments/clone.d.ts +5 -0
  68. package/dataflow/environments/clone.js +5 -0
  69. package/dataflow/environments/default-builtin-config.d.ts +2 -0
  70. package/dataflow/environments/default-builtin-config.js +164 -13
  71. package/dataflow/environments/define.d.ts +5 -1
  72. package/dataflow/environments/define.js +36 -10
  73. package/dataflow/environments/overwrite.js +4 -0
  74. package/dataflow/environments/remove.d.ts +6 -0
  75. package/dataflow/environments/remove.js +24 -0
  76. package/dataflow/environments/resolve-by-name.js +16 -5
  77. package/dataflow/extractor.js +2 -2
  78. package/dataflow/graph/dataflowgraph-builder.d.ts +79 -7
  79. package/dataflow/graph/dataflowgraph-builder.js +106 -8
  80. package/dataflow/graph/diff-dataflow-graph.d.ts +16 -0
  81. package/dataflow/graph/{diff.js → diff-dataflow-graph.js} +30 -56
  82. package/dataflow/graph/graph.d.ts +17 -4
  83. package/dataflow/graph/graph.js +51 -12
  84. package/dataflow/graph/vertex.d.ts +59 -4
  85. package/dataflow/graph/vertex.js +32 -0
  86. package/dataflow/internal/linker.d.ts +3 -2
  87. package/dataflow/internal/linker.js +36 -25
  88. package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +1 -1
  89. package/dataflow/internal/process/functions/call/argument/unpack-argument.js +1 -1
  90. package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +1 -0
  91. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +67 -54
  92. package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +6 -4
  93. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +108 -21
  94. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +54 -17
  95. package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +10 -0
  96. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +140 -0
  97. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +9 -4
  98. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +3 -2
  99. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +15 -4
  100. package/dataflow/internal/process/functions/call/built-in/built-in-get.js +4 -3
  101. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
  102. package/dataflow/internal/process/functions/call/built-in/built-in-library.js +4 -3
  103. package/dataflow/internal/process/functions/call/built-in/built-in-list.js +51 -17
  104. package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +1 -1
  105. package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +9 -7
  106. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +3 -2
  107. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +4 -0
  108. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +100 -31
  109. package/dataflow/internal/process/functions/call/built-in/built-in-rm.d.ts +7 -0
  110. package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +41 -0
  111. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +35 -8
  112. package/dataflow/internal/process/functions/call/built-in/built-in-special-bin-op.js +4 -3
  113. package/dataflow/internal/process/functions/call/built-in/built-in-vector.d.ts +15 -0
  114. package/dataflow/internal/process/functions/call/built-in/built-in-vector.js +75 -0
  115. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +3 -3
  116. package/dataflow/internal/process/functions/call/common.d.ts +5 -2
  117. package/dataflow/internal/process/functions/call/common.js +9 -5
  118. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +3 -2
  119. package/dataflow/internal/process/functions/call/known-call-handling.js +2 -1
  120. package/dataflow/internal/process/functions/call/named-call-handling.d.ts +2 -0
  121. package/dataflow/internal/process/functions/call/named-call-handling.js +10 -6
  122. package/dataflow/internal/process/functions/call/unnamed-call-handling.d.ts +1 -0
  123. package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
  124. package/dataflow/internal/process/process-named-call.d.ts +4 -1
  125. package/dataflow/internal/process/process-named-call.js +8 -5
  126. package/dataflow/origin/dfg-get-origin.d.ts +82 -0
  127. package/dataflow/origin/dfg-get-origin.js +116 -0
  128. package/documentation/doc-util/doc-cfg.d.ts +20 -4
  129. package/documentation/doc-util/doc-cfg.js +41 -7
  130. package/documentation/doc-util/doc-cli-option.js +4 -2
  131. package/documentation/doc-util/doc-code.js +10 -2
  132. package/documentation/doc-util/doc-dfg.js +3 -3
  133. package/documentation/doc-util/doc-escape.d.ts +7 -0
  134. package/documentation/doc-util/doc-escape.js +19 -0
  135. package/documentation/doc-util/doc-files.d.ts +1 -0
  136. package/documentation/doc-util/doc-files.js +2 -1
  137. package/documentation/doc-util/doc-normalized-ast.js +3 -3
  138. package/documentation/doc-util/doc-query.js +2 -2
  139. package/documentation/doc-util/doc-repl.js +1 -1
  140. package/documentation/doc-util/doc-search.js +1 -1
  141. package/documentation/doc-util/doc-server-message.js +2 -2
  142. package/documentation/doc-util/doc-structure.d.ts +1 -0
  143. package/documentation/doc-util/doc-structure.js +5 -0
  144. package/documentation/doc-util/doc-types.d.ts +7 -1
  145. package/documentation/doc-util/doc-types.js +13 -2
  146. package/documentation/print-capabilities-markdown.js +28 -2
  147. package/documentation/print-cfg-wiki.d.ts +1 -0
  148. package/documentation/print-cfg-wiki.js +572 -0
  149. package/documentation/print-core-wiki.js +2 -2
  150. package/documentation/print-dataflow-graph-wiki.js +180 -25
  151. package/documentation/print-engines-wiki.js +1 -1
  152. package/documentation/print-faq-wiki.d.ts +1 -0
  153. package/documentation/print-faq-wiki.js +75 -0
  154. package/documentation/print-interface-wiki.js +2 -1
  155. package/documentation/print-linting-and-testing-wiki.js +52 -36
  156. package/documentation/print-normalized-ast-wiki.js +1 -1
  157. package/documentation/print-onboarding-wiki.d.ts +1 -0
  158. package/documentation/print-onboarding-wiki.js +42 -0
  159. package/documentation/print-query-wiki.js +23 -3
  160. package/documentation/print-readme.js +10 -3
  161. package/package.json +10 -6
  162. package/queries/catalog/call-context-query/call-context-query-executor.js +5 -5
  163. package/queries/catalog/call-context-query/call-context-query-format.d.ts +1 -1
  164. package/queries/catalog/call-context-query/call-context-query-format.js +2 -2
  165. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -2
  166. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +24 -21
  167. package/queries/catalog/cluster-query/cluster-query-format.d.ts +1 -1
  168. package/queries/catalog/cluster-query/cluster-query-format.js +1 -1
  169. package/queries/catalog/config-query/config-query-format.d.ts +1 -1
  170. package/queries/catalog/config-query/config-query-format.js +2 -2
  171. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +1 -1
  172. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +2 -2
  173. package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +1 -1
  174. package/queries/catalog/dataflow-query/dataflow-query-format.js +2 -2
  175. package/queries/catalog/dependencies-query/dependencies-query-executor.js +17 -7
  176. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +2 -26
  177. package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -147
  178. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +24 -0
  179. package/queries/catalog/dependencies-query/function-info/function-info.js +10 -0
  180. package/queries/catalog/dependencies-query/function-info/library-functions.d.ts +2 -0
  181. package/queries/catalog/dependencies-query/function-info/library-functions.js +18 -0
  182. package/queries/catalog/dependencies-query/function-info/read-functions.d.ts +2 -0
  183. package/queries/catalog/dependencies-query/function-info/read-functions.js +101 -0
  184. package/queries/catalog/dependencies-query/function-info/source-functions.d.ts +2 -0
  185. package/queries/catalog/dependencies-query/function-info/source-functions.js +11 -0
  186. package/queries/catalog/dependencies-query/function-info/write-functions.d.ts +2 -0
  187. package/queries/catalog/dependencies-query/function-info/write-functions.js +87 -0
  188. package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +1 -1
  189. package/queries/catalog/happens-before-query/happens-before-query-executor.js +4 -4
  190. package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +1 -1
  191. package/queries/catalog/happens-before-query/happens-before-query-format.js +2 -2
  192. package/queries/catalog/id-map-query/id-map-query-format.d.ts +1 -1
  193. package/queries/catalog/id-map-query/id-map-query-format.js +2 -2
  194. package/queries/catalog/lineage-query/lineage-query-format.d.ts +1 -1
  195. package/queries/catalog/lineage-query/lineage-query-format.js +2 -2
  196. package/queries/catalog/location-map-query/location-map-query-format.d.ts +1 -1
  197. package/queries/catalog/location-map-query/location-map-query-format.js +2 -2
  198. package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +1 -1
  199. package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +2 -2
  200. package/queries/catalog/origin-query/origin-query-executor.d.ts +5 -0
  201. package/queries/catalog/origin-query/origin-query-executor.js +33 -0
  202. package/queries/catalog/origin-query/origin-query-format.d.ts +71 -0
  203. package/queries/catalog/origin-query/origin-query-format.js +27 -0
  204. package/queries/catalog/project-query/project-query-format.d.ts +1 -1
  205. package/queries/catalog/project-query/project-query-format.js +2 -2
  206. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +1 -1
  207. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -2
  208. package/queries/catalog/search-query/search-query-format.d.ts +1 -1
  209. package/queries/catalog/search-query/search-query-format.js +2 -2
  210. package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +1 -1
  211. package/queries/catalog/static-slice-query/static-slice-query-format.js +2 -2
  212. package/queries/query-print.d.ts +1 -1
  213. package/queries/query-print.js +4 -4
  214. package/queries/query.d.ts +61 -2
  215. package/queries/query.js +3 -1
  216. package/r-bridge/data/data.d.ts +2 -2
  217. package/r-bridge/data/data.js +2 -2
  218. package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +3 -2
  219. package/r-bridge/lang-4.x/ast/model/nodes/r-number.js +5 -0
  220. package/r-bridge/lang-4.x/ast/model/nodes/r-string.d.ts +3 -2
  221. package/r-bridge/lang-4.x/ast/model/nodes/r-string.js +5 -0
  222. package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +1 -1
  223. package/r-bridge/lang-4.x/ast/model/processing/decorate.js +1 -1
  224. package/r-bridge/lang-4.x/ast/model/processing/fold.js +3 -1
  225. package/r-bridge/lang-4.x/ast/model/processing/stateful-fold.d.ts +1 -1
  226. package/r-bridge/lang-4.x/ast/parser/main/internal/expression/normalize-expression.js +1 -1
  227. package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-argument.js +1 -1
  228. package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-call.js +1 -1
  229. package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-definition.js +1 -1
  230. package/r-bridge/lang-4.x/ast/parser/main/internal/normalize-access.js +1 -1
  231. package/r-bridge/lang-4.x/ast/parser/main/internal/operators/normalize-binary.js +1 -1
  232. package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.js +1 -1
  233. package/r-bridge/lang-4.x/ast/parser/main/internal/values/normalize-symbol.js +1 -1
  234. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.d.ts +2 -2
  235. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +4 -4
  236. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +26 -8
  237. package/r-bridge/retriever.js +1 -1
  238. package/search/search-executor/search-generators.d.ts +1 -1
  239. package/search/search-executor/search-transformer.d.ts +1 -1
  240. package/slicing/criterion/collect-all.js +1 -1
  241. package/slicing/static/slice-call.js +13 -3
  242. package/statistics/features/supported/assignments/post-process.js +1 -1
  243. package/statistics/features/supported/defined-functions/post-process.js +2 -2
  244. package/statistics/features/supported/used-functions/post-process.js +1 -1
  245. package/statistics/features/supported/used-packages/post-process.js +2 -2
  246. package/statistics/features/supported/values/post-process.js +2 -2
  247. package/statistics/output/print-stats.js +2 -2
  248. package/statistics/summarizer/post-process/clusterer.d.ts +1 -1
  249. package/statistics/summarizer/post-process/clusterer.js +1 -1
  250. package/statistics/summarizer/post-process/histogram.js +3 -3
  251. package/statistics/summarizer/post-process/post-process-output.js +3 -3
  252. package/statistics/summarizer/second-phase/process.js +2 -2
  253. package/statistics/summarizer/summarizer.js +2 -2
  254. package/util/assert.js +36 -1
  255. package/util/cfg/cfg.d.ts +0 -80
  256. package/util/cfg/cfg.js +0 -549
  257. package/util/{arrays.d.ts → collections/arrays.d.ts} +24 -1
  258. package/util/{arrays.js → collections/arrays.js} +44 -3
  259. package/util/collections/set.js +17 -0
  260. package/util/{list-access.d.ts → containers.d.ts} +24 -4
  261. package/util/{list-access.js → containers.js} +42 -12
  262. package/util/diff-graph.d.ts +47 -0
  263. package/util/diff-graph.js +61 -0
  264. package/util/diff.d.ts +6 -6
  265. package/util/diff.js +1 -1
  266. package/util/mermaid/ast.js +12 -1
  267. package/util/mermaid/cfg.d.ts +9 -2
  268. package/util/mermaid/cfg.js +65 -13
  269. package/util/mermaid/dfg.d.ts +2 -1
  270. package/util/mermaid/dfg.js +26 -10
  271. package/util/mermaid/mermaid.d.ts +2 -0
  272. package/util/mermaid/mermaid.js +6 -0
  273. package/util/parallel.d.ts +2 -1
  274. package/util/parallel.js +11 -2
  275. package/util/prefix.d.ts +13 -0
  276. package/util/prefix.js +34 -0
  277. package/util/quads.js +1 -1
  278. package/util/schema.d.ts +1 -1
  279. package/util/schema.js +1 -1
  280. package/util/summarizer.js +1 -1
  281. package/util/{text.js → text/text.js} +1 -1
  282. package/util/{time.js → text/time.js} +1 -1
  283. package/util/version.js +1 -1
  284. package/dataflow/graph/diff.d.ts +0 -36
  285. package/util/cfg/happens-before.d.ts +0 -7
  286. package/util/cfg/visitor.d.ts +0 -9
  287. package/util/cfg/visitor.js +0 -30
  288. package/util/set.js +0 -31
  289. /package/util/{bimap.d.ts → collections/bimap.d.ts} +0 -0
  290. /package/util/{bimap.js → collections/bimap.js} +0 -0
  291. /package/util/{defaultmap.d.ts → collections/defaultmap.d.ts} +0 -0
  292. /package/util/{defaultmap.js → collections/defaultmap.js} +0 -0
  293. /package/util/{set.d.ts → collections/set.d.ts} +0 -0
  294. /package/util/{ansi.d.ts → text/ansi.d.ts} +0 -0
  295. /package/util/{ansi.js → text/ansi.js} +0 -0
  296. /package/util/{args.d.ts → text/args.d.ts} +0 -0
  297. /package/util/{args.js → text/args.js} +0 -0
  298. /package/util/{strings.d.ts → text/strings.d.ts} +0 -0
  299. /package/util/{strings.js → text/strings.js} +0 -0
  300. /package/util/{text.d.ts → text/text.d.ts} +0 -0
  301. /package/util/{time.d.ts → text/time.d.ts} +0 -0
package/util/cfg/cfg.js CHANGED
@@ -1,551 +1,2 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ControlFlowGraph = void 0;
4
- exports.emptyControlFlowInformation = emptyControlFlowInformation;
5
- exports.extractCFG = extractCFG;
6
- exports.equalCfg = equalCfg;
7
- exports.cfg2quads = cfg2quads;
8
- const set_1 = require("../set");
9
- const quads_1 = require("../quads");
10
- const log_1 = require("../log");
11
- const json_1 = require("../json");
12
- const fold_1 = require("../../r-bridge/lang-4.x/ast/model/processing/fold");
13
- const convert_values_1 = require("../../r-bridge/lang-4.x/convert-values");
14
- const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
15
- const linker_1 = require("../../dataflow/internal/linker");
16
- const vertex_1 = require("../../dataflow/graph/vertex");
17
- /**
18
- * This class represents the control flow graph of an R program.
19
- * The control flow may be hierarchical when confronted with function definitions (see {@link CfgVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
20
- */
21
- class ControlFlowGraph {
22
- rootVertices = new Set();
23
- vertexInformation = new Map();
24
- edgeInformation = new Map();
25
- addVertex(vertex, rootVertex = true) {
26
- if (this.vertexInformation.has(vertex.id)) {
27
- throw new Error(`Node with id ${vertex.id} already exists`);
28
- }
29
- this.vertexInformation.set(vertex.id, vertex);
30
- if (rootVertex) {
31
- this.rootVertices.add(vertex.id);
32
- }
33
- return this;
34
- }
35
- addEdge(from, to, edge) {
36
- if (!this.edgeInformation.has(from)) {
37
- this.edgeInformation.set(from, new Map());
38
- }
39
- this.edgeInformation.get(from)?.set(to, edge);
40
- return this;
41
- }
42
- outgoing(node) {
43
- return this.edgeInformation.get(node);
44
- }
45
- rootVertexIds() {
46
- return this.rootVertices;
47
- }
48
- vertices() {
49
- return this.vertexInformation;
50
- }
51
- edges() {
52
- return this.edgeInformation;
53
- }
54
- merge(other, forceNested = false) {
55
- for (const [id, node] of other.vertexInformation) {
56
- this.addVertex(node, forceNested ? false : other.rootVertices.has(id));
57
- }
58
- for (const [from, edges] of other.edgeInformation) {
59
- for (const [to, edge] of edges) {
60
- this.addEdge(from, to, edge);
61
- }
62
- }
63
- return this;
64
- }
65
- }
66
- exports.ControlFlowGraph = ControlFlowGraph;
67
- function emptyControlFlowInformation() {
68
- return {
69
- returns: [],
70
- breaks: [],
71
- nexts: [],
72
- entryPoints: [],
73
- exitPoints: [],
74
- graph: new ControlFlowGraph()
75
- };
76
- }
77
- const cfgFolds = {
78
- foldNumber: cfgLeaf("expression" /* CfgVertexType.Expression */),
79
- foldString: cfgLeaf("expression" /* CfgVertexType.Expression */),
80
- foldLogical: cfgLeaf("expression" /* CfgVertexType.Expression */),
81
- foldSymbol: cfgLeaf("expression" /* CfgVertexType.Expression */),
82
- foldAccess: cfgAccess,
83
- foldBinaryOp: cfgBinaryOp,
84
- foldPipe: cfgBinaryOp,
85
- foldUnaryOp: cfgUnaryOp,
86
- other: {
87
- foldComment: cfgIgnore,
88
- foldLineDirective: cfgIgnore
89
- },
90
- loop: {
91
- foldFor: cfgFor,
92
- foldRepeat: cfgRepeat,
93
- foldWhile: cfgWhile,
94
- foldBreak: cfgBreak,
95
- foldNext: cfgNext
96
- },
97
- foldIfThenElse: cfgIfThenElse,
98
- foldExprList: cfgExprList,
99
- functions: {
100
- foldFunctionDefinition: cfgFunctionDefinition,
101
- foldFunctionCall: cfgFunctionCall,
102
- foldParameter: cfgArgumentOrParameter,
103
- foldArgument: cfgArgumentOrParameter
104
- }
105
- };
106
- function dataflowCfgFolds(dataflowGraph) {
107
- return {
108
- ...cfgFolds,
109
- functions: {
110
- ...cfgFolds.functions,
111
- foldFunctionCall: cfgFunctionCallWithDataflow(dataflowGraph)
112
- }
113
- };
114
- }
115
- /**
116
- * Given a normalized AST this approximates the control flow graph of the program.
117
- * This few is different from the computation of the dataflow graph and may differ,
118
- * especially because it focuses on intra-procedural analysis.
119
- *
120
- * @param ast - the normalized AST
121
- * @param graph - additional dataflow facts to consider by the control flow extraction
122
- */
123
- function extractCFG(ast, graph) {
124
- return (0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds);
125
- }
126
- function cfgLeaf(type) {
127
- return (leaf) => {
128
- const graph = new ControlFlowGraph();
129
- graph.addVertex({ id: leaf.info.id, name: leaf.type, type });
130
- return { graph, breaks: [], nexts: [], returns: [], exitPoints: [leaf.info.id], entryPoints: [leaf.info.id] };
131
- };
132
- }
133
- function cfgBreak(leaf) {
134
- return { ...cfgLeaf("statement" /* CfgVertexType.Statement */)(leaf), breaks: [leaf.info.id] };
135
- }
136
- function cfgNext(leaf) {
137
- return { ...cfgLeaf("statement" /* CfgVertexType.Statement */)(leaf), nexts: [leaf.info.id] };
138
- }
139
- function cfgIgnore(_leaf) {
140
- return { graph: new ControlFlowGraph(), breaks: [], nexts: [], returns: [], exitPoints: [], entryPoints: [] };
141
- }
142
- function identifyMayStatementType(node) {
143
- return node.info.role === "expr-list-child" /* RoleInParent.ExpressionListChild */ ? "statement" /* CfgVertexType.Statement */ : "expression" /* CfgVertexType.Expression */;
144
- }
145
- function cfgIfThenElse(ifNode, condition, then, otherwise) {
146
- const graph = new ControlFlowGraph();
147
- graph.addVertex({ id: ifNode.info.id, name: ifNode.type, type: identifyMayStatementType(ifNode) });
148
- graph.addVertex({ id: ifNode.info.id + '-exit', name: 'if-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
149
- graph.merge(condition.graph);
150
- graph.merge(then.graph);
151
- if (otherwise) {
152
- graph.merge(otherwise.graph);
153
- }
154
- for (const exitPoint of condition.exitPoints) {
155
- for (const entryPoint of then.entryPoints) {
156
- graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RTrue, caused: ifNode.info.id });
157
- }
158
- for (const entryPoint of otherwise?.entryPoints ?? []) {
159
- graph.addEdge(entryPoint, exitPoint, { label: 'CD', when: convert_values_1.RFalse, caused: ifNode.info.id });
160
- }
161
- }
162
- for (const entryPoint of condition.entryPoints) {
163
- graph.addEdge(entryPoint, ifNode.info.id, { label: 'FD' });
164
- }
165
- for (const exit of [...then.exitPoints, ...otherwise?.exitPoints ?? []]) {
166
- graph.addEdge(ifNode.info.id + '-exit', exit, { label: 'FD' });
167
- }
168
- if (!otherwise) {
169
- for (const exitPoint of condition.exitPoints) {
170
- graph.addEdge(ifNode.info.id + '-exit', exitPoint, { label: 'CD', when: convert_values_1.RFalse, caused: ifNode.info.id });
171
- }
172
- }
173
- return {
174
- graph,
175
- breaks: [...then.breaks, ...otherwise?.breaks ?? []],
176
- nexts: [...then.nexts, ...otherwise?.nexts ?? []],
177
- returns: [...then.returns, ...otherwise?.returns ?? []],
178
- exitPoints: [ifNode.info.id + '-exit'],
179
- entryPoints: [ifNode.info.id]
180
- };
181
- }
182
- function cfgRepeat(repeat, body) {
183
- const graph = body.graph;
184
- graph.addVertex({ id: repeat.info.id, name: repeat.type, type: identifyMayStatementType(repeat) });
185
- graph.addVertex({ id: repeat.info.id + '-exit', name: 'repeat-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
186
- for (const entryPoint of body.entryPoints) {
187
- graph.addEdge(entryPoint, repeat.info.id, { label: 'FD' });
188
- }
189
- // loops automatically
190
- for (const next of [...body.nexts, ...body.exitPoints]) {
191
- graph.addEdge(repeat.info.id, next, { label: 'FD' });
192
- }
193
- for (const breakPoint of body.breaks) {
194
- graph.addEdge(repeat.info.id + '-exit', breakPoint, { label: 'FD' });
195
- }
196
- return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [repeat.info.id + '-exit'], entryPoints: [repeat.info.id] };
197
- }
198
- function cfgWhile(whileLoop, condition, body) {
199
- const graph = condition.graph;
200
- graph.addVertex({ id: whileLoop.info.id, name: whileLoop.type, type: identifyMayStatementType(whileLoop) });
201
- graph.addVertex({ id: whileLoop.info.id + '-exit', name: 'while-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
202
- graph.merge(body.graph);
203
- for (const entry of condition.entryPoints) {
204
- graph.addEdge(entry, whileLoop.info.id, { label: 'FD' });
205
- }
206
- for (const exit of condition.exitPoints) {
207
- for (const entry of body.entryPoints) {
208
- graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue, caused: whileLoop.info.id });
209
- }
210
- }
211
- for (const entryPoint of body.entryPoints) {
212
- graph.addEdge(whileLoop.info.id, entryPoint, { label: 'FD' });
213
- }
214
- for (const next of [...body.nexts, ...body.exitPoints]) {
215
- graph.addEdge(whileLoop.info.id, next, { label: 'FD' });
216
- }
217
- for (const breakPoint of body.breaks) {
218
- graph.addEdge(whileLoop.info.id + '-exit', breakPoint, { label: 'FD' });
219
- }
220
- // while can break on the condition as well
221
- for (const exit of condition.exitPoints) {
222
- graph.addEdge(whileLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse, caused: whileLoop.info.id });
223
- }
224
- return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [whileLoop.info.id + '-exit'], entryPoints: [whileLoop.info.id] };
225
- }
226
- function cfgFor(forLoop, variable, vector, body) {
227
- const graph = variable.graph;
228
- graph.addVertex({ id: forLoop.info.id, name: forLoop.type, type: identifyMayStatementType(forLoop) });
229
- graph.addVertex({ id: forLoop.info.id + '-exit', name: 'for-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
230
- graph.merge(vector.graph);
231
- graph.merge(body.graph);
232
- for (const entry of vector.entryPoints) {
233
- graph.addEdge(entry, forLoop.info.id, { label: 'FD' });
234
- }
235
- for (const exit of vector.exitPoints) {
236
- for (const entry of variable.entryPoints) {
237
- graph.addEdge(entry, exit, { label: 'FD' });
238
- }
239
- }
240
- for (const exit of variable.exitPoints) {
241
- for (const entry of body.entryPoints) {
242
- graph.addEdge(entry, exit, { label: 'CD', when: convert_values_1.RTrue, caused: forLoop.info.id });
243
- }
244
- }
245
- for (const next of [...body.nexts, ...body.exitPoints]) {
246
- graph.addEdge(forLoop.info.id, next, { label: 'FD' });
247
- }
248
- for (const breakPoint of body.breaks) {
249
- graph.addEdge(forLoop.info.id + '-exit', breakPoint, { label: 'FD' });
250
- }
251
- // while can break on the condition as well
252
- for (const exit of variable.exitPoints) {
253
- graph.addEdge(forLoop.info.id + '-exit', exit, { label: 'CD', when: convert_values_1.RFalse, caused: forLoop.info.id });
254
- }
255
- return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [forLoop.info.id + '-exit'], entryPoints: [forLoop.info.id] };
256
- }
257
- function cfgFunctionDefinition(fn, params, body) {
258
- const graph = new ControlFlowGraph();
259
- const children = [fn.info.id + '-params', fn.info.id + '-exit'];
260
- graph.addVertex({ id: fn.info.id + '-params', name: 'function-parameters', type: "mid-marker" /* CfgVertexType.MidMarker */ }, false);
261
- graph.addVertex({ id: fn.info.id + '-exit', name: 'function-exit', type: "end-marker" /* CfgVertexType.EndMarker */ }, false);
262
- graph.addVertex({ id: fn.info.id, name: fn.type, children, type: identifyMayStatementType(fn) });
263
- graph.merge(body.graph, true);
264
- children.push(...body.graph.rootVertexIds());
265
- for (const param of params) {
266
- graph.merge(param.graph, true);
267
- children.push(...param.graph.rootVertexIds());
268
- for (const entry of param.entryPoints) {
269
- graph.addEdge(entry, fn.info.id, { label: 'FD' });
270
- }
271
- for (const exit of param.exitPoints) {
272
- graph.addEdge(fn.info.id + '-params', exit, { label: 'FD' });
273
- }
274
- }
275
- if (params.length === 0) {
276
- graph.addEdge(fn.info.id + '-params', fn.info.id, { label: 'FD' });
277
- }
278
- for (const entry of body.entryPoints) {
279
- graph.addEdge(entry, fn.info.id + '-params', { label: 'FD' });
280
- }
281
- // breaks and nexts should be illegal but safe is safe i guess
282
- for (const next of [...body.returns, ...body.breaks, ...body.nexts, ...body.exitPoints]) {
283
- graph.addEdge(fn.info.id + '-exit', next, { label: 'FD' });
284
- }
285
- return { graph: graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [fn.info.id], entryPoints: [fn.info.id] };
286
- }
287
- function cfgFunctionCall(call, name, args) {
288
- const graph = name.graph;
289
- const info = { graph, breaks: [...name.breaks], nexts: [...name.nexts], returns: [...name.returns], exitPoints: [call.info.id + '-exit'], entryPoints: [call.info.id] };
290
- graph.addVertex({ id: call.info.id, name: call.type, type: identifyMayStatementType(call) });
291
- for (const entryPoint of name.entryPoints) {
292
- graph.addEdge(entryPoint, call.info.id, { label: 'FD' });
293
- }
294
- graph.addVertex({ id: call.info.id + '-name', name: 'call-name', type: "mid-marker" /* CfgVertexType.MidMarker */ });
295
- for (const exitPoint of name.exitPoints) {
296
- graph.addEdge(call.info.id + '-name', exitPoint, { label: 'FD' });
297
- }
298
- graph.addVertex({ id: call.info.id + '-exit', name: 'call-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
299
- let lastArgExits = [call.info.id + '-name'];
300
- for (const arg of args) {
301
- if (arg === r_function_call_1.EmptyArgument) {
302
- continue;
303
- }
304
- graph.merge(arg.graph);
305
- info.breaks.push(...arg.breaks);
306
- info.nexts.push(...arg.nexts);
307
- info.returns.push(...arg.returns);
308
- for (const entry of arg.entryPoints) {
309
- for (const exit of lastArgExits) {
310
- graph.addEdge(entry, exit, { label: 'FD' });
311
- }
312
- }
313
- lastArgExits = arg.exitPoints;
314
- }
315
- for (const exit of lastArgExits) {
316
- graph.addEdge(call.info.id + '-exit', exit, { label: 'FD' });
317
- }
318
- // should not contain any breaks, nexts, or returns, (except for the body if something like 'break()')
319
- return info;
320
- }
321
- function cfgFunctionCallWithDataflow(graph) {
322
- return (call, name, args) => {
323
- const baseCFG = cfgFunctionCall(call, name, args);
324
- /* try to resolve the call and link the target definitions */
325
- const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
326
- const exits = [];
327
- for (const target of targets) {
328
- // we have to filter out non func-call targets as the call targets contains names and call ids
329
- if ((0, vertex_1.isFunctionDefinitionVertex)(graph.getVertex(target))) {
330
- baseCFG.graph.addEdge(call.info.id, target, { label: 'FD' });
331
- exits.push(target + '-exit');
332
- }
333
- }
334
- if (exits.length > 0) {
335
- baseCFG.graph.addVertex({
336
- id: call.info.id + '-resolved-call-exit',
337
- name: 'resolved-call-exit',
338
- type: "end-marker" /* CfgVertexType.EndMarker */
339
- });
340
- for (const exit of [...baseCFG.exitPoints, ...exits]) {
341
- baseCFG.graph.addEdge(call.info.id + '-resolved-call-exit', exit, { label: 'FD' });
342
- }
343
- return {
344
- ...baseCFG,
345
- exitPoints: [call.info.id + '-resolved-call-exit']
346
- };
347
- }
348
- else {
349
- return baseCFG;
350
- }
351
- };
352
- }
353
- function cfgArgumentOrParameter(node, name, value) {
354
- const graph = new ControlFlowGraph();
355
- const info = { graph, breaks: [], nexts: [], returns: [], exitPoints: [node.info.id + '-exit'], entryPoints: [node.info.id] };
356
- graph.addVertex({ id: node.info.id, name: node.type, type: "expression" /* CfgVertexType.Expression */ });
357
- let currentExitPoint = [node.info.id];
358
- if (name) {
359
- graph.merge(name.graph);
360
- info.breaks.push(...name.breaks);
361
- info.nexts.push(...name.nexts);
362
- info.returns.push(...name.returns);
363
- for (const entry of name.entryPoints) {
364
- graph.addEdge(entry, node.info.id, { label: 'FD' });
365
- }
366
- currentExitPoint = name.exitPoints;
367
- }
368
- graph.addVertex({ id: node.info.id + '-before-value', name: 'before-value', type: "mid-marker" /* CfgVertexType.MidMarker */ });
369
- for (const exitPoints of currentExitPoint) {
370
- graph.addEdge(node.info.id + '-before-value', exitPoints, { label: 'FD' });
371
- }
372
- currentExitPoint = [node.info.id + '-before-value'];
373
- if (value) {
374
- graph.merge(value.graph);
375
- info.breaks.push(...value.breaks);
376
- info.nexts.push(...value.nexts);
377
- info.returns.push(...value.returns);
378
- for (const exitPoint of currentExitPoint) {
379
- for (const entry of value.entryPoints) {
380
- graph.addEdge(entry, exitPoint, { label: 'FD' });
381
- }
382
- }
383
- currentExitPoint = value.exitPoints;
384
- }
385
- graph.addVertex({ id: node.info.id + '-exit', name: 'exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
386
- for (const exit of currentExitPoint) {
387
- graph.addEdge(node.info.id + '-exit', exit, { label: 'FD' });
388
- }
389
- return info;
390
- }
391
- function cfgBinaryOp(binOp, lhs, rhs) {
392
- const graph = new ControlFlowGraph().merge(lhs.graph).merge(rhs.graph);
393
- const result = { graph, breaks: [...lhs.breaks, ...rhs.breaks], nexts: [...lhs.nexts, ...rhs.nexts], returns: [...lhs.returns, ...rhs.returns], entryPoints: [binOp.info.id], exitPoints: [binOp.info.id + '-exit'] };
394
- graph.addVertex({ id: binOp.info.id, name: binOp.type, type: binOp.flavor === 'assignment' ? "statement" /* CfgVertexType.Statement */ : "expression" /* CfgVertexType.Expression */ });
395
- graph.addVertex({ id: binOp.info.id + '-exit', name: 'binOp-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
396
- for (const exitPoint of lhs.exitPoints) {
397
- for (const entryPoint of rhs.entryPoints) {
398
- result.graph.addEdge(entryPoint, exitPoint, { label: 'FD' });
399
- }
400
- }
401
- for (const entryPoint of lhs.entryPoints) {
402
- graph.addEdge(entryPoint, binOp.info.id, { label: 'FD' });
403
- }
404
- for (const exitPoint of rhs.exitPoints) {
405
- graph.addEdge(binOp.info.id + '-exit', exitPoint, { label: 'FD' });
406
- }
407
- return result;
408
- }
409
- function cfgAccess(access, name, accessors) {
410
- const result = name;
411
- const graph = result.graph;
412
- graph.addVertex({ id: access.info.id, name: access.type, type: "expression" /* CfgVertexType.Expression */ });
413
- graph.addVertex({ id: access.info.id + '-exit', name: 'access-exit', type: "end-marker" /* CfgVertexType.EndMarker */ });
414
- for (const entry of name.entryPoints) {
415
- graph.addEdge(entry, access.info.id, { label: 'FD' });
416
- }
417
- for (const exit of name.exitPoints) {
418
- graph.addEdge(access.info.id, exit, { label: 'FD' });
419
- }
420
- result.entryPoints = [access.info.id];
421
- result.exitPoints = [access.info.id + '-exit'];
422
- for (const accessor of accessors) {
423
- if (accessor === r_function_call_1.EmptyArgument) {
424
- continue;
425
- }
426
- graph.merge(accessor.graph);
427
- for (const entry of accessor.entryPoints) {
428
- graph.addEdge(entry, access.info.id, { label: 'FD' });
429
- }
430
- for (const exit of accessor.exitPoints) {
431
- graph.addEdge(access.info.id + '-exit', exit, { label: 'FD' });
432
- }
433
- }
434
- return result;
435
- }
436
- function cfgUnaryOp(unary, operand) {
437
- const graph = operand.graph;
438
- graph.addVertex({ id: unary.info.id, name: unary.type, type: "end-marker" /* CfgVertexType.EndMarker */ });
439
- for (const entry of operand.exitPoints) {
440
- graph.addEdge(unary.info.id, entry, { label: 'FD' });
441
- }
442
- return { ...operand, graph, exitPoints: [unary.info.id] };
443
- }
444
- function cfgExprList(_node, _grouping, expressions) {
445
- const result = { graph: new ControlFlowGraph(), breaks: [], nexts: [], returns: [], exitPoints: [], entryPoints: [] };
446
- let first = true;
447
- for (const expression of expressions) {
448
- if (first) {
449
- result.entryPoints = expression.entryPoints;
450
- first = false;
451
- }
452
- else {
453
- for (const previousExitPoint of result.exitPoints) {
454
- for (const entryPoint of expression.entryPoints) {
455
- result.graph.addEdge(entryPoint, previousExitPoint, { label: 'FD' });
456
- }
457
- }
458
- }
459
- result.graph.merge(expression.graph);
460
- result.breaks.push(...expression.breaks);
461
- result.nexts.push(...expression.nexts);
462
- result.returns.push(...expression.returns);
463
- result.exitPoints = expression.exitPoints;
464
- }
465
- return result;
466
- }
467
- function equalChildren(a, b) {
468
- if (!a || !b || a.length !== b.length) {
469
- return false;
470
- }
471
- for (let i = 0; i < a.length; ++i) {
472
- if (a[i] !== b[i]) {
473
- return false;
474
- }
475
- }
476
- return true;
477
- }
478
- /**
479
- * Returns true if the given CFG equals the other CFG. False otherwise.
480
- */
481
- function equalCfg(a, b) {
482
- if (!a || !b) {
483
- return a === b;
484
- }
485
- else if (!(0, set_1.setEquals)(a.rootVertexIds(), b.rootVertexIds())) {
486
- log_1.log.debug(`root vertex ids differ ${JSON.stringify(a.rootVertexIds(), json_1.jsonReplacer)} vs. ${JSON.stringify(b.rootVertexIds(), json_1.jsonReplacer)}.`);
487
- return false;
488
- }
489
- const aVert = a.vertices();
490
- const bVert = b.vertices();
491
- if (aVert.size !== bVert.size) {
492
- log_1.log.debug(`vertex count differs ${aVert.size} vs. ${bVert.size}.`);
493
- return false;
494
- }
495
- for (const [id, aInfo] of aVert) {
496
- const bInfo = bVert.get(id);
497
- if (bInfo === undefined || aInfo.name !== bInfo.name || equalChildren(aInfo.children, bInfo.children)) {
498
- log_1.log.debug(`vertex ${id} differs ${JSON.stringify(aInfo, json_1.jsonReplacer)} vs. ${JSON.stringify(bInfo, json_1.jsonReplacer)}.`);
499
- return false;
500
- }
501
- }
502
- const aEdges = a.edges();
503
- const bEdges = b.edges();
504
- if (aEdges.size !== bEdges.size) {
505
- log_1.log.debug(`edge count differs ${aEdges.size} vs. ${bEdges.size}.`);
506
- return false;
507
- }
508
- for (const [from, aTo] of aEdges) {
509
- const bTo = bEdges.get(from);
510
- if (bTo === undefined || aTo.size !== bTo.size) {
511
- log_1.log.debug(`edge count for ${from} differs ${aTo.size} vs. ${bTo?.size ?? '?'}.`);
512
- return false;
513
- }
514
- for (const [to, aEdge] of aTo) {
515
- const bEdge = bTo.get(to);
516
- if (bEdge === undefined || aEdge.label !== bEdge.label) {
517
- log_1.log.debug(`edge ${from} -> ${to} differs ${JSON.stringify(aEdge, json_1.jsonReplacer)} vs. ${JSON.stringify(bEdge, json_1.jsonReplacer)}.`);
518
- return false;
519
- }
520
- }
521
- }
522
- return true;
523
- }
524
- /**
525
- * @see df2quads
526
- * @see serialize2quads
527
- * @see graph2quads
528
- */
529
- function cfg2quads(cfg, config) {
530
- return (0, quads_1.graph2quads)({
531
- rootIds: [...cfg.graph.rootVertexIds()],
532
- vertices: [...cfg.graph.vertices().entries()]
533
- .map(([id, v]) => ({
534
- id,
535
- name: v.name,
536
- children: v.children
537
- })),
538
- edges: [...cfg.graph.edges()].flatMap(([fromId, targets]) => [...targets].map(([toId, info]) => ({
539
- from: fromId,
540
- to: toId,
541
- type: info.label,
542
- when: info.when
543
- }))),
544
- entryPoints: cfg.entryPoints,
545
- exitPoints: cfg.exitPoints,
546
- breaks: cfg.breaks,
547
- nexts: cfg.nexts,
548
- returns: cfg.returns
549
- }, config);
550
- }
551
2
  //# sourceMappingURL=cfg.js.map
@@ -64,4 +64,27 @@ export declare function arraySum(arr: readonly number[]): number;
64
64
  * Converts an array into a bag data-structure (in the form of a map mapping the entries/keys to their counts)
65
65
  */
66
66
  export declare function array2bag<T>(arr: T[]): Map<T, number>;
67
- export declare function arrayEqual<T>(a: readonly T[] | undefined, b: readonly T[] | undefined): boolean;
67
+ export declare function arrayEqual<T>(a: readonly T[] | undefined, b: readonly T[] | undefined, cmp?: (a: T, b: T) => boolean): boolean;
68
+ /**
69
+ * Samples elements from a list such that the distance between the sampled elements is as equal as possible.
70
+ *
71
+ * If the number of elements to sample is greater or equal to the number of elements in the list, the list is returned as is.
72
+ * If the number of elements to sample is less than or equal to 0, an empty list is returned.
73
+ *
74
+ * @param list - list of elements
75
+ * @param sampleCount - number of elements to sample
76
+ * @param rounding - rounding mode to use for the index calculation
77
+ * @returns - a list of elements equidistantly sampled from the input list
78
+ */
79
+ export declare function equidistantSampling<T>(list: readonly T[], sampleCount: number, rounding?: 'floor' | 'ceil'): T[];
80
+ /**
81
+ * Returns the cartesian product of the given arrays.
82
+ * @example
83
+ *
84
+ * ```ts
85
+ * cartesianProduct([1, 2], ['a', 'b', 'c'], [true, false])
86
+ * // -> [[1, 'a', true], [1, 'a', false], [1, 'b', true], [1, 'b', false], [1, 'c', true], [1, 'c', false], [2, 'a', true], [2, 'a', false], [2, 'b', true], [2, 'b', false], [2, 'c', true], [2, 'c', false]]
87
+ * ```
88
+ *
89
+ */
90
+ export declare function cartesianProduct<T>(...arrays: T[][]): T[][];
@@ -8,7 +8,9 @@ exports.getUniqueCombinationsOfSize = getUniqueCombinationsOfSize;
8
8
  exports.arraySum = arraySum;
9
9
  exports.array2bag = array2bag;
10
10
  exports.arrayEqual = arrayEqual;
11
- const assert_1 = require("./assert");
11
+ exports.equidistantSampling = equidistantSampling;
12
+ exports.cartesianProduct = cartesianProduct;
13
+ const assert_1 = require("../assert");
12
14
  /**
13
15
  * Splits the array every time the given predicate fires.
14
16
  * The element the split appears on will not be included!
@@ -160,7 +162,7 @@ function array2bag(arr) {
160
162
  }
161
163
  return result;
162
164
  }
163
- function arrayEqual(a, b) {
165
+ function arrayEqual(a, b, cmp = (a, b) => a === b) {
164
166
  if (a === undefined || b === undefined) {
165
167
  return a === b;
166
168
  }
@@ -168,10 +170,49 @@ function arrayEqual(a, b) {
168
170
  return false;
169
171
  }
170
172
  for (let i = 0; i < a.length; i++) {
171
- if (a[i] !== b[i]) {
173
+ if (!cmp(a[i], b[i])) {
172
174
  return false;
173
175
  }
174
176
  }
175
177
  return true;
176
178
  }
179
+ /**
180
+ * Samples elements from a list such that the distance between the sampled elements is as equal as possible.
181
+ *
182
+ * If the number of elements to sample is greater or equal to the number of elements in the list, the list is returned as is.
183
+ * If the number of elements to sample is less than or equal to 0, an empty list is returned.
184
+ *
185
+ * @param list - list of elements
186
+ * @param sampleCount - number of elements to sample
187
+ * @param rounding - rounding mode to use for the index calculation
188
+ * @returns - a list of elements equidistantly sampled from the input list
189
+ */
190
+ function equidistantSampling(list, sampleCount, rounding = 'ceil') {
191
+ if (sampleCount >= list.length) {
192
+ return list.slice();
193
+ }
194
+ else if (sampleCount <= 0) {
195
+ return [];
196
+ }
197
+ const result = [];
198
+ const step = list.length / sampleCount;
199
+ for (let i = 0; i < sampleCount; i++) {
200
+ const index = rounding === 'floor' ? Math.floor(i * step) : Math.ceil(i * step);
201
+ result.push(list[index]);
202
+ }
203
+ return result;
204
+ }
205
+ /**
206
+ * Returns the cartesian product of the given arrays.
207
+ * @example
208
+ *
209
+ * ```ts
210
+ * cartesianProduct([1, 2], ['a', 'b', 'c'], [true, false])
211
+ * // -> [[1, 'a', true], [1, 'a', false], [1, 'b', true], [1, 'b', false], [1, 'c', true], [1, 'c', false], [2, 'a', true], [2, 'a', false], [2, 'b', true], [2, 'b', false], [2, 'c', true], [2, 'c', false]]
212
+ * ```
213
+ *
214
+ */
215
+ function cartesianProduct(...arrays) {
216
+ return arrays.reduce((a, b) => a.flatMap(x => b.map(y => x.concat(y))), [[]]);
217
+ }
177
218
  //# sourceMappingURL=arrays.js.map
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setEquals = setEquals;
4
+ exports.setMinus = setMinus;
5
+ /**
6
+ * Given both sets, this checks if they contain the same elements.
7
+ */
8
+ function setEquals(a, b) {
9
+ return a.symmetricDifference(b).size === 0;
10
+ }
11
+ /**
12
+ * Returns `A – B`
13
+ */
14
+ function setMinus(a, b) {
15
+ return a.difference(b);
16
+ }
17
+ //# sourceMappingURL=set.js.map