@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
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ It offers a wide variety of features, for example:
|
|
|
48
48
|
|
|
49
49
|
```shell
|
|
50
50
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
51
|
-
flowR repl using flowR v2.2.
|
|
51
|
+
flowR repl using flowR v2.2.8, R v4.4.0 (r-shell engine)
|
|
52
52
|
R> :slicer test/testfiles/example.R --criterion "11@sum"
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -95,7 +95,7 @@ It offers a wide variety of features, for example:
|
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
* 🚀 **fast data- and control-flow graphs**\
|
|
98
|
-
Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">
|
|
98
|
+
Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">120.8 ms</span></i> (as of Feb 19, 2025),
|
|
99
99
|
_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,
|
|
100
100
|
and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/Dataflow-Graph) for more details on the dataflow graph.
|
|
101
101
|
|
|
@@ -131,7 +131,7 @@ It offers a wide variety of features, for example:
|
|
|
131
131
|
|
|
132
132
|
```shell
|
|
133
133
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
134
|
-
flowR repl using flowR v2.2.
|
|
134
|
+
flowR repl using flowR v2.2.8, R v4.4.0 (r-shell engine)
|
|
135
135
|
R> :dataflow* test/testfiles/example.R
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -140,7 +140,7 @@ It offers a wide variety of features, for example:
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
```text
|
|
143
|
-
https://mermaid.live/view#base64:
|
|
143
|
+
https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IEJUXG4gICAgMChbXCJgIzkxO1JTeW1ib2wjOTM7IHRlc3RcbiAgICAgICgwKVxuICAgICAgKjEuMS00KmBcIl0pXG4gICAgMShbXCJgIzkxO1JTeW1ib2wjOTM7IHRlc3RmaWxlc1xuICAgICAgKDEpXG4gICAgICAqMS42LTE0KmBcIl0pXG4gICAgMltbXCJgIzkxO1JCaW5hcnlPcCM5MzsgL1xuICAgICAgKDIpXG4gICAgICAqMS4xLTE0KlxuICAgICgwLCAxKWBcIl1dXG4gICAgMyhbXCJgIzkxO1JTeW1ib2wjOTM7IGV4YW1wbGUuUlxuICAgICAgKDMpXG4gICAgICAqMS4xNi0yNCpgXCJdKVxuICAgIDRbW1wiYCM5MTtSQmluYXJ5T3AjOTM7IC9cbiAgICAgICg0KVxuICAgICAgKjEuMS0yNCpcbiAgICAoMiwgMylgXCJdXVxuICAgIDIgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDBcbiAgICAyIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCAxXG4gICAgNCAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgMlxuICAgIDQgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDMiLCJtZXJtYWlkIjp7ImF1dG9TeW5jIjp0cnVlfX0=
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
|
|
@@ -149,6 +149,7 @@ It offers a wide variety of features, for example:
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
|
|
152
|
+
|
|
152
153
|
```mermaid
|
|
153
154
|
flowchart LR
|
|
154
155
|
1{{"`#91;RNumber#93; 0
|
|
@@ -374,8 +375,9 @@ It offers a wide variety of features, for example:
|
|
|
374
375
|
52 -->|"reads, argument"| 48
|
|
375
376
|
52 -->|"argument"| 50
|
|
376
377
|
```
|
|
378
|
+
|
|
377
379
|
|
|
378
|
-
(The analysis required
|
|
380
|
+
(The analysis required _22.72 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
|
|
379
381
|
|
|
380
382
|
|
|
381
383
|
|
|
@@ -111,6 +111,12 @@ exports.flowrMainOptionDefinitions = [
|
|
|
111
111
|
description: 'The path to the tree-sitter WASM binary to use. Defaults to the path specified by the tree-sitter package.',
|
|
112
112
|
multiple: false
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
name: 'engine.tree-sitter.lax',
|
|
116
|
+
type: Boolean,
|
|
117
|
+
description: 'Use the lax parser for parsing R code (allowing for syntax errors).',
|
|
118
|
+
multiple: false
|
|
119
|
+
},
|
|
114
120
|
{
|
|
115
121
|
name: 'default-engine',
|
|
116
122
|
type: String,
|
package/cli/flowr.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface FlowrCliOptions {
|
|
|
20
20
|
'engine.tree-sitter.disabled': boolean;
|
|
21
21
|
'engine.tree-sitter.wasm-path': string | undefined;
|
|
22
22
|
'engine.tree-sitter.tree-sitter-wasm-path': string | undefined;
|
|
23
|
+
'engine.tree-sitter.lax': boolean;
|
|
23
24
|
}
|
|
24
25
|
export declare const optionHelp: ({
|
|
25
26
|
header: string;
|
package/cli/flowr.js
CHANGED
|
@@ -79,7 +79,8 @@ if (!options['engine.tree-sitter.disabled']) {
|
|
|
79
79
|
(0, config_1.amendConfig)({ engines: [{
|
|
80
80
|
type: 'tree-sitter',
|
|
81
81
|
wasmPath: options['engine.tree-sitter.wasm-path'],
|
|
82
|
-
treeSitterWasmPath: options['engine.tree-sitter.tree-sitter-wasm-path']
|
|
82
|
+
treeSitterWasmPath: options['engine.tree-sitter.tree-sitter-wasm-path'],
|
|
83
|
+
lax: options['engine.tree-sitter.lax']
|
|
83
84
|
}] });
|
|
84
85
|
}
|
|
85
86
|
if (options['default-engine']) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compact = compact;
|
|
4
|
+
exports.uncompact = uncompact;
|
|
5
|
+
const json_1 = require("../../../util/json");
|
|
6
|
+
const msgpack_1 = require("@msgpack/msgpack");
|
|
7
|
+
function compact(obj) {
|
|
8
|
+
return Buffer.from((0, msgpack_1.encode)(JSON.parse(JSON.stringify(obj, json_1.jsonReplacer))));
|
|
9
|
+
}
|
|
10
|
+
function uncompact(buf) {
|
|
11
|
+
return (0, msgpack_1.decode)(new Uint8Array(Buffer.from(buf)));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=compact.js.map
|
|
@@ -60,6 +60,7 @@ const assert_1 = require("../../../util/assert");
|
|
|
60
60
|
const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
|
|
61
61
|
const message_query_1 = require("./messages/message-query");
|
|
62
62
|
const query_1 = require("../../../queries/query");
|
|
63
|
+
const compact_1 = require("./compact");
|
|
63
64
|
/**
|
|
64
65
|
* Each connection handles a single client, answering to its requests.
|
|
65
66
|
* There is no need to construct this class manually, {@link FlowRServer} will do it for you.
|
|
@@ -181,6 +182,15 @@ class FlowRServerConnection {
|
|
|
181
182
|
}
|
|
182
183
|
});
|
|
183
184
|
}
|
|
185
|
+
else if (message.format === 'compact') {
|
|
186
|
+
(0, send_1.sendMessage)(this.socket, {
|
|
187
|
+
type: 'response-file-analysis',
|
|
188
|
+
format: 'compact',
|
|
189
|
+
id: message.id,
|
|
190
|
+
cfg: cfg ? (0, compact_1.compact)(cfg) : undefined,
|
|
191
|
+
results: (0, compact_1.compact)(sanitizedResults)
|
|
192
|
+
});
|
|
193
|
+
}
|
|
184
194
|
else {
|
|
185
195
|
(0, send_1.sendMessage)(this.socket, {
|
|
186
196
|
type: 'response-file-analysis',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IdMessageBase, MessageDefinition } from './all-messages';
|
|
2
2
|
import type { ControlFlowInformation } from '../../../../util/cfg/cfg';
|
|
3
|
-
import type { DEFAULT_DATAFLOW_PIPELINE
|
|
3
|
+
import type { DEFAULT_DATAFLOW_PIPELINE } from '../../../../core/steps/pipeline/default-pipelines';
|
|
4
4
|
import type { PipelineOutput } from '../../../../core/steps/pipeline/pipeline';
|
|
5
5
|
/**
|
|
6
6
|
* Send by the client to request an analysis of a given file.
|
|
@@ -33,7 +33,7 @@ export interface FileAnalysisRequestMessage extends IdMessageBase {
|
|
|
33
33
|
/** Can be used to additionally extract the {@link ControlFlowInformation} of the file, which is not exposed (and not fully calculated) by default. */
|
|
34
34
|
cfg?: boolean;
|
|
35
35
|
/** Controls the serialization of the `results` (and the {@link ControlFlowGraph} if the corresponding flag is set). If missing, we assume _json_. */
|
|
36
|
-
format?: 'json' | 'n-quads';
|
|
36
|
+
format?: 'compact' | 'json' | 'n-quads';
|
|
37
37
|
}
|
|
38
38
|
export declare const requestAnalysisMessage: MessageDefinition<FileAnalysisRequestMessage>;
|
|
39
39
|
/**
|
|
@@ -45,20 +45,36 @@ export declare const requestAnalysisMessage: MessageDefinition<FileAnalysisReque
|
|
|
45
45
|
*
|
|
46
46
|
* @note The serialization of maps and sets is controlled by the {@link jsonReplacer} as part of {@link sendMessage}.
|
|
47
47
|
*
|
|
48
|
-
* @see FileAnalysisResponseMessageNQuads
|
|
48
|
+
* @see {@link FileAnalysisResponseMessageNQuads}
|
|
49
|
+
* @see {@link FileAnalysisResponseMessageCompact}
|
|
49
50
|
*/
|
|
50
51
|
export interface FileAnalysisResponseMessageJson extends IdMessageBase {
|
|
51
52
|
type: 'response-file-analysis';
|
|
52
53
|
format: 'json';
|
|
53
54
|
/**
|
|
54
|
-
* See the {@link
|
|
55
|
+
* See the {@link PipelineExecutor} and {@link DEFAULT_DATAFLOW_PIPELINE} for details on the results.
|
|
55
56
|
*/
|
|
56
|
-
results: PipelineOutput<typeof
|
|
57
|
+
results: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>;
|
|
57
58
|
/**
|
|
58
59
|
* Only if the {@link FileAnalysisRequestMessage} contained a `cfg: true` this will contain the {@link ControlFlowInformation} of the file.
|
|
59
60
|
*/
|
|
60
61
|
cfg?: ControlFlowInformation;
|
|
61
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Similar to {@link FileAnalysisResponseMessageJson} but using a compact serialization format.
|
|
65
|
+
*/
|
|
66
|
+
export interface FileAnalysisResponseMessageCompact extends IdMessageBase {
|
|
67
|
+
type: 'response-file-analysis';
|
|
68
|
+
format: 'compact';
|
|
69
|
+
/**
|
|
70
|
+
* See the {@link PipelineExecutor} and {@link DEFAULT_DATAFLOW_PIPELINE} for details on the results.
|
|
71
|
+
*/
|
|
72
|
+
results: Buffer;
|
|
73
|
+
/**
|
|
74
|
+
* Only if the {@link FileAnalysisRequestMessage} contained a `cfg: true` this will contain the {@link ControlFlowInformation} of the file.
|
|
75
|
+
*/
|
|
76
|
+
cfg?: Buffer;
|
|
77
|
+
}
|
|
62
78
|
/**
|
|
63
79
|
* Similar to {@link FileAnalysisResponseMessageJson} but using n-quads as serialization format.
|
|
64
80
|
*/
|
|
@@ -15,7 +15,7 @@ exports.requestAnalysisMessage = {
|
|
|
15
15
|
content: joi_1.default.string().optional().description('The content of the file or an R expression (either give this or the filepath).'),
|
|
16
16
|
filepath: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).optional().description('The path to the file(s) on the local machine (either give this or the content).'),
|
|
17
17
|
cfg: joi_1.default.boolean().optional().description('If you want to extract the control flow information of the file.'),
|
|
18
|
-
format: joi_1.default.string().valid('json', 'n-quads').optional().description('The format of the results, if missing we assume json.')
|
|
18
|
+
format: joi_1.default.string().valid('json', 'n-quads', 'compact').optional().description('The format of the results, if missing we assume json.')
|
|
19
19
|
}).xor('content', 'filepath')
|
|
20
20
|
};
|
|
21
21
|
const jsonSchema = joi_1.default.object({
|
|
@@ -25,6 +25,13 @@ const jsonSchema = joi_1.default.object({
|
|
|
25
25
|
results: joi_1.default.object().required().description('The results of the analysis (one field per step).'),
|
|
26
26
|
cfg: joi_1.default.object().optional().description('The control flow information of the file, only present if requested.')
|
|
27
27
|
}).description('The response in JSON format.');
|
|
28
|
+
const compactSchema = joi_1.default.object({
|
|
29
|
+
type: joi_1.default.string().valid('response-file-analysis').required().description('The type of the message.'),
|
|
30
|
+
id: joi_1.default.string().optional().description('The id of the message, if you passed one in the request.'),
|
|
31
|
+
format: joi_1.default.string().valid('bson').required().description('The format of the results in bson format.'),
|
|
32
|
+
results: joi_1.default.binary().required().description('The results of the analysis (one field per step).'),
|
|
33
|
+
cfg: joi_1.default.binary().optional().description('The control flow information of the file, only present if requested.')
|
|
34
|
+
});
|
|
28
35
|
const nquadsSchema = joi_1.default.object({
|
|
29
36
|
type: joi_1.default.string().valid('response-file-analysis').required().description('The type of the message.'),
|
|
30
37
|
id: joi_1.default.string().optional().description('The id of the message, if you passed one in the request.'),
|
|
@@ -34,6 +41,6 @@ const nquadsSchema = joi_1.default.object({
|
|
|
34
41
|
}).description('The response as n-quads.');
|
|
35
42
|
exports.analysisResponseMessage = {
|
|
36
43
|
type: 'response-file-analysis',
|
|
37
|
-
schema: joi_1.default.alternatives(jsonSchema, nquadsSchema).required().description('The response to a file analysis request (based on the `format` field).')
|
|
44
|
+
schema: joi_1.default.alternatives(jsonSchema, nquadsSchema, compactSchema).required().description('The response to a file analysis request (based on the `format` field).')
|
|
38
45
|
};
|
|
39
46
|
//# sourceMappingURL=message-analysis.js.map
|
package/config.d.ts
CHANGED
|
@@ -10,6 +10,30 @@ export declare enum VariableResolve {
|
|
|
10
10
|
/** Only resolve directly assigned builtin constants */
|
|
11
11
|
Builtin = "builtin"
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* How to infer the working directory from a script
|
|
15
|
+
*/
|
|
16
|
+
export declare enum InferWorkingDirectory {
|
|
17
|
+
/** Don't infer the working directory */
|
|
18
|
+
No = "no",
|
|
19
|
+
/** Infer the working directory from the main script */
|
|
20
|
+
MainScript = "main-script",
|
|
21
|
+
/** Infer the working directory from the active script */
|
|
22
|
+
ActiveScript = "active-script",
|
|
23
|
+
/** Infer the working directory from any script */
|
|
24
|
+
AnyScript = "any-script"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* How to handle fixed strings in a source path
|
|
28
|
+
*/
|
|
29
|
+
export declare enum DropPathsOption {
|
|
30
|
+
/** Don't drop any parts of the sourced path */
|
|
31
|
+
No = "no",
|
|
32
|
+
/** try to drop everything but the filename */
|
|
33
|
+
Once = "once",
|
|
34
|
+
/** try to drop every folder of the path */
|
|
35
|
+
All = "all"
|
|
36
|
+
}
|
|
13
37
|
export interface FlowrConfigOptions extends MergeableRecord {
|
|
14
38
|
/**
|
|
15
39
|
* Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped
|
|
@@ -17,7 +41,7 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
17
41
|
readonly ignoreSourceCalls: boolean;
|
|
18
42
|
/** Configure language semantics and how flowR handles them */
|
|
19
43
|
readonly semantics: {
|
|
20
|
-
/** Semantics regarding the
|
|
44
|
+
/** Semantics regarding the handling of the environment */
|
|
21
45
|
readonly environment: {
|
|
22
46
|
/** Do you want to overwrite (parts) of the builtin definition? */
|
|
23
47
|
readonly overwriteBuiltIns: {
|
|
@@ -49,6 +73,30 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
49
73
|
* containers and accesses
|
|
50
74
|
*/
|
|
51
75
|
readonly pointerTracking: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* If lax source calls are active, flowR searches for sourced files much more freely,
|
|
78
|
+
* based on the configurations you give it.
|
|
79
|
+
* This option is only in effect if {@link ignoreSourceCalls} is set to false.
|
|
80
|
+
*/
|
|
81
|
+
readonly resolveSource?: {
|
|
82
|
+
/**
|
|
83
|
+
* search for filenames matching in the lowercase
|
|
84
|
+
*/
|
|
85
|
+
readonly ignoreCapitalization: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* try to infer the working directory from the main or any script to analyze.
|
|
88
|
+
*/
|
|
89
|
+
readonly inferWorkingDirectory: InferWorkingDirectory;
|
|
90
|
+
/**
|
|
91
|
+
* Additionally search in these paths
|
|
92
|
+
*/
|
|
93
|
+
readonly searchPath: readonly string[];
|
|
94
|
+
/**
|
|
95
|
+
* Allow to drop the first or all parts of the sourced path,
|
|
96
|
+
* if it is relative.
|
|
97
|
+
*/
|
|
98
|
+
readonly dropPaths: DropPathsOption;
|
|
99
|
+
};
|
|
52
100
|
};
|
|
53
101
|
}
|
|
54
102
|
export interface TreeSitterEngineConfig extends MergeableRecord {
|
|
@@ -61,6 +109,10 @@ export interface TreeSitterEngineConfig extends MergeableRecord {
|
|
|
61
109
|
* The path to the tree-sitter WASM binary to use. If this is undefined, the path specified by the tree-sitter package will be used.
|
|
62
110
|
*/
|
|
63
111
|
readonly treeSitterWasmPath?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used.
|
|
114
|
+
*/
|
|
115
|
+
readonly lax?: boolean;
|
|
64
116
|
}
|
|
65
117
|
export interface RShellEngineConfig extends MergeableRecord {
|
|
66
118
|
readonly type: 'r-shell';
|
package/config.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.flowrConfigFileSchema = exports.defaultConfigOptions = exports.VariableResolve = void 0;
|
|
6
|
+
exports.flowrConfigFileSchema = exports.defaultConfigOptions = exports.DropPathsOption = exports.InferWorkingDirectory = exports.VariableResolve = void 0;
|
|
7
7
|
exports.setConfigFile = setConfigFile;
|
|
8
8
|
exports.parseConfig = parseConfig;
|
|
9
9
|
exports.setConfig = setConfig;
|
|
@@ -25,6 +25,33 @@ var VariableResolve;
|
|
|
25
25
|
/** Only resolve directly assigned builtin constants */
|
|
26
26
|
VariableResolve["Builtin"] = "builtin";
|
|
27
27
|
})(VariableResolve || (exports.VariableResolve = VariableResolve = {}));
|
|
28
|
+
/**
|
|
29
|
+
* How to infer the working directory from a script
|
|
30
|
+
*/
|
|
31
|
+
var InferWorkingDirectory;
|
|
32
|
+
(function (InferWorkingDirectory) {
|
|
33
|
+
/** Don't infer the working directory */
|
|
34
|
+
InferWorkingDirectory["No"] = "no";
|
|
35
|
+
/** Infer the working directory from the main script */
|
|
36
|
+
InferWorkingDirectory["MainScript"] = "main-script";
|
|
37
|
+
/** Infer the working directory from the active script */
|
|
38
|
+
InferWorkingDirectory["ActiveScript"] = "active-script";
|
|
39
|
+
/** Infer the working directory from any script */
|
|
40
|
+
InferWorkingDirectory["AnyScript"] = "any-script";
|
|
41
|
+
})(InferWorkingDirectory || (exports.InferWorkingDirectory = InferWorkingDirectory = {}));
|
|
42
|
+
/**
|
|
43
|
+
* How to handle fixed strings in a source path
|
|
44
|
+
*/
|
|
45
|
+
var DropPathsOption;
|
|
46
|
+
(function (DropPathsOption) {
|
|
47
|
+
/** Don't drop any parts of the sourced path */
|
|
48
|
+
DropPathsOption["No"] = "no";
|
|
49
|
+
/** try to drop everything but the filename */
|
|
50
|
+
DropPathsOption["Once"] = "once";
|
|
51
|
+
/** try to drop every folder of the path */
|
|
52
|
+
DropPathsOption["All"] = "all";
|
|
53
|
+
})(DropPathsOption || (exports.DropPathsOption = DropPathsOption = {}));
|
|
54
|
+
;
|
|
28
55
|
const defaultEngineConfigs = {
|
|
29
56
|
'tree-sitter': { type: 'tree-sitter' },
|
|
30
57
|
'r-shell': { type: 'r-shell' }
|
|
@@ -43,7 +70,13 @@ exports.defaultConfigOptions = {
|
|
|
43
70
|
defaultEngine: 'r-shell',
|
|
44
71
|
solver: {
|
|
45
72
|
variables: VariableResolve.Alias,
|
|
46
|
-
pointerTracking: true
|
|
73
|
+
pointerTracking: true,
|
|
74
|
+
resolveSource: {
|
|
75
|
+
dropPaths: DropPathsOption.No,
|
|
76
|
+
ignoreCapitalization: true,
|
|
77
|
+
inferWorkingDirectory: InferWorkingDirectory.ActiveScript,
|
|
78
|
+
searchPath: []
|
|
79
|
+
}
|
|
47
80
|
}
|
|
48
81
|
};
|
|
49
82
|
exports.flowrConfigFileSchema = joi_1.default.object({
|
|
@@ -54,12 +87,13 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
54
87
|
loadDefaults: joi_1.default.boolean().optional().description('Should the default configuration still be loaded?'),
|
|
55
88
|
definitions: joi_1.default.array().items(joi_1.default.object()).optional().description('The definitions to load/overwrite.')
|
|
56
89
|
}).optional().description('Do you want to overwrite (parts) of the builtin definition?')
|
|
57
|
-
}).optional().description('Semantics regarding
|
|
90
|
+
}).optional().description('Semantics regarding how to handle the R environment.')
|
|
58
91
|
}).description('Configure language semantics and how flowR handles them.'),
|
|
59
92
|
engines: joi_1.default.array().items(joi_1.default.alternatives(joi_1.default.object({
|
|
60
93
|
type: joi_1.default.string().required().valid('tree-sitter').description('Use the tree sitter engine.'),
|
|
61
94
|
wasmPath: joi_1.default.string().optional().description('The path to the tree-sitter-r WASM binary to use. If this is undefined, this uses the default path.'),
|
|
62
|
-
treeSitterWasmPath: joi_1.default.string().optional().description('The path to the tree-sitter WASM binary to use. If this is undefined, this uses the default path.')
|
|
95
|
+
treeSitterWasmPath: joi_1.default.string().optional().description('The path to the tree-sitter WASM binary to use. If this is undefined, this uses the default path.'),
|
|
96
|
+
lax: joi_1.default.boolean().optional().description('Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used.')
|
|
63
97
|
}).description('The configuration for the tree sitter engine.'), joi_1.default.object({
|
|
64
98
|
type: joi_1.default.string().required().valid('r-shell').description('Use the R shell engine.'),
|
|
65
99
|
rPath: joi_1.default.string().optional().description('The path to the R executable to use. If this is undefined, this uses the default path.')
|
|
@@ -67,7 +101,13 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
67
101
|
defaultEngine: joi_1.default.string().optional().valid('tree-sitter', 'r-shell').description('The default engine to use for interacting with R code. If this is undefined, an arbitrary engine from the specified list will be used.'),
|
|
68
102
|
solver: joi_1.default.object({
|
|
69
103
|
variables: joi_1.default.string().valid(...Object.values(VariableResolve)).description('How to resolve variables and their values.'),
|
|
70
|
-
pointerTracking: joi_1.default.boolean().description('Whether to track pointers in the dataflow graph, if not, the graph will be over-approximated wrt. containers and accesses.')
|
|
104
|
+
pointerTracking: joi_1.default.boolean().description('Whether to track pointers in the dataflow graph, if not, the graph will be over-approximated wrt. containers and accesses.'),
|
|
105
|
+
resolveSource: joi_1.default.object({
|
|
106
|
+
dropPaths: joi_1.default.string().valid(...Object.values(DropPathsOption)).description('Allow to drop the first or all parts of the sourced path, if it is relative.'),
|
|
107
|
+
ignoreCapitalization: joi_1.default.boolean().description('Search for filenames matching in the lowercase.'),
|
|
108
|
+
inferWorkingDirectory: joi_1.default.string().valid(...Object.values(InferWorkingDirectory)).description('Try to infer the working directory from the main or any script to analyze.'),
|
|
109
|
+
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.')
|
|
110
|
+
}).optional().description('If lax source calls are active, flowR searches for sourced files much more freely, based on the configurations you give it. This option is only in effect if `ignoreSourceCalls` is set to false.')
|
|
71
111
|
}).description('How to resolve constants, constraints, cells, ...')
|
|
72
112
|
}).description('The configuration file format for flowR.');
|
|
73
113
|
// we don't load from a config file at all by default unless setConfigFile is called
|
|
@@ -89,7 +89,7 @@ exports.BuiltInProcessorMapper = {
|
|
|
89
89
|
'builtin:repeat-loop': built_in_repeat_loop_1.processRepeatLoop,
|
|
90
90
|
'builtin:while-loop': built_in_while_loop_1.processWhileLoop,
|
|
91
91
|
'builtin:replacement': built_in_replacement_1.processReplacementFunction,
|
|
92
|
-
'builtin:list': built_in_list_1.processList
|
|
92
|
+
'builtin:list': built_in_list_1.processList
|
|
93
93
|
};
|
|
94
94
|
exports.BuiltInMemory = new Map();
|
|
95
95
|
exports.EmptyBuiltInMemory = new Map();
|
|
@@ -29,6 +29,10 @@ export declare class Environment implements IEnvironment {
|
|
|
29
29
|
memory: Map<Identifier, IdentifierDefinition[]>;
|
|
30
30
|
constructor(parent: IEnvironment);
|
|
31
31
|
}
|
|
32
|
+
export interface WorkingDirectoryReference {
|
|
33
|
+
readonly path: string;
|
|
34
|
+
readonly controlDependencies: ControlDependency[] | undefined;
|
|
35
|
+
}
|
|
32
36
|
/**
|
|
33
37
|
* An environment describes a ({@link IEnvironment#parent|scoped}) mapping of names to their definitions ({@link EnvironmentMemory}).
|
|
34
38
|
*
|
|
@@ -29,11 +29,11 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
|
|
|
29
29
|
}
|
|
30
30
|
if (node) {
|
|
31
31
|
const [fst] = node;
|
|
32
|
-
if (fst.
|
|
33
|
-
fst.
|
|
32
|
+
if (fst.cds && defaultCd && !fst.cds.includes(defaultCd)) {
|
|
33
|
+
fst.cds.push(defaultCd);
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
|
-
fst.
|
|
36
|
+
fst.cds = defaultCd ? [defaultCd] : [];
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
return { ...ref, controlDependencies: [...ref.controlDependencies ?? [], ...(defaultCd ? [defaultCd] : [])] };
|
|
@@ -221,7 +221,7 @@ function trackAliasesInGraph(id, graph, idMap) {
|
|
|
221
221
|
continue;
|
|
222
222
|
}
|
|
223
223
|
const [vertex, outgoingEdges] = res;
|
|
224
|
-
const cds = vertex.
|
|
224
|
+
const cds = vertex.cds;
|
|
225
225
|
for (const cd of cds ?? []) {
|
|
226
226
|
const target = graph.idMap?.get(cd.id);
|
|
227
227
|
if (target === undefined) {
|
package/dataflow/extractor.js
CHANGED
|
@@ -14,7 +14,6 @@ const named_call_handling_1 = require("./internal/process/functions/call/named-c
|
|
|
14
14
|
const make_argument_1 = require("./internal/process/functions/call/argument/make-argument");
|
|
15
15
|
const range_1 = require("../util/range");
|
|
16
16
|
const type_1 = require("../r-bridge/lang-4.x/ast/model/type");
|
|
17
|
-
const retriever_1 = require("../r-bridge/retriever");
|
|
18
17
|
const environment_1 = require("./environments/environment");
|
|
19
18
|
const built_in_source_1 = require("./internal/process/functions/call/built-in/built-in-source");
|
|
20
19
|
const cfg_1 = require("../util/cfg/cfg");
|
|
@@ -46,14 +45,17 @@ exports.processors = {
|
|
|
46
45
|
[type_1.RType.FunctionDefinition]: (n, d) => (0, process_named_call_1.processAsNamedCall)(n, d, n.lexeme, [...n.parameters, n.body]),
|
|
47
46
|
[type_1.RType.Parameter]: process_parameter_1.processFunctionParameter,
|
|
48
47
|
[type_1.RType.Argument]: process_argument_1.processFunctionArgument,
|
|
49
|
-
[type_1.RType.ExpressionList]: (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
[type_1.RType.ExpressionList]: ({ grouping, info, children, location }, d) => {
|
|
49
|
+
const groupStart = grouping?.[0];
|
|
50
|
+
return (0, named_call_handling_1.processNamedCall)({
|
|
51
|
+
type: type_1.RType.Symbol,
|
|
52
|
+
info: info,
|
|
53
|
+
content: groupStart?.content ?? '{',
|
|
54
|
+
lexeme: groupStart?.lexeme ?? '{',
|
|
55
|
+
location: location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1),
|
|
56
|
+
namespace: groupStart?.content ? undefined : 'base'
|
|
57
|
+
}, (0, make_argument_1.wrapArgumentsUnnamed)(children, d.completeAst.idMap), info.id, d);
|
|
58
|
+
}
|
|
57
59
|
};
|
|
58
60
|
function resolveLinkToSideEffects(ast, graph) {
|
|
59
61
|
let cfg = undefined;
|
|
@@ -94,7 +96,7 @@ function produceDataFlowGraph(parser, request, ast) {
|
|
|
94
96
|
processors: exports.processors,
|
|
95
97
|
currentRequest: firstRequest,
|
|
96
98
|
controlDependencies: undefined,
|
|
97
|
-
referenceChain: [
|
|
99
|
+
referenceChain: [firstRequest],
|
|
98
100
|
};
|
|
99
101
|
let df = (0, processor_1.processDataflowFor)(ast.ast, dfData);
|
|
100
102
|
if (multifile) {
|
|
@@ -44,7 +44,7 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
44
44
|
unknownReferences: subflow.unknownReferences.map(o => ({ ...o, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(o.nodeId), controlDependencies: o.controlDependencies?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })) }))
|
|
45
45
|
},
|
|
46
46
|
exitPoints: exitPoints.map(node_id_1.normalizeIdToNumberIfPossible),
|
|
47
|
-
|
|
47
|
+
cds: info?.controlDependencies?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })),
|
|
48
48
|
environment: info?.environment
|
|
49
49
|
}, asRoot);
|
|
50
50
|
}
|
|
@@ -66,7 +66,7 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
66
66
|
name,
|
|
67
67
|
args: args.map(a => a === r_function_call_1.EmptyArgument ? r_function_call_1.EmptyArgument : { ...a, nodeId: (0, node_id_1.normalizeIdToNumberIfPossible)(a.nodeId), controlDependencies: undefined }),
|
|
68
68
|
environment: (info?.onlyBuiltIn || onlyBuiltInAuto) ? undefined : info?.environment ?? (0, environment_1.initializeCleanEnvironments)(),
|
|
69
|
-
|
|
69
|
+
cds: info?.controlDependencies?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })),
|
|
70
70
|
onlyBuiltin: info?.onlyBuiltIn ?? onlyBuiltInAuto ?? false
|
|
71
71
|
}, asRoot);
|
|
72
72
|
this.addArgumentLinks(id, args);
|
|
@@ -96,7 +96,7 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
else if (!this.hasVertex(arg.nodeId, true)) {
|
|
99
|
-
this.use(arg.nodeId, arg.name, {
|
|
99
|
+
this.use(arg.nodeId, arg.name, { cds: arg.controlDependencies });
|
|
100
100
|
this.argument(id, arg.nodeId);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -115,7 +115,7 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
115
115
|
tag: vertex_1.VertexType.VariableDefinition,
|
|
116
116
|
id: (0, node_id_1.normalizeIdToNumberIfPossible)(id),
|
|
117
117
|
name,
|
|
118
|
-
|
|
118
|
+
cds: info?.controlDependencies?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })),
|
|
119
119
|
}, asRoot);
|
|
120
120
|
if (info?.definedBy) {
|
|
121
121
|
for (const def of info.definedBy) {
|
|
@@ -138,11 +138,11 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
138
138
|
tag: vertex_1.VertexType.Use,
|
|
139
139
|
id: (0, node_id_1.normalizeIdToNumberIfPossible)(id),
|
|
140
140
|
name,
|
|
141
|
-
|
|
141
|
+
cds: undefined,
|
|
142
142
|
environment: undefined
|
|
143
143
|
}, {
|
|
144
144
|
...info,
|
|
145
|
-
|
|
145
|
+
cds: info?.cds?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) }))
|
|
146
146
|
}), asRoot);
|
|
147
147
|
}
|
|
148
148
|
/**
|
|
@@ -157,7 +157,7 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
|
|
|
157
157
|
return this.addVertex({
|
|
158
158
|
tag: vertex_1.VertexType.Value,
|
|
159
159
|
id: (0, node_id_1.normalizeIdToNumberIfPossible)(id),
|
|
160
|
-
|
|
160
|
+
cds: options?.controlDependencies?.map(c => ({ ...c, id: (0, node_id_1.normalizeIdToNumberIfPossible)(c.id) })),
|
|
161
161
|
environment: undefined
|
|
162
162
|
}, asRoot);
|
|
163
163
|
}
|
package/dataflow/graph/diff.js
CHANGED
|
@@ -199,7 +199,7 @@ function diffVertices(ctx) {
|
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
(0, info_1.diffControlDependencies)(lInfo.
|
|
202
|
+
(0, info_1.diffControlDependencies)(lInfo.cds, rInfo.cds, { ...ctx, position: `Vertex ${id} differs in controlDependencies. ` });
|
|
203
203
|
if ((lInfo.environment === undefined && rInfo.environment !== undefined && !ctx.config.leftIsSubgraph)
|
|
204
204
|
|| (lInfo.environment !== undefined && rInfo.environment === undefined && !ctx.config.rightIsSubgraph)) {
|
|
205
205
|
/* only diff them if specified at all */
|
|
@@ -178,11 +178,11 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
178
178
|
*/
|
|
179
179
|
addVertex(vertex: DataflowGraphVertexArgument & Omit<Vertex, keyof DataflowGraphVertexArgument>, asRoot?: boolean): this;
|
|
180
180
|
/** {@inheritDoc} */
|
|
181
|
-
addEdge(from: NodeId, to: NodeId, type: EdgeType): this;
|
|
181
|
+
addEdge(from: NodeId, to: NodeId, type: EdgeType | number): this;
|
|
182
182
|
/** {@inheritDoc} */
|
|
183
|
-
addEdge(from: ReferenceForEdge, to: ReferenceForEdge, type: EdgeType): this;
|
|
183
|
+
addEdge(from: ReferenceForEdge, to: ReferenceForEdge, type: EdgeType | number): this;
|
|
184
184
|
/** {@inheritDoc} */
|
|
185
|
-
addEdge(from: NodeId | ReferenceForEdge, to: NodeId | ReferenceForEdge, type: EdgeType): this;
|
|
185
|
+
addEdge(from: NodeId | ReferenceForEdge, to: NodeId | ReferenceForEdge, type: EdgeType | number): this;
|
|
186
186
|
/**
|
|
187
187
|
* Merges the other graph into *this* one (in-place). The return value is only for convenience.
|
|
188
188
|
*
|
package/dataflow/graph/graph.js
CHANGED
|
@@ -272,7 +272,7 @@ class DataflowGraph {
|
|
|
272
272
|
const vertex = this.getVertex(reference.nodeId, true);
|
|
273
273
|
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${JSON.stringify(reference)} to set reference`);
|
|
274
274
|
if (vertex.tag === vertex_1.VertexType.FunctionDefinition || vertex.tag === vertex_1.VertexType.VariableDefinition) {
|
|
275
|
-
vertex.
|
|
275
|
+
vertex.cds = reference.controlDependencies;
|
|
276
276
|
}
|
|
277
277
|
else {
|
|
278
278
|
this.vertexInformation.set(reference.nodeId, { ...vertex, tag: vertex_1.VertexType.VariableDefinition });
|
|
@@ -292,17 +292,17 @@ class DataflowGraph {
|
|
|
292
292
|
to = to ? (0, node_id_1.normalizeIdToNumberIfPossible)(to) : undefined;
|
|
293
293
|
const vertex = this.getVertex(from, true);
|
|
294
294
|
(0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${from} to add control dependency`);
|
|
295
|
-
vertex.
|
|
295
|
+
vertex.cds ??= [];
|
|
296
296
|
if (to) {
|
|
297
297
|
let hasControlDependency = false;
|
|
298
|
-
for (const { id, when: cond } of vertex.
|
|
298
|
+
for (const { id, when: cond } of vertex.cds) {
|
|
299
299
|
if (id === to && when !== cond) {
|
|
300
300
|
hasControlDependency = true;
|
|
301
301
|
break;
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
if (!hasControlDependency) {
|
|
305
|
-
vertex.
|
|
305
|
+
vertex.cds.push({ id: to, when });
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
return this;
|
|
@@ -90,7 +90,7 @@ interface DataflowGraphVertexBase extends MergeableRecord {
|
|
|
90
90
|
/**
|
|
91
91
|
* @see {@link ControlDependency} - the collection of control dependencies which have an influence on whether the vertex is executed.
|
|
92
92
|
*/
|
|
93
|
-
|
|
93
|
+
cds: ControlDependency[] | undefined;
|
|
94
94
|
/**
|
|
95
95
|
* this attribute links a vertex to indices (pointer links) it may be affected by or related to
|
|
96
96
|
*/
|
|
@@ -53,7 +53,7 @@ function processAccess(name, args, rootId, data, config) {
|
|
|
53
53
|
}
|
|
54
54
|
/* access always reads all of its indices */
|
|
55
55
|
for (const arg of fnCall.processedArguments) {
|
|
56
|
-
if (arg
|
|
56
|
+
if (arg) {
|
|
57
57
|
info.graph.addEdge(name.info.id, arg.entryPoint, edge_1.EdgeType.Reads);
|
|
58
58
|
}
|
|
59
59
|
/* we include the read edges to the constant arguments as well so that they are included if necessary */
|
|
@@ -70,7 +70,7 @@ function processApply(name, args, rootId, data, { indexOfFunction = 1, nameOfFun
|
|
|
70
70
|
args: allOtherArguments,
|
|
71
71
|
environment: data.environment,
|
|
72
72
|
onlyBuiltin: false,
|
|
73
|
-
|
|
73
|
+
cds: data.controlDependencies
|
|
74
74
|
});
|
|
75
75
|
for (const arg of processedArguments) {
|
|
76
76
|
if (arg) {
|