@eagleoutice/flowr 2.2.11 → 2.2.12
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 +4 -4
- package/benchmark/slicer.d.ts +49 -22
- package/benchmark/slicer.js +88 -28
- package/benchmark/stats/print.js +16 -10
- package/benchmark/stats/size-of.js +18 -1
- package/benchmark/stats/stats.d.ts +3 -0
- package/benchmark/summarizer/second-phase/process.js +8 -2
- package/cli/benchmark-app.d.ts +5 -0
- package/cli/benchmark-app.js +49 -6
- package/cli/benchmark-helper-app.d.ts +4 -0
- package/cli/benchmark-helper-app.js +20 -4
- package/cli/common/options.js +13 -4
- package/cli/repl/commands/repl-commands.js +2 -0
- package/cli/repl/commands/repl-dataflow.d.ts +2 -0
- package/cli/repl/commands/repl-dataflow.js +35 -1
- package/config.d.ts +18 -2
- package/config.js +24 -4
- package/dataflow/environments/built-in-config.d.ts +5 -2
- package/dataflow/environments/built-in-config.js +8 -2
- package/dataflow/environments/built-in.d.ts +8 -1
- package/dataflow/environments/built-in.js +8 -1
- package/dataflow/environments/clone.d.ts +5 -0
- package/dataflow/environments/clone.js +5 -0
- package/dataflow/environments/default-builtin-config.js +93 -9
- package/dataflow/environments/define.d.ts +5 -1
- package/dataflow/environments/define.js +36 -10
- package/dataflow/environments/overwrite.js +4 -0
- package/dataflow/environments/remove.d.ts +6 -0
- package/dataflow/environments/remove.js +24 -0
- package/dataflow/environments/resolve-by-name.js +1 -1
- package/dataflow/graph/dataflowgraph-builder.d.ts +76 -6
- package/dataflow/graph/dataflowgraph-builder.js +102 -6
- package/dataflow/graph/graph.d.ts +6 -1
- package/dataflow/graph/graph.js +24 -0
- package/dataflow/graph/vertex.d.ts +42 -2
- package/dataflow/graph/vertex.js +32 -0
- package/dataflow/internal/linker.js +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +55 -45
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +6 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +27 -8
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +37 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +10 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +140 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-list.js +51 -17
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +3 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +83 -29
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.d.ts +7 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +41 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +17 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.d.ts +15 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-vector.js +75 -0
- package/dataflow/internal/process/functions/call/common.d.ts +1 -1
- package/dataflow/internal/process/functions/call/common.js +4 -2
- package/dataflow/internal/process/functions/call/named-call-handling.d.ts +2 -0
- package/dataflow/internal/process/functions/call/named-call-handling.js +9 -5
- package/dataflow/internal/process/process-named-call.d.ts +3 -0
- package/dataflow/internal/process/process-named-call.js +3 -0
- package/documentation/doc-util/doc-cfg.d.ts +11 -2
- package/documentation/doc-util/doc-cfg.js +35 -6
- package/documentation/doc-util/doc-code.js +10 -2
- package/documentation/print-capabilities-markdown.js +1 -1
- package/documentation/print-cfg-wiki.d.ts +1 -0
- package/documentation/print-cfg-wiki.js +84 -0
- package/documentation/print-core-wiki.js +2 -2
- package/documentation/print-interface-wiki.js +1 -0
- package/documentation/print-query-wiki.js +2 -2
- package/package.json +2 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +13 -5
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -25
- package/queries/catalog/dependencies-query/dependencies-query-format.js +2 -145
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +24 -0
- package/queries/catalog/dependencies-query/function-info/function-info.js +10 -0
- package/queries/catalog/dependencies-query/function-info/library-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/library-functions.js +18 -0
- package/queries/catalog/dependencies-query/function-info/read-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/read-functions.js +101 -0
- package/queries/catalog/dependencies-query/function-info/source-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/source-functions.js +11 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.js +87 -0
- package/r-bridge/data/data.d.ts +2 -2
- package/r-bridge/data/data.js +2 -2
- package/util/arrays.d.ts +23 -0
- package/util/arrays.js +41 -0
- package/util/cfg/visitor.d.ts +1 -1
- package/util/cfg/visitor.js +2 -2
- package/util/{list-access.d.ts → containers.d.ts} +24 -4
- package/util/{list-access.js → containers.js} +42 -12
- package/util/mermaid/ast.js +12 -1
- package/util/mermaid/cfg.js +2 -2
- package/util/parallel.d.ts +2 -1
- package/util/parallel.js +11 -2
- package/util/prefix.d.ts +13 -0
- package/util/prefix.js +34 -0
- package/util/version.js +1 -1
|
@@ -6,16 +6,15 @@ const known_call_handling_1 = require("../known-call-handling");
|
|
|
6
6
|
const log_1 = require("../../../../../../util/log");
|
|
7
7
|
const built_in_assignment_1 = require("./built-in-assignment");
|
|
8
8
|
const common_1 = require("../common");
|
|
9
|
-
const assert_1 = require("../../../../../../util/assert");
|
|
10
9
|
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
11
10
|
const logger_1 = require("../../../../../logger");
|
|
12
|
-
const vertex_1 = require("../../../../../graph/vertex");
|
|
13
11
|
const graph_1 = require("../../../../../graph/graph");
|
|
14
12
|
const edge_1 = require("../../../../../graph/edge");
|
|
15
|
-
const dfg_1 = require("../../../../../../util/mermaid/dfg");
|
|
16
13
|
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
17
|
-
const
|
|
14
|
+
const containers_1 = require("../../../../../../util/containers");
|
|
18
15
|
const config_1 = require("../../../../../../config");
|
|
16
|
+
const unpack_argument_1 = require("../argument/unpack-argument");
|
|
17
|
+
const built_in_access_1 = require("./built-in-access");
|
|
19
18
|
function processReplacementFunction(name,
|
|
20
19
|
/** The last one has to be the value */
|
|
21
20
|
args, rootId, data, config) {
|
|
@@ -25,45 +24,38 @@ args, rootId, data, config) {
|
|
|
25
24
|
}
|
|
26
25
|
/* we only get here if <-, <<-, ... or whatever is part of the replacement is not overwritten */
|
|
27
26
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Replacement ${name.content} with ${JSON.stringify(args)}, processing`);
|
|
28
|
-
let indices =
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
const accessedArg = nonEmptyArgs.find(arg => arg.info.role === "accessed" /* RoleInParent.Accessed */);
|
|
32
|
-
const accessArg = nonEmptyArgs.find(arg => arg.info.role === "index-access" /* RoleInParent.IndexAccess */);
|
|
33
|
-
if (accessArg !== undefined && accessedArg != undefined) {
|
|
34
|
-
const leafIndex = { lexeme: accessArg.lexeme, nodeId: accessedArg.info.parent ?? '' };
|
|
35
|
-
const accessIndices = {
|
|
36
|
-
indices: [leafIndex],
|
|
37
|
-
isContainer: false
|
|
38
|
-
};
|
|
39
|
-
// Check for nested access
|
|
40
|
-
if (accessedArg.value?.type === type_1.RType.Access) {
|
|
41
|
-
indices = (0, list_access_1.constructNestedAccess)(accessedArg.value, accessIndices);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
// use access node as reference to get complete line in slice
|
|
45
|
-
indices = [accessIndices];
|
|
46
|
-
}
|
|
47
|
-
}
|
|
27
|
+
let indices = config.activeIndices;
|
|
28
|
+
if ((0, config_1.getConfig)().solver.pointerTracking) {
|
|
29
|
+
indices ??= constructAccessedIndices(name.content, args);
|
|
48
30
|
}
|
|
49
31
|
/* we assign the first argument by the last for now and maybe mark as maybe!, we can keep the symbol as we now know we have an assignment */
|
|
50
32
|
const res = (0, built_in_assignment_1.processAssignment)(name, [args[0], args[args.length - 1]], rootId, data, {
|
|
51
33
|
superAssignment: config.assignmentOperator === '<<-',
|
|
52
34
|
makeMaybe: indices !== undefined ? false : config.makeMaybe,
|
|
53
|
-
indicesCollection: indices
|
|
35
|
+
indicesCollection: indices,
|
|
36
|
+
canBeReplacement: true
|
|
54
37
|
});
|
|
38
|
+
const convertedArgs = config.readIndices ? args.slice(1, -1) : (0, built_in_access_1.symbolArgumentsToStrings)(args.slice(1, -1), 0);
|
|
55
39
|
/* now, we soft-inject other arguments, so that calls like `x[y] <- 3` are linked correctly */
|
|
56
40
|
const { callArgs } = (0, common_1.processAllArguments)({
|
|
57
41
|
functionName: (0, info_1.initializeCleanDataflowInformation)(rootId, data),
|
|
58
|
-
args:
|
|
42
|
+
args: convertedArgs,
|
|
59
43
|
data,
|
|
60
44
|
functionRootId: rootId,
|
|
61
45
|
finalGraph: res.graph,
|
|
62
46
|
forceArgs: config.forceArgs,
|
|
63
47
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
(0, common_1.patchFunctionCall)({
|
|
49
|
+
nextGraph: res.graph,
|
|
50
|
+
data,
|
|
51
|
+
rootId,
|
|
52
|
+
name,
|
|
53
|
+
argumentProcessResult: args.map(a => a === r_function_call_1.EmptyArgument ? undefined : { entryPoint: (0, unpack_argument_1.unpackArgument)(a)?.info.id })
|
|
54
|
+
});
|
|
55
|
+
const firstArg = (0, unpack_argument_1.unpackArgument)(args[0])?.info.id;
|
|
56
|
+
if (firstArg) {
|
|
57
|
+
res.graph.addEdge(firstArg, rootId, edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Reads);
|
|
58
|
+
}
|
|
67
59
|
/* a replacement reads all of its call args as well, at least as far as I am aware of */
|
|
68
60
|
for (const arg of callArgs) {
|
|
69
61
|
const ref = (0, graph_1.getReferenceOfArgument)(arg);
|
|
@@ -73,4 +65,66 @@ args, rootId, data, config) {
|
|
|
73
65
|
}
|
|
74
66
|
return res;
|
|
75
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Constructs accessed indices of replacement function recursively.
|
|
70
|
+
*
|
|
71
|
+
* Example:
|
|
72
|
+
* ```r
|
|
73
|
+
* a$b <- 1
|
|
74
|
+
* # results in index with lexeme b as identifier
|
|
75
|
+
*
|
|
76
|
+
* a[[1]]$b
|
|
77
|
+
* # results in index with index 1 as identifier with a sub-index with lexeme b as identifier
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @param operation - Operation of replacement function e.g. '$\<-', '[\<-', '[[\<-'
|
|
81
|
+
* @param args - Arguments of the replacement function
|
|
82
|
+
* @returns Accessed indices construct
|
|
83
|
+
*/
|
|
84
|
+
function constructAccessedIndices(operation, args) {
|
|
85
|
+
const { accessedArg, accessArg } = (0, containers_1.getAccessOperands)(args);
|
|
86
|
+
if (accessedArg === undefined || accessArg?.value === undefined || !isSupportedOperation(operation, accessArg.value)) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
const constructIdentifier = getIdentifierBuilder(operation);
|
|
90
|
+
const leafIndex = {
|
|
91
|
+
identifier: constructIdentifier(accessArg),
|
|
92
|
+
nodeId: accessedArg.info.parent ?? ''
|
|
93
|
+
};
|
|
94
|
+
const accessIndices = {
|
|
95
|
+
indices: [leafIndex],
|
|
96
|
+
isContainer: false
|
|
97
|
+
};
|
|
98
|
+
// Check for nested access
|
|
99
|
+
let indicesCollection = undefined;
|
|
100
|
+
if (accessedArg.value?.type === type_1.RType.Access) {
|
|
101
|
+
indicesCollection = (0, containers_1.constructNestedAccess)(accessedArg.value, accessIndices, constructIdentifier);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// use access node as reference to get complete line in slice
|
|
105
|
+
indicesCollection = [accessIndices];
|
|
106
|
+
}
|
|
107
|
+
return indicesCollection;
|
|
108
|
+
}
|
|
109
|
+
function isSupportedOperation(operation, value) {
|
|
110
|
+
const isNameBasedAccess = (operation === '$<-' || operation === '@<-') && value.type === type_1.RType.Symbol;
|
|
111
|
+
const isNumericalIndexBasedAccess = (operation === '[[<-' || operation === '[<-') && value.type === type_1.RType.Number;
|
|
112
|
+
return isNameBasedAccess || isNumericalIndexBasedAccess;
|
|
113
|
+
}
|
|
114
|
+
function getIdentifierBuilder(operation) {
|
|
115
|
+
if (operation === '$<-' || operation == '@<-') {
|
|
116
|
+
return (arg) => {
|
|
117
|
+
return {
|
|
118
|
+
index: undefined,
|
|
119
|
+
lexeme: arg.lexeme,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// [[<- and [<-
|
|
124
|
+
return (arg) => {
|
|
125
|
+
return {
|
|
126
|
+
index: Number(arg.lexeme),
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
}
|
|
76
130
|
//# sourceMappingURL=built-in-replacement.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
2
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
3
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
5
|
+
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
6
|
+
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
export declare function processRm<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processRm = processRm;
|
|
4
|
+
const known_call_handling_1 = require("../known-call-handling");
|
|
5
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
6
|
+
const logger_1 = require("../../../../../logger");
|
|
7
|
+
const remove_1 = require("../../../../../environments/remove");
|
|
8
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
|
+
function processRm(name, args, rootId, data) {
|
|
10
|
+
if (args.length === 0) {
|
|
11
|
+
logger_1.dataflowLogger.warn('empty rm, skipping');
|
|
12
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
|
|
13
|
+
}
|
|
14
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
|
|
15
|
+
const names = [];
|
|
16
|
+
for (const arg of args) {
|
|
17
|
+
if (arg === r_function_call_1.EmptyArgument) {
|
|
18
|
+
logger_1.dataflowLogger.warn('empty argument in rm, skipping');
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const unpacked = arg.value;
|
|
22
|
+
if (unpacked === undefined || (unpacked.type !== type_1.RType.Symbol && unpacked.type !== type_1.RType.String)) {
|
|
23
|
+
logger_1.dataflowLogger.warn(`argument is not a symbol or string, skipping ${JSON.stringify(unpacked)}`);
|
|
24
|
+
}
|
|
25
|
+
else if (unpacked.type === type_1.RType.Symbol) {
|
|
26
|
+
names.push(unpacked.content);
|
|
27
|
+
}
|
|
28
|
+
else if (unpacked.type === type_1.RType.String) {
|
|
29
|
+
names.push(unpacked.content.str);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
let env = res.environment;
|
|
33
|
+
for (const name of names) {
|
|
34
|
+
env = (0, remove_1.remove)(name, env);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...res,
|
|
38
|
+
environment: env
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=built-in-rm.js.map
|
|
@@ -103,6 +103,10 @@ function findSource(seed, data) {
|
|
|
103
103
|
return found;
|
|
104
104
|
}
|
|
105
105
|
function processSourceCall(name, args, rootId, data, config) {
|
|
106
|
+
if (args.length !== 1) {
|
|
107
|
+
logger_1.dataflowLogger.warn(`Expected exactly one argument for source currently, but got ${args.length} instead, skipping`);
|
|
108
|
+
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
|
|
109
|
+
}
|
|
106
110
|
const information = config.includeFunctionCall ?
|
|
107
111
|
(0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information
|
|
108
112
|
: (0, info_1.initializeCleanDataflowInformation)(rootId, data);
|
|
@@ -135,12 +139,14 @@ function processSourceCall(name, args, rootId, data, config) {
|
|
|
135
139
|
if (filepath !== undefined) {
|
|
136
140
|
const request = sourceProvider.createRequest(filepath);
|
|
137
141
|
// check if the sourced file has already been dataflow analyzed, and if so, skip it
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
const limit = (0, config_1.getConfig)().solver.resolveSource?.repeatedSourceLimit ?? 0;
|
|
143
|
+
const findCount = data.referenceChain.filter(e => e.request === request.request && e.content === request.content).length;
|
|
144
|
+
if (findCount > limit) {
|
|
145
|
+
logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
|
|
140
146
|
information.graph.markIdForUnknownSideEffects(rootId);
|
|
141
147
|
return information;
|
|
142
148
|
}
|
|
143
|
-
return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)(path, name.location));
|
|
149
|
+
return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + path, name.location));
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
(0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
|
|
@@ -193,7 +199,13 @@ function sourceRequest(rootId, request, data, information, getId) {
|
|
|
193
199
|
for (const [k, v] of normalized.idMap) {
|
|
194
200
|
data.completeAst.idMap.set(k, v);
|
|
195
201
|
}
|
|
196
|
-
return
|
|
202
|
+
return {
|
|
203
|
+
...newInformation,
|
|
204
|
+
in: newInformation.in.concat(dataflow.in),
|
|
205
|
+
out: newInformation.out.concat(dataflow.out),
|
|
206
|
+
unknownReferences: newInformation.unknownReferences.concat(dataflow.unknownReferences),
|
|
207
|
+
exitPoints: dataflow.exitPoints
|
|
208
|
+
};
|
|
197
209
|
}
|
|
198
210
|
function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
|
|
199
211
|
const path = inputRequest.request === 'file' ? inputRequest.content : '-inline-';
|
|
@@ -210,6 +222,6 @@ function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
|
|
|
210
222
|
currentRequest: request,
|
|
211
223
|
environment: information.environment,
|
|
212
224
|
referenceChain: [...data.referenceChain, inputRequest]
|
|
213
|
-
}, information, (0, decorate_1.deterministicPrefixIdGenerator)(path + '
|
|
225
|
+
}, information, (0, decorate_1.deterministicPrefixIdGenerator)(path + '::' + uniqueSourceId));
|
|
214
226
|
}
|
|
215
227
|
//# sourceMappingURL=built-in-source.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
2
|
+
import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
3
|
+
import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
+
import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
5
|
+
import type { DataflowInformation } from '../../../../../info';
|
|
6
|
+
import type { DataflowProcessorInformation } from '../../../../../processor';
|
|
7
|
+
/**
|
|
8
|
+
* Process a vector call.
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* ```r
|
|
12
|
+
* c(1, 2, 3, 4)
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function processVector<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processVector = processVector;
|
|
4
|
+
const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
5
|
+
const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
|
|
6
|
+
const known_call_handling_1 = require("../known-call-handling");
|
|
7
|
+
const config_1 = require("../../../../../../config");
|
|
8
|
+
const containers_1 = require("../../../../../../util/containers");
|
|
9
|
+
/**
|
|
10
|
+
* Process a vector call.
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* ```r
|
|
14
|
+
* c(1, 2, 3, 4)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function processVector(name, args, rootId, data) {
|
|
18
|
+
const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
|
|
19
|
+
if (!(0, config_1.getConfig)().solver.pointerTracking) {
|
|
20
|
+
return fnCall.information;
|
|
21
|
+
}
|
|
22
|
+
const vectorArgs = [];
|
|
23
|
+
let argIndex = 1;
|
|
24
|
+
for (const arg of args) {
|
|
25
|
+
// Skip invalid argument types
|
|
26
|
+
if (arg === r_function_call_1.EmptyArgument || arg.type !== type_1.RType.Argument || arg.value === undefined) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (isPrimitive(arg.value.type)) {
|
|
30
|
+
vectorArgs.push({
|
|
31
|
+
identifier: { index: argIndex++ },
|
|
32
|
+
nodeId: arg.value.info.id,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Check whether argument value can be resolved
|
|
37
|
+
let indicesCollection;
|
|
38
|
+
if (arg.value.type === type_1.RType.Symbol) {
|
|
39
|
+
indicesCollection = (0, containers_1.resolveIndicesByName)(arg.value.lexeme, data.environment);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Check whether argument is nested container
|
|
43
|
+
indicesCollection = fnCall.information.graph.getVertex(arg.value.info.id)?.indicesCollection;
|
|
44
|
+
}
|
|
45
|
+
const flattenedIndices = indicesCollection?.flatMap(indices => indices.indices)
|
|
46
|
+
.map(index => {
|
|
47
|
+
return {
|
|
48
|
+
identifier: { index: argIndex++ },
|
|
49
|
+
nodeId: index.nodeId,
|
|
50
|
+
};
|
|
51
|
+
}) ?? [];
|
|
52
|
+
vectorArgs.push(...flattenedIndices);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if ((0, config_1.isOverPointerAnalysisThreshold)(vectorArgs.length)) {
|
|
56
|
+
return fnCall.information;
|
|
57
|
+
}
|
|
58
|
+
const indices = {
|
|
59
|
+
indices: vectorArgs,
|
|
60
|
+
isContainer: true,
|
|
61
|
+
};
|
|
62
|
+
// Add resolved indices to vertex
|
|
63
|
+
const vertex = fnCall.information.graph.getVertex(rootId);
|
|
64
|
+
if (vertex) {
|
|
65
|
+
vertex.indicesCollection = [indices];
|
|
66
|
+
}
|
|
67
|
+
return fnCall.information;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks whether the passed type is primitive i.e. number, logical or string.
|
|
71
|
+
*/
|
|
72
|
+
function isPrimitive(type) {
|
|
73
|
+
return type === type_1.RType.Number || type === type_1.RType.Logical || type === type_1.RType.String;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=built-in-vector.js.map
|
|
@@ -34,6 +34,6 @@ export interface PatchFunctionCallInput<OtherInfo> {
|
|
|
34
34
|
readonly rootId: NodeId;
|
|
35
35
|
readonly name: RSymbol<OtherInfo & ParentInformation>;
|
|
36
36
|
readonly data: DataflowProcessorInformation<OtherInfo & ParentInformation>;
|
|
37
|
-
readonly argumentProcessResult: readonly (DataflowInformation | undefined)[];
|
|
37
|
+
readonly argumentProcessResult: readonly (Pick<DataflowInformation, 'entryPoint'> | undefined)[];
|
|
38
38
|
}
|
|
39
39
|
export declare function patchFunctionCall<OtherInfo>({ nextGraph, rootId, name, data, argumentProcessResult }: PatchFunctionCallInput<OtherInfo>): void;
|
|
@@ -64,9 +64,12 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
|
|
|
64
64
|
}
|
|
65
65
|
processedArguments.push(processed);
|
|
66
66
|
finalEnv = (0, overwrite_1.overwriteEnvironment)(finalEnv, processed.environment);
|
|
67
|
+
finalGraph.mergeWith(processed.graph);
|
|
67
68
|
// resolve reads within argument, we resolve before adding the `processed.environment` to avoid cyclic dependencies
|
|
68
69
|
for (const ingoing of [...processed.in, ...processed.unknownReferences]) {
|
|
69
|
-
|
|
70
|
+
// check if it is called directly
|
|
71
|
+
const vtx = finalGraph.getVertex(ingoing.nodeId);
|
|
72
|
+
const tryToResolve = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, argEnv, vtx?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Unknown) : undefined;
|
|
70
73
|
if (tryToResolve === undefined) {
|
|
71
74
|
remainingReadInArgs.push(ingoing);
|
|
72
75
|
}
|
|
@@ -90,7 +93,6 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
|
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
argEnv = (0, overwrite_1.overwriteEnvironment)(argEnv, processed.environment);
|
|
93
|
-
finalGraph.mergeWith(processed.graph);
|
|
94
96
|
if (arg.type !== type_1.RType.Argument || !arg.name) {
|
|
95
97
|
callArgs.push({ nodeId: processed.entryPoint, controlDependencies: undefined, type: identifier_1.ReferenceType.Argument });
|
|
96
98
|
}
|
|
@@ -4,4 +4,6 @@ import type { ParentInformation } from '../../../../../r-bridge/lang-4.x/ast/mod
|
|
|
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';
|
|
6
6
|
import type { NodeId } from '../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
7
|
+
import type { DataflowGraph } from '../../../../graph/graph';
|
|
8
|
+
export declare function markAsOnlyBuiltIn(graph: DataflowGraph, rootId: NodeId): void;
|
|
7
9
|
export declare function processNamedCall<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.markAsOnlyBuiltIn = markAsOnlyBuiltIn;
|
|
3
4
|
exports.processNamedCall = processNamedCall;
|
|
4
5
|
const info_1 = require("../../../../info");
|
|
5
6
|
const known_call_handling_1 = require("./known-call-handling");
|
|
@@ -27,6 +28,13 @@ function processDefaultFunctionProcessor(information, name, args, rootId, data)
|
|
|
27
28
|
const call = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: (resolve?.length ?? 0) > 0 ? undefined : 'all' });
|
|
28
29
|
return mergeInformation(information, call.information);
|
|
29
30
|
}
|
|
31
|
+
function markAsOnlyBuiltIn(graph, rootId) {
|
|
32
|
+
const v = graph.getVertex(rootId);
|
|
33
|
+
if (v?.tag === vertex_1.VertexType.FunctionCall) {
|
|
34
|
+
v.onlyBuiltin = true;
|
|
35
|
+
v.environment = undefined;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
30
38
|
function processNamedCall(name, args, rootId, data) {
|
|
31
39
|
const resolved = (0, resolve_by_name_1.resolveByName)(name.content, data.environment, identifier_1.ReferenceType.Function) ?? [];
|
|
32
40
|
let defaultProcessor = resolved.length === 0;
|
|
@@ -46,11 +54,7 @@ function processNamedCall(name, args, rootId, data) {
|
|
|
46
54
|
}
|
|
47
55
|
else if (information && builtIn) {
|
|
48
56
|
// mark the function call as built in only
|
|
49
|
-
|
|
50
|
-
if (v?.tag === vertex_1.VertexType.FunctionCall) {
|
|
51
|
-
v.onlyBuiltin = true;
|
|
52
|
-
v.environment = undefined;
|
|
53
|
-
}
|
|
57
|
+
markAsOnlyBuiltIn(information.graph, rootId);
|
|
54
58
|
}
|
|
55
59
|
return information ?? (0, info_1.initializeCleanDataflowInformation)(rootId, data);
|
|
56
60
|
}
|
|
@@ -3,4 +3,7 @@ import type { DataflowInformation } from '../../info';
|
|
|
3
3
|
import type { Base, RNode, Location } from '../../../r-bridge/lang-4.x/ast/model/model';
|
|
4
4
|
import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
5
|
import type { EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
6
|
+
/**
|
|
7
|
+
* Helper function for {@link processNamedCall} using the given `functionName` as the name of the function.
|
|
8
|
+
*/
|
|
6
9
|
export declare function processAsNamedCall<OtherInfo>(functionName: RNode<OtherInfo & ParentInformation> & Base<OtherInfo> & Location, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, name: string, args: readonly (RNode<OtherInfo & ParentInformation> | typeof EmptyArgument | undefined)[]): DataflowInformation;
|
|
@@ -4,6 +4,9 @@ exports.processAsNamedCall = processAsNamedCall;
|
|
|
4
4
|
const named_call_handling_1 = require("./functions/call/named-call-handling");
|
|
5
5
|
const make_argument_1 = require("./functions/call/argument/make-argument");
|
|
6
6
|
const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
|
|
7
|
+
/**
|
|
8
|
+
* Helper function for {@link processNamedCall} using the given `functionName` as the name of the function.
|
|
9
|
+
*/
|
|
7
10
|
function processAsNamedCall(functionName, data, name, args) {
|
|
8
11
|
return (0, named_call_handling_1.processNamedCall)({
|
|
9
12
|
type: type_1.RType.Symbol,
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import type { ControlFlowInformation } from '../../util/cfg/cfg';
|
|
2
|
-
import type { RShell } from '../../r-bridge/shell';
|
|
3
2
|
import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
|
|
3
|
+
import type { KnownParser } from '../../r-bridge/parser';
|
|
4
|
+
import type { DataflowInformation } from '../../dataflow/info';
|
|
5
|
+
export declare function getCfg(parser: KnownParser, code: string): Promise<{
|
|
5
6
|
info: ControlFlowInformation;
|
|
6
7
|
ast: NormalizedAst;
|
|
8
|
+
dataflow: DataflowInformation;
|
|
7
9
|
}>;
|
|
10
|
+
export declare function printCfg(cfg: ControlFlowInformation, ast: NormalizedAst, prefix?: string): string;
|
|
11
|
+
export interface PrintCfgOptions {
|
|
12
|
+
readonly showCode?: boolean;
|
|
13
|
+
readonly openCode?: boolean;
|
|
14
|
+
readonly prefix?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function printCFGCode(parser: KnownParser, code: string, { showCode, openCode, prefix }?: PrintCfgOptions): Promise<string>;
|
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getCfg = getCfg;
|
|
4
|
+
exports.printCfg = printCfg;
|
|
5
|
+
exports.printCFGCode = printCFGCode;
|
|
4
6
|
const cfg_1 = require("../../util/cfg/cfg");
|
|
5
|
-
const pipeline_executor_1 = require("../../core/pipeline-executor");
|
|
6
7
|
const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
|
|
7
8
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const time_1 = require("../../util/time");
|
|
10
|
+
const doc_files_1 = require("./doc-files");
|
|
11
|
+
const cfg_2 = require("../../util/mermaid/cfg");
|
|
12
|
+
const doc_code_1 = require("./doc-code");
|
|
13
|
+
async function getCfg(parser, code) {
|
|
14
|
+
const result = await (0, default_pipelines_1.createDataflowPipeline)(parser, {
|
|
11
15
|
request: (0, retriever_1.requestFromInput)(code)
|
|
12
16
|
}).allRemainingSteps();
|
|
17
|
+
const cfg = (0, cfg_1.extractCFG)(result.normalize, result.dataflow.graph);
|
|
13
18
|
return {
|
|
14
|
-
info:
|
|
15
|
-
ast:
|
|
19
|
+
info: cfg,
|
|
20
|
+
ast: result.normalize,
|
|
21
|
+
dataflow: result.dataflow
|
|
16
22
|
};
|
|
17
23
|
}
|
|
24
|
+
function printCfg(cfg, ast, prefix = 'flowchart TD\n') {
|
|
25
|
+
return `
|
|
26
|
+
${(0, doc_code_1.codeBlock)('mermaid', (0, cfg_2.cfgToMermaid)(cfg, ast, prefix))}
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
async function printCFGCode(parser, code, { showCode = true, openCode = false, prefix = 'flowchart BT\n' } = {}) {
|
|
30
|
+
const now = performance.now();
|
|
31
|
+
const res = await getCfg(parser, code);
|
|
32
|
+
const duration = performance.now() - now;
|
|
33
|
+
const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including the dataflow analysis, normalization, and parsing with the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
|
|
34
|
+
return '\n\n' + printCfg(res.info, res.ast, prefix) + (showCode ? `
|
|
35
|
+
<details${openCode ? ' open' : ''}>
|
|
36
|
+
|
|
37
|
+
<summary style="color:gray">R Code of the CFG</summary>
|
|
38
|
+
|
|
39
|
+
${metaInfo}
|
|
40
|
+
|
|
41
|
+
${(0, doc_code_1.codeBlock)('r', code)}
|
|
42
|
+
|
|
43
|
+
</details>
|
|
44
|
+
|
|
45
|
+
` : '\n(' + metaInfo + ')\n\n');
|
|
46
|
+
}
|
|
18
47
|
//# sourceMappingURL=doc-cfg.js.map
|
|
@@ -4,17 +4,25 @@ exports.codeBlock = codeBlock;
|
|
|
4
4
|
exports.codeInline = codeInline;
|
|
5
5
|
exports.jsonWithLimit = jsonWithLimit;
|
|
6
6
|
const json_1 = require("../../util/json");
|
|
7
|
+
const environment_1 = require("../../dataflow/environments/environment");
|
|
7
8
|
function codeBlock(language, code) {
|
|
8
9
|
return `\n\`\`\`${language}\n${code?.trim() ?? ''}\n\`\`\`\n`;
|
|
9
10
|
}
|
|
10
11
|
function codeInline(code) {
|
|
11
12
|
return `<code>${code}</code>`;
|
|
12
13
|
}
|
|
13
|
-
function jsonWithLimit(object, maxLength = 5_000, tooLongText = '_As the code is pretty long, we inhibit pretty printing and syntax highlighting (JSON):_') {
|
|
14
|
+
function jsonWithLimit(object, maxLength = 5_000, tooLongText = '_As the code is pretty long, we inhibit pretty printing and syntax highlighting (JSON, hiding built-in):_') {
|
|
14
15
|
const prettyPrinted = JSON.stringify(object, json_1.jsonReplacer, 2);
|
|
15
16
|
return `
|
|
16
17
|
${prettyPrinted.length > maxLength ? tooLongText : ''}
|
|
17
|
-
${codeBlock(prettyPrinted.length > maxLength ? 'text' : 'json', prettyPrinted.length > 5_000 ? JSON.stringify(object,
|
|
18
|
+
${codeBlock(prettyPrinted.length > maxLength ? 'text' : 'json', prettyPrinted.length > 5_000 ? JSON.stringify(object, (k, v) => {
|
|
19
|
+
if (typeof v === 'object' && v !== null && 'id' in v && v['id'] === 0 && 'memory' in v && v['memory']) {
|
|
20
|
+
return '<BuiltInEnvironment>';
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return (0, environment_1.builtInEnvJsonReplacer)(k, v);
|
|
24
|
+
}
|
|
25
|
+
}) : prettyPrinted)}
|
|
18
26
|
`;
|
|
19
27
|
}
|
|
20
28
|
//# sourceMappingURL=doc-code.js.map
|
|
@@ -86,7 +86,7 @@ async function printSingleCapability(info, depth, index, capability) {
|
|
|
86
86
|
if (capability.url) {
|
|
87
87
|
nextLine += '\\\nSee ' + (0, strings_1.joinWithLast)(capability.url.map(({ name, href }) => `[${name}](${href})`)) + ' for more info.';
|
|
88
88
|
}
|
|
89
|
-
nextLine += '
|
|
89
|
+
nextLine += ' (internal ID: `' + capability.id + '`)';
|
|
90
90
|
if (capability.example) {
|
|
91
91
|
nextLine += `\n${(0, doc_general_1.prefixLines)(typeof capability.example === 'string' ? capability.example : await capability.example(info.parser), nextLineIndent + '> ')}`;
|
|
92
92
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const shell_1 = require("../r-bridge/shell");
|
|
7
|
+
const log_1 = require("../../test/functionality/_helper/log");
|
|
8
|
+
const doc_auto_gen_1 = require("./doc-util/doc-auto-gen");
|
|
9
|
+
const doc_code_1 = require("./doc-util/doc-code");
|
|
10
|
+
const doc_types_1 = require("./doc-util/doc-types");
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const doc_files_1 = require("./doc-util/doc-files");
|
|
13
|
+
const doc_cli_option_1 = require("./doc-util/doc-cli-option");
|
|
14
|
+
const doc_structure_1 = require("./doc-util/doc-structure");
|
|
15
|
+
const doc_issue_1 = require("./doc-util/doc-issue");
|
|
16
|
+
const doc_cfg_1 = require("./doc-util/doc-cfg");
|
|
17
|
+
const visitor_1 = require("../util/cfg/visitor");
|
|
18
|
+
async function getText(shell) {
|
|
19
|
+
const rversion = (await shell.usedRVersion())?.format() ?? 'unknown';
|
|
20
|
+
const types = (0, doc_types_1.getTypesFromFolderAsMermaid)({
|
|
21
|
+
rootFolder: path_1.default.resolve('./src'),
|
|
22
|
+
typeName: 'RNode',
|
|
23
|
+
inlineTypes: doc_types_1.mermaidHide
|
|
24
|
+
});
|
|
25
|
+
return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'control flow graph', rVersion: rversion })}
|
|
26
|
+
|
|
27
|
+
_flowR_ produces two main perspectives of the program: 1) a [normalized version of the AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST)
|
|
28
|
+
and 2) a [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph). However, for further analyses, we also provide an explicit control flow graph
|
|
29
|
+
that is calculated from the normalized AST **and** the dataflow graph to incorporate change in language semantics.
|
|
30
|
+
flowR also uses this CFG for some of its queries (e.g., to link to the last call in a [Call-Context Query](${doc_files_1.FlowrWikiBaseRef}/Query-API))
|
|
31
|
+
but does not incorporate it into its core analysis.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
${(0, doc_structure_1.block)({
|
|
35
|
+
type: 'TIP',
|
|
36
|
+
content: `If you want to investigate the Control Flow Graph,
|
|
37
|
+
you can use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL (see the [Interface wiki page](${doc_files_1.FlowrWikiBaseRef}/Interface) for more information).`
|
|
38
|
+
})}
|
|
39
|
+
|
|
40
|
+
The CFG may be a little bit uncommon compared to the classical CFG with basic blocks. This is mostly due to historical reasons.
|
|
41
|
+
Please [open a new issue](${doc_issue_1.NewIssueUrl}) if you are interested in such a perspective.
|
|
42
|
+
|
|
43
|
+
But for now, let's look at a simple CFG for a program without any branching:
|
|
44
|
+
|
|
45
|
+
${(0, doc_code_1.codeBlock)('r', 'x <- 2 * 3 + 1')}
|
|
46
|
+
|
|
47
|
+
The corresponding CFG is a directed, labeled graph with two types of edges (control and flow dependencies):
|
|
48
|
+
|
|
49
|
+
${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
|
|
50
|
+
|
|
51
|
+
Every normalized node of the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST) that has any relevance to the
|
|
52
|
+
execution is added and automatically linked using its id (similarly to vertices of the [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph)).
|
|
53
|
+
Higher expressions, such as \`2 * 3\` get an additional node with an artificial id that ends in \`-exit\` to mark whenever their calculation is over.
|
|
54
|
+
|
|
55
|
+
To gain a better understanding, let's have a look at a simple program with a single branching structure:
|
|
56
|
+
|
|
57
|
+
${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
|
|
58
|
+
|
|
59
|
+
Here, you can see the \`if\` node followed by the condition (in this case merely \`u\`) that then splits into two branches for the two possible outcomes.
|
|
60
|
+
The \`if\` structure is terminated by the corresponding \`-exit\` node.
|
|
61
|
+
|
|
62
|
+
For you to compare, the following shows the CFG of an \`if\` without an \`else\` branch:
|
|
63
|
+
|
|
64
|
+
${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
|
|
65
|
+
|
|
66
|
+
The control flow graph also harmonizes with function definitions, and calls:
|
|
67
|
+
|
|
68
|
+
${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
|
|
69
|
+
|
|
70
|
+
In general, it is probably best to use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL to investigate the CFG interactively.
|
|
71
|
+
Have a look at the ${(0, doc_types_1.shortLink)(visitor_1.visitCfgInReverseOrder.name, types.info)} function for a generic CFG visitor.
|
|
72
|
+
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
if (require.main === module) {
|
|
76
|
+
(0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */);
|
|
77
|
+
const shell = new shell_1.RShell();
|
|
78
|
+
void getText(shell).then(str => {
|
|
79
|
+
console.log(str);
|
|
80
|
+
}).finally(() => {
|
|
81
|
+
shell.close();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=print-cfg-wiki.js.map
|