@eagleoutice/flowr 2.2.12 → 2.2.14
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.js +2 -2
- 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 +1 -1
- package/benchmark/summarizer/summarizer.js +1 -1
- package/cli/common/options.js +4 -4
- 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 +4 -2
- package/cli/repl/commands/repl-dataflow.js +3 -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 +47 -24
- package/config.js +3 -3
- 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.js +9 -6
- package/dataflow/environments/built-in.d.ts +8 -4
- package/dataflow/environments/built-in.js +47 -5
- package/dataflow/environments/default-builtin-config.d.ts +2 -0
- package/dataflow/environments/default-builtin-config.js +81 -14
- package/dataflow/environments/resolve-by-name.js +15 -4
- package/dataflow/extractor.js +2 -2
- package/dataflow/graph/dataflowgraph-builder.d.ts +3 -1
- package/dataflow/graph/dataflowgraph-builder.js +4 -2
- 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 +11 -3
- package/dataflow/graph/graph.js +27 -12
- package/dataflow/graph/vertex.d.ts +17 -2
- package/dataflow/internal/linker.d.ts +3 -2
- package/dataflow/internal/linker.js +33 -24
- 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.js +12 -9
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +84 -16
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +23 -16
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +5 -5
- 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 +1 -1
- 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 +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +19 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +19 -4
- 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.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +3 -3
- package/dataflow/internal/process/functions/call/common.d.ts +4 -1
- package/dataflow/internal/process/functions/call/common.js +5 -3
- 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.js +1 -1
- 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 +1 -1
- package/dataflow/internal/process/process-named-call.js +5 -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 +13 -6
- package/documentation/doc-util/doc-cfg.js +20 -15
- package/documentation/doc-util/doc-cli-option.js +4 -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 +27 -1
- package/documentation/print-cfg-wiki.js +508 -20
- 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 +1 -1
- package/documentation/print-linter-wiki.d.ts +1 -0
- package/documentation/print-linter-wiki.js +76 -0
- 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 +21 -1
- package/documentation/print-readme.js +10 -3
- package/linter/linter-executor.d.ts +9 -0
- package/linter/linter-executor.js +26 -0
- package/linter/linter-format.d.ts +65 -0
- package/linter/linter-format.js +9 -0
- package/linter/linter-rules.d.ts +42 -0
- package/linter/linter-rules.js +14 -0
- package/linter/rules/1-deprecated-functions.d.ts +34 -0
- package/linter/rules/1-deprecated-functions.js +54 -0
- package/linter/rules/2-file-path-validity.d.ts +48 -0
- package/linter/rules/2-file-path-validity.js +93 -0
- 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 +3 -3
- package/queries/catalog/call-context-query/call-context-query-format.js +7 -3
- 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 +3 -1
- package/queries/catalog/cluster-query/cluster-query-format.js +6 -2
- package/queries/catalog/config-query/config-query-format.d.ts +2 -1
- package/queries/catalog/config-query/config-query-format.js +4 -3
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +2 -1
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +4 -3
- package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +3 -1
- package/queries/catalog/dataflow-query/dataflow-query-format.js +11 -3
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +4 -2
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +2 -1
- package/queries/catalog/dependencies-query/dependencies-query-format.js +12 -3
- 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 +2 -1
- package/queries/catalog/happens-before-query/happens-before-query-format.js +4 -3
- package/queries/catalog/id-map-query/id-map-query-format.d.ts +2 -1
- package/queries/catalog/id-map-query/id-map-query-format.js +4 -3
- package/queries/catalog/lineage-query/lineage-query-format.d.ts +2 -1
- package/queries/catalog/lineage-query/lineage-query-format.js +7 -3
- package/queries/catalog/linter-query/linter-query-executor.d.ts +3 -0
- package/queries/catalog/linter-query/linter-query-executor.js +28 -0
- package/queries/catalog/linter-query/linter-query-format.d.ts +80 -0
- package/queries/catalog/linter-query/linter-query-format.js +43 -0
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +2 -1
- package/queries/catalog/location-map-query/location-map-query-format.js +4 -3
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +2 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +4 -3
- 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 +73 -0
- package/queries/catalog/origin-query/origin-query-format.js +31 -0
- package/queries/catalog/project-query/project-query-executor.js +1 -1
- package/queries/catalog/project-query/project-query-format.d.ts +2 -1
- package/queries/catalog/project-query/project-query-format.js +4 -3
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +4 -3
- package/queries/catalog/search-query/search-query-format.d.ts +2 -1
- package/queries/catalog/search-query/search-query-format.js +7 -3
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +3 -1
- package/queries/catalog/static-slice-query/static-slice-query-format.js +11 -3
- package/queries/query-print.d.ts +1 -1
- package/queries/query-print.js +4 -4
- package/queries/query.d.ts +143 -2
- package/queries/query.js +5 -1
- 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 +2 -2
- package/search/flowr-search-builder.d.ts +31 -2
- package/search/flowr-search-builder.js +30 -0
- package/search/flowr-search.d.ts +7 -1
- package/search/search-executor/search-enrichers.d.ts +73 -0
- package/search/search-executor/search-enrichers.js +98 -0
- package/search/search-executor/search-generators.d.ts +7 -2
- package/search/search-executor/search-generators.js +21 -1
- package/search/search-executor/search-mappers.d.ts +19 -0
- package/search/search-executor/search-mappers.js +21 -0
- package/search/search-executor/search-transformer.d.ts +13 -1
- package/search/search-executor/search-transformer.js +11 -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} +1 -1
- package/util/{arrays.js → collections/arrays.js} +3 -3
- package/util/collections/set.js +17 -0
- 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/cfg.d.ts +9 -2
- package/util/mermaid/cfg.js +64 -12
- 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/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
|
@@ -45,10 +45,10 @@ const message_slice_1 = require("./messages/message-slice");
|
|
|
45
45
|
const server_1 = require("./server");
|
|
46
46
|
const message_repl_1 = require("./messages/message-repl");
|
|
47
47
|
const core_1 = require("../core");
|
|
48
|
-
const
|
|
48
|
+
const extract_cfg_1 = require("../../../control-flow/extract-cfg");
|
|
49
49
|
const quads_1 = require("../../../util/quads");
|
|
50
50
|
const print_1 = require("../../../core/print/print");
|
|
51
|
-
const ansi_1 = require("../../../util/ansi");
|
|
51
|
+
const ansi_1 = require("../../../util/text/ansi");
|
|
52
52
|
const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipelines");
|
|
53
53
|
const graph_1 = require("../../../dataflow/graph/graph");
|
|
54
54
|
const tmp = __importStar(require("tmp"));
|
|
@@ -160,7 +160,7 @@ class FlowRServerConnection {
|
|
|
160
160
|
async sendFileAnalysisResponse(slicer, results, message) {
|
|
161
161
|
let cfg = undefined;
|
|
162
162
|
if (message.cfg) {
|
|
163
|
-
cfg = (0,
|
|
163
|
+
cfg = (0, extract_cfg_1.extractCfg)(results.normalize, results.dataflow?.graph);
|
|
164
164
|
}
|
|
165
165
|
const config = () => ({ context: message.filename ?? 'unknown', getId: (0, quads_1.defaultQuadIdGenerator)() });
|
|
166
166
|
const sanitizedResults = sanitizeAnalysisResults(results);
|
|
@@ -174,7 +174,7 @@ class FlowRServerConnection {
|
|
|
174
174
|
type: 'response-file-analysis',
|
|
175
175
|
format: 'n-quads',
|
|
176
176
|
id: message.id,
|
|
177
|
-
cfg: cfg ? (0,
|
|
177
|
+
cfg: cfg ? (0, extract_cfg_1.cfg2quads)(cfg, config()) : undefined,
|
|
178
178
|
results: {
|
|
179
179
|
parse: await (0, print_1.printStepResult)(parseStep, sanitizedResults.parse, 5 /* StepOutputFormat.RdfQuads */, config()),
|
|
180
180
|
normalize: await (0, print_1.printStepResult)(normalizedStep, sanitizedResults.normalize, 5 /* StepOutputFormat.RdfQuads */, config()),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IdMessageBase, MessageDefinition } from './all-messages';
|
|
2
|
-
import type { ControlFlowInformation } from '../../../../util/cfg/cfg';
|
|
3
2
|
import type { DEFAULT_DATAFLOW_PIPELINE } from '../../../../core/steps/pipeline/default-pipelines';
|
|
4
3
|
import type { PipelineOutput } from '../../../../core/steps/pipeline/pipeline';
|
|
4
|
+
import type { ControlFlowInformation } from '../../../../control-flow/control-flow-graph';
|
|
5
5
|
/**
|
|
6
6
|
* Send by the client to request an analysis of a given file.
|
|
7
7
|
* Answered by either an {@link FlowrErrorMessage} or a {@link FileAnalysisResponseMessageJson}.
|
|
@@ -15,7 +15,7 @@ const log_1 = require("../../util/log");
|
|
|
15
15
|
const statistics_helper_core_1 = require("./statistics-helper-core");
|
|
16
16
|
const command_line_args_1 = __importDefault(require("command-line-args"));
|
|
17
17
|
const scripts_info_1 = require("../common/scripts-info");
|
|
18
|
-
const ansi_1 = require("../../util/ansi");
|
|
18
|
+
const ansi_1 = require("../../util/text/ansi");
|
|
19
19
|
const testRegex = /[^/]*\/test/i;
|
|
20
20
|
const exampleRegex = /[^/]*\/example/i;
|
|
21
21
|
function getPrefixForFile(file) {
|
|
@@ -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
|
@@ -35,6 +35,52 @@ export declare enum DropPathsOption {
|
|
|
35
35
|
/** try to drop every folder of the path */
|
|
36
36
|
All = "all"
|
|
37
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
|
+
}
|
|
38
84
|
export interface FlowrConfigOptions extends MergeableRecord {
|
|
39
85
|
/**
|
|
40
86
|
* Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped
|
|
@@ -88,30 +134,7 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
88
134
|
* based on the configurations you give it.
|
|
89
135
|
* This option is only in effect if {@link ignoreSourceCalls} is set to false.
|
|
90
136
|
*/
|
|
91
|
-
readonly resolveSource?:
|
|
92
|
-
/**
|
|
93
|
-
* search for filenames matching in the lowercase
|
|
94
|
-
*/
|
|
95
|
-
readonly ignoreCapitalization: boolean;
|
|
96
|
-
/**
|
|
97
|
-
* try to infer the working directory from the main or any script to analyze.
|
|
98
|
-
*/
|
|
99
|
-
readonly inferWorkingDirectory: InferWorkingDirectory;
|
|
100
|
-
/**
|
|
101
|
-
* Additionally search in these paths
|
|
102
|
-
*/
|
|
103
|
-
readonly searchPath: readonly string[];
|
|
104
|
-
/**
|
|
105
|
-
* Allow to drop the first or all parts of the sourced path,
|
|
106
|
-
* if it is relative.
|
|
107
|
-
*/
|
|
108
|
-
readonly dropPaths: DropPathsOption;
|
|
109
|
-
/**
|
|
110
|
-
* How often the same file can be sourced within a single run?
|
|
111
|
-
* Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit.
|
|
112
|
-
*/
|
|
113
|
-
readonly repeatedSourceLimit?: number;
|
|
114
|
-
};
|
|
137
|
+
readonly resolveSource?: FlowrLaxSourcingOptions;
|
|
115
138
|
/**
|
|
116
139
|
* The configuration for flowR's slicer
|
|
117
140
|
*/
|
package/config.js
CHANGED
|
@@ -52,7 +52,6 @@ var DropPathsOption;
|
|
|
52
52
|
/** try to drop every folder of the path */
|
|
53
53
|
DropPathsOption["All"] = "all";
|
|
54
54
|
})(DropPathsOption || (exports.DropPathsOption = DropPathsOption = {}));
|
|
55
|
-
;
|
|
56
55
|
const defaultEngineConfigs = {
|
|
57
56
|
'tree-sitter': { type: 'tree-sitter' },
|
|
58
57
|
'r-shell': { type: 'r-shell' }
|
|
@@ -72,7 +71,7 @@ exports.defaultConfigOptions = {
|
|
|
72
71
|
solver: {
|
|
73
72
|
variables: VariableResolve.Alias,
|
|
74
73
|
evalStrings: true,
|
|
75
|
-
pointerTracking:
|
|
74
|
+
pointerTracking: false,
|
|
76
75
|
resolveSource: {
|
|
77
76
|
dropPaths: DropPathsOption.No,
|
|
78
77
|
ignoreCapitalization: true,
|
|
@@ -116,7 +115,8 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
116
115
|
ignoreCapitalization: joi_1.default.boolean().description('Search for filenames matching in the lowercase.'),
|
|
117
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.'),
|
|
118
117
|
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.'),
|
|
119
|
-
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.')
|
|
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')
|
|
120
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.'),
|
|
121
121
|
slicer: joi_1.default.object({
|
|
122
122
|
threshold: joi_1.default.number().optional().description('The maximum number of iterations to perform on a single function call during slicing.')
|
|
@@ -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
|