@eagleoutice/flowr 2.2.1 → 2.2.3

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.
Files changed (95) hide show
  1. package/cli/flowr.js +2 -1
  2. package/cli/repl/commands/repl-cfg.js +30 -7
  3. package/cli/repl/commands/repl-dataflow.js +29 -6
  4. package/cli/repl/commands/repl-normalize.js +22 -2
  5. package/cli/repl/commands/repl-parse.js +50 -3
  6. package/cli/repl/core.js +4 -0
  7. package/cli/repl/print-version.d.ts +1 -0
  8. package/cli/repl/print-version.js +7 -2
  9. package/cli/repl/server/connection.js +11 -9
  10. package/cli/script-core/statistics-helper-core.js +1 -1
  11. package/config.js +8 -1
  12. package/core/pipeline-executor.d.ts +6 -0
  13. package/core/pipeline-executor.js +8 -0
  14. package/core/print/dataflow-printer.js +3 -0
  15. package/core/steps/all/core/01-parse-tree-sitter.d.ts +7 -0
  16. package/core/steps/pipeline/default-pipelines.d.ts +57 -47
  17. package/core/steps/pipeline/default-pipelines.js +23 -2
  18. package/core/steps/pipeline/pipeline.d.ts +1 -1
  19. package/core/steps/pipeline/pipeline.js +1 -1
  20. package/core/steps/pipeline-step.d.ts +1 -3
  21. package/dataflow/environments/resolve-by-name.d.ts +3 -2
  22. package/dataflow/environments/resolve-by-name.js +4 -4
  23. package/dataflow/extractor.d.ts +10 -0
  24. package/dataflow/extractor.js +11 -1
  25. package/dataflow/graph/dataflowgraph-builder.d.ts +11 -10
  26. package/dataflow/graph/dataflowgraph-builder.js +11 -10
  27. package/dataflow/graph/edge.d.ts +1 -1
  28. package/dataflow/graph/edge.js +2 -2
  29. package/dataflow/graph/vertex.d.ts +6 -6
  30. package/dataflow/graph/vertex.js +5 -5
  31. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +9 -5
  32. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +1 -1
  33. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -6
  34. package/documentation/doc-util/doc-cfg.js +2 -2
  35. package/documentation/doc-util/doc-dfg.d.ts +5 -3
  36. package/documentation/doc-util/doc-dfg.js +10 -8
  37. package/documentation/doc-util/doc-files.d.ts +1 -1
  38. package/documentation/doc-util/doc-files.js +1 -1
  39. package/documentation/doc-util/doc-normalized-ast.d.ts +2 -1
  40. package/documentation/doc-util/doc-normalized-ast.js +4 -5
  41. package/documentation/doc-util/doc-repl.d.ts +6 -2
  42. package/documentation/doc-util/doc-repl.js +10 -6
  43. package/documentation/doc-util/doc-structure.d.ts +1 -1
  44. package/documentation/doc-util/doc-types.d.ts +7 -5
  45. package/documentation/doc-util/doc-types.js +17 -12
  46. package/documentation/index.d.ts +9 -0
  47. package/documentation/index.js +26 -0
  48. package/documentation/print-capabilities-markdown.js +105 -19
  49. package/documentation/print-core-wiki.d.ts +1 -0
  50. package/documentation/print-core-wiki.js +406 -0
  51. package/documentation/print-dataflow-graph-wiki.js +27 -27
  52. package/documentation/print-interface-wiki.js +1 -3
  53. package/documentation/print-linting-and-testing-wiki.js +26 -8
  54. package/documentation/print-normalized-ast-wiki.js +22 -17
  55. package/documentation/print-query-wiki.js +37 -7
  56. package/documentation/print-search-wiki.js +2 -1
  57. package/package.json +10 -7
  58. package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
  59. package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +1 -1
  60. package/queries/catalog/happens-before-query/happens-before-query-executor.js +2 -2
  61. package/queries/catalog/happens-before-query/happens-before-query-format.js +1 -1
  62. package/queries/catalog/resolve-value-query/resolve-value-query-executor.d.ts +4 -0
  63. package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +34 -0
  64. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +72 -0
  65. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +49 -0
  66. package/queries/catalog/search-query/search-query-format.js +1 -1
  67. package/queries/query.d.ts +60 -1
  68. package/queries/query.js +3 -1
  69. package/r-bridge/data/data.d.ts +50 -9
  70. package/r-bridge/data/data.js +64 -10
  71. package/r-bridge/data/types.d.ts +7 -1
  72. package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +2 -0
  73. package/r-bridge/lang-4.x/ast/model/processing/node-id.js +2 -5
  74. package/r-bridge/lang-4.x/ast/parser/json/format.d.ts +6 -0
  75. package/r-bridge/lang-4.x/ast/parser/json/format.js +6 -0
  76. package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +13 -2
  77. package/r-bridge/lang-4.x/ast/parser/json/parser.js +19 -3
  78. package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.d.ts +3 -0
  79. package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.js +3 -0
  80. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +51 -29
  81. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.d.ts +4 -1
  82. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.js +3 -0
  83. package/r-bridge/parser.d.ts +10 -0
  84. package/r-bridge/parser.js +26 -2
  85. package/search/flowr-search-builder.d.ts +1 -2
  86. package/search/flowr-search-builder.js +1 -3
  87. package/util/cfg/cfg.d.ts +10 -1
  88. package/util/cfg/cfg.js +56 -2
  89. package/util/mermaid/dfg.d.ts +3 -0
  90. package/util/mermaid/dfg.js +24 -8
  91. package/util/range.d.ts +21 -0
  92. package/util/range.js +3 -0
  93. package/util/strings.d.ts +9 -0
  94. package/util/strings.js +14 -0
  95. package/util/version.js +1 -1
