@eagleoutice/flowr 2.9.12 → 2.9.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 +35 -23
- package/abstract-interpretation/absint-visitor.d.ts +1 -1
- package/abstract-interpretation/absint-visitor.js +20 -20
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +2 -2
- package/benchmark/slicer.d.ts +5 -3
- package/benchmark/slicer.js +26 -10
- package/benchmark/stats/print.js +12 -0
- package/benchmark/stats/stats.d.ts +3 -2
- package/benchmark/stats/stats.js +1 -1
- package/benchmark/summarizer/data.d.ts +1 -0
- package/benchmark/summarizer/second-phase/process.js +5 -0
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +2 -1
- package/cli/benchmark-helper-app.js +6 -3
- package/cli/common/options.d.ts +8 -0
- package/cli/common/options.js +3 -1
- package/cli/common/scripts-info.d.ts +8 -0
- package/cli/export-quads-app.js +1 -1
- package/cli/flowr.js +3 -3
- package/cli/repl/commands/repl-dataflow.js +5 -5
- package/cli/repl/core.d.ts +3 -3
- package/cli/repl/parser/slice-query-parser.d.ts +1 -1
- package/cli/repl/parser/slice-query-parser.js +2 -2
- package/cli/repl/server/connection.d.ts +2 -2
- package/cli/repl/server/connection.js +2 -2
- package/cli/repl/server/messages/message-slice.d.ts +1 -1
- package/cli/repl/server/messages/message-slice.js +2 -2
- package/cli/repl/server/server.d.ts +2 -2
- package/cli/script-core/statistics-core.d.ts +2 -2
- package/cli/script-core/statistics-helper-core.d.ts +2 -2
- package/cli/script-core/statistics-helper-core.js +1 -1
- package/cli/slicer-app.js +2 -2
- package/cli/statistics-app.js +1 -1
- package/cli/statistics-helper-app.js +1 -1
- package/cli/wiki.js +2 -2
- package/config.d.ts +65 -24
- package/config.js +197 -161
- package/control-flow/extract-cfg.js +7 -10
- package/control-flow/semantic-cfg-guided-visitor.d.ts +1 -1
- package/control-flow/semantic-cfg-guided-visitor.js +43 -43
- package/control-flow/useless-loop.d.ts +1 -1
- package/control-flow/useless-loop.js +3 -3
- package/core/print/dataflow-printer.d.ts +0 -14
- package/core/print/dataflow-printer.js +0 -21
- package/core/steps/all/core/20-dataflow.d.ts +3 -3
- package/core/steps/all/core/20-dataflow.js +3 -2
- package/core/steps/all/static-slicing/00-slice.d.ts +2 -5
- package/core/steps/all/static-slicing/00-slice.js +6 -8
- package/core/steps/pipeline/default-pipelines.d.ts +89 -89
- package/core/steps/pipeline-step.d.ts +2 -2
- package/dataflow/environments/built-in-proc-name.d.ts +83 -0
- package/dataflow/environments/built-in-proc-name.js +88 -0
- package/dataflow/environments/built-in.d.ts +1 -83
- package/dataflow/environments/built-in.js +37 -120
- package/dataflow/environments/default-builtin-config.d.ts +1 -1
- package/dataflow/environments/default-builtin-config.js +75 -75
- package/dataflow/environments/identifier.d.ts +1 -0
- package/dataflow/environments/identifier.js +1 -0
- package/dataflow/eval/resolve/alias-tracking.js +12 -15
- package/dataflow/eval/resolve/resolve.js +2 -2
- package/dataflow/fn/exceptions-of-function.d.ts +1 -1
- package/dataflow/fn/exceptions-of-function.js +2 -2
- package/dataflow/graph/call-graph.d.ts +49 -19
- package/dataflow/graph/call-graph.js +117 -114
- package/dataflow/graph/dataflowgraph-builder.d.ts +1 -1
- package/dataflow/graph/dataflowgraph-builder.js +2 -2
- package/dataflow/graph/df-helper.d.ts +132 -0
- package/dataflow/graph/df-helper.js +131 -0
- package/dataflow/graph/diff-dataflow-graph.d.ts +5 -10
- package/dataflow/graph/diff-dataflow-graph.js +3 -28
- package/dataflow/graph/edge.d.ts +1 -0
- package/dataflow/graph/edge.js +1 -0
- package/dataflow/graph/graph-helper.d.ts +55 -0
- package/dataflow/graph/graph-helper.js +105 -0
- package/dataflow/graph/graph.d.ts +6 -1
- package/dataflow/graph/graph.js +14 -9
- package/dataflow/graph/vertex.d.ts +1 -1
- package/dataflow/info.d.ts +14 -4
- package/dataflow/info.js +28 -16
- package/dataflow/internal/linker.d.ts +14 -10
- package/dataflow/internal/linker.js +29 -32
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +7 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +1 -1
- 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 +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-get.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-library.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-local.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-local.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-recall.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +5 -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-s-seven-dispatch.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-s-three-dispatch.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-s-three-dispatch.js +7 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +23 -12
- package/dataflow/internal/process/functions/call/built-in/built-in-special-bin-op.js +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +6 -9
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +2 -2
- package/dataflow/internal/process/functions/call/known-call-handling.js +2 -2
- package/dataflow/internal/process/functions/call/named-call-handling.d.ts +1 -1
- package/dataflow/internal/process/functions/call/named-call-handling.js +1 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +2 -2
- package/dataflow/internal/process/process-uninteresting-leaf.d.ts +1 -1
- package/dataflow/internal/process/process-uninteresting-leaf.js +1 -1
- package/dataflow/origin/dfg-get-origin.d.ts +1 -1
- package/dataflow/origin/dfg-get-symbol-refs.js +6 -6
- package/documentation/doc-readme.js +2 -2
- package/documentation/doc-util/doc-dfg.d.ts +3 -0
- package/documentation/doc-util/doc-dfg.js +5 -7
- package/documentation/doc-util/doc-normalized-ast.d.ts +0 -6
- package/documentation/doc-util/doc-normalized-ast.js +0 -23
- package/documentation/doc-util/doc-structure.js +3 -3
- package/documentation/doc-util/doc-types.js +3 -3
- package/documentation/wiki-analyzer.js +7 -5
- package/documentation/wiki-core.js +6 -7
- package/documentation/wiki-dataflow-graph.js +15 -13
- package/documentation/wiki-interface.js +8 -6
- package/documentation/wiki-linter.js +6 -5
- package/documentation/wiki-mk/doc-context.js +3 -4
- package/documentation/wiki-normalized-ast.js +5 -4
- package/documentation/wiki-query.js +28 -3
- package/engines.d.ts +2 -2
- package/engines.js +4 -4
- package/linter/linter-rules.d.ts +24 -1
- package/linter/linter-rules.js +3 -1
- package/linter/rules/dataframe-access-validation.js +5 -5
- package/linter/rules/naming-convention.d.ts +1 -1
- package/linter/rules/naming-convention.js +7 -3
- package/linter/rules/seeded-randomness.js +2 -2
- package/linter/rules/stop-with-call-arg.d.ts +35 -0
- package/linter/rules/stop-with-call-arg.js +72 -0
- package/linter/rules/useless-loop.d.ts +1 -1
- package/package.json +3 -1
- package/project/cache/flowr-analyzer-cache.d.ts +1 -1
- package/project/cache/flowr-analyzer-cache.js +1 -1
- package/project/context/flowr-analyzer-context.d.ts +6 -6
- package/project/context/flowr-analyzer-context.js +2 -2
- package/project/context/flowr-analyzer-files-context.d.ts +2 -2
- package/project/context/flowr-analyzer-files-context.js +28 -8
- package/project/flowr-analyzer-builder.d.ts +13 -6
- package/project/flowr-analyzer-builder.js +12 -3
- package/project/flowr-analyzer.d.ts +4 -4
- package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.js +2 -2
- package/queries/catalog/call-graph-query/call-graph-query-format.d.ts +1 -1
- package/queries/catalog/call-graph-query/call-graph-query-format.js +2 -2
- package/queries/catalog/cluster-query/cluster-query-format.js +2 -2
- package/queries/catalog/config-query/config-query-format.d.ts +5 -5
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +2 -2
- package/queries/catalog/dataflow-query/dataflow-query-format.js +2 -2
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +1 -2
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +2 -2
- package/queries/catalog/does-call-query/does-call-query-executor.js +2 -2
- package/queries/catalog/does-call-query/does-call-query-format.d.ts +2 -2
- package/queries/catalog/files-query/files-query-format.d.ts +3 -3
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +2 -2
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +1 -1
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +1 -1
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +2 -2
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -3
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +2 -2
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +2 -2
- package/queries/catalog/linter-query/linter-query-format.d.ts +3 -3
- package/queries/catalog/location-map-query/location-map-query-executor.js +2 -2
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +2 -2
- package/queries/catalog/origin-query/origin-query-executor.d.ts +1 -1
- package/queries/catalog/origin-query/origin-query-executor.js +3 -3
- package/queries/catalog/origin-query/origin-query-format.d.ts +2 -2
- package/queries/catalog/provenance-query/provenance-query-executor.d.ts +9 -0
- package/queries/catalog/provenance-query/provenance-query-executor.js +37 -0
- package/queries/catalog/provenance-query/provenance-query-format.d.ts +35 -0
- package/queries/catalog/provenance-query/provenance-query-format.js +62 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +4 -4
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +4 -0
- package/queries/catalog/search-query/search-query-format.js +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +4 -2
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +4 -4
- package/queries/catalog/static-slice-query/static-slice-query-format.js +3 -3
- package/queries/query.d.ts +27 -19
- package/queries/query.js +2 -0
- package/r-bridge/lang-4.x/ast/model/model.d.ts +13 -2
- package/r-bridge/lang-4.x/ast/model/model.js +20 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +8 -1
- package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.js +13 -0
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +2 -2
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +6 -2
- package/search/flowr-search-filters.d.ts +1 -1
- package/search/flowr-search-printer.js +3 -3
- package/search/search-executor/search-enrichers.js +2 -2
- package/search/search-executor/search-generators.js +1 -1
- package/slicing/criterion/parse.d.ts +40 -16
- package/slicing/criterion/parse.js +67 -63
- package/slicing/static/slicer-types.d.ts +2 -3
- package/slicing/static/static-slicer.d.ts +3 -4
- package/slicing/static/static-slicer.js +9 -12
- package/statistics/statistics.d.ts +2 -2
- package/util/diff.d.ts +2 -2
- package/util/mermaid/ast.js +4 -4
- package/util/mermaid/cfg.js +5 -5
- package/util/mermaid/dfg.d.ts +33 -18
- package/util/mermaid/dfg.js +46 -31
- package/util/mermaid/mermaid.d.ts +57 -12
- package/util/mermaid/mermaid.js +74 -67
- package/util/objects.d.ts +12 -0
- package/util/objects.js +28 -0
- package/util/range.d.ts +8 -0
- package/util/range.js +13 -1
- package/util/slice-direction.d.ts +7 -0
- package/util/slice-direction.js +12 -0
- package/util/summarizer.js +1 -1
- package/util/version.js +1 -1
- package/dataflow/graph/invert-dfg.d.ts +0 -6
- package/dataflow/graph/invert-dfg.js +0 -20
- package/dataflow/graph/resolve-graph.d.ts +0 -8
- package/dataflow/graph/resolve-graph.js +0 -59
|
@@ -5,7 +5,6 @@ const processor_1 = require("../../../../../processor");
|
|
|
5
5
|
const info_1 = require("../../../../../info");
|
|
6
6
|
const known_call_handling_1 = require("../known-call-handling");
|
|
7
7
|
const logger_1 = require("../../../../../logger");
|
|
8
|
-
const built_in_1 = require("../../../../../environments/built-in");
|
|
9
8
|
const linker_1 = require("../../../../linker");
|
|
10
9
|
const common_1 = require("../common");
|
|
11
10
|
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
@@ -15,6 +14,7 @@ const identifier_1 = require("../../../../../environments/identifier");
|
|
|
15
14
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
16
15
|
const range_1 = require("../../../../../../util/range");
|
|
17
16
|
const r_argument_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-argument");
|
|
17
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
18
18
|
/**
|
|
19
19
|
* Process an S3 dispatch call like `UseMethod`.
|
|
20
20
|
*/
|
|
@@ -28,13 +28,13 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
28
28
|
[config.args.object]: 'object',
|
|
29
29
|
'...': '...'
|
|
30
30
|
};
|
|
31
|
-
const argMaps = (0, linker_1.
|
|
31
|
+
const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
|
|
32
32
|
const generic = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('generic')?.[0]));
|
|
33
33
|
if (!generic && !config.inferFromClosure) {
|
|
34
34
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
35
35
|
}
|
|
36
36
|
const obj = (0, unpack_argument_1.unpackArg)(r_argument_1.RArgument.getWithId(args, argMaps.get('object')?.[0]));
|
|
37
|
-
const dfObj = obj ? (0, processor_1.processDataflowFor)(obj, data) :
|
|
37
|
+
const dfObj = obj ? (0, processor_1.processDataflowFor)(obj, data) : info_1.DataflowInformation.initialize(rootId, data);
|
|
38
38
|
if ((0, info_1.alwaysExits)(dfObj)) {
|
|
39
39
|
(0, common_1.patchFunctionCall)({
|
|
40
40
|
nextGraph: dfObj.graph,
|
|
@@ -42,7 +42,7 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
42
42
|
name,
|
|
43
43
|
data,
|
|
44
44
|
argumentProcessResult: [dfObj],
|
|
45
|
-
origin:
|
|
45
|
+
origin: built_in_proc_name_1.BuiltInProcName.S3Dispatch
|
|
46
46
|
});
|
|
47
47
|
return dfObj;
|
|
48
48
|
}
|
|
@@ -53,7 +53,7 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
53
53
|
name,
|
|
54
54
|
data,
|
|
55
55
|
argumentProcessResult: [dfObj],
|
|
56
|
-
origin:
|
|
56
|
+
origin: built_in_proc_name_1.BuiltInProcName.S3DispatchNext
|
|
57
57
|
});
|
|
58
58
|
const ingoing = dfObj.in.concat(dfObj.unknownReferences);
|
|
59
59
|
ingoing.push({ nodeId: rootId, name: name.content, cds: data.cds, type: identifier_1.ReferenceType.Function });
|
|
@@ -95,7 +95,7 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
95
95
|
name: symbol,
|
|
96
96
|
data,
|
|
97
97
|
argumentProcessResult: [], // arguments will be attached by the accompanying enveloping function definition
|
|
98
|
-
origin:
|
|
98
|
+
origin: built_in_proc_name_1.BuiltInProcName.S3Dispatch
|
|
99
99
|
});
|
|
100
100
|
(0, common_1.patchFunctionCall)({
|
|
101
101
|
nextGraph: dfGeneric.graph,
|
|
@@ -103,7 +103,7 @@ function processS3Dispatch(name, args, rootId, data, config) {
|
|
|
103
103
|
name,
|
|
104
104
|
data,
|
|
105
105
|
argumentProcessResult: [dfGeneric, dfObj],
|
|
106
|
-
origin:
|
|
106
|
+
origin: built_in_proc_name_1.BuiltInProcName.Function
|
|
107
107
|
});
|
|
108
108
|
const ingoing = dfObj.in.concat(dfGeneric.in, dfObj.unknownReferences, dfGeneric.unknownReferences);
|
|
109
109
|
ingoing.push({ nodeId: rootId, name: name.content, cds: data.cds, type: identifier_1.ReferenceType.Function });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
2
|
-
import {
|
|
2
|
+
import { DataflowInformation } from '../../../../../info';
|
|
3
3
|
import { type FlowrLaxSourcingOptions, InferWorkingDirectory } from '../../../../../../config';
|
|
4
4
|
import { type RParseRequest } from '../../../../../../r-bridge/retriever';
|
|
5
5
|
import { type IdGenerator, type ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
@@ -45,7 +45,7 @@ export declare function processSourceCall<OtherInfo>(name: RSymbol<OtherInfo & P
|
|
|
45
45
|
* Processes a source request with the given dataflow processor information and existing dataflow information
|
|
46
46
|
* Otherwise, this can be an {@link RProjectFile} representing a standalone source file
|
|
47
47
|
*/
|
|
48
|
-
export declare function sourceRequest<OtherInfo>(rootId: NodeId, request: RParseRequest | RProjectFile<OtherInfo & ParentInformation>, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, information: DataflowInformation, getId?: IdGenerator<NoInfo>): DataflowInformation;
|
|
48
|
+
export declare function sourceRequest<OtherInfo>(rootId: NodeId, request: RParseRequest | RProjectFile<OtherInfo & ParentInformation>, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, information: DataflowInformation, makeMaybe: boolean, getId?: IdGenerator<NoInfo>): DataflowInformation;
|
|
49
49
|
/**
|
|
50
50
|
* Processes a standalone source file (i.e., not from a source function call)
|
|
51
51
|
*/
|
|
@@ -29,7 +29,8 @@ const general_1 = require("../../../../../eval/values/general");
|
|
|
29
29
|
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
30
30
|
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
31
31
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
32
|
-
const
|
|
32
|
+
const edge_1 = require("../../../../../graph/edge");
|
|
33
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
33
34
|
/**
|
|
34
35
|
* Infers working directories based on the given option and reference chain
|
|
35
36
|
*/
|
|
@@ -117,8 +118,8 @@ function findSource(resolveSource, seed, data) {
|
|
|
117
118
|
const effectivePath = explore ? path_1.default.join(explore, tryPath) : tryPath;
|
|
118
119
|
const context = data.ctx.files;
|
|
119
120
|
const get = context.exists(effectivePath, capitalization) ?? context.exists(returnPlatformPath(effectivePath), capitalization);
|
|
120
|
-
if (get && !found.includes(
|
|
121
|
-
found.push(returnPlatformPath(
|
|
121
|
+
if (get && !found.includes(returnPlatformPath(get))) {
|
|
122
|
+
found.push(returnPlatformPath(get));
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
}
|
|
@@ -136,8 +137,8 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
136
137
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
|
|
137
138
|
}
|
|
138
139
|
const information = config.includeFunctionCall ?
|
|
139
|
-
(0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin:
|
|
140
|
-
:
|
|
140
|
+
(0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.Source }).information
|
|
141
|
+
: info_1.DataflowInformation.initialize(rootId, data);
|
|
141
142
|
const sourceFileArgument = args[0];
|
|
142
143
|
if (!config.forceFollow && data.ctx.config.ignoreSourceCalls) {
|
|
143
144
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Skipping source call ${JSON.stringify(sourceFileArgument)} (disabled in config file)`);
|
|
@@ -176,7 +177,7 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
176
177
|
result = sourceRequest(rootId, {
|
|
177
178
|
request: 'file',
|
|
178
179
|
content: f
|
|
179
|
-
}, data, result, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + f, name.location));
|
|
180
|
+
}, data, result, true, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + f, name.location));
|
|
180
181
|
}
|
|
181
182
|
return result;
|
|
182
183
|
}
|
|
@@ -189,7 +190,7 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
189
190
|
* Processes a source request with the given dataflow processor information and existing dataflow information
|
|
190
191
|
* Otherwise, this can be an {@link RProjectFile} representing a standalone source file
|
|
191
192
|
*/
|
|
192
|
-
function sourceRequest(rootId, request, data, information, getId) {
|
|
193
|
+
function sourceRequest(rootId, request, data, information, makeMaybe, getId) {
|
|
193
194
|
// parse, normalize and dataflow the sourced file
|
|
194
195
|
let dataflow;
|
|
195
196
|
let fst;
|
|
@@ -239,11 +240,21 @@ function sourceRequest(rootId, request, data, information, getId) {
|
|
|
239
240
|
}
|
|
240
241
|
// take the entry point as well as all the written references, and give them a control dependency to the source call to show that they are conditional
|
|
241
242
|
if (!String(rootId).startsWith('file-')) {
|
|
242
|
-
if (
|
|
243
|
-
dataflow.graph.
|
|
243
|
+
if (makeMaybe) {
|
|
244
|
+
if (dataflow.graph.hasVertex(dataflow.entryPoint)) {
|
|
245
|
+
dataflow.graph.addControlDependency(dataflow.entryPoint, rootId, true);
|
|
246
|
+
}
|
|
247
|
+
for (const out of dataflow.out) {
|
|
248
|
+
dataflow.graph.addControlDependency(out.nodeId, rootId, true);
|
|
249
|
+
}
|
|
244
250
|
}
|
|
245
|
-
|
|
246
|
-
dataflow.graph.
|
|
251
|
+
else {
|
|
252
|
+
if (dataflow.graph.hasVertex(dataflow.entryPoint)) {
|
|
253
|
+
dataflow.graph.addEdge(dataflow.entryPoint, rootId, edge_1.EdgeType.Reads);
|
|
254
|
+
}
|
|
255
|
+
for (const out of dataflow.out) {
|
|
256
|
+
dataflow.graph.addEdge(out.nodeId, rootId, edge_1.EdgeType.Reads);
|
|
257
|
+
}
|
|
247
258
|
}
|
|
248
259
|
}
|
|
249
260
|
data.ctx.files.addConsideredFile(filePath ?? '<inline>');
|
|
@@ -272,6 +283,6 @@ function standaloneSourceFile(idx, file, data, information) {
|
|
|
272
283
|
...data,
|
|
273
284
|
environment: information.environment,
|
|
274
285
|
referenceChain: [...data.referenceChain, file.filePath]
|
|
275
|
-
}, information);
|
|
286
|
+
}, information, false);
|
|
276
287
|
}
|
|
277
288
|
//# sourceMappingURL=built-in-source.js.map
|
|
@@ -4,8 +4,8 @@ exports.processSpecialBinOp = processSpecialBinOp;
|
|
|
4
4
|
const known_call_handling_1 = require("../known-call-handling");
|
|
5
5
|
const logger_1 = require("../../../../../logger");
|
|
6
6
|
const edge_1 = require("../../../../../graph/edge");
|
|
7
|
-
const built_in_1 = require("../../../../../environments/built-in");
|
|
8
7
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
8
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
9
9
|
/**
|
|
10
10
|
* Process a special built-in binary operator, possibly lazily.
|
|
11
11
|
* For example, the logical AND `&&` and OR `||` operators only evaluate their right-hand side if necessary.
|
|
@@ -13,7 +13,7 @@ const identifier_1 = require("../../../../../environments/identifier");
|
|
|
13
13
|
*/
|
|
14
14
|
function processSpecialBinOp(name, args, rootId, data, config) {
|
|
15
15
|
if (!config.lazy) {
|
|
16
|
-
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin:
|
|
16
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.SpecialBinOp }).information;
|
|
17
17
|
}
|
|
18
18
|
else if (args.length != 2) {
|
|
19
19
|
logger_1.dataflowLogger.warn(`Logical bin-op ${identifier_1.Identifier.toString(name.content)} has something else than 2 arguments, skipping`);
|
|
@@ -26,7 +26,7 @@ function processSpecialBinOp(name, args, rootId, data, config) {
|
|
|
26
26
|
}
|
|
27
27
|
return d;
|
|
28
28
|
},
|
|
29
|
-
origin:
|
|
29
|
+
origin: built_in_proc_name_1.BuiltInProcName.SpecialBinOp
|
|
30
30
|
});
|
|
31
31
|
for (const arg of processedArguments) {
|
|
32
32
|
if (arg) {
|
|
@@ -9,8 +9,8 @@ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
|
9
9
|
const general_1 = require("../../../../../eval/values/general");
|
|
10
10
|
const assert_1 = require("../../../../../../util/assert");
|
|
11
11
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
12
|
-
const built_in_1 = require("../../../../../environments/built-in");
|
|
13
12
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
13
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
14
14
|
/**
|
|
15
15
|
* Processes a built-in 'stopifnot' function call.
|
|
16
16
|
* This is special in that it may take a number of boolean expressions either via `...` or
|
|
@@ -26,7 +26,7 @@ const identifier_1 = require("../../../../../environments/identifier");
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
function processStopIfNot(name, args, rootId, data) {
|
|
29
|
-
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin:
|
|
29
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.StopIfNot }).information;
|
|
30
30
|
if (args.length === 0) {
|
|
31
31
|
logger_1.dataflowLogger.warn(`stopifnot (${identifier_1.Identifier.toString(name.content)}) has no argument, assuming trivially true and skipping`);
|
|
32
32
|
return res;
|
|
@@ -11,20 +11,17 @@ const unpack_argument_1 = require("../argument/unpack-argument");
|
|
|
11
11
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
12
12
|
const assert_1 = require("../../../../../../util/assert");
|
|
13
13
|
const edge_1 = require("../../../../../graph/edge");
|
|
14
|
-
const built_in_1 = require("../../../../../environments/built-in");
|
|
15
14
|
const unnamed_call_handling_1 = require("../unnamed-call-handling");
|
|
16
15
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
17
16
|
const identifier_2 = require("../../../../../environments/identifier");
|
|
18
17
|
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
19
18
|
const log_1 = require("../../../../../../util/log");
|
|
20
|
-
|
|
21
|
-
return new Set(argMaps.entries().filter(([, v]) => v === name).map(([k]) => k));
|
|
22
|
-
}
|
|
19
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
23
20
|
/**
|
|
24
21
|
* Process a built-in try-catch or similar handler.
|
|
25
22
|
*/
|
|
26
23
|
function processTryCatch(name, args, rootId, data, config) {
|
|
27
|
-
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: args.map(unpack_argument_1.tryUnpackNoNameArg), rootId, data, origin:
|
|
24
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: args.map(unpack_argument_1.tryUnpackNoNameArg), rootId, data, origin: built_in_proc_name_1.BuiltInProcName.Try, forceArgs: 'all' });
|
|
28
25
|
if (args.length < 1 || args[0] === r_function_call_1.EmptyArgument) {
|
|
29
26
|
logger_1.dataflowLogger.warn(`TryCatch Handler ${identifier_1.Identifier.toString(name.content)} does not have 1 argument, skipping`);
|
|
30
27
|
return res.information;
|
|
@@ -43,9 +40,9 @@ function processTryCatch(name, args, rootId, data, config) {
|
|
|
43
40
|
// only remove exit points from the block
|
|
44
41
|
const argMaps = (0, linker_1.pMatch)(res.callArgs, params);
|
|
45
42
|
const info = res.information;
|
|
46
|
-
const blockArg =
|
|
47
|
-
const errorArg =
|
|
48
|
-
const finallyArg =
|
|
43
|
+
const blockArg = new Set(argMaps.get('block'));
|
|
44
|
+
const errorArg = new Set(argMaps.get('error'));
|
|
45
|
+
const finallyArg = new Set(argMaps.get('finally'));
|
|
49
46
|
// only take those exit points from the block
|
|
50
47
|
// check whether blockArg has *always* happening exceptions, if so we do not constrain the error handler
|
|
51
48
|
const blockErrorExitPoints = [];
|
|
@@ -158,7 +155,7 @@ function promoteCallToFunction(call, arg, info, data) {
|
|
|
158
155
|
environment: data.environment,
|
|
159
156
|
onlyBuiltin: false,
|
|
160
157
|
cds: data.cds,
|
|
161
|
-
origin: [
|
|
158
|
+
origin: [built_in_proc_name_1.BuiltInProcName.Function]
|
|
162
159
|
});
|
|
163
160
|
return functionId;
|
|
164
161
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.processVector = processVector;
|
|
4
4
|
const known_call_handling_1 = require("../known-call-handling");
|
|
5
|
-
const
|
|
5
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
6
6
|
/**
|
|
7
7
|
* Process a vector call.
|
|
8
8
|
*
|
|
@@ -12,6 +12,6 @@ const built_in_1 = require("../../../../../environments/built-in");
|
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
14
|
function processVector(name, args, rootId, data) {
|
|
15
|
-
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin:
|
|
15
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: built_in_proc_name_1.BuiltInProcName.Vector }).information;
|
|
16
16
|
}
|
|
17
17
|
//# sourceMappingURL=built-in-vector.js.map
|
|
@@ -13,8 +13,8 @@ const identifier_1 = require("../../../../../environments/identifier");
|
|
|
13
13
|
const general_1 = require("../../../../../eval/values/general");
|
|
14
14
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
15
15
|
const reference_to_maybe_1 = require("../../../../../environments/reference-to-maybe");
|
|
16
|
-
const built_in_1 = require("../../../../../environments/built-in");
|
|
17
16
|
const append_1 = require("../../../../../environments/append");
|
|
17
|
+
const built_in_proc_name_1 = require("../../../../../environments/built-in-proc-name");
|
|
18
18
|
/**
|
|
19
19
|
* Process a while loop like `while(cond) { ... }`.
|
|
20
20
|
*/
|
|
@@ -44,7 +44,7 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
44
44
|
rootId,
|
|
45
45
|
data,
|
|
46
46
|
markAsNSE: [1],
|
|
47
|
-
origin:
|
|
47
|
+
origin: built_in_proc_name_1.BuiltInProcName.WhileLoop
|
|
48
48
|
});
|
|
49
49
|
const [condition, body] = processedArguments;
|
|
50
50
|
// If the condition is always false, we don't include the body
|
|
@@ -10,7 +10,7 @@ const edge_1 = require("../../../../graph/edge");
|
|
|
10
10
|
const logger_1 = require("../../../../logger");
|
|
11
11
|
const vertex_1 = require("../../../../graph/vertex");
|
|
12
12
|
const unknown_side_effect_1 = require("../../../../graph/unknown-side-effect");
|
|
13
|
-
const
|
|
13
|
+
const built_in_proc_name_1 = require("../../../../environments/built-in-proc-name");
|
|
14
14
|
/**
|
|
15
15
|
* Marks the given arguments as being involved in R's non-standard evaluation.
|
|
16
16
|
*/
|
|
@@ -49,7 +49,7 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
|
|
|
49
49
|
onlyBuiltin: false,
|
|
50
50
|
cds: data.cds,
|
|
51
51
|
args: reverseOrder ? callArgs.toReversed() : callArgs,
|
|
52
|
-
origin: origin === 'default' ? [
|
|
52
|
+
origin: origin === 'default' ? [built_in_proc_name_1.BuiltInProcName.Function] : [origin]
|
|
53
53
|
}, data.ctx.env.makeCleanEnv());
|
|
54
54
|
if (hasUnknownSideEffect) {
|
|
55
55
|
(0, unknown_side_effect_1.handleUnknownSideEffect)(finalGraph, data.environment, rootId);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataflowProcessorInformation } from '../../../../processor';
|
|
2
|
-
import {
|
|
2
|
+
import { DataflowInformation } from '../../../../info';
|
|
3
3
|
import type { ParentInformation } from '../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
4
|
import type { RFunctionArgument } from '../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
5
|
import type { RSymbol } from '../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
@@ -64,6 +64,6 @@ function processNamedCall(name, args, rootId, data) {
|
|
|
64
64
|
// mark the function call as built in only
|
|
65
65
|
markAsOnlyBuiltIn(information.graph, rootId);
|
|
66
66
|
}
|
|
67
|
-
return information ??
|
|
67
|
+
return information ?? info_1.DataflowInformation.initialize(rootId, data);
|
|
68
68
|
}
|
|
69
69
|
//# sourceMappingURL=named-call-handling.js.map
|
|
@@ -11,7 +11,7 @@ const vertex_1 = require("../../../../graph/vertex");
|
|
|
11
11
|
const type_1 = require("../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
12
12
|
const logger_1 = require("../../../../logger");
|
|
13
13
|
const identifier_1 = require("../../../../environments/identifier");
|
|
14
|
-
const
|
|
14
|
+
const built_in_proc_name_1 = require("../../../../environments/built-in-proc-name");
|
|
15
15
|
exports.UnnamedFunctionCallPrefix = 'unnamed-fc-';
|
|
16
16
|
/**
|
|
17
17
|
* Processes an unnamed function call.
|
|
@@ -45,7 +45,7 @@ function processUnnamedFunctionCall(functionCall, data) {
|
|
|
45
45
|
onlyBuiltin: false,
|
|
46
46
|
cds: data.cds,
|
|
47
47
|
args: callArgs, // same reference
|
|
48
|
-
origin: [
|
|
48
|
+
origin: [built_in_proc_name_1.BuiltInProcName.Unnamed]
|
|
49
49
|
}, data.ctx.env.makeCleanEnv());
|
|
50
50
|
let inIds = remainingReadInArgs;
|
|
51
51
|
inIds.push({ nodeId: functionRootId, name: functionCallName, cds: data.cds, type: identifier_1.ReferenceType.Function });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DataflowInformation } from '../../info';
|
|
2
2
|
import type { DataflowProcessorInformation } from '../../processor';
|
|
3
3
|
import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
4
|
/**
|
|
@@ -8,6 +8,6 @@ const info_1 = require("../../info");
|
|
|
8
8
|
* This can be used to ignore nodes that do not affect dataflow analysis.
|
|
9
9
|
*/
|
|
10
10
|
function processUninterestingLeaf(leaf, info) {
|
|
11
|
-
return
|
|
11
|
+
return info_1.DataflowInformation.initialize(leaf.info.id, info);
|
|
12
12
|
}
|
|
13
13
|
//# sourceMappingURL=process-uninteresting-leaf.js.map
|
|
@@ -76,5 +76,5 @@ export type Origin = SimpleOrigin | FunctionCallOrigin | BuiltInFunctionOrigin;
|
|
|
76
76
|
*
|
|
77
77
|
* This returns undefined only if there is no dataflow correspondence (e.g. in case of unevaluated non-standard eval).
|
|
78
78
|
*/
|
|
79
|
-
export declare function getOriginInDfg(dfg: DataflowGraph, id: NodeId): Origin[] | undefined;
|
|
79
|
+
export declare function getOriginInDfg(this: void, dfg: DataflowGraph, id: NodeId): Origin[] | undefined;
|
|
80
80
|
export {};
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getAllRefsToSymbol = getAllRefsToSymbol;
|
|
4
4
|
const edge_1 = require("../graph/edge");
|
|
5
5
|
const info_1 = require("../info");
|
|
6
|
-
const
|
|
6
|
+
const df_helper_1 = require("../graph/df-helper");
|
|
7
7
|
/**
|
|
8
8
|
* Finds the definition of a variable and all other uses from that point on
|
|
9
9
|
*
|
|
@@ -22,7 +22,7 @@ const dfg_get_origin_1 = require("./dfg-get-origin");
|
|
|
22
22
|
*/
|
|
23
23
|
function getAllRefsToSymbol(graph, nodeId) {
|
|
24
24
|
// Get all origins and filter for ones that happen for sure
|
|
25
|
-
const origins =
|
|
25
|
+
const origins = df_helper_1.Dataflow.origin(graph, nodeId);
|
|
26
26
|
if (origins === undefined) {
|
|
27
27
|
return undefined;
|
|
28
28
|
}
|
|
@@ -32,13 +32,13 @@ function getAllRefsToSymbol(graph, nodeId) {
|
|
|
32
32
|
}
|
|
33
33
|
// Gather all the references
|
|
34
34
|
const res = new Set();
|
|
35
|
-
for (const
|
|
36
|
-
res.add(
|
|
37
|
-
graph.ingoingEdges(
|
|
35
|
+
for (const { id } of definitiveOrigins) {
|
|
36
|
+
res.add(id);
|
|
37
|
+
graph.ingoingEdges(id)
|
|
38
38
|
?.entries()
|
|
39
39
|
.filter(([_, edge]) => edge_1.DfEdge.includesType(edge, edge_1.EdgeType.Reads))
|
|
40
40
|
.forEach(([node, _]) => res.add(node));
|
|
41
|
-
graph.outgoingEdges(
|
|
41
|
+
graph.outgoingEdges(id)
|
|
42
42
|
?.entries()
|
|
43
43
|
.filter(([_, edge]) => edge_1.DfEdge.includesType(edge, edge_1.EdgeType.DefinedByOnCall))
|
|
44
44
|
.forEach(([node, _]) => res.add(node));
|
|
@@ -21,7 +21,7 @@ const PublicationsMain = [
|
|
|
21
21
|
header: 'Statically Analyzing the Dataflow of R Programs (OOPSLA \'25)',
|
|
22
22
|
description: 'Please cite this paper if you are using flowR in your research.',
|
|
23
23
|
doi: 'https://doi.org/10.1145/3763087',
|
|
24
|
-
bibtex: `@article{10.1145/3763087,
|
|
24
|
+
bibtex: String.raw `@article{10.1145/3763087,
|
|
25
25
|
author = {Sihler, Florian and Tichy, Matthias},
|
|
26
26
|
title = {Statically Analyzing the Dataflow of R Programs},
|
|
27
27
|
year = {2025},
|
|
@@ -32,7 +32,7 @@ const PublicationsMain = [
|
|
|
32
32
|
number = {OOPSLA2},
|
|
33
33
|
url = {https://doi.org/10.1145/3763087},
|
|
34
34
|
doi = {10.1145/3763087},
|
|
35
|
-
abstract = {The R programming language is primarily designed for statistical computing and mostly used by researchers without a background in computer science. R provides a wide range of dynamic features and peculiarities that are difficult to analyze statically like dynamic scoping and lazy evaluation with dynamic side effects. At the same time, the R ecosystem lacks sophisticated analysis tools that support researchers in understanding and improving their code. In this paper, we present a novel static dataflow analysis framework for the R programming language that is capable of handling the dynamic nature of R programs and produces the dataflow graph of given R programs. This graph can be essential in a range of analyses, including program slicing, which we implement as a proof of concept. The core analysis works as a stateful fold over a normalized version of the abstract syntax tree of the R program, which tracks (re-)definitions, values, function calls, side effects, external files, and a dynamic control flow to produce one dataflow graph per program. We evaluate the correctness of our analysis using output equivalence testing on a manually curated dataset of 779 sensible slicing points from executable real-world R scripts. Additionally, we use a set of systematic test cases based on the capabilities of the R language and the implementation of the R interpreter and measure the runtimes well as the memory consumption on a set of 4,230 real-world R scripts and 20,815 packages available on R’s package manager CRAN. Furthermore, we evaluate the recall of our program slicer, its accuracy using shrinking, and its improvement over the state of the art. We correctly analyze almost all programs in our equivalence test suite, preserving the identical output for 99.7
|
|
35
|
+
abstract = {The R programming language is primarily designed for statistical computing and mostly used by researchers without a background in computer science. R provides a wide range of dynamic features and peculiarities that are difficult to analyze statically like dynamic scoping and lazy evaluation with dynamic side effects. At the same time, the R ecosystem lacks sophisticated analysis tools that support researchers in understanding and improving their code. In this paper, we present a novel static dataflow analysis framework for the R programming language that is capable of handling the dynamic nature of R programs and produces the dataflow graph of given R programs. This graph can be essential in a range of analyses, including program slicing, which we implement as a proof of concept. The core analysis works as a stateful fold over a normalized version of the abstract syntax tree of the R program, which tracks (re-)definitions, values, function calls, side effects, external files, and a dynamic control flow to produce one dataflow graph per program. We evaluate the correctness of our analysis using output equivalence testing on a manually curated dataset of 779 sensible slicing points from executable real-world R scripts. Additionally, we use a set of systematic test cases based on the capabilities of the R language and the implementation of the R interpreter and measure the runtimes well as the memory consumption on a set of 4,230 real-world R scripts and 20,815 packages available on R’s package manager CRAN. Furthermore, we evaluate the recall of our program slicer, its accuracy using shrinking, and its improvement over the state of the art. We correctly analyze almost all programs in our equivalence test suite, preserving the identical output for 99.7\% of the manually curated slicing points. On average, we require 576ms to analyze the dataflow and around 213kB to store the graph of a research script. This shows that our analysis is capable of analyzing real-world sources quickly and correctly. Our slicer achieves an average reduction of 84.8\% of tokens indicating its potential to improve program comprehension.},
|
|
36
36
|
journal = {Proc. ACM Program. Lang.},
|
|
37
37
|
month = oct,
|
|
38
38
|
articleno = {309},
|
|
@@ -8,6 +8,9 @@ import type { MermaidMarkdownMark } from '../../util/mermaid/info';
|
|
|
8
8
|
* Please use this only for documentation purposes, for programmatic usage use {@link graphToMermaid} directly.
|
|
9
9
|
*/
|
|
10
10
|
export declare function printDfGraph(graph: DataflowGraph, mark?: ReadonlySet<MermaidMarkdownMark>, simplified?: boolean): string;
|
|
11
|
+
/**
|
|
12
|
+
* Options for {@link printDfGraphForCode}.
|
|
13
|
+
*/
|
|
11
14
|
export interface PrintDataflowGraphOptions {
|
|
12
15
|
readonly mark?: ReadonlySet<MermaidMarkdownMark>;
|
|
13
16
|
readonly showCode?: boolean;
|
|
@@ -4,16 +4,14 @@ exports.printDfGraph = printDfGraph;
|
|
|
4
4
|
exports.formatSideEffect = formatSideEffect;
|
|
5
5
|
exports.printDfGraphForCode = printDfGraphForCode;
|
|
6
6
|
exports.verifyExpectedSubgraph = verifyExpectedSubgraph;
|
|
7
|
-
const dfg_1 = require("../../util/mermaid/dfg");
|
|
8
7
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
9
8
|
const decorate_1 = require("../../r-bridge/lang-4.x/ast/model/processing/decorate");
|
|
10
|
-
const resolve_graph_1 = require("../../dataflow/graph/resolve-graph");
|
|
11
|
-
const diff_dataflow_graph_1 = require("../../dataflow/graph/diff-dataflow-graph");
|
|
12
9
|
const assert_1 = require("../../util/assert");
|
|
13
10
|
const time_1 = require("../../util/text/time");
|
|
14
11
|
const doc_files_1 = require("./doc-files");
|
|
15
12
|
const doc_code_1 = require("./doc-code");
|
|
16
13
|
const flowr_analyzer_context_1 = require("../../project/context/flowr-analyzer-context");
|
|
14
|
+
const df_helper_1 = require("../../dataflow/graph/df-helper");
|
|
17
15
|
const call_graph_1 = require("../../dataflow/graph/call-graph");
|
|
18
16
|
/**
|
|
19
17
|
* Visualizes the dataflow graph as a mermaid graph inside a markdown code block.
|
|
@@ -21,7 +19,7 @@ const call_graph_1 = require("../../dataflow/graph/call-graph");
|
|
|
21
19
|
*/
|
|
22
20
|
function printDfGraph(graph, mark, simplified = false) {
|
|
23
21
|
return `
|
|
24
|
-
${(0, doc_code_1.codeBlock)('mermaid',
|
|
22
|
+
${(0, doc_code_1.codeBlock)('mermaid', df_helper_1.Dataflow.visualize.mermaid.convert({
|
|
25
23
|
graph,
|
|
26
24
|
prefix: 'flowchart LR',
|
|
27
25
|
mark,
|
|
@@ -55,7 +53,7 @@ async function printDfGraphForCode(parser, code, { callGraph = false, simplified
|
|
|
55
53
|
(0, assert_1.guard)(showCode, 'can not switch code and graph if code is not shown');
|
|
56
54
|
}
|
|
57
55
|
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parse and normalize, using the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
|
|
58
|
-
const graph = callGraph ?
|
|
56
|
+
const graph = callGraph ? call_graph_1.CallGraph.compute(result.dataflow.graph) : result.dataflow.graph;
|
|
59
57
|
const dfGraph = printDfGraph(graph, mark, simplified);
|
|
60
58
|
const simplyText = simplified ? '(simplified) ' : '';
|
|
61
59
|
const graphName = callGraph ? 'Call Graph' : 'Dataflow Graph';
|
|
@@ -92,8 +90,8 @@ async function verifyExpectedSubgraph(parser, code, expectedSubgraph) {
|
|
|
92
90
|
getId: (0, decorate_1.deterministicCountingIdGenerator)(0)
|
|
93
91
|
}).allRemainingSteps();
|
|
94
92
|
expectedSubgraph.setIdMap(info.normalize.idMap);
|
|
95
|
-
expectedSubgraph =
|
|
96
|
-
const report =
|
|
93
|
+
expectedSubgraph = df_helper_1.Dataflow.resolveGraphCriteria(expectedSubgraph, context);
|
|
94
|
+
const report = df_helper_1.Dataflow.diffGraphs({ name: 'expected', graph: expectedSubgraph }, { name: 'got', graph: info.dataflow.graph }, {
|
|
97
95
|
leftIsSubgraph: true
|
|
98
96
|
});
|
|
99
97
|
(0, assert_1.guard)(report.isEqual(), () => `report:\n * ${report.comments()?.join('\n * ') ?? ''}`);
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
2
|
-
import type { RShell } from '../../r-bridge/shell';
|
|
3
1
|
import { type ParentInformation, type RNodeWithParent } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
2
|
import type { KnownParser } from '../../r-bridge/parser';
|
|
5
3
|
import type { RProject } from '../../r-bridge/lang-4.x/ast/model/nodes/r-project';
|
|
@@ -17,7 +15,3 @@ export interface PrintNormalizedAstOptions {
|
|
|
17
15
|
* This is intended for documentation purposes.
|
|
18
16
|
*/
|
|
19
17
|
export declare function printNormalizedAstForCode(parser: KnownParser, code: string, { showCode, prefix }?: PrintNormalizedAstOptions): Promise<string>;
|
|
20
|
-
/**
|
|
21
|
-
* returns resolved expected df graph
|
|
22
|
-
*/
|
|
23
|
-
export declare function verifyExpectedSubgraph(shell: RShell, code: string, expectedSubgraph: DataflowGraph): Promise<DataflowGraph>;
|
|
@@ -2,12 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.printNormalizedAst = printNormalizedAst;
|
|
4
4
|
exports.printNormalizedAstForCode = printNormalizedAstForCode;
|
|
5
|
-
exports.verifyExpectedSubgraph = verifyExpectedSubgraph;
|
|
6
5
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
7
|
-
const decorate_1 = require("../../r-bridge/lang-4.x/ast/model/processing/decorate");
|
|
8
|
-
const resolve_graph_1 = require("../../dataflow/graph/resolve-graph");
|
|
9
|
-
const diff_dataflow_graph_1 = require("../../dataflow/graph/diff-dataflow-graph");
|
|
10
|
-
const assert_1 = require("../../util/assert");
|
|
11
6
|
const ast_1 = require("../../util/mermaid/ast");
|
|
12
7
|
const time_1 = require("../../util/text/time");
|
|
13
8
|
const doc_files_1 = require("./doc-files");
|
|
@@ -59,22 +54,4 @@ ${(0, ast_1.normalizedAstToMermaid)(result.normalize.ast, { prefix })}
|
|
|
59
54
|
|
|
60
55
|
` : '\n(' + metaInfo + ')\n\n');
|
|
61
56
|
}
|
|
62
|
-
/**
|
|
63
|
-
* returns resolved expected df graph
|
|
64
|
-
*/
|
|
65
|
-
async function verifyExpectedSubgraph(shell, code, expectedSubgraph) {
|
|
66
|
-
/* we verify that we get what we want first! */
|
|
67
|
-
const context = (0, flowr_analyzer_context_1.contextFromInput)(code);
|
|
68
|
-
const info = await (0, default_pipelines_1.createDataflowPipeline)(shell, {
|
|
69
|
-
context: context,
|
|
70
|
-
getId: (0, decorate_1.deterministicCountingIdGenerator)(0)
|
|
71
|
-
}).allRemainingSteps();
|
|
72
|
-
expectedSubgraph.setIdMap(info.normalize.idMap);
|
|
73
|
-
expectedSubgraph = (0, resolve_graph_1.resolveDataflowGraph)(expectedSubgraph, context);
|
|
74
|
-
const report = (0, diff_dataflow_graph_1.diffOfDataflowGraphs)({ name: 'expected', graph: expectedSubgraph }, { name: 'got', graph: info.dataflow.graph }, {
|
|
75
|
-
leftIsSubgraph: true
|
|
76
|
-
});
|
|
77
|
-
(0, assert_1.guard)(report.isEqual(), () => `report:\n * ${report.comments()?.join('\n * ') ?? ''}`);
|
|
78
|
-
return expectedSubgraph;
|
|
79
|
-
}
|
|
80
57
|
//# sourceMappingURL=doc-normalized-ast.js.map
|
|
@@ -5,8 +5,8 @@ exports.block = block;
|
|
|
5
5
|
exports.section = section;
|
|
6
6
|
exports.collapsibleToc = collapsibleToc;
|
|
7
7
|
const doc_general_1 = require("./doc-general");
|
|
8
|
-
const mermaid_1 = require("../../util/mermaid/mermaid");
|
|
9
8
|
const strings_1 = require("../../util/text/strings");
|
|
9
|
+
const mermaid_1 = require("../../util/mermaid/mermaid");
|
|
10
10
|
/**
|
|
11
11
|
*
|
|
12
12
|
*/
|
|
@@ -31,7 +31,7 @@ ${(0, doc_general_1.prefixLines)(content, '> ')}
|
|
|
31
31
|
/**
|
|
32
32
|
*
|
|
33
33
|
*/
|
|
34
|
-
function section(title, depth = 2, anchor =
|
|
34
|
+
function section(title, depth = 2, anchor = mermaid_1.Mermaid.escapeId(title)) {
|
|
35
35
|
return `<h${depth} id="${anchor}">${title}</h${depth}>`;
|
|
36
36
|
}
|
|
37
37
|
function strToLink(str) {
|
|
@@ -40,7 +40,7 @@ function strToLink(str) {
|
|
|
40
40
|
const [, name, link] = match;
|
|
41
41
|
return `[${name}](${link})`;
|
|
42
42
|
}
|
|
43
|
-
return `[${str}](#${
|
|
43
|
+
return `[${str}](#${mermaid_1.Mermaid.escapeId(str)})`;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Supported pattern: `Name@link`
|
|
@@ -54,11 +54,11 @@ const assert_1 = require("../../util/assert");
|
|
|
54
54
|
const doc_files_1 = require("./doc-files");
|
|
55
55
|
const fs_1 = __importDefault(require("fs"));
|
|
56
56
|
const path_1 = __importDefault(require("path"));
|
|
57
|
-
const mermaid_1 = require("../../util/mermaid/mermaid");
|
|
58
57
|
const doc_code_1 = require("./doc-code");
|
|
59
58
|
const doc_structure_1 = require("./doc-structure");
|
|
60
59
|
const html_hover_over_1 = require("../../util/html-hover-over");
|
|
61
60
|
const doc_general_1 = require("./doc-general");
|
|
61
|
+
const mermaid_1 = require("../../util/mermaid/mermaid");
|
|
62
62
|
const options = {
|
|
63
63
|
target: typescript_1.default.ScriptTarget.ESNext,
|
|
64
64
|
skipLibCheck: true,
|
|
@@ -186,7 +186,7 @@ function formatNode(node, sourceFile, typeChecker) {
|
|
|
186
186
|
}
|
|
187
187
|
const type = getType(node, typeChecker);
|
|
188
188
|
const typeAnnotation = type.includes('=>') ? type.replaceAll(/\s+=>\s+/g, ' ') : ': ' + type;
|
|
189
|
-
return `${prefix}${
|
|
189
|
+
return `${prefix}${mermaid_1.Mermaid.escape(name + typeAnnotation)}${suffix}`;
|
|
190
190
|
}
|
|
191
191
|
function getType(node, typeChecker) {
|
|
192
192
|
const tryDirect = typeChecker.getTypeAtLocation(node);
|
|
@@ -381,7 +381,7 @@ function generateMermaidClassDiagram(hierarchyList, rootName, options, visited =
|
|
|
381
381
|
if (node.kind === 'type') {
|
|
382
382
|
collect.nodeLines.push(`style ${node.name} opacity:.35,fill:#FAFAFA`);
|
|
383
383
|
}
|
|
384
|
-
collect.nodeLines.push(`click ${node.name} href "${getTypePathLink(node)}" "${
|
|
384
|
+
collect.nodeLines.push(`click ${node.name} href "${getTypePathLink(node)}" "${mermaid_1.Mermaid.escape(node.comments?.join('; ').replace(/\n/g, ' ') ?? '')}"`);
|
|
385
385
|
const inline = [...options.inlineTypes ?? [], ...defaultSkip];
|
|
386
386
|
let baseTypes = node.extends;
|
|
387
387
|
if (options.reverse) {
|