@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.
- package/README.md +82 -20
- package/benchmark/slicer.d.ts +49 -22
- package/benchmark/slicer.js +89 -29
- package/benchmark/stats/print.js +16 -10
- package/benchmark/stats/size-of.js +18 -1
- package/benchmark/stats/stats.d.ts +3 -0
- package/benchmark/summarizer/first-phase/input.js +1 -1
- package/benchmark/summarizer/first-phase/process.js +3 -3
- package/benchmark/summarizer/second-phase/process.js +9 -3
- package/benchmark/summarizer/summarizer.js +1 -1
- package/cli/benchmark-app.d.ts +5 -0
- package/cli/benchmark-app.js +49 -6
- package/cli/benchmark-helper-app.d.ts +4 -0
- package/cli/benchmark-helper-app.js +20 -4
- package/cli/common/options.js +15 -6
- package/cli/common/script.js +1 -1
- package/cli/flowr.js +1 -1
- package/cli/repl/commands/repl-cfg.d.ts +2 -0
- package/cli/repl/commands/repl-cfg.js +38 -24
- package/cli/repl/commands/repl-commands.js +6 -2
- package/cli/repl/commands/repl-dataflow.d.ts +2 -0
- package/cli/repl/commands/repl-dataflow.js +37 -3
- package/cli/repl/commands/repl-execute.js +1 -1
- package/cli/repl/commands/repl-main.d.ts +1 -1
- package/cli/repl/commands/repl-main.js +1 -1
- package/cli/repl/commands/repl-normalize.js +1 -1
- package/cli/repl/commands/repl-query.js +2 -2
- package/cli/repl/core.js +1 -1
- package/cli/repl/prompt.js +1 -1
- package/cli/repl/server/connection.js +4 -4
- package/cli/repl/server/messages/message-analysis.d.ts +1 -1
- package/cli/script-core/statistics-core.js +1 -1
- package/cli/script-core/statistics-helper-core.js +4 -4
- package/config.d.ts +60 -21
- package/config.js +24 -4
- package/control-flow/basic-cfg-guided-visitor.d.ts +39 -0
- package/control-flow/basic-cfg-guided-visitor.js +114 -0
- package/control-flow/cfg-properties.d.ts +26 -0
- package/control-flow/cfg-properties.js +100 -0
- package/control-flow/cfg-simplification.d.ts +18 -0
- package/control-flow/cfg-simplification.js +55 -0
- package/control-flow/cfg-to-basic-blocks.d.ts +5 -0
- package/control-flow/cfg-to-basic-blocks.js +81 -0
- package/control-flow/control-flow-graph.d.ts +247 -0
- package/control-flow/control-flow-graph.js +290 -0
- package/control-flow/dfg-cfg-guided-visitor.d.ts +32 -0
- package/control-flow/dfg-cfg-guided-visitor.js +71 -0
- package/control-flow/diff-cfg.d.ts +11 -0
- package/control-flow/diff-cfg.js +161 -0
- package/control-flow/extract-cfg.d.ts +30 -0
- package/control-flow/extract-cfg.js +475 -0
- package/control-flow/happens-before.d.ts +7 -0
- package/{util/cfg → control-flow}/happens-before.js +3 -3
- package/control-flow/semantic-cfg-guided-visitor.d.ts +452 -0
- package/control-flow/semantic-cfg-guided-visitor.js +492 -0
- package/control-flow/simple-visitor.d.ts +25 -0
- package/control-flow/simple-visitor.js +80 -0
- package/control-flow/syntax-cfg-guided-visitor.d.ts +128 -0
- package/control-flow/syntax-cfg-guided-visitor.js +166 -0
- package/core/print/print.d.ts +1 -1
- package/core/print/slice-diff-ansi.js +1 -1
- package/core/steps/pipeline/create-pipeline.js +1 -1
- package/dataflow/environments/built-in-config.d.ts +5 -2
- package/dataflow/environments/built-in-config.js +17 -8
- package/dataflow/environments/built-in.d.ts +16 -5
- package/dataflow/environments/built-in.js +55 -6
- package/dataflow/environments/clone.d.ts +5 -0
- package/dataflow/environments/clone.js +5 -0
- package/dataflow/environments/default-builtin-config.d.ts +2 -0
- package/dataflow/environments/default-builtin-config.js +164 -13
- package/dataflow/environments/define.d.ts +5 -1
- package/dataflow/environments/define.js +36 -10
- package/dataflow/environments/overwrite.js +4 -0
- package/dataflow/environments/remove.d.ts +6 -0
- package/dataflow/environments/remove.js +24 -0
- package/dataflow/environments/resolve-by-name.js +16 -5
- package/dataflow/extractor.js +2 -2
- package/dataflow/graph/dataflowgraph-builder.d.ts +79 -7
- package/dataflow/graph/dataflowgraph-builder.js +106 -8
- package/dataflow/graph/diff-dataflow-graph.d.ts +16 -0
- package/dataflow/graph/{diff.js → diff-dataflow-graph.js} +30 -56
- package/dataflow/graph/graph.d.ts +17 -4
- package/dataflow/graph/graph.js +51 -12
- package/dataflow/graph/vertex.d.ts +59 -4
- package/dataflow/graph/vertex.js +32 -0
- package/dataflow/internal/linker.d.ts +3 -2
- package/dataflow/internal/linker.js +36 -25
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +1 -1
- package/dataflow/internal/process/functions/call/argument/unpack-argument.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +67 -54
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +6 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +108 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +54 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +10 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +140 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +9 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +15 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-get.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-library.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +51 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +9 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +4 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +100 -31
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.d.ts +7 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +41 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +35 -8
- package/dataflow/internal/process/functions/call/built-in/built-in-special-bin-op.js +4 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.d.ts +15 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.js +75 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +3 -3
- package/dataflow/internal/process/functions/call/common.d.ts +5 -2
- package/dataflow/internal/process/functions/call/common.js +9 -5
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +3 -2
- package/dataflow/internal/process/functions/call/known-call-handling.js +2 -1
- package/dataflow/internal/process/functions/call/named-call-handling.d.ts +2 -0
- package/dataflow/internal/process/functions/call/named-call-handling.js +10 -6
- package/dataflow/internal/process/functions/call/unnamed-call-handling.d.ts +1 -0
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
- package/dataflow/internal/process/process-named-call.d.ts +4 -1
- package/dataflow/internal/process/process-named-call.js +8 -5
- package/dataflow/origin/dfg-get-origin.d.ts +82 -0
- package/dataflow/origin/dfg-get-origin.js +116 -0
- package/documentation/doc-util/doc-cfg.d.ts +20 -4
- package/documentation/doc-util/doc-cfg.js +41 -7
- package/documentation/doc-util/doc-cli-option.js +4 -2
- package/documentation/doc-util/doc-code.js +10 -2
- package/documentation/doc-util/doc-dfg.js +3 -3
- package/documentation/doc-util/doc-escape.d.ts +7 -0
- package/documentation/doc-util/doc-escape.js +19 -0
- package/documentation/doc-util/doc-files.d.ts +1 -0
- package/documentation/doc-util/doc-files.js +2 -1
- package/documentation/doc-util/doc-normalized-ast.js +3 -3
- package/documentation/doc-util/doc-query.js +2 -2
- package/documentation/doc-util/doc-repl.js +1 -1
- package/documentation/doc-util/doc-search.js +1 -1
- package/documentation/doc-util/doc-server-message.js +2 -2
- package/documentation/doc-util/doc-structure.d.ts +1 -0
- package/documentation/doc-util/doc-structure.js +5 -0
- package/documentation/doc-util/doc-types.d.ts +7 -1
- package/documentation/doc-util/doc-types.js +13 -2
- package/documentation/print-capabilities-markdown.js +28 -2
- package/documentation/print-cfg-wiki.d.ts +1 -0
- package/documentation/print-cfg-wiki.js +572 -0
- package/documentation/print-core-wiki.js +2 -2
- package/documentation/print-dataflow-graph-wiki.js +180 -25
- package/documentation/print-engines-wiki.js +1 -1
- package/documentation/print-faq-wiki.d.ts +1 -0
- package/documentation/print-faq-wiki.js +75 -0
- package/documentation/print-interface-wiki.js +2 -1
- package/documentation/print-linting-and-testing-wiki.js +52 -36
- package/documentation/print-normalized-ast-wiki.js +1 -1
- package/documentation/print-onboarding-wiki.d.ts +1 -0
- package/documentation/print-onboarding-wiki.js +42 -0
- package/documentation/print-query-wiki.js +23 -3
- package/documentation/print-readme.js +10 -3
- package/package.json +10 -6
- package/queries/catalog/call-context-query/call-context-query-executor.js +5 -5
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +1 -1
- package/queries/catalog/call-context-query/call-context-query-format.js +2 -2
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -2
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +24 -21
- package/queries/catalog/cluster-query/cluster-query-format.d.ts +1 -1
- package/queries/catalog/cluster-query/cluster-query-format.js +1 -1
- package/queries/catalog/config-query/config-query-format.d.ts +1 -1
- package/queries/catalog/config-query/config-query-format.js +2 -2
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +1 -1
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +2 -2
- package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +1 -1
- package/queries/catalog/dataflow-query/dataflow-query-format.js +2 -2
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +17 -7
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +2 -26
- package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -147
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +24 -0
- package/queries/catalog/dependencies-query/function-info/function-info.js +10 -0
- package/queries/catalog/dependencies-query/function-info/library-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/library-functions.js +18 -0
- package/queries/catalog/dependencies-query/function-info/read-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/read-functions.js +101 -0
- package/queries/catalog/dependencies-query/function-info/source-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/source-functions.js +11 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.js +87 -0
- package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +4 -4
- package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-format.js +2 -2
- package/queries/catalog/id-map-query/id-map-query-format.d.ts +1 -1
- package/queries/catalog/id-map-query/id-map-query-format.js +2 -2
- package/queries/catalog/lineage-query/lineage-query-format.d.ts +1 -1
- package/queries/catalog/lineage-query/lineage-query-format.js +2 -2
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +1 -1
- package/queries/catalog/location-map-query/location-map-query-format.js +2 -2
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +1 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +2 -2
- package/queries/catalog/origin-query/origin-query-executor.d.ts +5 -0
- package/queries/catalog/origin-query/origin-query-executor.js +33 -0
- package/queries/catalog/origin-query/origin-query-format.d.ts +71 -0
- package/queries/catalog/origin-query/origin-query-format.js +27 -0
- package/queries/catalog/project-query/project-query-format.d.ts +1 -1
- package/queries/catalog/project-query/project-query-format.js +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +1 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -2
- package/queries/catalog/search-query/search-query-format.d.ts +1 -1
- package/queries/catalog/search-query/search-query-format.js +2 -2
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-format.js +2 -2
- package/queries/query-print.d.ts +1 -1
- package/queries/query-print.js +4 -4
- package/queries/query.d.ts +61 -2
- package/queries/query.js +3 -1
- package/r-bridge/data/data.d.ts +2 -2
- package/r-bridge/data/data.js +2 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +3 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-number.js +5 -0
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.d.ts +3 -2
- package/r-bridge/lang-4.x/ast/model/nodes/r-string.js +5 -0
- package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +1 -1
- package/r-bridge/lang-4.x/ast/model/processing/decorate.js +1 -1
- package/r-bridge/lang-4.x/ast/model/processing/fold.js +3 -1
- package/r-bridge/lang-4.x/ast/model/processing/stateful-fold.d.ts +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/expression/normalize-expression.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-argument.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-call.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-definition.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/normalize-access.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/operators/normalize-binary.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.js +1 -1
- package/r-bridge/lang-4.x/ast/parser/main/internal/values/normalize-symbol.js +1 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.d.ts +2 -2
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +4 -4
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +26 -8
- package/r-bridge/retriever.js +1 -1
- package/search/search-executor/search-generators.d.ts +1 -1
- package/search/search-executor/search-transformer.d.ts +1 -1
- package/slicing/criterion/collect-all.js +1 -1
- package/slicing/static/slice-call.js +13 -3
- package/statistics/features/supported/assignments/post-process.js +1 -1
- package/statistics/features/supported/defined-functions/post-process.js +2 -2
- package/statistics/features/supported/used-functions/post-process.js +1 -1
- package/statistics/features/supported/used-packages/post-process.js +2 -2
- package/statistics/features/supported/values/post-process.js +2 -2
- package/statistics/output/print-stats.js +2 -2
- package/statistics/summarizer/post-process/clusterer.d.ts +1 -1
- package/statistics/summarizer/post-process/clusterer.js +1 -1
- package/statistics/summarizer/post-process/histogram.js +3 -3
- package/statistics/summarizer/post-process/post-process-output.js +3 -3
- package/statistics/summarizer/second-phase/process.js +2 -2
- package/statistics/summarizer/summarizer.js +2 -2
- package/util/assert.js +36 -1
- package/util/cfg/cfg.d.ts +0 -80
- package/util/cfg/cfg.js +0 -549
- package/util/{arrays.d.ts → collections/arrays.d.ts} +24 -1
- package/util/{arrays.js → collections/arrays.js} +44 -3
- package/util/collections/set.js +17 -0
- package/util/{list-access.d.ts → containers.d.ts} +24 -4
- package/util/{list-access.js → containers.js} +42 -12
- package/util/diff-graph.d.ts +47 -0
- package/util/diff-graph.js +61 -0
- package/util/diff.d.ts +6 -6
- package/util/diff.js +1 -1
- package/util/mermaid/ast.js +12 -1
- package/util/mermaid/cfg.d.ts +9 -2
- package/util/mermaid/cfg.js +65 -13
- package/util/mermaid/dfg.d.ts +2 -1
- package/util/mermaid/dfg.js +26 -10
- package/util/mermaid/mermaid.d.ts +2 -0
- package/util/mermaid/mermaid.js +6 -0
- package/util/parallel.d.ts +2 -1
- package/util/parallel.js +11 -2
- package/util/prefix.d.ts +13 -0
- package/util/prefix.js +34 -0
- package/util/quads.js +1 -1
- package/util/schema.d.ts +1 -1
- package/util/schema.js +1 -1
- package/util/summarizer.js +1 -1
- package/util/{text.js → text/text.js} +1 -1
- package/util/{time.js → text/time.js} +1 -1
- package/util/version.js +1 -1
- package/dataflow/graph/diff.d.ts +0 -36
- package/util/cfg/happens-before.d.ts +0 -7
- package/util/cfg/visitor.d.ts +0 -9
- package/util/cfg/visitor.js +0 -30
- package/util/set.js +0 -31
- /package/util/{bimap.d.ts → collections/bimap.d.ts} +0 -0
- /package/util/{bimap.js → collections/bimap.js} +0 -0
- /package/util/{defaultmap.d.ts → collections/defaultmap.d.ts} +0 -0
- /package/util/{defaultmap.js → collections/defaultmap.js} +0 -0
- /package/util/{set.d.ts → collections/set.d.ts} +0 -0
- /package/util/{ansi.d.ts → text/ansi.d.ts} +0 -0
- /package/util/{ansi.js → text/ansi.js} +0 -0
- /package/util/{args.d.ts → text/args.d.ts} +0 -0
- /package/util/{args.js → text/args.js} +0 -0
- /package/util/{strings.d.ts → text/strings.d.ts} +0 -0
- /package/util/{strings.js → text/strings.js} +0 -0
- /package/util/{text.d.ts → text/text.d.ts} +0 -0
- /package/util/{time.d.ts → text/time.d.ts} +0 -0
|
@@ -9,7 +9,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
9
|
const shell_1 = require("../../r-bridge/shell");
|
|
10
10
|
const statistics_file_1 = require("../../statistics/output/statistics-file");
|
|
11
11
|
const statistics_1 = require("../../statistics/statistics");
|
|
12
|
-
const
|
|
12
|
+
const extract_cfg_1 = require("../../control-flow/extract-cfg");
|
|
13
13
|
const print_1 = require("../../core/print/print");
|
|
14
14
|
const _00_parse_1 = require("../../core/steps/all/core/00-parse");
|
|
15
15
|
const _10_normalize_1 = require("../../core/steps/all/core/10-normalize");
|
|
@@ -17,9 +17,9 @@ const _20_dataflow_1 = require("../../core/steps/all/core/20-dataflow");
|
|
|
17
17
|
const json_1 = require("../../util/json");
|
|
18
18
|
const log_1 = require("../../util/log");
|
|
19
19
|
const assert_1 = require("../../util/assert");
|
|
20
|
-
const time_1 = require("../../util/time");
|
|
20
|
+
const time_1 = require("../../util/text/time");
|
|
21
21
|
const tar_1 = require("tar");
|
|
22
|
-
const ansi_1 = require("../../util/ansi");
|
|
22
|
+
const ansi_1 = require("../../util/text/ansi");
|
|
23
23
|
function compressFolder(folder, target) {
|
|
24
24
|
return (0, tar_1.create)({
|
|
25
25
|
gzip: true,
|
|
@@ -58,7 +58,7 @@ async function getStatsForSingleFile(options) {
|
|
|
58
58
|
if (stats.outputs.size === 1) {
|
|
59
59
|
if (options['dump-json']) {
|
|
60
60
|
const [, output] = [...stats.outputs.entries()][0];
|
|
61
|
-
const cfg = (0,
|
|
61
|
+
const cfg = (0, extract_cfg_1.extractCFG)(output.normalize, output.dataflow.graph);
|
|
62
62
|
statistics_file_1.statisticsFileProvider.append('output-json', 'parse', await (0, print_1.printStepResult)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, output.parse, 2 /* StepOutputFormat.Json */));
|
|
63
63
|
statistics_file_1.statisticsFileProvider.append('output-json', 'normalize', await (0, print_1.printStepResult)(_10_normalize_1.NORMALIZE, output.normalize, 2 /* StepOutputFormat.Json */));
|
|
64
64
|
statistics_file_1.statisticsFileProvider.append('output-json', 'dataflow', await (0, print_1.printStepResult)(_20_dataflow_1.STATIC_DATAFLOW, output.dataflow, 2 /* StepOutputFormat.Json */));
|
package/config.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { MergeableRecord } from './util/objects';
|
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import type { BuiltInDefinitions } from './dataflow/environments/built-in-config';
|
|
4
4
|
import type { KnownParser } from './r-bridge/parser';
|
|
5
|
+
import type { DeepPartial } from 'ts-essentials';
|
|
5
6
|
export declare enum VariableResolve {
|
|
6
7
|
/** Don't resolve constants at all */
|
|
7
8
|
Disabled = "disabled",
|
|
@@ -34,6 +35,52 @@ export declare enum DropPathsOption {
|
|
|
34
35
|
/** try to drop every folder of the path */
|
|
35
36
|
All = "all"
|
|
36
37
|
}
|
|
38
|
+
export interface FlowrLaxSourcingOptions extends MergeableRecord {
|
|
39
|
+
/**
|
|
40
|
+
* search for filenames matching in the lowercase
|
|
41
|
+
*/
|
|
42
|
+
readonly ignoreCapitalization: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* try to infer the working directory from the main or any script to analyze.
|
|
45
|
+
*/
|
|
46
|
+
readonly inferWorkingDirectory: InferWorkingDirectory;
|
|
47
|
+
/**
|
|
48
|
+
* Additionally search in these paths
|
|
49
|
+
*/
|
|
50
|
+
readonly searchPath: readonly string[];
|
|
51
|
+
/**
|
|
52
|
+
* Allow to drop the first or all parts of the sourced path,
|
|
53
|
+
* if it is relative.
|
|
54
|
+
*/
|
|
55
|
+
readonly dropPaths: DropPathsOption;
|
|
56
|
+
/**
|
|
57
|
+
* How often the same file can be sourced within a single run?
|
|
58
|
+
* Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit.
|
|
59
|
+
*/
|
|
60
|
+
readonly repeatedSourceLimit?: number;
|
|
61
|
+
/**
|
|
62
|
+
* sometimes files may have a different name in the source call (e.g., due to later replacements),
|
|
63
|
+
* with this setting you can provide a list of replacements to apply for each sourced file.
|
|
64
|
+
* Every replacement consists of a record that maps a regex to a replacement string.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* [
|
|
69
|
+
* { }, // no replacement -> still try the original name/path
|
|
70
|
+
* { '.*\\.R$': 'main.R' }, // replace all .R files with main.R
|
|
71
|
+
* { '\s' : '_' }, // replace all spaces with underscores
|
|
72
|
+
* { '\s' : '-', 'oo': 'aa' }, // replace all spaces with dashes and oo with aa
|
|
73
|
+
* ]
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* Given a `source("foo bar.R")` this configuration will search for (in this order):
|
|
77
|
+
* - `foo bar.R` (original name)
|
|
78
|
+
* - `main.R` (replaced with main.R)
|
|
79
|
+
* - `foo_bar.R` (replaced spaces)
|
|
80
|
+
* - `foo-bar.R` (replaced spaces and oo)
|
|
81
|
+
*/
|
|
82
|
+
readonly applyReplacements?: Record<string, string>[];
|
|
83
|
+
}
|
|
37
84
|
export interface FlowrConfigOptions extends MergeableRecord {
|
|
38
85
|
/**
|
|
39
86
|
* Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped
|
|
@@ -67,36 +114,27 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
67
114
|
* How to resolve variables and their values
|
|
68
115
|
*/
|
|
69
116
|
readonly variables: VariableResolve;
|
|
117
|
+
/**
|
|
118
|
+
* Should we include eval(parse(text="...")) calls in the dataflow graph?
|
|
119
|
+
*/
|
|
120
|
+
readonly evalStrings: boolean;
|
|
70
121
|
/**
|
|
71
122
|
* Whether to track pointers in the dataflow graph,
|
|
72
123
|
* if not, the graph will be over-approximated wrt.
|
|
73
124
|
* containers and accesses
|
|
74
125
|
*/
|
|
75
|
-
readonly pointerTracking: boolean
|
|
126
|
+
readonly pointerTracking: boolean | {
|
|
127
|
+
/**
|
|
128
|
+
* The maximum number of indices tracked per obj with the pointer analysis (currently this focuses on initialization)
|
|
129
|
+
*/
|
|
130
|
+
readonly maxIndexCount: number;
|
|
131
|
+
};
|
|
76
132
|
/**
|
|
77
133
|
* If lax source calls are active, flowR searches for sourced files much more freely,
|
|
78
134
|
* based on the configurations you give it.
|
|
79
135
|
* This option is only in effect if {@link ignoreSourceCalls} is set to false.
|
|
80
136
|
*/
|
|
81
|
-
readonly resolveSource?:
|
|
82
|
-
/**
|
|
83
|
-
* search for filenames matching in the lowercase
|
|
84
|
-
*/
|
|
85
|
-
readonly ignoreCapitalization: boolean;
|
|
86
|
-
/**
|
|
87
|
-
* try to infer the working directory from the main or any script to analyze.
|
|
88
|
-
*/
|
|
89
|
-
readonly inferWorkingDirectory: InferWorkingDirectory;
|
|
90
|
-
/**
|
|
91
|
-
* Additionally search in these paths
|
|
92
|
-
*/
|
|
93
|
-
readonly searchPath: readonly string[];
|
|
94
|
-
/**
|
|
95
|
-
* Allow to drop the first or all parts of the sourced path,
|
|
96
|
-
* if it is relative.
|
|
97
|
-
*/
|
|
98
|
-
readonly dropPaths: DropPathsOption;
|
|
99
|
-
};
|
|
137
|
+
readonly resolveSource?: FlowrLaxSourcingOptions;
|
|
100
138
|
/**
|
|
101
139
|
* The configuration for flowR's slicer
|
|
102
140
|
*/
|
|
@@ -139,8 +177,9 @@ export declare const flowrConfigFileSchema: Joi.ObjectSchema<any>;
|
|
|
139
177
|
export declare function setConfigFile(file: string | undefined, workingDirectory?: string, forceLoad?: boolean): void;
|
|
140
178
|
export declare function parseConfig(jsonString: string): FlowrConfigOptions | undefined;
|
|
141
179
|
export declare function setConfig(config: FlowrConfigOptions): void;
|
|
142
|
-
export declare function amendConfig(amendment:
|
|
180
|
+
export declare function amendConfig(amendment: DeepPartial<FlowrConfigOptions>): void;
|
|
143
181
|
export declare function getConfig(): FlowrConfigOptions;
|
|
144
182
|
export declare function getEngineConfig<T extends EngineConfig['type']>(engine: T): EngineConfig & {
|
|
145
183
|
type: T;
|
|
146
184
|
} | undefined;
|
|
185
|
+
export declare function isOverPointerAnalysisThreshold(count: number): boolean;
|
package/config.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.setConfig = setConfig;
|
|
|
10
10
|
exports.amendConfig = amendConfig;
|
|
11
11
|
exports.getConfig = getConfig;
|
|
12
12
|
exports.getEngineConfig = getEngineConfig;
|
|
13
|
+
exports.isOverPointerAnalysisThreshold = isOverPointerAnalysisThreshold;
|
|
13
14
|
const objects_1 = require("./util/objects");
|
|
14
15
|
const path_1 = __importDefault(require("path"));
|
|
15
16
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -51,7 +52,6 @@ var DropPathsOption;
|
|
|
51
52
|
/** try to drop every folder of the path */
|
|
52
53
|
DropPathsOption["All"] = "all";
|
|
53
54
|
})(DropPathsOption || (exports.DropPathsOption = DropPathsOption = {}));
|
|
54
|
-
;
|
|
55
55
|
const defaultEngineConfigs = {
|
|
56
56
|
'tree-sitter': { type: 'tree-sitter' },
|
|
57
57
|
'r-shell': { type: 'r-shell' }
|
|
@@ -70,12 +70,14 @@ exports.defaultConfigOptions = {
|
|
|
70
70
|
defaultEngine: 'r-shell',
|
|
71
71
|
solver: {
|
|
72
72
|
variables: VariableResolve.Alias,
|
|
73
|
+
evalStrings: true,
|
|
73
74
|
pointerTracking: false,
|
|
74
75
|
resolveSource: {
|
|
75
76
|
dropPaths: DropPathsOption.No,
|
|
76
77
|
ignoreCapitalization: true,
|
|
77
78
|
inferWorkingDirectory: InferWorkingDirectory.ActiveScript,
|
|
78
|
-
searchPath: []
|
|
79
|
+
searchPath: [],
|
|
80
|
+
repeatedSourceLimit: 2
|
|
79
81
|
},
|
|
80
82
|
slicer: {
|
|
81
83
|
threshold: 50
|
|
@@ -104,12 +106,17 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
104
106
|
defaultEngine: joi_1.default.string().optional().valid('tree-sitter', 'r-shell').description('The default engine to use for interacting with R code. If this is undefined, an arbitrary engine from the specified list will be used.'),
|
|
105
107
|
solver: joi_1.default.object({
|
|
106
108
|
variables: joi_1.default.string().valid(...Object.values(VariableResolve)).description('How to resolve variables and their values.'),
|
|
107
|
-
|
|
109
|
+
evalStrings: joi_1.default.boolean().description('Should we include eval(parse(text="...")) calls in the dataflow graph?'),
|
|
110
|
+
pointerTracking: joi_1.default.alternatives(joi_1.default.boolean(), joi_1.default.object({
|
|
111
|
+
maxIndexCount: joi_1.default.number().required().description('The maximum number of indices tracked per object with the pointer analysis.')
|
|
112
|
+
})).description('Whether to track pointers in the dataflow graph, if not, the graph will be over-approximated wrt. containers and accesses.'),
|
|
108
113
|
resolveSource: joi_1.default.object({
|
|
109
114
|
dropPaths: joi_1.default.string().valid(...Object.values(DropPathsOption)).description('Allow to drop the first or all parts of the sourced path, if it is relative.'),
|
|
110
115
|
ignoreCapitalization: joi_1.default.boolean().description('Search for filenames matching in the lowercase.'),
|
|
111
116
|
inferWorkingDirectory: joi_1.default.string().valid(...Object.values(InferWorkingDirectory)).description('Try to infer the working directory from the main or any script to analyze.'),
|
|
112
|
-
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.')
|
|
117
|
+
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.'),
|
|
118
|
+
repeatedSourceLimit: joi_1.default.number().optional().description('How often the same file can be sourced within a single run? Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit.'),
|
|
119
|
+
applyReplacements: joi_1.default.array().items(joi_1.default.object()).description('Provide name replacements for loaded files')
|
|
113
120
|
}).optional().description('If lax source calls are active, flowR searches for sourced files much more freely, based on the configurations you give it. This option is only in effect if `ignoreSourceCalls` is set to false.'),
|
|
114
121
|
slicer: joi_1.default.object({
|
|
115
122
|
threshold: joi_1.default.number().optional().description('The maximum number of iterations to perform on a single function call during slicing.')
|
|
@@ -175,6 +182,19 @@ function getEngineConfig(engine) {
|
|
|
175
182
|
return config.find(e => e.type == engine);
|
|
176
183
|
}
|
|
177
184
|
}
|
|
185
|
+
function getPointerAnalysisThreshold() {
|
|
186
|
+
const config = getConfig().solver.pointerTracking;
|
|
187
|
+
if (typeof config === 'object') {
|
|
188
|
+
return config.maxIndexCount;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
return config ? 'unlimited' : 'disabled';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function isOverPointerAnalysisThreshold(count) {
|
|
195
|
+
const threshold = getPointerAnalysisThreshold();
|
|
196
|
+
return threshold !== 'unlimited' && (threshold === 'disabled' || count > threshold);
|
|
197
|
+
}
|
|
178
198
|
function loadConfigFromFile(configFile, workingDirectory) {
|
|
179
199
|
if (configFile !== undefined) {
|
|
180
200
|
if (path_1.default.isAbsolute(configFile) && fs_1.default.existsSync(configFile)) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CfgBasicBlockVertex, CfgEndMarkerVertex, CfgExpressionVertex, CfgMidMarkerVertex, CfgSimpleVertex, CfgStatementVertex, ControlFlowInformation } from './control-flow-graph';
|
|
2
|
+
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
|
+
export interface BasicCfgGuidedVisitorConfiguration<Cfg extends ControlFlowInformation = ControlFlowInformation> {
|
|
4
|
+
readonly controlFlow: Cfg;
|
|
5
|
+
readonly defaultVisitingOrder: 'forward' | 'backward';
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* In contrast to {@link visitCfgInOrder} and {@link visitCfgInReverseOrder}, this visitor is not a simple visitor
|
|
9
|
+
* and serves as the basis for a variety of more complicated visiting orders of the control flow graph.
|
|
10
|
+
* It includes features to provide additional information using the {@link NormalizedAst} and the {@link DataflowGraph}.
|
|
11
|
+
*
|
|
12
|
+
* Use {@link BasicCfgGuidedVisitor#start} to start the traversal.
|
|
13
|
+
*/
|
|
14
|
+
export declare class BasicCfgGuidedVisitor<Cfg extends ControlFlowInformation = ControlFlowInformation, Config extends BasicCfgGuidedVisitorConfiguration<Cfg> = BasicCfgGuidedVisitorConfiguration<Cfg>> {
|
|
15
|
+
protected readonly config: Config;
|
|
16
|
+
protected readonly visited: Map<NodeId, number>;
|
|
17
|
+
constructor(config: Config);
|
|
18
|
+
/**
|
|
19
|
+
* call this function to indicate that a node is to be considered visited.
|
|
20
|
+
*
|
|
21
|
+
* @returns `true` if the node was not visited before, `false` otherwise
|
|
22
|
+
*/
|
|
23
|
+
protected visitNode(node: NodeId): boolean;
|
|
24
|
+
protected startVisitor(start: readonly NodeId[]): void;
|
|
25
|
+
/**
|
|
26
|
+
* Start the visiting process.
|
|
27
|
+
*/
|
|
28
|
+
start(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get the control flow vertex for the given node id or fail if it does not exist.
|
|
31
|
+
*/
|
|
32
|
+
protected getCfgVertex(id: NodeId): CfgSimpleVertex | undefined;
|
|
33
|
+
protected onVisitNode(node: NodeId): void;
|
|
34
|
+
protected onBasicBlockNode(node: CfgBasicBlockVertex): void;
|
|
35
|
+
protected onStatementNode(_node: CfgStatementVertex): void;
|
|
36
|
+
protected onExpressionNode(_node: CfgExpressionVertex): void;
|
|
37
|
+
protected onMidMarkerNode(_node: CfgMidMarkerVertex): void;
|
|
38
|
+
protected onEndMarkerNode(_node: CfgEndMarkerVertex): void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BasicCfgGuidedVisitor = void 0;
|
|
4
|
+
const control_flow_graph_1 = require("./control-flow-graph");
|
|
5
|
+
const assert_1 = require("../util/assert");
|
|
6
|
+
/**
|
|
7
|
+
* In contrast to {@link visitCfgInOrder} and {@link visitCfgInReverseOrder}, this visitor is not a simple visitor
|
|
8
|
+
* and serves as the basis for a variety of more complicated visiting orders of the control flow graph.
|
|
9
|
+
* It includes features to provide additional information using the {@link NormalizedAst} and the {@link DataflowGraph}.
|
|
10
|
+
*
|
|
11
|
+
* Use {@link BasicCfgGuidedVisitor#start} to start the traversal.
|
|
12
|
+
*/
|
|
13
|
+
class BasicCfgGuidedVisitor {
|
|
14
|
+
config;
|
|
15
|
+
visited;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.config = { ...config };
|
|
18
|
+
this.visited = new Map();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* call this function to indicate that a node is to be considered visited.
|
|
22
|
+
*
|
|
23
|
+
* @returns `true` if the node was not visited before, `false` otherwise
|
|
24
|
+
*/
|
|
25
|
+
visitNode(node) {
|
|
26
|
+
if (this.visited.has(node)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
this.visited.set(node, 1);
|
|
30
|
+
this.onVisitNode(node);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
startVisitor(start) {
|
|
34
|
+
const g = this.config.controlFlow.graph;
|
|
35
|
+
const n = this.config.defaultVisitingOrder === 'forward' ?
|
|
36
|
+
(n) => g.ingoingEdges(n) :
|
|
37
|
+
(n) => g.outgoingEdges(n);
|
|
38
|
+
const stack = [...start];
|
|
39
|
+
while (stack.length > 0) {
|
|
40
|
+
const current = stack.shift();
|
|
41
|
+
if (!this.visitNode(current)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const outgoing = n(current) ?? [];
|
|
45
|
+
for (const [to] of outgoing) {
|
|
46
|
+
stack.unshift(to);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Start the visiting process.
|
|
52
|
+
*/
|
|
53
|
+
start() {
|
|
54
|
+
this.startVisitor(this.config.defaultVisitingOrder === 'forward' ? this.config.controlFlow.entryPoints : this.config.controlFlow.exitPoints);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the control flow vertex for the given node id or fail if it does not exist.
|
|
58
|
+
*/
|
|
59
|
+
getCfgVertex(id) {
|
|
60
|
+
return this.config.controlFlow.graph.getVertex(id);
|
|
61
|
+
}
|
|
62
|
+
onVisitNode(node) {
|
|
63
|
+
const vertex = this.getCfgVertex(node);
|
|
64
|
+
if (vertex === undefined) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const type = vertex.type;
|
|
68
|
+
switch (type) {
|
|
69
|
+
case control_flow_graph_1.CfgVertexType.Statement:
|
|
70
|
+
this.onStatementNode(vertex);
|
|
71
|
+
break;
|
|
72
|
+
case control_flow_graph_1.CfgVertexType.Expression:
|
|
73
|
+
this.onExpressionNode(vertex);
|
|
74
|
+
break;
|
|
75
|
+
case control_flow_graph_1.CfgVertexType.MidMarker:
|
|
76
|
+
this.onMidMarkerNode(vertex);
|
|
77
|
+
break;
|
|
78
|
+
case control_flow_graph_1.CfgVertexType.EndMarker:
|
|
79
|
+
this.onEndMarkerNode(vertex);
|
|
80
|
+
break;
|
|
81
|
+
case control_flow_graph_1.CfgVertexType.Block:
|
|
82
|
+
this.onBasicBlockNode(vertex);
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
(0, assert_1.assertUnreachable)(type);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
onBasicBlockNode(node) {
|
|
89
|
+
if (this.config.defaultVisitingOrder === 'forward') {
|
|
90
|
+
for (const elem of node.elems.toReversed()) {
|
|
91
|
+
this.visitNode(elem.id);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
for (const elem of node.elems) {
|
|
96
|
+
this.visitNode(elem.id);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
onStatementNode(_node) {
|
|
101
|
+
/* does nothing by default */
|
|
102
|
+
}
|
|
103
|
+
onExpressionNode(_node) {
|
|
104
|
+
/* does nothing by default */
|
|
105
|
+
}
|
|
106
|
+
onMidMarkerNode(_node) {
|
|
107
|
+
/* does nothing by default */
|
|
108
|
+
}
|
|
109
|
+
onEndMarkerNode(_node) {
|
|
110
|
+
/* does nothing by default */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.BasicCfgGuidedVisitor = BasicCfgGuidedVisitor;
|
|
114
|
+
//# sourceMappingURL=basic-cfg-guided-visitor.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ControlFlowInformation } from './control-flow-graph';
|
|
2
|
+
/**
|
|
3
|
+
* The collection of properties that can be checked on a control flow graph.
|
|
4
|
+
*/
|
|
5
|
+
declare const CfgProperties: {
|
|
6
|
+
readonly 'single-entry-and-exit': typeof checkSingleEntryAndExit;
|
|
7
|
+
readonly 'has-entry-and-exit': typeof hasEntryAndExit;
|
|
8
|
+
readonly 'entry-reaches-all': typeof checkEntryReachesAll;
|
|
9
|
+
readonly 'exit-reaches-all': typeof checkExitIsReachedByAll;
|
|
10
|
+
readonly 'no-direct-fd-cycles': (c: ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>) => boolean;
|
|
11
|
+
readonly 'no-direct-cd-cycles': (c: ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>) => boolean;
|
|
12
|
+
};
|
|
13
|
+
export type CfgProperty = keyof typeof CfgProperties;
|
|
14
|
+
declare function checkSingleEntryAndExit(cfg: ControlFlowInformation): boolean;
|
|
15
|
+
declare function hasEntryAndExit(cfg: ControlFlowInformation): boolean;
|
|
16
|
+
declare function checkExitIsReachedByAll(cfg: ControlFlowInformation): boolean;
|
|
17
|
+
declare function checkEntryReachesAll(cfg: ControlFlowInformation): boolean;
|
|
18
|
+
/** either returns true or the name of the property that is not satisfied */
|
|
19
|
+
export type PropertyReport = true | CfgProperty;
|
|
20
|
+
/**
|
|
21
|
+
* Check if the given CFG satisfies all properties.
|
|
22
|
+
* @param cfg - The control flow graph to check.
|
|
23
|
+
* @param excludeProperties - If provided, exclude the given properties, otherwise this checks all properties.
|
|
24
|
+
*/
|
|
25
|
+
export declare function assertCfgSatisfiesProperties(cfg: ControlFlowInformation, excludeProperties?: readonly CfgProperty[]): PropertyReport;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertCfgSatisfiesProperties = assertCfgSatisfiesProperties;
|
|
4
|
+
const set_1 = require("../util/collections/set");
|
|
5
|
+
const log_1 = require("../util/log");
|
|
6
|
+
const simple_visitor_1 = require("./simple-visitor");
|
|
7
|
+
/**
|
|
8
|
+
* The collection of properties that can be checked on a control flow graph.
|
|
9
|
+
*/
|
|
10
|
+
const CfgProperties = {
|
|
11
|
+
'single-entry-and-exit': checkSingleEntryAndExit,
|
|
12
|
+
'has-entry-and-exit': hasEntryAndExit,
|
|
13
|
+
'entry-reaches-all': checkEntryReachesAll,
|
|
14
|
+
'exit-reaches-all': checkExitIsReachedByAll,
|
|
15
|
+
/* currently not satisfied for function calls
|
|
16
|
+
'at-most-one-in-fd': c => checkFdIOCount(c, 'in', 'at-most', 1),
|
|
17
|
+
'exactly-one-in-fd': c => checkFdIOCount(c, 'in', 'exact', 1),
|
|
18
|
+
'at-most-one-out-fd': c => checkFdIOCount(c, 'out', 'at-most', 1),
|
|
19
|
+
'exactly-one-out-fd': c => checkFdIOCount(c, 'out', 'exact', 1),
|
|
20
|
+
*/
|
|
21
|
+
'no-direct-fd-cycles': c => checkNoDirectCycles(c, 0 /* CfgEdgeType.Fd */),
|
|
22
|
+
'no-direct-cd-cycles': c => checkNoDirectCycles(c, 1 /* CfgEdgeType.Cd */),
|
|
23
|
+
};
|
|
24
|
+
function checkSingleEntryAndExit(cfg) {
|
|
25
|
+
return new Set(cfg.entryPoints).size === 1 && new Set(cfg.exitPoints).size === 1 && new Set(cfg.breaks).size === 0 &&
|
|
26
|
+
new Set(cfg.returns).size === 0 && new Set(cfg.nexts).size === 0;
|
|
27
|
+
}
|
|
28
|
+
function hasEntryAndExit(cfg) {
|
|
29
|
+
return cfg.entryPoints.every(e => cfg.graph.hasVertex(e)) && cfg.exitPoints.every(e => cfg.graph.hasVertex(e));
|
|
30
|
+
}
|
|
31
|
+
function checkReachFrom(label, cfg, start, collect) {
|
|
32
|
+
if (start === undefined) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const collected = new Set();
|
|
36
|
+
collect(cfg.graph, [start], node => {
|
|
37
|
+
collected.add(node);
|
|
38
|
+
});
|
|
39
|
+
// we only require the roots to be there
|
|
40
|
+
const allVertices = cfg.graph.rootIds();
|
|
41
|
+
const diff = (0, set_1.setMinus)(allVertices, collected);
|
|
42
|
+
if (diff.size > 0) {
|
|
43
|
+
log_1.log.error(`Unreachable vertices from ${label}:`, diff);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
function checkExitIsReachedByAll(cfg) {
|
|
49
|
+
return checkReachFrom('exit', cfg, cfg.exitPoints[0], simple_visitor_1.visitCfgInReverseOrder);
|
|
50
|
+
}
|
|
51
|
+
function checkEntryReachesAll(cfg) {
|
|
52
|
+
return checkReachFrom('entry', cfg, cfg.entryPoints[0], simple_visitor_1.visitCfgInOrder);
|
|
53
|
+
}
|
|
54
|
+
function _checkFdIOCount(cfg, dir, type, limit) {
|
|
55
|
+
const counts = new Map();
|
|
56
|
+
for (const [from, targets] of cfg.graph.edges()) {
|
|
57
|
+
for (const [to, edge] of targets) {
|
|
58
|
+
const important = dir === 'in' ? to : from;
|
|
59
|
+
if (edge.label === 0 /* CfgEdgeType.Fd */) {
|
|
60
|
+
counts.set(important, (counts.get(important) ?? 0) + 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const check = type === 'exact' ? (a) => a === limit : (a) => a <= limit;
|
|
65
|
+
for (const [node, count] of counts) {
|
|
66
|
+
if (type === 'exact' && (cfg.entryPoints.includes(node) || cfg.exitPoints.includes(node) || !cfg.graph.rootIds().has(node))) {
|
|
67
|
+
continue; // skip entry and exit points, they do not have to satisfy this
|
|
68
|
+
}
|
|
69
|
+
if (!check(count)) {
|
|
70
|
+
log_1.log.error(`Node ${node} has ${count} ${dir} edges, expected ${type} ${limit}`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function checkNoDirectCycles(cfg, type) {
|
|
77
|
+
for (const [from, targets] of cfg.graph.edges()) {
|
|
78
|
+
for (const [to, edge] of targets) {
|
|
79
|
+
if (edge.label === type && to === from) {
|
|
80
|
+
log_1.log.error(`Node ${from} has a direct cycle with ${to}`);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if the given CFG satisfies all properties.
|
|
89
|
+
* @param cfg - The control flow graph to check.
|
|
90
|
+
* @param excludeProperties - If provided, exclude the given properties, otherwise this checks all properties.
|
|
91
|
+
*/
|
|
92
|
+
function assertCfgSatisfiesProperties(cfg, excludeProperties) {
|
|
93
|
+
for (const [propName, prop] of Object.entries(CfgProperties)) {
|
|
94
|
+
if ((!excludeProperties || !excludeProperties.includes(propName)) && !prop(cfg)) {
|
|
95
|
+
return propName;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=cfg-properties.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ControlFlowInformation } from './control-flow-graph';
|
|
2
|
+
export type CfgSimplificationPass = (cfg: ControlFlowInformation) => ControlFlowInformation;
|
|
3
|
+
declare const CfgSimplificationPasses: {
|
|
4
|
+
readonly 'unique-cf-sets': typeof uniqueControlFlowSets;
|
|
5
|
+
readonly 'remove-dead-code': typeof cfgRemoveDeadCode;
|
|
6
|
+
readonly 'to-basic-blocks': typeof toBasicBlocks;
|
|
7
|
+
};
|
|
8
|
+
export type CfgSimplificationPassName = keyof typeof CfgSimplificationPasses;
|
|
9
|
+
export declare const DefaultCfgSimplificationOrder: ["unique-cf-sets"];
|
|
10
|
+
/**
|
|
11
|
+
* Simplify the control flow information by applying the given passes.
|
|
12
|
+
* This may reduce the vertex count, in- and outgoing edges, entry and exit points, etc.
|
|
13
|
+
*/
|
|
14
|
+
export declare function simplifyControlFlowInformation(cfg: ControlFlowInformation, passes?: readonly CfgSimplificationPassName[]): ControlFlowInformation;
|
|
15
|
+
declare function uniqueControlFlowSets(cfg: ControlFlowInformation): ControlFlowInformation;
|
|
16
|
+
declare function cfgRemoveDeadCode(cfg: ControlFlowInformation): ControlFlowInformation;
|
|
17
|
+
declare function toBasicBlocks(cfg: ControlFlowInformation): ControlFlowInformation;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultCfgSimplificationOrder = void 0;
|
|
4
|
+
exports.simplifyControlFlowInformation = simplifyControlFlowInformation;
|
|
5
|
+
const simple_visitor_1 = require("./simple-visitor");
|
|
6
|
+
const cfg_to_basic_blocks_1 = require("./cfg-to-basic-blocks");
|
|
7
|
+
const CfgSimplificationPasses = {
|
|
8
|
+
'unique-cf-sets': uniqueControlFlowSets,
|
|
9
|
+
'remove-dead-code': cfgRemoveDeadCode,
|
|
10
|
+
'to-basic-blocks': toBasicBlocks
|
|
11
|
+
};
|
|
12
|
+
exports.DefaultCfgSimplificationOrder = [
|
|
13
|
+
'unique-cf-sets',
|
|
14
|
+
// 'remove-dead-code' // way too expensive for conventional use!
|
|
15
|
+
// basic blocks must be requested
|
|
16
|
+
];
|
|
17
|
+
/**
|
|
18
|
+
* Simplify the control flow information by applying the given passes.
|
|
19
|
+
* This may reduce the vertex count, in- and outgoing edges, entry and exit points, etc.
|
|
20
|
+
*/
|
|
21
|
+
function simplifyControlFlowInformation(cfg, passes = exports.DefaultCfgSimplificationOrder) {
|
|
22
|
+
for (const pass of passes) {
|
|
23
|
+
const passFn = CfgSimplificationPasses[pass];
|
|
24
|
+
cfg = passFn(cfg);
|
|
25
|
+
}
|
|
26
|
+
return cfg;
|
|
27
|
+
}
|
|
28
|
+
function uniqueControlFlowSets(cfg) {
|
|
29
|
+
return {
|
|
30
|
+
returns: [...new Set(cfg.returns)],
|
|
31
|
+
entryPoints: [...new Set(cfg.entryPoints)],
|
|
32
|
+
exitPoints: [...new Set(cfg.exitPoints)],
|
|
33
|
+
breaks: [...new Set(cfg.breaks)],
|
|
34
|
+
nexts: [...new Set(cfg.nexts)],
|
|
35
|
+
graph: cfg.graph
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/* currently this does not do work on function definitions */
|
|
39
|
+
function cfgRemoveDeadCode(cfg) {
|
|
40
|
+
// remove every root level node and accompanying vertices that can not be reached from the entry points
|
|
41
|
+
const reachable = new Set();
|
|
42
|
+
(0, simple_visitor_1.visitCfgInOrder)(cfg.graph, cfg.entryPoints, node => {
|
|
43
|
+
reachable.add(node);
|
|
44
|
+
});
|
|
45
|
+
for (const id of cfg.graph.rootIds()) {
|
|
46
|
+
if (!reachable.has(id)) {
|
|
47
|
+
cfg.graph.removeVertex(id);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return cfg;
|
|
51
|
+
}
|
|
52
|
+
function toBasicBlocks(cfg) {
|
|
53
|
+
return (0, cfg_to_basic_blocks_1.convertCfgToBasicBlocks)(cfg);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cfg-simplification.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ControlFlowInformation } from './control-flow-graph';
|
|
2
|
+
/**
|
|
3
|
+
* Take a control flow information of a graph without any basic blocks and convert it to a graph with basic blocks.
|
|
4
|
+
*/
|
|
5
|
+
export declare function convertCfgToBasicBlocks(cfInfo: ControlFlowInformation): ControlFlowInformation;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertCfgToBasicBlocks = convertCfgToBasicBlocks;
|
|
4
|
+
const control_flow_graph_1 = require("./control-flow-graph");
|
|
5
|
+
/** if true, return the target */
|
|
6
|
+
function singleOutgoingFd(outgoing) {
|
|
7
|
+
if (!outgoing || outgoing.size !== 1) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const next = outgoing.entries().next().value;
|
|
11
|
+
if (next?.[1].label === 0 /* CfgEdgeType.Fd */) {
|
|
12
|
+
return next[0];
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Take a control flow information of a graph without any basic blocks and convert it to a graph with basic blocks.
|
|
20
|
+
*/
|
|
21
|
+
function convertCfgToBasicBlocks(cfInfo) {
|
|
22
|
+
const newCfg = wrapEveryVertexInBasicBlock(cfInfo.graph);
|
|
23
|
+
if (!newCfg) {
|
|
24
|
+
return cfInfo;
|
|
25
|
+
}
|
|
26
|
+
for (const [id, vtx] of newCfg.vertices(false)) {
|
|
27
|
+
if (vtx.type !== control_flow_graph_1.CfgVertexType.Block) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const outgoing = newCfg.outgoingEdges(id);
|
|
31
|
+
const target = singleOutgoingFd(outgoing);
|
|
32
|
+
if (target) {
|
|
33
|
+
const targetIn = newCfg.ingoingEdges(target);
|
|
34
|
+
if (targetIn && targetIn.size === 1) {
|
|
35
|
+
newCfg.mergeTwoBasicBlocks(id, target);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const ingoing = newCfg.ingoingEdges(id);
|
|
39
|
+
const ingoingTarget = singleOutgoingFd(ingoing);
|
|
40
|
+
if (ingoingTarget) {
|
|
41
|
+
const ingoingOut = newCfg.outgoingEdges(ingoingTarget);
|
|
42
|
+
if (ingoingOut && ingoingOut.size === 1) {
|
|
43
|
+
newCfg.mergeTwoBasicBlocks(ingoingTarget, id);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const findEntries = cfInfo.entryPoints.map(e => newCfg.getBasicBlock(e)?.id);
|
|
48
|
+
const findExits = cfInfo.exitPoints.map(e => newCfg.getBasicBlock(e)?.id);
|
|
49
|
+
if (findEntries.some(f => f === undefined) || findExits.some(f => f === undefined)) {
|
|
50
|
+
/* something went wrong */
|
|
51
|
+
return cfInfo;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
...cfInfo,
|
|
55
|
+
graph: newCfg,
|
|
56
|
+
entryPoints: findEntries,
|
|
57
|
+
exitPoints: findExits,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** only returns undefined when the cfg already contains basic blocks */
|
|
61
|
+
function wrapEveryVertexInBasicBlock(existing) {
|
|
62
|
+
const newGraph = new control_flow_graph_1.ControlFlowGraph();
|
|
63
|
+
for (const [id, vertex] of existing.vertices(false)) {
|
|
64
|
+
if (vertex.type === control_flow_graph_1.CfgVertexType.Block) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
newGraph.addVertex({
|
|
68
|
+
type: control_flow_graph_1.CfgVertexType.Block,
|
|
69
|
+
elems: [vertex],
|
|
70
|
+
id: 'bb-' + id,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// promote all edges
|
|
74
|
+
for (const [from, outgoing] of existing.edges().entries()) {
|
|
75
|
+
for (const [to, edge] of outgoing.entries()) {
|
|
76
|
+
newGraph.addEdge('bb-' + from, 'bb-' + to, edge);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return newGraph;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=cfg-to-basic-blocks.js.map
|