@@ -7,6 +7,9 @@ const retriever_1 = require("../../../../retriever");
7
7
  const assert_1 = require("../../../../../util/assert");
8
8
  const type_1 = require("../../model/type");
9
9
  exports.RootId = 0;
10
+ /**
11
+ * Takes the raw {@link RShell} output and extracts the csv information contained
12
+ */
10
13
  function prepareParsedData(data) {
11
14
  let json;
12
15
  try {
@@ -36,6 +39,9 @@ function prepareParsedData(data) {
36
39
  }
37
40
  return roots;
38
41
  }
42
+ /**
43
+ * Takes the CSV-Entries and maps them to the old json format for compatibility.
44
+ */
39
45
  function convertPreparedParsedData(roots) {
40
46
  const partialEntry = {
41
47
  token: type_1.RawRType.ExpressionList,
@@ -1,10 +1,21 @@
1
1
  import type { IdGenerator, NormalizedAst } from '../../model/processing/decorate';
2
- import type { NoInfo } from '../../model/model';
2
+ import type { NoInfo, RNode } from '../../model/model';
3
3
  import type { ParseStepOutputTS } from '../../../../../core/steps/all/core/01-parse-tree-sitter';
4
4
  import type { ParseStepOutput } from '../../../../parser';
5
5
  export declare const parseLog: import("tslog").Logger<import("tslog").ILogObj>;
6
6
  /**
7
7
  * Take the output as produced by the parse step and normalize the AST from the R parser.
8
+ *
9
+ * @see {@link normalizeButNotDecorated} for a version that does not decorate the AST
10
+ * @see {@link normalizeTreeSitter} for a version that normalizes the AST from the TreeSitter parser
11
+ */
12
+ export declare function normalize(parsed: ParseStepOutput<string>, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
13
+ /**
14
+ * Take the output as produced by the parse step and normalize the AST from the R parser.
15
+ * For additional decoration with ${@link decorateAst} use {@link normalize}.
16
+ */
17
+ export declare function normalizeButNotDecorated({ parsed }: ParseStepOutput<string>): RNode;
18
+ /**
19
+ * Tree-Sitter pendant to {@link normalize}.
8
20
  */
9
- export declare function normalize({ parsed }: ParseStepOutput<string>, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
10
21
  export declare function normalizeTreeSitter({ parsed }: ParseStepOutputTS, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseLog = void 0;
4
4
  exports.normalize = normalize;
5
+ exports.normalizeButNotDecorated = normalizeButNotDecorated;
5
6
  exports.normalizeTreeSitter = normalizeTreeSitter;
6
7
  const format_1 = require("./format");
7
8
  const log_1 = require("../../../../../util/log");
@@ -11,13 +12,28 @@ const tree_sitter_normalize_1 = require("../../../tree-sitter/tree-sitter-normal
11
12
  exports.parseLog = log_1.log.getSubLogger({ name: 'ast-parser' });
12
13
  /**
13
14
  * Take the output as produced by the parse step and normalize the AST from the R parser.
15
+ *
16
+ * @see {@link normalizeButNotDecorated} for a version that does not decorate the AST
17
+ * @see {@link normalizeTreeSitter} for a version that normalizes the AST from the TreeSitter parser
14
18
  */
15
- function normalize({ parsed }, getId = (0, decorate_1.deterministicCountingIdGenerator)(0), file) {
19
+ function normalize(parsed, getId = (0, decorate_1.deterministicCountingIdGenerator)(0), file) {
20
+ return (0, decorate_1.decorateAst)(normalizeButNotDecorated(parsed), { getId, file });
21
+ }
22
+ /**
23
+ * Take the output as produced by the parse step and normalize the AST from the R parser.
24
+ * For additional decoration with ${@link decorateAst} use {@link normalize}.
25
+ */
26
+ function normalizeButNotDecorated({ parsed }) {
16
27
  const data = { currentRange: undefined, currentLexeme: undefined };
17
28
  const object = (0, format_1.convertPreparedParsedData)((0, format_1.prepareParsedData)(parsed));
18
- return (0, decorate_1.decorateAst)((0, normalize_root_1.normalizeRootObjToAst)(data, object), { getId, file });
29
+ return (0, normalize_root_1.normalizeRootObjToAst)(data, object);
19
30
  }
31
+ /**
32
+ * Tree-Sitter pendant to {@link normalize}.
33
+ */
20
34
  function normalizeTreeSitter({ parsed }, getId = (0, decorate_1.deterministicCountingIdGenerator)(0), file) {
21
- return (0, decorate_1.decorateAst)((0, tree_sitter_normalize_1.normalizeTreeSitterTreeToAst)(parsed), { getId, file });
35
+ const result = (0, decorate_1.decorateAst)((0, tree_sitter_normalize_1.normalizeTreeSitterTreeToAst)(parsed), { getId, file });
36
+ result.hasError = parsed.rootNode.hasError;
37
+ return result;
22
38
  }
23
39
  //# sourceMappingURL=parser.js.map
@@ -1,4 +1,7 @@
1
1
  import type { NormalizerData } from '../../normalizer-data';
2
2
  import type { RExpressionList } from '../../../../model/nodes/r-expression-list';
3
3
  import type { JsonEntry } from '../../../json/format';
4
+ /**
5
+ * Takes the parse dta as object and produces an undecorated, normalized AST.
6
+ */
4
7
  export declare function normalizeRootObjToAst(data: NormalizerData, obj: JsonEntry): RExpressionList;
@@ -6,6 +6,9 @@ const normalize_expressions_1 = require("./normalize-expressions");
6
6
  const log_1 = require("../../../../../../../util/log");
7
7
  const arrays_1 = require("../../../../../../../util/arrays");
8
8
  const type_1 = require("../../../../model/type");
9
+ /**
10
+ * Takes the parse dta as object and produces an undecorated, normalized AST.
11
+ */
9
12
  function normalizeRootObjToAst(data, obj) {
10
13
  const exprContent = obj.token;
11
14
  (0, normalize_meta_1.assureTokenType)(exprContent, type_1.RawRType.ExpressionList);
@@ -17,6 +17,14 @@ function normalizeTreeSitterTreeToAst(tree) {
17
17
  }
18
18
  return root;
19
19
  }
20
+ function nonErrorChildren(node) {
21
+ if (node.hasError) {
22
+ return [];
23
+ }
24
+ else {
25
+ return node.children;
26
+ }
27
+ }
20
28
  function convertTreeNode(node) {
21
29
  // generally, the grammar source file dictates what children a node has in what order:
22
30
  // https://github.com/r-lib/tree-sitter-r/blob/main/grammar.js
@@ -30,7 +38,7 @@ function convertTreeNode(node) {
30
38
  };
31
39
  switch (node.type) {
32
40
  case tree_sitter_types_1.TreeSitterType.Program: {
33
- const [comments, children] = splitComments(node.children);
41
+ const [comments, children] = splitComments(nonErrorChildren(node));
34
42
  const body = children.map(n => [n, convertTreeNode(n)]);
35
43
  const remainingComments = linkCommentsToNextNodes(body, comments);
36
44
  return {
@@ -45,7 +53,7 @@ function convertTreeNode(node) {
45
53
  }
46
54
  case tree_sitter_types_1.TreeSitterType.BracedExpression:
47
55
  case tree_sitter_types_1.TreeSitterType.ParenthesizedExpression: {
48
- const [comments, children] = splitComments(node.children);
56
+ const [comments, children] = splitComments(nonErrorChildren(node));
49
57
  const opening = children[0];
50
58
  const body = children.slice(1, -1).map(n => [n, convertTreeNode(n)]);
51
59
  const remainingComments = linkCommentsToNextNodes(body, comments);
@@ -78,9 +86,10 @@ function convertTreeNode(node) {
78
86
  };
79
87
  }
80
88
  case tree_sitter_types_1.TreeSitterType.BinaryOperator: {
81
- const lhs = convertTreeNode(node.children[0]);
82
- const rhs = convertTreeNode(node.children[node.children.length - 1]);
83
- const [commentsBoth, [op]] = splitComments(node.children.slice(1, -1));
89
+ const children = nonErrorChildren(node);
90
+ const lhs = convertTreeNode(children[0]);
91
+ const rhs = convertTreeNode(children[children.length - 1]);
92
+ const [commentsBoth, [op]] = splitComments(children.slice(1, -1));
84
93
  const comments = commentsBoth.map(c => c[1]);
85
94
  const opSource = makeSourceRange(op);
86
95
  const lhsAsArg = {
@@ -150,7 +159,7 @@ function convertTreeNode(node) {
150
159
  }
151
160
  }
152
161
  case tree_sitter_types_1.TreeSitterType.UnaryOperator: {
153
- const [op, operand] = node.children;
162
+ const [op, operand] = nonErrorChildren(node);
154
163
  return {
155
164
  type: type_1.RType.UnaryOp,
156
165
  operand: convertTreeNode(operand),
@@ -161,7 +170,7 @@ function convertTreeNode(node) {
161
170
  };
162
171
  }
163
172
  case tree_sitter_types_1.TreeSitterType.NamespaceOperator: {
164
- const [lhs, /* :: or ::: */ , rhs] = node.children;
173
+ const [lhs, /* :: or ::: */ , rhs] = nonErrorChildren(node);
165
174
  return {
166
175
  type: type_1.RType.Symbol,
167
176
  location: makeSourceRange(rhs),
@@ -176,6 +185,7 @@ function convertTreeNode(node) {
176
185
  case tree_sitter_types_1.TreeSitterType.Na:
177
186
  case tree_sitter_types_1.TreeSitterType.Null:
178
187
  case tree_sitter_types_1.TreeSitterType.Dots:
188
+ case tree_sitter_types_1.TreeSitterType.DotDotI:
179
189
  case tree_sitter_types_1.TreeSitterType.Identifier:
180
190
  case tree_sitter_types_1.TreeSitterType.Return:
181
191
  return {
@@ -187,22 +197,24 @@ function convertTreeNode(node) {
187
197
  ...defaultInfo
188
198
  };
189
199
  case tree_sitter_types_1.TreeSitterType.IfStatement: {
190
- const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = node.children;
200
+ const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = nonErrorChildren(node);
201
+ const filteredOtherwise = otherwise.filter(n => n.type !== tree_sitter_types_1.TreeSitterType.ElseStatement);
191
202
  return {
192
203
  type: type_1.RType.IfThenElse,
193
204
  condition: convertTreeNode(condition),
194
205
  then: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(then)),
195
- otherwise: otherwise.length > 0 ? (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(otherwise[0])) : undefined,
206
+ otherwise: filteredOtherwise.length > 0 ? (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(filteredOtherwise[0])) : undefined,
196
207
  location: makeSourceRange(ifNode),
197
208
  lexeme: ifNode.text,
198
209
  ...defaultInfo
199
210
  };
200
211
  }
201
212
  case tree_sitter_types_1.TreeSitterType.ForStatement: {
202
- const forNode = node.children[0]; // we follow with a (
203
- const variable = getNodesUntil(node.children, 'in', 2); // we follow with the "in"
204
- const sequence = getNodesUntil(node.children, ')', 2 + variable.length + 1); // we follow with a (
205
- const body = node.children[2 + variable.length + 1 + sequence.length + 1];
213
+ const children = nonErrorChildren(node);
214
+ const forNode = children[0]; // we follow with a (
215
+ const variable = getNodesUntil(children, 'in', 2); // we follow with the "in"
216
+ const sequence = getNodesUntil(children, ')', 2 + variable.length + 1); // we follow with a (
217
+ const body = children[2 + variable.length + 1 + sequence.length + 1];
206
218
  const [variableComments, [variableNode]] = splitComments(variable);
207
219
  const [sequenceComments, [sequenceNode]] = splitComments(sequence);
208
220
  return {
@@ -231,7 +243,7 @@ function convertTreeNode(node) {
231
243
  };
232
244
  }
233
245
  case tree_sitter_types_1.TreeSitterType.WhileStatement: {
234
- const [whileNode, /* ( */ , condition, /* ) */ , body] = node.children;
246
+ const [whileNode, /* ( */ , condition, /* ) */ , body] = nonErrorChildren(node);
235
247
  return {
236
248
  type: type_1.RType.WhileLoop,
237
249
  condition: convertTreeNode(condition),
@@ -242,7 +254,7 @@ function convertTreeNode(node) {
242
254
  };
243
255
  }
244
256
  case tree_sitter_types_1.TreeSitterType.RepeatStatement: {
245
- const [repeatNode, body] = node.children;
257
+ const [repeatNode, body] = nonErrorChildren(node);
246
258
  return {
247
259
  type: type_1.RType.RepeatLoop,
248
260
  body: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(body)),
@@ -252,7 +264,7 @@ function convertTreeNode(node) {
252
264
  };
253
265
  }
254
266
  case tree_sitter_types_1.TreeSitterType.Call: {
255
- const [func, argsParentheses] = node.children;
267
+ const [func, argsParentheses] = nonErrorChildren(node);
256
268
  // tree-sitter wraps next and break in a function call, but we don't, so unwrap
257
269
  if (func.type === tree_sitter_types_1.TreeSitterType.Next || func.type == tree_sitter_types_1.TreeSitterType.Break) {
258
270
  return {
@@ -260,7 +272,7 @@ function convertTreeNode(node) {
260
272
  ...defaultInfo
261
273
  };
262
274
  }
263
- const args = (0, arrays_1.splitArrayOn)(argsParentheses.children.slice(1, -1), x => x.type === 'comma');
275
+ const args = (0, arrays_1.splitArrayOn)(nonErrorChildren(argsParentheses).slice(1, -1), x => x.type === 'comma');
264
276
  const funcRange = makeSourceRange(func);
265
277
  const call = {
266
278
  arguments: args.map(n => n.length == 0 ? r_function_call_1.EmptyArgument : convertTreeNode(n[0])),
@@ -302,7 +314,7 @@ function convertTreeNode(node) {
302
314
  }
303
315
  }
304
316
  case tree_sitter_types_1.TreeSitterType.FunctionDefinition: {
305
- const [name, paramsParens, body] = node.children;
317
+ const [name, paramsParens, body] = nonErrorChildren(node);
306
318
  const params = (0, arrays_1.splitArrayOn)(paramsParens.children.slice(1, -1), x => x.type === 'comma');
307
319
  return {
308
320
  type: type_1.RType.FunctionDefinition,
@@ -353,9 +365,9 @@ function convertTreeNode(node) {
353
365
  case tree_sitter_types_1.TreeSitterType.Subset:
354
366
  case tree_sitter_types_1.TreeSitterType.Subset2: {
355
367
  // subset has children like a and [x]
356
- const [func, content] = node.children;
368
+ const [func, content] = nonErrorChildren(node);
357
369
  // bracket is now [ or [[ and argsClosing is x] or x]]
358
- const [bracket, ...argsClosing] = content.children;
370
+ const [bracket, ...argsClosing] = nonErrorChildren(content);
359
371
  const args = (0, arrays_1.splitArrayOn)(argsClosing.slice(0, -1), x => x.type === 'comma');
360
372
  return {
361
373
  type: type_1.RType.Access,
@@ -368,7 +380,7 @@ function convertTreeNode(node) {
368
380
  };
369
381
  }
370
382
  case tree_sitter_types_1.TreeSitterType.ExtractOperator: {
371
- const [lhs, operator, rhs] = node.children;
383
+ const [lhs, operator, rhs] = nonErrorChildren(node);
372
384
  const rhsRange = makeSourceRange(rhs);
373
385
  return {
374
386
  type: type_1.RType.Access,
@@ -395,11 +407,12 @@ function convertTreeNode(node) {
395
407
  };
396
408
  }
397
409
  case tree_sitter_types_1.TreeSitterType.Parameter: {
398
- const name = node.children[0];
410
+ const children = nonErrorChildren(node);
411
+ const name = children[0];
399
412
  const nameRange = makeSourceRange(name);
400
413
  let defaultValue = undefined;
401
- if (node.children.length == 3) {
402
- defaultValue = convertTreeNode(node.children[2]);
414
+ if (children.length == 3) {
415
+ defaultValue = convertTreeNode(children[2]);
403
416
  }
404
417
  return {
405
418
  type: type_1.RType.Parameter,
@@ -427,8 +440,9 @@ function convertTreeNode(node) {
427
440
  };
428
441
  }
429
442
  case tree_sitter_types_1.TreeSitterType.Argument: {
430
- if (node.children.length == 1) {
431
- const [arg] = node.children;
443
+ const children = nonErrorChildren(node);
444
+ if (children.length == 1) {
445
+ const [arg] = children;
432
446
  return {
433
447
  type: type_1.RType.Argument,
434
448
  name: undefined,
@@ -439,7 +453,7 @@ function convertTreeNode(node) {
439
453
  };
440
454
  }
441
455
  else {
442
- const [nameNode, /* = */ , valueNode] = node.children;
456
+ const [nameNode, /* = */ , valueNode] = children;
443
457
  let name = convertTreeNode(nameNode);
444
458
  // unescape argument names
445
459
  if (name.type === type_1.RType.String) {
@@ -457,7 +471,7 @@ function convertTreeNode(node) {
457
471
  return {
458
472
  type: type_1.RType.Argument,
459
473
  name: name,
460
- value: convertTreeNode(valueNode),
474
+ value: valueNode ? convertTreeNode(valueNode) : undefined,
461
475
  location: nameRange,
462
476
  lexeme: nameNode.text,
463
477
  info: {
@@ -468,8 +482,16 @@ function convertTreeNode(node) {
468
482
  };
469
483
  }
470
484
  }
485
+ case tree_sitter_types_1.TreeSitterType.Comment:
486
+ return {
487
+ type: type_1.RType.Comment,
488
+ location: range,
489
+ content: node.text.slice(1),
490
+ lexeme: node.text,
491
+ ...defaultInfo
492
+ };
471
493
  default:
472
- throw new normalizer_data_1.ParseError(`unexpected node type ${node.type}`);
494
+ throw new normalizer_data_1.ParseError(`unexpected node type ${node.type} at ${JSON.stringify(range)}`);
473
495
  }
474
496
  }
475
497
  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
- Comment = "comment"
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
@@ -27,6 +27,16 @@ export interface ParseRequiredInput<T> {
27
27
  export interface ParseStepOutput<T> {
28
28
  /** The parsed AST of the R code as given by the R parse side */
29
29
  readonly parsed: T;
30
+ /** Additional meta information about the parse */
31
+ readonly '.parse-meta'?: {
32
+ /** The number of tokens in the AST */
33
+ readonly tokenCount: number;
34
+ };
30
35
  }
36
+ /**
37
+ * Takes an input program and parses it using the given parser.
38
+ * @param _results - just a proxy for the pipeline, signifies that this function does not need prior knowledge of the pipeline
39
+ * @param input - the input to the parse step
40
+ */
31
41
  export declare function parseRequests<T extends KnownParserType>(_results: unknown, input: Partial<ParseRequiredInput<T>>): Promise<ParseStepOutput<T>>;
32
42
  export {};
@@ -1,14 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseRequests = parseRequests;
4
+ function countChildren(node) {
5
+ let ret = 1;
6
+ for (const child of node.children) {
7
+ ret += countChildren(child);
8
+ }
9
+ return ret;
10
+ }
11
+ /**
12
+ * Takes an input program and parses it using the given parser.
13
+ * @param _results - just a proxy for the pipeline, signifies that this function does not need prior knowledge of the pipeline
14
+ * @param input - the input to the parse step
15
+ */
4
16
  async function parseRequests(_results, input) {
5
17
  /* in the future, we want to expose all cases */
6
18
  const request = (Array.isArray(input.request) ? input.request[0] : input.request);
7
19
  if (input.parser?.async) {
8
- return { parsed: await input.parser.parse(request) };
20
+ const parsed = await input.parser.parse(request);
21
+ return {
22
+ parsed,
23
+ '.parse-meta': typeof parsed === 'object' && 'rootNode' in parsed ? {
24
+ tokenCount: countChildren(parsed.rootNode),
25
+ } : undefined
26
+ };
9
27
  }
10
28
  else {
11
- return { parsed: input.parser.parse(request) };
29
+ const parsed = input.parser.parse(request);
30
+ return {
31
+ parsed,
32
+ '.parse-meta': typeof parsed === 'object' && 'rootNode' in parsed ? {
33
+ tokenCount: countChildren(parsed.rootNode),
34
+ } : undefined
35
+ };
12
36
  }
13
37
  }
14
38
  //# sourceMappingURL=parser.js.map
@@ -111,7 +111,6 @@ export declare const Q: {
111
111
  readonly id: (id: NodeId) => FlowrSearchBuilder<"get">;
112
112
  };
113
113
  export type FlowrSearchBuilderType<Generator extends GeneratorNames = GeneratorNames, Transformers extends TransformerNames[] = TransformerNames[], Info = ParentInformation, ElementType = FlowrSearchElements<Info, FlowrSearchElement<Info>[]>> = FlowrSearchBuilder<Generator, Transformers, Info, ElementType>;
114
- type GetElements<F> = F extends FlowrSearchElements<infer Info, infer Elements> ? Elements extends FlowrSearchElement<Info>[] ? Elements : never : never;
115
114
  /**
116
115
  * The search query is a combination of a generator and a list of transformers
117
116
  * and allows this view to pass such queries in a serialized form.
@@ -172,7 +171,7 @@ export declare class FlowrSearchBuilder<Generator extends GeneratorNames, Transf
172
171
  /**
173
172
  * merge combines the search results with those of another search.
174
173
  */
175
- merge<Generator2 extends GeneratorNames, Transformers2 extends TransformerNames[], OtherElementType extends FlowrSearchElements<Info, FlowrSearchElement<Info>[]>>(other: FlowrSearchBuilder<Generator2, Transformers2, Info, OtherElementType>): FlowrSearchBuilder<Generator, Transformers, Info, FlowrSearchElements<Info, [...GetElements<ElementType>, ...GetElements<OtherElementType>]>>;
174
+ merge<Generator2 extends GeneratorNames, Transformers2 extends TransformerNames[], OtherElementType extends FlowrSearchElements<Info, FlowrSearchElement<Info>[]>>(other: FlowrSearchBuilder<Generator2, Transformers2, Info, OtherElementType>): FlowrSearchBuilder<Generator, Transformers, Info>;
176
175
  /**
177
176
  * Construct the final search (this may happen automatically with most search handlers).
178
177
  *
@@ -161,9 +161,7 @@ class FlowrSearchBuilder {
161
161
  /**
162
162
  * merge combines the search results with those of another search.
163
163
  */
164
- merge(other /* | FlowrSearch<Info, Generator2, Transformers2, OtherElementType> */
165
- // @ts-expect-error -- this works when merging, there is no info disparity
166
- ) {
164
+ merge(other /* | FlowrSearch<Info, Generator2, Transformers2, OtherElementType> */) {
167
165
  this.search.push({ type: 'transformer', name: 'merge', args: { generator: other.generator, search: other.search } });
168
166
  return this;
169
167
  }
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
- export declare function extractCFG<Info = ParentInformation>(ast: NormalizedAst<Info>): ControlFlowInformation;
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 extractCFG(ast) {
105
- return (0, fold_1.foldAst)(ast.ast, cfgFolds);
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] };
@@ -18,6 +18,8 @@ interface MermaidGraph {
18
18
  /** in the form of from-\>to because I am lazy, see {@link encodeEdge} */
19
19
  presentEdges: Set<string>;
20
20
  rootGraph: DataflowGraph;
21
+ /** if given, the dataflow graph will only focus on the "important" parts */
22
+ simplified?: boolean;
21
23
  }
22
24
  /**
23
25
  * Prints a {@link SourceRange|range} as a human readable string.
@@ -33,6 +35,7 @@ interface MermaidGraphConfiguration {
33
35
  markStyle?: MermaidMarkStyle;
34
36
  rootGraph?: DataflowGraph;
35
37
  presentEdges?: Set<string>;
38
+ simplified?: boolean;
36
39
  }
37
40
  export declare function graphToMermaid(config: MermaidGraphConfiguration): {
38
41
  string: string;
@@ -37,14 +37,24 @@ function subflowToMermaid(nodeId, exitPoints, subflow, mermaid, idPrefix = '') {
37
37
  return;
38
38
  }
39
39
  const subflowId = `${idPrefix}flow-${nodeId}`;
40
- mermaid.nodeLines.push(`\nsubgraph "${subflowId}" [function ${nodeId}]`);
40
+ if (mermaid.simplified) {
41
+ // get parent
42
+ const idMap = mermaid.rootGraph.idMap;
43
+ const node = idMap?.get(nodeId);
44
+ const nodeLexeme = node?.info.fullLexeme ?? node?.lexeme ?? '??';
45
+ mermaid.nodeLines.push(`\nsubgraph "${subflowId}" ["${(0, mermaid_1.escapeMarkdown)(nodeLexeme ?? 'function')}"]`);
46
+ }
47
+ else {
48
+ mermaid.nodeLines.push(`\nsubgraph "${subflowId}" [function ${nodeId}]`);
49
+ }
41
50
  const subgraph = graphToMermaidGraph(subflow.graph, {
42
51
  graph: mermaid.rootGraph,
43
52
  rootGraph: mermaid.rootGraph,
44
53
  idPrefix,
45
54
  includeEnvironments: mermaid.includeEnvironments,
46
55
  mark: mermaid.mark,
47
- prefix: null
56
+ prefix: null,
57
+ simplified: mermaid.simplified
48
58
  });
49
59
  mermaid.nodeLines.push(...subgraph.nodeLines);
50
60
  mermaid.edgeLines.push(...subgraph.edgeLines);
@@ -143,10 +153,16 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
143
153
  }
144
154
  const node = mermaid.rootGraph.idMap?.get(info.id);
145
155
  const lexeme = node?.lexeme ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0]?.lexeme : '') ?? '??';
146
- const escapedName = (0, mermaid_1.escapeMarkdown)(node ? `[${node.type}] ${lexeme}` : '??');
147
- const deps = info.controlDependencies ? ', :may:' + info.controlDependencies.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
148
- const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
149
- mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
156
+ if (mermaid.simplified) {
157
+ const escapedName = '**' + (0, mermaid_1.escapeMarkdown)(node ? `${lexeme}` : '??') + '**' + (node ? `\n*${node.type}*` : '');
158
+ mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}\`"${close}`);
159
+ }
160
+ else {
161
+ const escapedName = (0, mermaid_1.escapeMarkdown)(node ? `[${node.type}] ${lexeme}` : '??');
162
+ const deps = info.controlDependencies ? ', :may:' + info.controlDependencies.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
163
+ const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
164
+ mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
165
+ }
150
166
  if (mark?.has(id)) {
151
167
  mermaid.nodeLines.push(` style ${idPrefix}${id} ${mermaid.markStyle.vertex} `);
152
168
  }
@@ -176,8 +192,8 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
176
192
  }
177
193
  }
178
194
  // make the passing of root ids more performant again
179
- function graphToMermaidGraph(rootIds, { graph, prefix = 'flowchart TD', idPrefix = '', includeEnvironments = true, mark, rootGraph, presentEdges = new Set(), markStyle = { vertex: 'stroke:teal,stroke-width:7px,stroke-opacity:.8;', edge: 'stroke:teal,stroke-width:4.2px,stroke-opacity:.8' } }) {
180
- const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments, markStyle };
195
+ function graphToMermaidGraph(rootIds, { simplified, graph, prefix = 'flowchart TD', idPrefix = '', includeEnvironments = !simplified, mark, rootGraph, presentEdges = new Set(), markStyle = { vertex: 'stroke:teal,stroke-width:7px,stroke-opacity:.8;', edge: 'stroke:teal,stroke-width:4.2px,stroke-opacity:.8' } }) {
196
+ const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments, markStyle, simplified };
181
197
  for (const [id, info] of graph.vertices(true)) {
182
198
  if (rootIds.has(id)) {
183
199
  vertexToMermaid(info, mermaid, id, idPrefix, mark);