@eagleoutice/flowr 2.2.7 → 2.2.9
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 +7 -5
- package/cli/flowr-main-options.js +6 -0
- package/cli/flowr.d.ts +1 -0
- package/cli/flowr.js +2 -1
- package/cli/repl/server/compact.d.ts +2 -0
- package/cli/repl/server/compact.js +13 -0
- package/cli/repl/server/connection.js +10 -0
- package/cli/repl/server/messages/message-analysis.d.ts +21 -5
- package/cli/repl/server/messages/message-analysis.js +9 -2
- package/config.d.ts +53 -1
- package/config.js +45 -5
- package/dataflow/environments/built-in.js +1 -1
- package/dataflow/environments/environment.d.ts +4 -0
- package/dataflow/environments/environment.js +3 -3
- package/dataflow/environments/resolve-by-name.js +1 -1
- package/dataflow/extractor.js +12 -10
- package/dataflow/graph/dataflowgraph-builder.js +7 -7
- package/dataflow/graph/diff.js +1 -1
- package/dataflow/graph/graph.d.ts +3 -3
- package/dataflow/graph/graph.js +4 -4
- package/dataflow/graph/vertex.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +10 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +11 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +94 -16
- package/dataflow/internal/process/functions/call/common.js +1 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +1 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +2 -3
- package/dataflow/internal/process/functions/process-argument.js +1 -1
- package/dataflow/internal/process/process-symbol.js +1 -1
- package/dataflow/internal/process/process-value.d.ts +1 -1
- package/dataflow/internal/process/process-value.js +6 -6
- package/dataflow/processor.d.ts +2 -2
- package/documentation/data/server/doc-data-server-messages.js +31 -0
- package/documentation/doc-util/doc-dfg.js +4 -7
- package/documentation/print-engines-wiki.js +1 -0
- package/documentation/print-interface-wiki.js +7 -1
- package/documentation/print-normalized-ast-wiki.js +3 -3
- package/documentation/print-readme.js +1 -1
- package/package.json +4 -3
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.d.ts +3 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.js +29 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +72 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +24 -0
- package/queries/query.d.ts +60 -1
- package/queries/query.js +2 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.d.ts +5 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +28 -7
- package/r-bridge/retriever.d.ts +3 -2
- package/r-bridge/retriever.js +26 -7
- package/slicing/static/static-slicer.js +2 -2
- package/util/mermaid/cfg.js +1 -1
- package/util/mermaid/dfg.d.ts +4 -3
- package/util/mermaid/dfg.js +13 -10
- package/util/objects.d.ts +2 -2
- package/util/simple-df/dfg-view.d.ts +16 -0
- package/util/simple-df/dfg-view.js +64 -0
- package/util/version.js +1 -1
|
@@ -51,7 +51,7 @@ function processNextExpression(currentElement, environment, listEnvironments, re
|
|
|
51
51
|
}
|
|
52
52
|
function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextGraph) {
|
|
53
53
|
for (const { functionCall, called } of calledEnvs) {
|
|
54
|
-
const callDependencies = nextGraph.getVertex(functionCall, true)?.
|
|
54
|
+
const callDependencies = nextGraph.getVertex(functionCall, true)?.cds;
|
|
55
55
|
for (const calledFn of called) {
|
|
56
56
|
(0, assert_1.guard)(calledFn.tag === vertex_1.VertexType.FunctionDefinition, 'called function must be a function definition');
|
|
57
57
|
// only merge the environments they have in common
|
|
@@ -68,7 +68,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
68
68
|
tag: vertex_1.VertexType.Use,
|
|
69
69
|
id: read.nodeId,
|
|
70
70
|
environment: undefined,
|
|
71
|
-
|
|
71
|
+
cds: undefined
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -87,7 +87,7 @@ function processFunctionDefinition(name, args, rootId, data) {
|
|
|
87
87
|
tag: vertex_1.VertexType.FunctionDefinition,
|
|
88
88
|
id: name.info.id,
|
|
89
89
|
environment: (0, scoping_1.popLocalEnvironment)(outEnvironment),
|
|
90
|
-
|
|
90
|
+
cds: data.controlDependencies,
|
|
91
91
|
subflow: flow,
|
|
92
92
|
exitPoints: exitPoints?.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 0 /* ExitPointType.Default */).map(e => e.nodeId) ?? []
|
|
93
93
|
});
|
|
@@ -10,7 +10,7 @@ const vertex_1 = require("../../../../../graph/vertex");
|
|
|
10
10
|
const edge_1 = require("../../../../../graph/edge");
|
|
11
11
|
const identifier_1 = require("../../../../../environments/identifier");
|
|
12
12
|
function processPipe(name, args, rootId, data) {
|
|
13
|
-
const { information } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
|
|
13
|
+
const { information, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
|
|
14
14
|
if (args.length !== 2) {
|
|
15
15
|
logger_1.dataflowLogger.warn(`Pipe ${name.content} has something else than 2 arguments, skipping`);
|
|
16
16
|
return information;
|
|
@@ -32,8 +32,15 @@ function processPipe(name, args, rootId, data) {
|
|
|
32
32
|
controlDependencies: data.controlDependencies,
|
|
33
33
|
type: identifier_1.ReferenceType.Function
|
|
34
34
|
});
|
|
35
|
-
information.graph.addEdge(functionCallNode.id, argId, edge_1.EdgeType.Argument);
|
|
35
|
+
information.graph.addEdge(functionCallNode.id, argId, edge_1.EdgeType.Argument | edge_1.EdgeType.Reads);
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
const firstArgument = processedArguments[0];
|
|
38
|
+
return {
|
|
39
|
+
...information,
|
|
40
|
+
in: [...information.in, ...firstArgument.in],
|
|
41
|
+
out: [...information.out, ...firstArgument.out],
|
|
42
|
+
unknownReferences: [...information.unknownReferences, ...firstArgument.unknownReferences],
|
|
43
|
+
entryPoint: rootId
|
|
44
|
+
};
|
|
38
45
|
}
|
|
39
46
|
//# sourceMappingURL=built-in-pipe.js.map
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { type DataflowProcessorInformation } from '../../../../../processor';
|
|
2
2
|
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
-
import
|
|
3
|
+
import { InferWorkingDirectory } from '../../../../../../config';
|
|
4
|
+
import type { RParseRequest, RParseRequestProvider } from '../../../../../../r-bridge/retriever';
|
|
4
5
|
import type { IdGenerator, ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
6
|
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
6
7
|
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
7
8
|
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
9
|
import type { NoInfo } from '../../../../../../r-bridge/lang-4.x/ast/model/model';
|
|
9
10
|
export declare function setSourceProvider(provider: RParseRequestProvider): void;
|
|
11
|
+
export declare function inferWdFromScript(option: InferWorkingDirectory, referenceChain: readonly RParseRequest[]): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Tries to find sourced by a source request and returns the first path that exists
|
|
14
|
+
* @param seed - the path originally requested in the `source` call
|
|
15
|
+
* @param data - more information on the loading context
|
|
16
|
+
*/
|
|
17
|
+
export declare function findSource(seed: string, data: {
|
|
18
|
+
referenceChain: readonly RParseRequest[];
|
|
19
|
+
}): string[] | undefined;
|
|
10
20
|
export declare function processSourceCall<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: {
|
|
11
21
|
/** should this produce an explicit source function call in the graph? */
|
|
12
22
|
includeFunctionCall?: boolean;
|
|
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.setSourceProvider = setSourceProvider;
|
|
7
|
+
exports.inferWdFromScript = inferWdFromScript;
|
|
8
|
+
exports.findSource = findSource;
|
|
7
9
|
exports.processSourceCall = processSourceCall;
|
|
8
10
|
exports.sourceRequest = sourceRequest;
|
|
9
11
|
exports.standaloneSourceFile = standaloneSourceFile;
|
|
@@ -23,10 +25,83 @@ const parser_1 = require("../../../../../../r-bridge/lang-4.x/ast/parser/json/pa
|
|
|
23
25
|
const shell_executor_1 = require("../../../../../../r-bridge/shell-executor");
|
|
24
26
|
const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
|
|
25
27
|
const assert_1 = require("../../../../../../util/assert");
|
|
28
|
+
const path_1 = __importDefault(require("path"));
|
|
26
29
|
let sourceProvider = (0, retriever_1.requestProviderFromFile)();
|
|
27
30
|
function setSourceProvider(provider) {
|
|
28
31
|
sourceProvider = provider;
|
|
29
32
|
}
|
|
33
|
+
function inferWdFromScript(option, referenceChain) {
|
|
34
|
+
switch (option) {
|
|
35
|
+
case config_1.InferWorkingDirectory.MainScript:
|
|
36
|
+
return referenceChain[0]?.request === 'file' ? [platformDirname(referenceChain[0].content)] : [];
|
|
37
|
+
case config_1.InferWorkingDirectory.ActiveScript:
|
|
38
|
+
return referenceChain[referenceChain.length - 1] ? [platformDirname(referenceChain[referenceChain.length - 1].content)] : [];
|
|
39
|
+
case config_1.InferWorkingDirectory.AnyScript:
|
|
40
|
+
return referenceChain.filter(e => e.request === 'file').map(e => platformDirname(e.content));
|
|
41
|
+
case config_1.InferWorkingDirectory.No:
|
|
42
|
+
default:
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const AnyPathSeparator = /[/\\]/g;
|
|
47
|
+
function platformBasename(p) {
|
|
48
|
+
const normalized = p.replaceAll(path_1.default.win32.sep, path_1.default.posix.sep);
|
|
49
|
+
return path_1.default.posix.basename(normalized);
|
|
50
|
+
}
|
|
51
|
+
function platformDirname(p) {
|
|
52
|
+
const normalized = p.replaceAll(path_1.default.win32.sep, path_1.default.posix.sep);
|
|
53
|
+
return path_1.default.posix.dirname(normalized);
|
|
54
|
+
}
|
|
55
|
+
function returnPlatformPath(p) {
|
|
56
|
+
return p.replaceAll(AnyPathSeparator, path_1.default.sep);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Tries to find sourced by a source request and returns the first path that exists
|
|
60
|
+
* @param seed - the path originally requested in the `source` call
|
|
61
|
+
* @param data - more information on the loading context
|
|
62
|
+
*/
|
|
63
|
+
function findSource(seed, data) {
|
|
64
|
+
const config = (0, config_1.getConfig)().solver.resolveSource;
|
|
65
|
+
const capitalization = config?.ignoreCapitalization ?? false;
|
|
66
|
+
const explorePaths = [
|
|
67
|
+
...(config?.searchPath ?? []),
|
|
68
|
+
...(inferWdFromScript(config?.inferWorkingDirectory ?? config_1.InferWorkingDirectory.No, data.referenceChain))
|
|
69
|
+
];
|
|
70
|
+
const tryPaths = [seed];
|
|
71
|
+
switch (config?.dropPaths ?? config_1.DropPathsOption.No) {
|
|
72
|
+
case config_1.DropPathsOption.Once: {
|
|
73
|
+
const first = platformBasename(seed);
|
|
74
|
+
tryPaths.push(first);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case config_1.DropPathsOption.All: {
|
|
78
|
+
const paths = platformDirname(seed).split(AnyPathSeparator);
|
|
79
|
+
const basename = platformBasename(seed);
|
|
80
|
+
if (paths.length === 1 && paths[0] === '.') {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
for (let i = 0; i < paths.length; i++) {
|
|
84
|
+
tryPaths.push(path_1.default.join(...paths.slice(i), basename));
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
default:
|
|
89
|
+
case config_1.DropPathsOption.No:
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
const found = [];
|
|
93
|
+
for (const explore of [undefined, ...explorePaths]) {
|
|
94
|
+
for (const tryPath of tryPaths) {
|
|
95
|
+
const effectivePath = explore ? path_1.default.join(explore, tryPath) : tryPath;
|
|
96
|
+
const get = sourceProvider.exists(effectivePath, capitalization) ?? sourceProvider.exists(returnPlatformPath(effectivePath), capitalization);
|
|
97
|
+
if (get && !found.includes(effectivePath)) {
|
|
98
|
+
found.push(returnPlatformPath(effectivePath));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
log_1.log.info(`Found sourced file ${JSON.stringify(seed)} at ${JSON.stringify(found)}`);
|
|
103
|
+
return found;
|
|
104
|
+
}
|
|
30
105
|
function processSourceCall(name, args, rootId, data, config) {
|
|
31
106
|
const information = config.includeFunctionCall ?
|
|
32
107
|
(0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information
|
|
@@ -53,20 +128,24 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
53
128
|
}
|
|
54
129
|
if (sourceFile && sourceFile.length === 1) {
|
|
55
130
|
const path = (0, retriever_1.removeRQuotes)(sourceFile[0]);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
131
|
+
let filepath = path ? findSource(path, data) : path;
|
|
132
|
+
if (Array.isArray(filepath)) {
|
|
133
|
+
filepath = filepath?.[0];
|
|
134
|
+
}
|
|
135
|
+
if (filepath !== undefined) {
|
|
136
|
+
const request = sourceProvider.createRequest(filepath);
|
|
137
|
+
// check if the sourced file has already been dataflow analyzed, and if so, skip it
|
|
138
|
+
if (data.referenceChain.find(e => e.request === request.request && e.content === request.content)) {
|
|
139
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Found loop in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
140
|
+
information.graph.markIdForUnknownSideEffects(rootId);
|
|
141
|
+
return information;
|
|
142
|
+
}
|
|
143
|
+
return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)(path, name.location));
|
|
62
144
|
}
|
|
63
|
-
return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)(path, name.location));
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
|
|
67
|
-
information.graph.markIdForUnknownSideEffects(rootId);
|
|
68
|
-
return information;
|
|
69
145
|
}
|
|
146
|
+
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
|
|
147
|
+
information.graph.markIdForUnknownSideEffects(rootId);
|
|
148
|
+
return information;
|
|
70
149
|
}
|
|
71
150
|
function sourceRequest(rootId, request, data, information, getId) {
|
|
72
151
|
if (request.request === 'file') {
|
|
@@ -89,7 +168,7 @@ function sourceRequest(rootId, request, data, information, getId) {
|
|
|
89
168
|
...data,
|
|
90
169
|
currentRequest: request,
|
|
91
170
|
environment: information.environment,
|
|
92
|
-
referenceChain: [...data.referenceChain,
|
|
171
|
+
referenceChain: [...data.referenceChain, request]
|
|
93
172
|
});
|
|
94
173
|
}
|
|
95
174
|
catch (e) {
|
|
@@ -118,9 +197,8 @@ function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
|
|
|
118
197
|
const path = inputRequest.request === 'file' ? inputRequest.content : '-inline-';
|
|
119
198
|
/* this way we can still pass content */
|
|
120
199
|
const request = inputRequest.request === 'file' ? sourceProvider.createRequest(inputRequest.content) : inputRequest;
|
|
121
|
-
const fingerprint = (0, retriever_1.requestFingerprint)(request);
|
|
122
200
|
// check if the sourced file has already been dataflow analyzed, and if so, skip it
|
|
123
|
-
if (data.referenceChain.
|
|
201
|
+
if (data.referenceChain.find(e => e.request === request.request && e.content === request.content)) {
|
|
124
202
|
logger_1.dataflowLogger.info(`Found loop in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
125
203
|
information.graph.markIdForUnknownSideEffects(uniqueSourceId);
|
|
126
204
|
return information;
|
|
@@ -129,7 +207,7 @@ function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
|
|
|
129
207
|
...data,
|
|
130
208
|
currentRequest: request,
|
|
131
209
|
environment: information.environment,
|
|
132
|
-
referenceChain: [...data.referenceChain,
|
|
210
|
+
referenceChain: [...data.referenceChain, inputRequest]
|
|
133
211
|
}, information, (0, decorate_1.deterministicPrefixIdGenerator)(path + '@' + uniqueSourceId));
|
|
134
212
|
}
|
|
135
213
|
//# sourceMappingURL=built-in-source.js.map
|
|
@@ -109,7 +109,7 @@ function patchFunctionCall({ nextGraph, rootId, name, data, argumentProcessResul
|
|
|
109
109
|
environment: data.environment,
|
|
110
110
|
/* will be overwritten accordingly */
|
|
111
111
|
onlyBuiltin: false,
|
|
112
|
-
|
|
112
|
+
cds: data.controlDependencies,
|
|
113
113
|
args: argumentProcessResult.map(arg => arg === undefined ? r_function_call_1.EmptyArgument : { nodeId: arg.entryPoint, controlDependencies: undefined, call: undefined, type: identifier_1.ReferenceType.Argument }),
|
|
114
114
|
});
|
|
115
115
|
for (const arg of argumentProcessResult) {
|
|
@@ -40,7 +40,7 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
|
|
|
40
40
|
name: functionCallName,
|
|
41
41
|
/* will be overwritten accordingly */
|
|
42
42
|
onlyBuiltin: false,
|
|
43
|
-
|
|
43
|
+
cds: data.controlDependencies,
|
|
44
44
|
args: reverseOrder ? [...callArgs].reverse() : callArgs,
|
|
45
45
|
indicesCollection: indicesCollection,
|
|
46
46
|
});
|
|
@@ -20,8 +20,7 @@ function processUnnamedFunctionCall(functionCall, data) {
|
|
|
20
20
|
const functionCallName = `${exports.UnnamedFunctionCallPrefix}${functionRootId}`;
|
|
21
21
|
logger_1.dataflowLogger.debug(`Using ${functionRootId} as root for the unnamed function call`);
|
|
22
22
|
// we know that it calls the toplevel:
|
|
23
|
-
finalGraph.addEdge(functionRootId, calledRootId, edge_1.EdgeType.Calls);
|
|
24
|
-
finalGraph.addEdge(functionRootId, calledRootId, edge_1.EdgeType.Reads);
|
|
23
|
+
finalGraph.addEdge(functionRootId, calledRootId, edge_1.EdgeType.Calls | edge_1.EdgeType.Reads);
|
|
25
24
|
// keep the defined function
|
|
26
25
|
finalGraph.mergeWith(calledFunction.graph);
|
|
27
26
|
const { finalEnv, callArgs, remainingReadInArgs } = (0, common_1.processAllArguments)({
|
|
@@ -39,7 +38,7 @@ function processUnnamedFunctionCall(functionCall, data) {
|
|
|
39
38
|
name: functionCallName,
|
|
40
39
|
/* can never be a direct built-in-call */
|
|
41
40
|
onlyBuiltin: false,
|
|
42
|
-
|
|
41
|
+
cds: data.controlDependencies,
|
|
43
42
|
args: callArgs // same reference
|
|
44
43
|
});
|
|
45
44
|
const inIds = remainingReadInArgs;
|
|
@@ -18,7 +18,7 @@ function processSymbol(symbol, data) {
|
|
|
18
18
|
graph: new graph_1.DataflowGraph(data.completeAst.idMap).addVertex({
|
|
19
19
|
tag: vertex_1.VertexType.Use,
|
|
20
20
|
id: symbol.info.id,
|
|
21
|
-
|
|
21
|
+
cds: data.controlDependencies
|
|
22
22
|
}),
|
|
23
23
|
entryPoint: symbol.info.id,
|
|
24
24
|
exitPoints: [{ nodeId: symbol.info.id, type: 0 /* ExitPointType.Default */, controlDependencies: data.controlDependencies }]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type 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
|
-
export declare function processValue<OtherInfo>(
|
|
4
|
+
export declare function processValue<OtherInfo>({ info: { id } }: RNodeWithParent, data: DataflowProcessorInformation<OtherInfo>): DataflowInformation;
|
|
@@ -4,19 +4,19 @@ exports.processValue = processValue;
|
|
|
4
4
|
const graph_1 = require("../../graph/graph");
|
|
5
5
|
const vertex_1 = require("../../graph/vertex");
|
|
6
6
|
const identifier_1 = require("../../environments/identifier");
|
|
7
|
-
function processValue(
|
|
7
|
+
function processValue({ info: { id } }, data) {
|
|
8
8
|
return {
|
|
9
9
|
unknownReferences: [],
|
|
10
|
-
in: [{ nodeId:
|
|
10
|
+
in: [{ nodeId: id, name: undefined, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Constant }],
|
|
11
11
|
out: [],
|
|
12
12
|
environment: data.environment,
|
|
13
13
|
graph: new graph_1.DataflowGraph(data.completeAst.idMap).addVertex({
|
|
14
14
|
tag: vertex_1.VertexType.Value,
|
|
15
|
-
id:
|
|
16
|
-
|
|
15
|
+
id: id,
|
|
16
|
+
cds: data.controlDependencies
|
|
17
17
|
}),
|
|
18
|
-
exitPoints: [{ nodeId:
|
|
19
|
-
entryPoint:
|
|
18
|
+
exitPoints: [{ nodeId: id, type: 0 /* ExitPointType.Default */, controlDependencies: data.controlDependencies }],
|
|
19
|
+
entryPoint: id
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=process-value.js.map
|
package/dataflow/processor.d.ts
CHANGED
|
@@ -27,10 +27,10 @@ export interface DataflowProcessorInformation<OtherInfo> {
|
|
|
27
27
|
*/
|
|
28
28
|
readonly currentRequest: RParseRequest;
|
|
29
29
|
/**
|
|
30
|
-
* The chain of {@link RParseRequests}
|
|
30
|
+
* The chain of {@link RParseRequests} that lead to the {@link currentRequest}.
|
|
31
31
|
* The most recent (last) entry is expected to always be the {@link currentRequest}.
|
|
32
32
|
*/
|
|
33
|
-
readonly referenceChain:
|
|
33
|
+
readonly referenceChain: RParseRequest[];
|
|
34
34
|
/**
|
|
35
35
|
* The chain of control-flow {@link NodeId}s that lead to the current node (e.g., of known ifs).
|
|
36
36
|
*/
|
|
@@ -195,6 +195,37 @@ ${await (0, doc_server_message_1.documentServerMessageResponse)({
|
|
|
195
195
|
Please note, that the base message format is still JSON. Only the individual results get converted.
|
|
196
196
|
While the context is derived from the \`filename\`, we currently offer no way to customize other parts of the quads
|
|
197
197
|
(please open a [new issue](${doc_issue_1.NewIssueUrl}) if you require this).
|
|
198
|
+
|
|
199
|
+
`
|
|
200
|
+
}]
|
|
201
|
+
})}
|
|
202
|
+
|
|
203
|
+
<a id="analysis-format-compact"></a>
|
|
204
|
+
**Retrieve the Output in a compactedForm**
|
|
205
|
+
|
|
206
|
+
The default response is formatted as JSON. But this can get very big quickly.
|
|
207
|
+
By specifying \`format: "compact"\`, you can retrieve the results heavily compacted (using [msgpack](https://www.npmjs.com/package/@msgpack/msgpack)).
|
|
208
|
+
This works with and without the control flow graph as described [above](#analysis-include-cfg).
|
|
209
|
+
|
|
210
|
+
${await (0, doc_server_message_1.documentServerMessageResponse)({
|
|
211
|
+
shell,
|
|
212
|
+
title: 'Requesting Compacted Results',
|
|
213
|
+
messages: [{
|
|
214
|
+
type: 'request',
|
|
215
|
+
message: {
|
|
216
|
+
type: 'request-file-analysis',
|
|
217
|
+
id: '1',
|
|
218
|
+
filetoken: 'x',
|
|
219
|
+
content: 'x <- 1\nx + 1',
|
|
220
|
+
format: 'compact',
|
|
221
|
+
cfg: true
|
|
222
|
+
},
|
|
223
|
+
mark: true
|
|
224
|
+
}, {
|
|
225
|
+
type: 'response',
|
|
226
|
+
expectedType: 'response-file-analysis',
|
|
227
|
+
description: `
|
|
228
|
+
Please note, that the base message format is still JSON. Only the individual results are printed as binary objects.
|
|
198
229
|
`
|
|
199
230
|
}]
|
|
200
231
|
})}
|
|
@@ -14,16 +14,15 @@ const diff_1 = require("../../dataflow/graph/diff");
|
|
|
14
14
|
const assert_1 = require("../../util/assert");
|
|
15
15
|
const time_1 = require("../../util/time");
|
|
16
16
|
const doc_files_1 = require("./doc-files");
|
|
17
|
+
const doc_code_1 = require("./doc-code");
|
|
17
18
|
function printDfGraph(graph, mark, simplified = false) {
|
|
18
19
|
return `
|
|
19
|
-
|
|
20
|
-
${(0, dfg_1.graphToMermaid)({
|
|
20
|
+
${(0, doc_code_1.codeBlock)('mermaid', (0, dfg_1.graphToMermaid)({
|
|
21
21
|
graph,
|
|
22
22
|
prefix: 'flowchart LR',
|
|
23
23
|
mark,
|
|
24
24
|
simplified
|
|
25
|
-
}).string}
|
|
26
|
-
\`\`\`
|
|
25
|
+
}).string)}
|
|
27
26
|
`;
|
|
28
27
|
}
|
|
29
28
|
function formatSideEffect(ef) {
|
|
@@ -48,9 +47,7 @@ async function printDfGraphForCode(parser, code, { simplified = false, mark, sho
|
|
|
48
47
|
const simplyText = simplified ? '(simplified) ' : '';
|
|
49
48
|
let resultText = '\n\n';
|
|
50
49
|
if (showCode) {
|
|
51
|
-
const codeText =
|
|
52
|
-
${code}
|
|
53
|
-
\`\`\``;
|
|
50
|
+
const codeText = (0, doc_code_1.codeBlock)('r', code);
|
|
54
51
|
resultText += switchCodeAndGraph ? codeText : dfGraph;
|
|
55
52
|
resultText += `
|
|
56
53
|
<details${codeOpen ? ' open' : ''}>
|
|
@@ -39,6 +39,7 @@ are exposed with some command line options (e.g., when using the docker image of
|
|
|
39
39
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.r-shell.disabled', false)} to disable the ${(0, doc_types_1.shortLink)(shell_1.RShell.name, types.info)} engine
|
|
40
40
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.r-shell.r-path', false)} (which is the canonical version of ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'r-path')})
|
|
41
41
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.tree-sitter.disabled', false)} to disable the ${(0, doc_types_1.shortLink)(tree_sitter_executor_1.TreeSitterExecutor.name, types.info)} engine
|
|
42
|
+
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.tree-sitter.lax', false)} to use lax parsing with tree-sitter
|
|
42
43
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.tree-sitter.wasm-path', false)} pass the path to the wasm of the r grammar of tree-sitter (see [below](#tree-sitter))
|
|
43
44
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'engine.tree-sitter.tree-sitter-wasm-path', false)} pass the path to the wasm of tree-sitter (see [below](#tree-sitter))
|
|
44
45
|
- ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'default-engine', false)} to set the default engine to use
|
|
@@ -203,7 +203,13 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
|
|
|
203
203
|
engines: [{ type: 'r-shell' }],
|
|
204
204
|
solver: {
|
|
205
205
|
variables: config_1.VariableResolve.Alias,
|
|
206
|
-
pointerTracking: true
|
|
206
|
+
pointerTracking: true,
|
|
207
|
+
resolveSource: {
|
|
208
|
+
dropPaths: config_1.DropPathsOption.No,
|
|
209
|
+
ignoreCapitalization: true,
|
|
210
|
+
inferWorkingDirectory: config_1.InferWorkingDirectory.ActiveScript,
|
|
211
|
+
searchPath: []
|
|
212
|
+
}
|
|
207
213
|
}
|
|
208
214
|
}, null, 2))}
|
|
209
215
|
|
|
@@ -86,10 +86,10 @@ ${(0, doc_structure_1.details)('Normalized AST Node Types', (0, doc_types_1.prin
|
|
|
86
86
|
|
|
87
87
|
The following segments intend to give you an overview of how to work with the normalized AST:
|
|
88
88
|
|
|
89
|
-
* [How to get a
|
|
89
|
+
* [How to get a Normalized AST](#how-to-get-a-normalized-ast)
|
|
90
90
|
* [Visitors and Folds](#visitors-and-folds)
|
|
91
91
|
|
|
92
|
-
## How Get a Normalized AST
|
|
92
|
+
## How to Get a Normalized AST
|
|
93
93
|
|
|
94
94
|
As explained alongside the [Interface](${doc_files_1.FlowrWikiBaseRef}/Interface#the-pipeline-executor) wiki page, you can use the
|
|
95
95
|
${(0, doc_types_1.shortLink)(pipeline_executor_1.PipelineExecutor.name, types.info)} to get the ${(0, doc_types_1.shortLink)('NormalizedAst', types.info)}. If you are only interested in the normalization,
|
|
@@ -115,7 +115,7 @@ We provide two ways to traverse the normalized AST: [Visitors](#visitors) and [F
|
|
|
115
115
|
If you want a simple visitor which traverses the AST, the ${(0, doc_types_1.shortLink)(visitor_1.visitAst.name, types.info)} function is a good starting point.
|
|
116
116
|
You may specify functions to be called whenever you enter and exit a node during the traversal, and any
|
|
117
117
|
computation is to be done by side effects.
|
|
118
|
-
For example, if you want to collect all the \`id\`s present within a normalized (sub-)
|
|
118
|
+
For example, if you want to collect all the \`id\`s present within a normalized (sub-)AST,
|
|
119
119
|
as it is done by the ${(0, doc_types_1.shortLink)(collect_1.collectAllIds.name, types.info)} function, you can use the following visitor:
|
|
120
120
|
|
|
121
121
|
${(0, doc_code_1.codeBlock)('ts', `
|
|
@@ -65,7 +65,7 @@ The following showcases the dependency view of the [Visual Studio Code extension
|
|
|
65
65
|
`), ' ')}
|
|
66
66
|
|
|
67
67
|
* 🚀 **fast data- and control-flow graphs**\\
|
|
68
|
-
Within just ${'<i>' + (0, html_hover_over_1.textWithTooltip)((0, numbers_1.roundToDecimals)(await (0, doc_benchmarks_1.getLatestDfAnalysisTime)('"social-science" Benchmark Suite (tree-sitter)'), 1) + ' ms
|
|
68
|
+
Within just ${'<i>' + (0, html_hover_over_1.textWithTooltip)((0, numbers_1.roundToDecimals)(await (0, doc_benchmarks_1.getLatestDfAnalysisTime)('"social-science" Benchmark Suite (tree-sitter)'), 1) + ' ms', 'This measurement is automatically fetched from the latest benchmark!') + '</i>'} (as of ${new Date(await (0, doc_benchmarks_1.getLastBenchmarkUpdate)()).toLocaleDateString('en-US', dateOptions)}),
|
|
69
69
|
_flowR_ can analyze the data- and control-flow of the average real-world R script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
|
|
70
70
|
and consult the [wiki pages](${doc_files_1.FlowrWikiBaseRef}/Dataflow-Graph) for more details on the dataflow graph.
|
|
71
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.9",
|
|
4
4
|
"description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"repository": {
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
"@types/tmp": "^0.2.6",
|
|
185
185
|
"@types/ws": "^8.5.14",
|
|
186
186
|
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
187
|
-
"@vitest/coverage-v8": "^3.0.
|
|
187
|
+
"@vitest/coverage-v8": "^3.0.6",
|
|
188
188
|
"esbuild": "^0.25.0",
|
|
189
189
|
"eslint": "^9.20.1",
|
|
190
190
|
"license-checker": "^25.0.1",
|
|
@@ -196,9 +196,10 @@
|
|
|
196
196
|
"typedoc-theme-hierarchy": "^5.0.4",
|
|
197
197
|
"typedoc-umlclass": "^0.10.1",
|
|
198
198
|
"typescript": "^5.7.3",
|
|
199
|
-
"vitest": "^3.0.
|
|
199
|
+
"vitest": "^3.0.6"
|
|
200
200
|
},
|
|
201
201
|
"dependencies": {
|
|
202
|
+
"@msgpack/msgpack": "^3.0.1",
|
|
202
203
|
"@xmldom/xmldom": "^0.9.7",
|
|
203
204
|
"clipboardy": "^4.0.0",
|
|
204
205
|
"command-line-args": "^6.0.1",
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DataflowLensQuery, DataflowLensQueryResult } from './dataflow-lens-query-format';
|
|
2
|
+
import type { BasicQueryData } from '../../base-query-format';
|
|
3
|
+
export declare function executeDataflowLensQuery({ dataflow: { graph } }: BasicQueryData, queries: readonly DataflowLensQuery[]): DataflowLensQueryResult;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeDataflowLensQuery = executeDataflowLensQuery;
|
|
4
|
+
const log_1 = require("../../../util/log");
|
|
5
|
+
const dfg_view_1 = require("../../../util/simple-df/dfg-view");
|
|
6
|
+
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
7
|
+
function executeDataflowLensQuery({ dataflow: { graph } }, queries) {
|
|
8
|
+
if (queries.length !== 1) {
|
|
9
|
+
log_1.log.warn('Dataflow query expects only up to one query, but got', queries.length);
|
|
10
|
+
}
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
const simplifiedGraph = (0, dfg_view_1.reduceDfg)(graph, {
|
|
13
|
+
vertices: {
|
|
14
|
+
keepEnv: false,
|
|
15
|
+
keepCd: true,
|
|
16
|
+
tags: [vertex_1.VertexType.Use, vertex_1.VertexType.VariableDefinition, vertex_1.VertexType.FunctionDefinition, vertex_1.VertexType.FunctionCall],
|
|
17
|
+
nameRegex: '<-|<<-|->|->>|=|+|-|*|/|\\|>|function|repeat|if|next|break',
|
|
18
|
+
blacklistWithName: true
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const timing = Date.now() - now;
|
|
22
|
+
return {
|
|
23
|
+
'.meta': {
|
|
24
|
+
timing
|
|
25
|
+
},
|
|
26
|
+
simplifiedGraph
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=dataflow-lens-query-executor.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
|
|
2
|
+
import type { DataflowGraph } from '../../../dataflow/graph/graph';
|
|
3
|
+
import { executeDataflowLensQuery } from './dataflow-lens-query-executor';
|
|
4
|
+
import Joi from 'joi';
|
|
5
|
+
/**
|
|
6
|
+
* Returns a simplified view on the dataflow graph of the analysis
|
|
7
|
+
*/
|
|
8
|
+
export interface DataflowLensQuery extends BaseQueryFormat {
|
|
9
|
+
readonly type: 'dataflow-lens';
|
|
10
|
+
}
|
|
11
|
+
export interface DataflowLensQueryResult extends BaseQueryResult {
|
|
12
|
+
/** This is the simplified dataflow graph */
|
|
13
|
+
readonly simplifiedGraph: DataflowGraph;
|
|
14
|
+
}
|
|
15
|
+
export declare const DataflowLensQueryDefinition: {
|
|
16
|
+
readonly executor: typeof executeDataflowLensQuery;
|
|
17
|
+
readonly asciiSummarizer: (formatter: import("../../../util/ansi").OutputFormatter, _processed: import("../../../core/steps/pipeline/pipeline").PipelineOutput<import("../../../core/steps/pipeline/pipeline").Pipeline<{
|
|
18
|
+
readonly name: "parse";
|
|
19
|
+
readonly humanReadableName: "parse with R shell";
|
|
20
|
+
readonly description: "Parse the given R code into an AST";
|
|
21
|
+
readonly processor: (_results: unknown, input: Partial<import("../../../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../../../r-bridge/parser").ParseStepOutput<string>>;
|
|
22
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
23
|
+
readonly printer: {
|
|
24
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
25
|
+
readonly 2: {
|
|
26
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
27
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
28
|
+
};
|
|
29
|
+
readonly 5: ({ parsed }: import("../../../r-bridge/parser").ParseStepOutput<string>, config: import("../../../util/quads").QuadSerializationConfiguration) => string;
|
|
30
|
+
};
|
|
31
|
+
readonly dependencies: readonly [];
|
|
32
|
+
readonly requiredInput: import("../../../r-bridge/parser").ParseRequiredInput<string>;
|
|
33
|
+
} | {
|
|
34
|
+
readonly name: "normalize";
|
|
35
|
+
readonly humanReadableName: "normalize";
|
|
36
|
+
readonly description: "Normalize the AST to flowR's AST";
|
|
37
|
+
readonly processor: (results: {
|
|
38
|
+
parse?: import("../../../r-bridge/parser").ParseStepOutput<string>;
|
|
39
|
+
}, input: Partial<import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../../r-bridge/lang-4.x/ast/model/model").RNode<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
|
|
40
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
41
|
+
readonly printer: {
|
|
42
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
43
|
+
readonly 2: typeof import("../../../core/print/normalize-printer").normalizedAstToJson;
|
|
44
|
+
readonly 5: typeof import("../../../core/print/normalize-printer").normalizedAstToQuads;
|
|
45
|
+
readonly 3: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaid;
|
|
46
|
+
readonly 4: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
|
|
47
|
+
};
|
|
48
|
+
readonly dependencies: readonly ["parse"];
|
|
49
|
+
readonly requiredInput: import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput;
|
|
50
|
+
} | {
|
|
51
|
+
readonly humanReadableName: "dataflow";
|
|
52
|
+
readonly processor: (results: {
|
|
53
|
+
normalize?: import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
54
|
+
}, input: {
|
|
55
|
+
request?: import("../../../r-bridge/retriever").RParseRequests;
|
|
56
|
+
parser?: import("../../../r-bridge/parser").Parser<import("../../../r-bridge/parser").KnownParserType>;
|
|
57
|
+
}) => import("../../../dataflow/info").DataflowInformation;
|
|
58
|
+
readonly requiredInput: {};
|
|
59
|
+
readonly name: "dataflow";
|
|
60
|
+
readonly description: "Construct the dataflow graph";
|
|
61
|
+
readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
62
|
+
readonly printer: {
|
|
63
|
+
readonly 0: typeof import("../../../core/print/print").internalPrinter;
|
|
64
|
+
readonly 2: typeof import("../../../core/print/dataflow-printer").dataflowGraphToJson;
|
|
65
|
+
readonly 5: typeof import("../../../core/print/dataflow-printer").dataflowGraphToQuads;
|
|
66
|
+
readonly 3: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaid;
|
|
67
|
+
readonly 4: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
|
|
68
|
+
};
|
|
69
|
+
readonly dependencies: readonly ["normalize"];
|
|
70
|
+
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
71
|
+
readonly schema: Joi.ObjectSchema<any>;
|
|
72
|
+
};
|