@eagleoutice/flowr 2.2.6 → 2.2.8
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/cli/flowr-main-options.js +6 -0
- package/cli/flowr.d.ts +1 -0
- package/cli/flowr.js +2 -1
- package/config.d.ts +4 -0
- package/config.js +2 -1
- package/dataflow/environments/resolve-by-name.d.ts +6 -5
- package/dataflow/environments/resolve-by-name.js +42 -8
- package/documentation/print-engines-wiki.js +1 -0
- package/package.json +1 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +3 -3
- package/queries/catalog/dependencies-query/dependencies-query-format.js +1 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +2 -2
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.d.ts +6 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +14 -5
- 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/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.7, 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!">118 ms</i></span> (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.7, R v4.4.0 (r-shell engine)
|
|
135
135
|
R> :dataflow* test/testfiles/example.R
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -375,7 +375,7 @@ It offers a wide variety of features, for example:
|
|
|
375
375
|
52 -->|"argument"| 50
|
|
376
376
|
```
|
|
377
377
|
|
|
378
|
-
(The analysis required
|
|
378
|
+
(The analysis required _23.15 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
|
|
379
379
|
|
|
380
380
|
|
|
381
381
|
|
|
@@ -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']) {
|
package/config.d.ts
CHANGED
|
@@ -61,6 +61,10 @@ export interface TreeSitterEngineConfig extends MergeableRecord {
|
|
|
61
61
|
* 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
62
|
*/
|
|
63
63
|
readonly treeSitterWasmPath?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used.
|
|
66
|
+
*/
|
|
67
|
+
readonly lax?: boolean;
|
|
64
68
|
}
|
|
65
69
|
export interface RShellEngineConfig extends MergeableRecord {
|
|
66
70
|
readonly type: 'r-shell';
|
package/config.js
CHANGED
|
@@ -59,7 +59,8 @@ exports.flowrConfigFileSchema = joi_1.default.object({
|
|
|
59
59
|
engines: joi_1.default.array().items(joi_1.default.alternatives(joi_1.default.object({
|
|
60
60
|
type: joi_1.default.string().required().valid('tree-sitter').description('Use the tree sitter engine.'),
|
|
61
61
|
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.')
|
|
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.'),
|
|
63
|
+
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
64
|
}).description('The configuration for the tree sitter engine.'), joi_1.default.object({
|
|
64
65
|
type: joi_1.default.string().required().valid('r-shell').description('Use the R shell engine.'),
|
|
65
66
|
rPath: joi_1.default.string().optional().description('The path to the R executable to use. If this is undefined, this uses the default path.')
|
|
@@ -27,7 +27,7 @@ export declare function trackAliasesInGraph(id: NodeId, graph: DataflowGraph, id
|
|
|
27
27
|
* Convenience function using the variable resolver as specified within the configuration file
|
|
28
28
|
* In the future we may want to have this set once at the start of the analysis
|
|
29
29
|
*
|
|
30
|
-
* @see {@link
|
|
30
|
+
* @see {@link resolveIdToValue} - for a more general approach which "evaluates" a node based on value resolve
|
|
31
31
|
*/
|
|
32
32
|
export declare function resolveValueOfVariable(identifier: Identifier | undefined, environment: REnvironmentInformation, idMap?: AstIdMap): unknown[] | undefined;
|
|
33
33
|
export interface ResolveInfo {
|
|
@@ -43,9 +43,10 @@ export interface ResolveInfo {
|
|
|
43
43
|
/**
|
|
44
44
|
* Generalized {@link resolveValueOfVariable} function which evaluates a node based on the value resolve
|
|
45
45
|
*
|
|
46
|
-
* @param id
|
|
46
|
+
* @param id - The node id or node to resolve
|
|
47
47
|
* @param environment - The current environment used for name resolution
|
|
48
|
-
* @param
|
|
49
|
-
* @param
|
|
48
|
+
* @param graph - The graph to resolve in
|
|
49
|
+
* @param idMap - The id map to resolve the node if given as an id
|
|
50
|
+
* @param full - Whether to track variables
|
|
50
51
|
*/
|
|
51
|
-
export declare function
|
|
52
|
+
export declare function resolveIdToValue(id: NodeId | RNodeWithParent, { environment, graph, idMap, full }: ResolveInfo): unknown[] | undefined;
|
|
@@ -7,7 +7,7 @@ exports.getAliases = getAliases;
|
|
|
7
7
|
exports.trackAliasInEnvironments = trackAliasInEnvironments;
|
|
8
8
|
exports.trackAliasesInGraph = trackAliasesInGraph;
|
|
9
9
|
exports.resolveValueOfVariable = resolveValueOfVariable;
|
|
10
|
-
exports.
|
|
10
|
+
exports.resolveIdToValue = resolveIdToValue;
|
|
11
11
|
const environment_1 = require("./environment");
|
|
12
12
|
const logic_1 = require("../../util/logic");
|
|
13
13
|
const identifier_1 = require("./identifier");
|
|
@@ -189,6 +189,20 @@ function trackAliasInEnvironments(identifier, use, idMap) {
|
|
|
189
189
|
}
|
|
190
190
|
return values;
|
|
191
191
|
}
|
|
192
|
+
function isNestedInLoop(node, ast) {
|
|
193
|
+
const parent = node?.info.parent;
|
|
194
|
+
if (node === undefined || !parent) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
const parentNode = ast.get(parent);
|
|
198
|
+
if (parentNode === undefined) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (parentNode.type === type_1.RType.WhileLoop || parentNode.type === type_1.RType.RepeatLoop) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return isNestedInLoop(parentNode, ast);
|
|
205
|
+
}
|
|
192
206
|
function trackAliasesInGraph(id, graph, idMap) {
|
|
193
207
|
idMap ??= graph.idMap;
|
|
194
208
|
(0, assert_1.guard)(idMap !== undefined, 'The ID map is required to get the lineage of a node');
|
|
@@ -198,6 +212,7 @@ function trackAliasesInGraph(id, graph, idMap) {
|
|
|
198
212
|
const clean = (0, environment_1.initializeCleanEnvironments)();
|
|
199
213
|
const cleanFingerprint = (0, fingerprint_1.envFingerprint)(clean);
|
|
200
214
|
queue.add(id, clean, cleanFingerprint, false);
|
|
215
|
+
let forceBot = false;
|
|
201
216
|
const resultIds = [];
|
|
202
217
|
while (queue.nonEmpty()) {
|
|
203
218
|
const { id, baseEnvironment } = queue.next();
|
|
@@ -206,18 +221,36 @@ function trackAliasesInGraph(id, graph, idMap) {
|
|
|
206
221
|
continue;
|
|
207
222
|
}
|
|
208
223
|
const [vertex, outgoingEdges] = res;
|
|
224
|
+
const cds = vertex.controlDependencies;
|
|
225
|
+
for (const cd of cds ?? []) {
|
|
226
|
+
const target = graph.idMap?.get(cd.id);
|
|
227
|
+
if (target === undefined) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (target.type === type_1.RType.WhileLoop || target.type === type_1.RType.RepeatLoop) {
|
|
231
|
+
forceBot = true;
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!forceBot && (cds?.length === 0 && isNestedInLoop(idMap.get(id), idMap))) {
|
|
236
|
+
forceBot = true;
|
|
237
|
+
}
|
|
238
|
+
if (forceBot) {
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
209
241
|
if (vertex.tag === vertex_1.VertexType.Value) {
|
|
210
242
|
resultIds.push(id);
|
|
211
243
|
continue;
|
|
212
244
|
}
|
|
213
245
|
// travel all read and defined-by edges
|
|
214
246
|
for (const [targetId, edge] of outgoingEdges) {
|
|
215
|
-
|
|
247
|
+
// currently, they have to be exact!
|
|
248
|
+
if (edge.types === edge_1.EdgeType.Reads || edge.types === edge_1.EdgeType.DefinedBy || edge.types === edge_1.EdgeType.DefinedByOnCall) {
|
|
216
249
|
queue.add(targetId, baseEnvironment, cleanFingerprint, false);
|
|
217
250
|
}
|
|
218
251
|
}
|
|
219
252
|
}
|
|
220
|
-
if (resultIds.length === 0) {
|
|
253
|
+
if (forceBot || resultIds.length === 0) {
|
|
221
254
|
return undefined;
|
|
222
255
|
}
|
|
223
256
|
const values = [];
|
|
@@ -233,7 +266,7 @@ function trackAliasesInGraph(id, graph, idMap) {
|
|
|
233
266
|
* Convenience function using the variable resolver as specified within the configuration file
|
|
234
267
|
* In the future we may want to have this set once at the start of the analysis
|
|
235
268
|
*
|
|
236
|
-
* @see {@link
|
|
269
|
+
* @see {@link resolveIdToValue} - for a more general approach which "evaluates" a node based on value resolve
|
|
237
270
|
*/
|
|
238
271
|
function resolveValueOfVariable(identifier, environment, idMap) {
|
|
239
272
|
const resolve = (0, config_1.getConfig)().solver.variables;
|
|
@@ -247,12 +280,13 @@ function resolveValueOfVariable(identifier, environment, idMap) {
|
|
|
247
280
|
/**
|
|
248
281
|
* Generalized {@link resolveValueOfVariable} function which evaluates a node based on the value resolve
|
|
249
282
|
*
|
|
250
|
-
* @param id
|
|
283
|
+
* @param id - The node id or node to resolve
|
|
251
284
|
* @param environment - The current environment used for name resolution
|
|
252
|
-
* @param
|
|
253
|
-
* @param
|
|
285
|
+
* @param graph - The graph to resolve in
|
|
286
|
+
* @param idMap - The id map to resolve the node if given as an id
|
|
287
|
+
* @param full - Whether to track variables
|
|
254
288
|
*/
|
|
255
|
-
function
|
|
289
|
+
function resolveIdToValue(id, { environment, graph, idMap, full }) {
|
|
256
290
|
idMap ??= graph?.idMap;
|
|
257
291
|
const node = typeof id === 'object' ? id : idMap?.get(id);
|
|
258
292
|
if (node === undefined) {
|
|
@@ -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
|
package/package.json
CHANGED
|
@@ -76,7 +76,7 @@ function executeDependenciesQuery(data, queries) {
|
|
|
76
76
|
nodeId: id,
|
|
77
77
|
functionName: vertex.name,
|
|
78
78
|
// write functions that don't have argIndex are assumed to write to stdout
|
|
79
|
-
destination: value ??
|
|
79
|
+
destination: value ?? 'stdout',
|
|
80
80
|
lexemeOfArgument: getLexeme(value, argId),
|
|
81
81
|
linkedIds: linkedIds?.length ? linkedIds : undefined
|
|
82
82
|
}));
|
|
@@ -160,7 +160,7 @@ function collectValuesFromLinks(args, data, linkedIds) {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
return map;
|
|
163
|
+
return map.size ? map : undefined;
|
|
164
164
|
}
|
|
165
165
|
function hasCharacterOnly(data, vertex, idMap) {
|
|
166
166
|
if (!vertex.args || vertex.args.length === 0 || !idMap) {
|
|
@@ -193,7 +193,7 @@ function resolveBasedOnConfig(data, vertex, argument, environment, idMap, resolv
|
|
|
193
193
|
full = false;
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
return (0, resolve_by_name_1.
|
|
196
|
+
return (0, resolve_by_name_1.resolveIdToValue)(argument, { environment, graph: data.dataflow.graph, full });
|
|
197
197
|
}
|
|
198
198
|
function unwrapRValue(value) {
|
|
199
199
|
if (value === undefined) {
|
|
@@ -18,7 +18,7 @@ var DependencyInfoLinkConstraint;
|
|
|
18
18
|
// these lists are originally based on https://github.com/duncantl/CodeDepends/blob/7fd96dfee16b252e5f642c77a7ababf48e9326f8/R/codeTypes.R
|
|
19
19
|
exports.LibraryFunctions = [
|
|
20
20
|
{ name: 'library', argIdx: 0, argName: 'package', resolveValue: 'library' },
|
|
21
|
-
{ name: 'require', argIdx: 0, argName: 'package', resolveValue:
|
|
21
|
+
{ name: 'require', argIdx: 0, argName: 'package', resolveValue: 'library' },
|
|
22
22
|
{ name: 'loadNamespace', argIdx: 0, argName: 'package', resolveValue: true },
|
|
23
23
|
{ name: 'attachNamespace', argIdx: 0, argName: 'ns', resolveValue: true },
|
|
24
24
|
{ name: 'attach', argIdx: 0, argName: 'what', resolveValue: true },
|
|
@@ -18,9 +18,9 @@ function executeResolveValueQuery({ dataflow: { graph }, ast }, queries) {
|
|
|
18
18
|
}
|
|
19
19
|
const values = query.criteria
|
|
20
20
|
.map(criteria => (0, parse_1.slicingCriterionToId)(criteria, ast.idMap))
|
|
21
|
-
.flatMap(ident => (0, resolve_by_name_1.
|
|
21
|
+
.flatMap(ident => (0, resolve_by_name_1.resolveIdToValue)(ident, { graph, full: true, idMap: ast.idMap }) ?? []);
|
|
22
22
|
results[key] = {
|
|
23
|
-
values: [...new Set(values)]
|
|
23
|
+
values: values ? [...new Set(values)] : []
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
return {
|
|
@@ -10,7 +10,12 @@ export declare class TreeSitterExecutor implements SyncParser<Parser.Tree> {
|
|
|
10
10
|
readonly name = "tree-sitter";
|
|
11
11
|
readonly parser: Parser;
|
|
12
12
|
private static language;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Initializes the underlying tree-sitter parser. This only needs to be called once globally.
|
|
15
|
+
* @param overrideWasmPath - The path to the tree-sitter-r wasm file, which takes precedence over the config and default paths if set.
|
|
16
|
+
* @param overrideTreeSitterWasmPath - The path to the tree-sitter wasm file, which takes precedence over the config and default paths if set.
|
|
17
|
+
*/
|
|
18
|
+
static initTreeSitter(overrideWasmPath?: string, overrideTreeSitterWasmPath?: string): Promise<void>;
|
|
14
19
|
constructor();
|
|
15
20
|
rVersion(): Promise<string | 'unknown' | 'none'>;
|
|
16
21
|
treeSitterVersion(): number;
|
|
@@ -7,8 +7,10 @@ exports.TreeSitterExecutor = exports.DEFAULT_TREE_SITTER_WASM_PATH = exports.DEF
|
|
|
7
7
|
const web_tree_sitter_1 = __importDefault(require("web-tree-sitter"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const config_1 = require("../../../config");
|
|
10
|
+
const log_1 = require("../../../util/log");
|
|
10
11
|
exports.DEFAULT_TREE_SITTER_R_WASM_PATH = `${__dirname}/tree-sitter-r.wasm`;
|
|
11
12
|
exports.DEFAULT_TREE_SITTER_WASM_PATH = `${__dirname}/tree-sitter.wasm`;
|
|
13
|
+
const wasmLog = log_1.log.getSubLogger({ name: 'tree-sitter-wasm' });
|
|
12
14
|
/**
|
|
13
15
|
* Synchronous and (way) faster alternative to the {@link RShell} using tree-sitter.
|
|
14
16
|
*/
|
|
@@ -16,9 +18,13 @@ class TreeSitterExecutor {
|
|
|
16
18
|
name = 'tree-sitter';
|
|
17
19
|
parser;
|
|
18
20
|
static language;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Initializes the underlying tree-sitter parser. This only needs to be called once globally.
|
|
23
|
+
* @param overrideWasmPath - The path to the tree-sitter-r wasm file, which takes precedence over the config and default paths if set.
|
|
24
|
+
* @param overrideTreeSitterWasmPath - The path to the tree-sitter wasm file, which takes precedence over the config and default paths if set.
|
|
25
|
+
*/
|
|
26
|
+
static async initTreeSitter(overrideWasmPath, overrideTreeSitterWasmPath) {
|
|
27
|
+
const treeSitterWasmPath = overrideTreeSitterWasmPath ?? (0, config_1.getEngineConfig)('tree-sitter')?.treeSitterWasmPath ?? exports.DEFAULT_TREE_SITTER_WASM_PATH;
|
|
22
28
|
// noinspection JSUnusedGlobalSymbols - this is used by emscripten, see https://emscripten.org/docs/api_reference/module.html
|
|
23
29
|
await web_tree_sitter_1.default.init({
|
|
24
30
|
locateFile: (path, prefix) => {
|
|
@@ -27,9 +33,12 @@ class TreeSitterExecutor {
|
|
|
27
33
|
return treeSitterWasmPath;
|
|
28
34
|
}
|
|
29
35
|
return prefix + path;
|
|
30
|
-
}
|
|
36
|
+
},
|
|
37
|
+
onAbort: (s) => wasmLog.error(`Tree-sitter wasm aborted: ${s}`),
|
|
38
|
+
print: (s) => wasmLog.debug(s),
|
|
39
|
+
printErr: (s) => wasmLog.error(s)
|
|
31
40
|
});
|
|
32
|
-
const wasmPath =
|
|
41
|
+
const wasmPath = overrideWasmPath ?? (0, config_1.getEngineConfig)('tree-sitter')?.wasmPath ?? exports.DEFAULT_TREE_SITTER_R_WASM_PATH;
|
|
33
42
|
TreeSitterExecutor.language = await web_tree_sitter_1.default.Language.load(wasmPath);
|
|
34
43
|
}
|
|
35
44
|
constructor() {
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { RExpressionList } from '../ast/model/nodes/r-expression-list';
|
|
2
2
|
import type { Tree } from 'web-tree-sitter';
|
|
3
|
+
/**
|
|
4
|
+
* @param tree - The tree to normalize
|
|
5
|
+
*/
|
|
3
6
|
export declare function normalizeTreeSitterTreeToAst(tree: Tree): RExpressionList;
|
|
7
|
+
export declare function makeTreeSitterLax(): void;
|
|
8
|
+
export declare function makeTreeSitterStrict(): void;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizeTreeSitterTreeToAst = normalizeTreeSitterTreeToAst;
|
|
4
|
+
exports.makeTreeSitterLax = makeTreeSitterLax;
|
|
5
|
+
exports.makeTreeSitterStrict = makeTreeSitterStrict;
|
|
4
6
|
const normalizer_data_1 = require("../ast/parser/main/normalizer-data");
|
|
5
7
|
const tree_sitter_types_1 = require("./tree-sitter-types");
|
|
6
8
|
const type_1 = require("../ast/model/type");
|
|
@@ -10,20 +12,39 @@ const normalize_meta_1 = require("../ast/parser/main/normalize-meta");
|
|
|
10
12
|
const arrays_1 = require("../../../util/arrays");
|
|
11
13
|
const r_function_call_1 = require("../ast/model/nodes/r-function-call");
|
|
12
14
|
const strings_1 = require("../../../util/strings");
|
|
15
|
+
const config_1 = require("../../../config");
|
|
16
|
+
const log_1 = require("../../../util/log");
|
|
17
|
+
/**
|
|
18
|
+
* @param tree - The tree to normalize
|
|
19
|
+
*/
|
|
13
20
|
function normalizeTreeSitterTreeToAst(tree) {
|
|
21
|
+
const lax = (0, config_1.getEngineConfig)('tree-sitter')?.lax;
|
|
22
|
+
if (lax) {
|
|
23
|
+
makeTreeSitterLax();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
makeTreeSitterStrict();
|
|
27
|
+
}
|
|
14
28
|
const root = convertTreeNode(tree.rootNode);
|
|
15
29
|
if (root.type !== type_1.RType.ExpressionList) {
|
|
16
30
|
throw new normalizer_data_1.ParseError(`expected root to resolve to an expression list, got a ${root.type}`);
|
|
17
31
|
}
|
|
18
32
|
return root;
|
|
19
33
|
}
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
function nonErrorChildrenStrict(node) {
|
|
35
|
+
return node.hasError ? [] : node.children;
|
|
36
|
+
}
|
|
37
|
+
function nonErrorChildrenLax(node) {
|
|
38
|
+
return node.hasError ? node.children.filter(n => n.type !== tree_sitter_types_1.TreeSitterType.Error) : node.children;
|
|
39
|
+
}
|
|
40
|
+
let nonErrorChildren = nonErrorChildrenStrict;
|
|
41
|
+
function makeTreeSitterLax() {
|
|
42
|
+
log_1.log.info('[Tree-Sitter] Lax parsing active');
|
|
43
|
+
nonErrorChildren = nonErrorChildrenLax;
|
|
44
|
+
}
|
|
45
|
+
function makeTreeSitterStrict() {
|
|
46
|
+
log_1.log.info('[Tree-Sitter] Strict parsing active');
|
|
47
|
+
nonErrorChildren = nonErrorChildrenStrict;
|
|
27
48
|
}
|
|
28
49
|
function convertTreeNode(node) {
|
|
29
50
|
// generally, the grammar source file dictates what children a node has in what order:
|
package/util/version.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flowrVersion = flowrVersion;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
// this is automatically replaced with the current version by release-it
|
|
6
|
-
const version = '2.2.
|
|
6
|
+
const version = '2.2.8';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|