@eagleoutice/flowr 2.2.1 → 2.2.2
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/cli/flowr.js +2 -1
- package/cli/repl/commands/repl-cfg.js +30 -7
- package/cli/repl/commands/repl-dataflow.js +22 -2
- package/cli/repl/commands/repl-normalize.js +22 -2
- package/cli/repl/commands/repl-parse.js +8 -2
- package/cli/repl/core.js +4 -0
- package/cli/repl/server/connection.js +1 -1
- package/cli/script-core/statistics-helper-core.js +1 -1
- package/config.js +8 -1
- package/dataflow/extractor.js +1 -1
- package/dataflow/graph/dataflowgraph-builder.d.ts +11 -10
- package/dataflow/graph/dataflowgraph-builder.js +11 -10
- package/dataflow/graph/edge.d.ts +1 -1
- package/dataflow/graph/edge.js +2 -2
- package/dataflow/graph/vertex.d.ts +6 -6
- package/dataflow/graph/vertex.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +9 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +2 -2
- package/documentation/doc-util/doc-cfg.js +2 -2
- package/documentation/doc-util/doc-types.js +3 -3
- package/documentation/print-interface-wiki.js +0 -2
- package/documentation/print-query-wiki.js +30 -0
- package/package.json +8 -6
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.d.ts +4 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +34 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +72 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +49 -0
- package/queries/query.d.ts +60 -1
- package/queries/query.js +3 -1
- package/r-bridge/data/data.d.ts +2 -2
- package/r-bridge/data/data.js +2 -2
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +46 -29
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.d.ts +4 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.js +3 -0
- package/util/cfg/cfg.d.ts +10 -1
- package/util/cfg/cfg.js +56 -2
- package/util/range.d.ts +21 -0
- package/util/range.js +3 -0
- package/util/version.js +1 -1
|
@@ -17,6 +17,9 @@ function normalizeTreeSitterTreeToAst(tree) {
|
|
|
17
17
|
}
|
|
18
18
|
return root;
|
|
19
19
|
}
|
|
20
|
+
function nonErrorChildren(node) {
|
|
21
|
+
return node.children.filter(n => n.type !== tree_sitter_types_1.TreeSitterType.Error);
|
|
22
|
+
}
|
|
20
23
|
function convertTreeNode(node) {
|
|
21
24
|
// generally, the grammar source file dictates what children a node has in what order:
|
|
22
25
|
// https://github.com/r-lib/tree-sitter-r/blob/main/grammar.js
|
|
@@ -30,7 +33,7 @@ function convertTreeNode(node) {
|
|
|
30
33
|
};
|
|
31
34
|
switch (node.type) {
|
|
32
35
|
case tree_sitter_types_1.TreeSitterType.Program: {
|
|
33
|
-
const [comments, children] = splitComments(node
|
|
36
|
+
const [comments, children] = splitComments(nonErrorChildren(node));
|
|
34
37
|
const body = children.map(n => [n, convertTreeNode(n)]);
|
|
35
38
|
const remainingComments = linkCommentsToNextNodes(body, comments);
|
|
36
39
|
return {
|
|
@@ -45,7 +48,7 @@ function convertTreeNode(node) {
|
|
|
45
48
|
}
|
|
46
49
|
case tree_sitter_types_1.TreeSitterType.BracedExpression:
|
|
47
50
|
case tree_sitter_types_1.TreeSitterType.ParenthesizedExpression: {
|
|
48
|
-
const [comments, children] = splitComments(node
|
|
51
|
+
const [comments, children] = splitComments(nonErrorChildren(node));
|
|
49
52
|
const opening = children[0];
|
|
50
53
|
const body = children.slice(1, -1).map(n => [n, convertTreeNode(n)]);
|
|
51
54
|
const remainingComments = linkCommentsToNextNodes(body, comments);
|
|
@@ -78,9 +81,10 @@ function convertTreeNode(node) {
|
|
|
78
81
|
};
|
|
79
82
|
}
|
|
80
83
|
case tree_sitter_types_1.TreeSitterType.BinaryOperator: {
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
+
const children = nonErrorChildren(node);
|
|
85
|
+
const lhs = convertTreeNode(children[0]);
|
|
86
|
+
const rhs = convertTreeNode(children[children.length - 1]);
|
|
87
|
+
const [commentsBoth, [op]] = splitComments(children.slice(1, -1));
|
|
84
88
|
const comments = commentsBoth.map(c => c[1]);
|
|
85
89
|
const opSource = makeSourceRange(op);
|
|
86
90
|
const lhsAsArg = {
|
|
@@ -150,7 +154,7 @@ function convertTreeNode(node) {
|
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
case tree_sitter_types_1.TreeSitterType.UnaryOperator: {
|
|
153
|
-
const [op, operand] = node
|
|
157
|
+
const [op, operand] = nonErrorChildren(node);
|
|
154
158
|
return {
|
|
155
159
|
type: type_1.RType.UnaryOp,
|
|
156
160
|
operand: convertTreeNode(operand),
|
|
@@ -161,7 +165,7 @@ function convertTreeNode(node) {
|
|
|
161
165
|
};
|
|
162
166
|
}
|
|
163
167
|
case tree_sitter_types_1.TreeSitterType.NamespaceOperator: {
|
|
164
|
-
const [lhs, /* :: or ::: */ , rhs] = node
|
|
168
|
+
const [lhs, /* :: or ::: */ , rhs] = nonErrorChildren(node);
|
|
165
169
|
return {
|
|
166
170
|
type: type_1.RType.Symbol,
|
|
167
171
|
location: makeSourceRange(rhs),
|
|
@@ -176,6 +180,7 @@ function convertTreeNode(node) {
|
|
|
176
180
|
case tree_sitter_types_1.TreeSitterType.Na:
|
|
177
181
|
case tree_sitter_types_1.TreeSitterType.Null:
|
|
178
182
|
case tree_sitter_types_1.TreeSitterType.Dots:
|
|
183
|
+
case tree_sitter_types_1.TreeSitterType.DotDotI:
|
|
179
184
|
case tree_sitter_types_1.TreeSitterType.Identifier:
|
|
180
185
|
case tree_sitter_types_1.TreeSitterType.Return:
|
|
181
186
|
return {
|
|
@@ -187,22 +192,24 @@ function convertTreeNode(node) {
|
|
|
187
192
|
...defaultInfo
|
|
188
193
|
};
|
|
189
194
|
case tree_sitter_types_1.TreeSitterType.IfStatement: {
|
|
190
|
-
const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = node
|
|
195
|
+
const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = nonErrorChildren(node);
|
|
196
|
+
const filteredOtherwise = otherwise.filter(n => n.type !== tree_sitter_types_1.TreeSitterType.ElseStatement);
|
|
191
197
|
return {
|
|
192
198
|
type: type_1.RType.IfThenElse,
|
|
193
199
|
condition: convertTreeNode(condition),
|
|
194
200
|
then: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(then)),
|
|
195
|
-
otherwise:
|
|
201
|
+
otherwise: filteredOtherwise.length > 0 ? (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(filteredOtherwise[0])) : undefined,
|
|
196
202
|
location: makeSourceRange(ifNode),
|
|
197
203
|
lexeme: ifNode.text,
|
|
198
204
|
...defaultInfo
|
|
199
205
|
};
|
|
200
206
|
}
|
|
201
207
|
case tree_sitter_types_1.TreeSitterType.ForStatement: {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
208
|
+
const children = nonErrorChildren(node);
|
|
209
|
+
const forNode = children[0]; // we follow with a (
|
|
210
|
+
const variable = getNodesUntil(children, 'in', 2); // we follow with the "in"
|
|
211
|
+
const sequence = getNodesUntil(children, ')', 2 + variable.length + 1); // we follow with a (
|
|
212
|
+
const body = children[2 + variable.length + 1 + sequence.length + 1];
|
|
206
213
|
const [variableComments, [variableNode]] = splitComments(variable);
|
|
207
214
|
const [sequenceComments, [sequenceNode]] = splitComments(sequence);
|
|
208
215
|
return {
|
|
@@ -231,7 +238,7 @@ function convertTreeNode(node) {
|
|
|
231
238
|
};
|
|
232
239
|
}
|
|
233
240
|
case tree_sitter_types_1.TreeSitterType.WhileStatement: {
|
|
234
|
-
const [whileNode, /* ( */ , condition, /* ) */ , body] = node
|
|
241
|
+
const [whileNode, /* ( */ , condition, /* ) */ , body] = nonErrorChildren(node);
|
|
235
242
|
return {
|
|
236
243
|
type: type_1.RType.WhileLoop,
|
|
237
244
|
condition: convertTreeNode(condition),
|
|
@@ -242,7 +249,7 @@ function convertTreeNode(node) {
|
|
|
242
249
|
};
|
|
243
250
|
}
|
|
244
251
|
case tree_sitter_types_1.TreeSitterType.RepeatStatement: {
|
|
245
|
-
const [repeatNode, body] = node
|
|
252
|
+
const [repeatNode, body] = nonErrorChildren(node);
|
|
246
253
|
return {
|
|
247
254
|
type: type_1.RType.RepeatLoop,
|
|
248
255
|
body: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(body)),
|
|
@@ -252,7 +259,7 @@ function convertTreeNode(node) {
|
|
|
252
259
|
};
|
|
253
260
|
}
|
|
254
261
|
case tree_sitter_types_1.TreeSitterType.Call: {
|
|
255
|
-
const [func, argsParentheses] = node
|
|
262
|
+
const [func, argsParentheses] = nonErrorChildren(node);
|
|
256
263
|
// tree-sitter wraps next and break in a function call, but we don't, so unwrap
|
|
257
264
|
if (func.type === tree_sitter_types_1.TreeSitterType.Next || func.type == tree_sitter_types_1.TreeSitterType.Break) {
|
|
258
265
|
return {
|
|
@@ -260,7 +267,7 @@ function convertTreeNode(node) {
|
|
|
260
267
|
...defaultInfo
|
|
261
268
|
};
|
|
262
269
|
}
|
|
263
|
-
const args = (0, arrays_1.splitArrayOn)(argsParentheses.
|
|
270
|
+
const args = (0, arrays_1.splitArrayOn)(nonErrorChildren(argsParentheses).slice(1, -1), x => x.type === 'comma');
|
|
264
271
|
const funcRange = makeSourceRange(func);
|
|
265
272
|
const call = {
|
|
266
273
|
arguments: args.map(n => n.length == 0 ? r_function_call_1.EmptyArgument : convertTreeNode(n[0])),
|
|
@@ -302,7 +309,7 @@ function convertTreeNode(node) {
|
|
|
302
309
|
}
|
|
303
310
|
}
|
|
304
311
|
case tree_sitter_types_1.TreeSitterType.FunctionDefinition: {
|
|
305
|
-
const [name, paramsParens, body] = node
|
|
312
|
+
const [name, paramsParens, body] = nonErrorChildren(node);
|
|
306
313
|
const params = (0, arrays_1.splitArrayOn)(paramsParens.children.slice(1, -1), x => x.type === 'comma');
|
|
307
314
|
return {
|
|
308
315
|
type: type_1.RType.FunctionDefinition,
|
|
@@ -353,9 +360,9 @@ function convertTreeNode(node) {
|
|
|
353
360
|
case tree_sitter_types_1.TreeSitterType.Subset:
|
|
354
361
|
case tree_sitter_types_1.TreeSitterType.Subset2: {
|
|
355
362
|
// subset has children like a and [x]
|
|
356
|
-
const [func, content] = node
|
|
363
|
+
const [func, content] = nonErrorChildren(node);
|
|
357
364
|
// bracket is now [ or [[ and argsClosing is x] or x]]
|
|
358
|
-
const [bracket, ...argsClosing] = content
|
|
365
|
+
const [bracket, ...argsClosing] = nonErrorChildren(content);
|
|
359
366
|
const args = (0, arrays_1.splitArrayOn)(argsClosing.slice(0, -1), x => x.type === 'comma');
|
|
360
367
|
return {
|
|
361
368
|
type: type_1.RType.Access,
|
|
@@ -368,7 +375,7 @@ function convertTreeNode(node) {
|
|
|
368
375
|
};
|
|
369
376
|
}
|
|
370
377
|
case tree_sitter_types_1.TreeSitterType.ExtractOperator: {
|
|
371
|
-
const [lhs, operator, rhs] = node
|
|
378
|
+
const [lhs, operator, rhs] = nonErrorChildren(node);
|
|
372
379
|
const rhsRange = makeSourceRange(rhs);
|
|
373
380
|
return {
|
|
374
381
|
type: type_1.RType.Access,
|
|
@@ -395,11 +402,12 @@ function convertTreeNode(node) {
|
|
|
395
402
|
};
|
|
396
403
|
}
|
|
397
404
|
case tree_sitter_types_1.TreeSitterType.Parameter: {
|
|
398
|
-
const
|
|
405
|
+
const children = nonErrorChildren(node);
|
|
406
|
+
const name = children[0];
|
|
399
407
|
const nameRange = makeSourceRange(name);
|
|
400
408
|
let defaultValue = undefined;
|
|
401
|
-
if (
|
|
402
|
-
defaultValue = convertTreeNode(
|
|
409
|
+
if (children.length == 3) {
|
|
410
|
+
defaultValue = convertTreeNode(children[2]);
|
|
403
411
|
}
|
|
404
412
|
return {
|
|
405
413
|
type: type_1.RType.Parameter,
|
|
@@ -427,8 +435,9 @@ function convertTreeNode(node) {
|
|
|
427
435
|
};
|
|
428
436
|
}
|
|
429
437
|
case tree_sitter_types_1.TreeSitterType.Argument: {
|
|
430
|
-
|
|
431
|
-
|
|
438
|
+
const children = nonErrorChildren(node);
|
|
439
|
+
if (children.length == 1) {
|
|
440
|
+
const [arg] = children;
|
|
432
441
|
return {
|
|
433
442
|
type: type_1.RType.Argument,
|
|
434
443
|
name: undefined,
|
|
@@ -439,7 +448,7 @@ function convertTreeNode(node) {
|
|
|
439
448
|
};
|
|
440
449
|
}
|
|
441
450
|
else {
|
|
442
|
-
const [nameNode, /* = */ , valueNode] =
|
|
451
|
+
const [nameNode, /* = */ , valueNode] = children;
|
|
443
452
|
let name = convertTreeNode(nameNode);
|
|
444
453
|
// unescape argument names
|
|
445
454
|
if (name.type === type_1.RType.String) {
|
|
@@ -457,7 +466,7 @@ function convertTreeNode(node) {
|
|
|
457
466
|
return {
|
|
458
467
|
type: type_1.RType.Argument,
|
|
459
468
|
name: name,
|
|
460
|
-
value: convertTreeNode(valueNode),
|
|
469
|
+
value: valueNode ? convertTreeNode(valueNode) : undefined,
|
|
461
470
|
location: nameRange,
|
|
462
471
|
lexeme: nameNode.text,
|
|
463
472
|
info: {
|
|
@@ -468,8 +477,16 @@ function convertTreeNode(node) {
|
|
|
468
477
|
};
|
|
469
478
|
}
|
|
470
479
|
}
|
|
480
|
+
case tree_sitter_types_1.TreeSitterType.Comment:
|
|
481
|
+
return {
|
|
482
|
+
type: type_1.RType.Comment,
|
|
483
|
+
location: range,
|
|
484
|
+
content: node.text.slice(1),
|
|
485
|
+
lexeme: node.text,
|
|
486
|
+
...defaultInfo
|
|
487
|
+
};
|
|
471
488
|
default:
|
|
472
|
-
throw new normalizer_data_1.ParseError(`unexpected node type ${node.type}`);
|
|
489
|
+
throw new normalizer_data_1.ParseError(`unexpected node type ${node.type} at ${JSON.stringify(range)}`);
|
|
473
490
|
}
|
|
474
491
|
}
|
|
475
492
|
function makeSourceRange(node) {
|
|
@@ -7,6 +7,7 @@ export declare enum TreeSitterType {
|
|
|
7
7
|
NamespaceOperator = "namespace_operator",
|
|
8
8
|
Identifier = "identifier",
|
|
9
9
|
IfStatement = "if_statement",
|
|
10
|
+
ElseStatement = "else",
|
|
10
11
|
ForStatement = "for_statement",
|
|
11
12
|
WhileStatement = "while_statement",
|
|
12
13
|
RepeatStatement = "repeat_statement",
|
|
@@ -31,5 +32,7 @@ export declare enum TreeSitterType {
|
|
|
31
32
|
Parameter = "parameter",
|
|
32
33
|
Argument = "argument",
|
|
33
34
|
Dots = "dots",
|
|
34
|
-
|
|
35
|
+
DotDotI = "dot_dot_i",
|
|
36
|
+
Comment = "comment",
|
|
37
|
+
Error = "ERROR"
|
|
35
38
|
}
|
|
@@ -11,6 +11,7 @@ var TreeSitterType;
|
|
|
11
11
|
TreeSitterType["NamespaceOperator"] = "namespace_operator";
|
|
12
12
|
TreeSitterType["Identifier"] = "identifier";
|
|
13
13
|
TreeSitterType["IfStatement"] = "if_statement";
|
|
14
|
+
TreeSitterType["ElseStatement"] = "else";
|
|
14
15
|
TreeSitterType["ForStatement"] = "for_statement";
|
|
15
16
|
TreeSitterType["WhileStatement"] = "while_statement";
|
|
16
17
|
TreeSitterType["RepeatStatement"] = "repeat_statement";
|
|
@@ -35,6 +36,8 @@ var TreeSitterType;
|
|
|
35
36
|
TreeSitterType["Parameter"] = "parameter";
|
|
36
37
|
TreeSitterType["Argument"] = "argument";
|
|
37
38
|
TreeSitterType["Dots"] = "dots";
|
|
39
|
+
TreeSitterType["DotDotI"] = "dot_dot_i";
|
|
38
40
|
TreeSitterType["Comment"] = "comment";
|
|
41
|
+
TreeSitterType["Error"] = "ERROR";
|
|
39
42
|
})(TreeSitterType || (exports.TreeSitterType = TreeSitterType = {}));
|
|
40
43
|
//# sourceMappingURL=tree-sitter-types.js.map
|
package/util/cfg/cfg.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { QuadSerializationConfiguration } from '../quads';
|
|
|
3
3
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
4
|
import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
5
|
import { RFalse, RTrue } from '../../r-bridge/lang-4.x/convert-values';
|
|
6
|
+
import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
6
7
|
export declare const enum CfgVertexType {
|
|
7
8
|
/** Marks a break point in a construct (e.g., between the name and the value of an argument, or the formals and the body of a function) */
|
|
8
9
|
MidMarker = "mid-marker",
|
|
@@ -57,7 +58,15 @@ export interface ControlFlowInformation extends MergeableRecord {
|
|
|
57
58
|
graph: ControlFlowGraph;
|
|
58
59
|
}
|
|
59
60
|
export declare function emptyControlFlowInformation(): ControlFlowInformation;
|
|
60
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Given a normalized AST this approximates the control flow graph of the program.
|
|
63
|
+
* This few is different from the computation of the dataflow graph and may differ,
|
|
64
|
+
* especially because it focuses on intra-procedural analysis.
|
|
65
|
+
*
|
|
66
|
+
* @param ast - the normalized AST
|
|
67
|
+
* @param graph - additional dataflow facts to consider by the control flow extraction
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractCFG<Info = ParentInformation>(ast: NormalizedAst<Info>, graph?: DataflowGraph): ControlFlowInformation;
|
|
61
70
|
/**
|
|
62
71
|
* Returns true if the given CFG equals the other CFG. False otherwise.
|
|
63
72
|
*/
|
package/util/cfg/cfg.js
CHANGED
|
@@ -12,6 +12,8 @@ const json_1 = require("../json");
|
|
|
12
12
|
const fold_1 = require("../../r-bridge/lang-4.x/ast/model/processing/fold");
|
|
13
13
|
const convert_values_1 = require("../../r-bridge/lang-4.x/convert-values");
|
|
14
14
|
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
15
|
+
const linker_1 = require("../../dataflow/internal/linker");
|
|
16
|
+
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
15
17
|
/**
|
|
16
18
|
* This class represents the control flow graph of an R program.
|
|
17
19
|
* The control flow may be hierarchical when confronted with function definitions (see {@link CfgVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
|
|
@@ -101,8 +103,25 @@ const cfgFolds = {
|
|
|
101
103
|
foldArgument: cfgArgumentOrParameter
|
|
102
104
|
}
|
|
103
105
|
};
|
|
104
|
-
function
|
|
105
|
-
return
|
|
106
|
+
function dataflowCfgFolds(dataflowGraph) {
|
|
107
|
+
return {
|
|
108
|
+
...cfgFolds,
|
|
109
|
+
functions: {
|
|
110
|
+
...cfgFolds.functions,
|
|
111
|
+
foldFunctionCall: cfgFunctionCallWithDataflow(dataflowGraph)
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Given a normalized AST this approximates the control flow graph of the program.
|
|
117
|
+
* This few is different from the computation of the dataflow graph and may differ,
|
|
118
|
+
* especially because it focuses on intra-procedural analysis.
|
|
119
|
+
*
|
|
120
|
+
* @param ast - the normalized AST
|
|
121
|
+
* @param graph - additional dataflow facts to consider by the control flow extraction
|
|
122
|
+
*/
|
|
123
|
+
function extractCFG(ast, graph) {
|
|
124
|
+
return (0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds);
|
|
106
125
|
}
|
|
107
126
|
function cfgLeaf(type) {
|
|
108
127
|
return (leaf) => {
|
|
@@ -253,6 +272,9 @@ function cfgFunctionDefinition(fn, params, body) {
|
|
|
253
272
|
graph.addEdge(fn.info.id + '-params', exit, { label: 'FD' });
|
|
254
273
|
}
|
|
255
274
|
}
|
|
275
|
+
if (params.length === 0) {
|
|
276
|
+
graph.addEdge(fn.info.id + '-params', fn.info.id, { label: 'FD' });
|
|
277
|
+
}
|
|
256
278
|
for (const entry of body.entryPoints) {
|
|
257
279
|
graph.addEdge(entry, fn.info.id + '-params', { label: 'FD' });
|
|
258
280
|
}
|
|
@@ -296,6 +318,38 @@ function cfgFunctionCall(call, name, args) {
|
|
|
296
318
|
// should not contain any breaks, nexts, or returns, (except for the body if something like 'break()')
|
|
297
319
|
return info;
|
|
298
320
|
}
|
|
321
|
+
function cfgFunctionCallWithDataflow(graph) {
|
|
322
|
+
return (call, name, args) => {
|
|
323
|
+
const baseCFG = cfgFunctionCall(call, name, args);
|
|
324
|
+
/* try to resolve the call and link the target definitions */
|
|
325
|
+
const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
|
|
326
|
+
const exits = [];
|
|
327
|
+
for (const target of targets) {
|
|
328
|
+
// we have to filter out non func-call targets as the call targets contains names and call ids
|
|
329
|
+
if ((0, vertex_1.isFunctionDefinitionVertex)(graph.getVertex(target))) {
|
|
330
|
+
baseCFG.graph.addEdge(call.info.id, target, { label: 'FD' });
|
|
331
|
+
exits.push(target + '-exit');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (exits.length > 0) {
|
|
335
|
+
baseCFG.graph.addVertex({
|
|
336
|
+
id: call.info.id + '-resolved-call-exit',
|
|
337
|
+
name: 'resolved-call-exit',
|
|
338
|
+
type: "end-marker" /* CfgVertexType.EndMarker */
|
|
339
|
+
});
|
|
340
|
+
for (const exit of [...baseCFG.exitPoints, ...exits]) {
|
|
341
|
+
baseCFG.graph.addEdge(call.info.id + '-resolved-call-exit', exit, { label: 'FD' });
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
...baseCFG,
|
|
345
|
+
exitPoints: [call.info.id + '-resolved-call-exit']
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
return baseCFG;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
299
353
|
function cfgArgumentOrParameter(node, name, value) {
|
|
300
354
|
const graph = new ControlFlowGraph();
|
|
301
355
|
const info = { graph, breaks: [], nexts: [], returns: [], exitPoints: [node.info.id + '-exit'], entryPoints: [node.info.id] };
|
package/util/range.d.ts
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A source position in a file.
|
|
3
|
+
*
|
|
4
|
+
* Please note that some packages like `xmlparsedata` use their own start and end only to break ties
|
|
5
|
+
* (e.g., `xmlparsedata` calculates them on a max col width approximation)
|
|
6
|
+
*/
|
|
1
7
|
export type SourcePosition = [
|
|
2
8
|
/** starts with 1 */
|
|
3
9
|
line: number,
|
|
4
10
|
/** starts with 1 */
|
|
5
11
|
column: number
|
|
6
12
|
];
|
|
13
|
+
/**
|
|
14
|
+
* Describe the start and end {@link SourcePosition|source position} of an element.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link rangeFrom} - to create a range
|
|
17
|
+
* @see {@link mergeRanges} - to merge multiple ranges
|
|
18
|
+
* @see {@link getRangeStart} - to get the start of a range
|
|
19
|
+
* @see {@link getRangeEnd} - to get the end of a range
|
|
20
|
+
* @see {@link rangeStartsCompletelyBefore} - to check if one range starts before another
|
|
21
|
+
* @see {@link rangesOverlap} - to check if two ranges overlap
|
|
22
|
+
* @see {@link addRanges} - to add two ranges
|
|
23
|
+
* @see {@link rangeCompare} - to compare two ranges
|
|
24
|
+
*/
|
|
7
25
|
export type SourceRange = [
|
|
8
26
|
/** inclusive start position */
|
|
9
27
|
startLine: number,
|
|
@@ -36,6 +54,9 @@ export declare function rangeStartsCompletelyBefore([, , r1el, r1ec]: SourceRang
|
|
|
36
54
|
* Checks if the two ranges overlap.
|
|
37
55
|
*/
|
|
38
56
|
export declare function rangesOverlap([r1sl, r1sc, r1el, r1ec]: SourceRange, [r2sl, r2sc, r2el, r2ec]: SourceRange): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Calculate the component-wise sum of two ranges
|
|
59
|
+
*/
|
|
39
60
|
export declare function addRanges([r1sl, r1sc, r1el, r1ec]: SourceRange, [r2sl, r2sc, r2el, r2ec]: SourceRange): SourceRange;
|
|
40
61
|
/**
|
|
41
62
|
* Provides a comparator for {@link SourceRange}s that sorts them in ascending order.
|
package/util/range.js
CHANGED
|
@@ -45,6 +45,9 @@ function rangeStartsCompletelyBefore([, , r1el, r1ec], [r2sl, r2sc, ,]) {
|
|
|
45
45
|
function rangesOverlap([r1sl, r1sc, r1el, r1ec], [r2sl, r2sc, r2el, r2ec]) {
|
|
46
46
|
return r1sl <= r2el && r2sl <= r1el && r1sc <= r2ec && r2sc <= r1ec;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Calculate the component-wise sum of two ranges
|
|
50
|
+
*/
|
|
48
51
|
function addRanges([r1sl, r1sc, r1el, r1ec], [r2sl, r2sc, r2el, r2ec]) {
|
|
49
52
|
return [r1sl + r2sl, r1sc + r2sc, r1el + r2el, r1ec + r2ec];
|
|
50
53
|
}
|
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.2';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|