@eagleoutice/flowr 2.2.10 → 2.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +4 -4
  2. package/benchmark/slicer.d.ts +49 -22
  3. package/benchmark/slicer.js +88 -28
  4. package/benchmark/stats/print.js +16 -10
  5. package/benchmark/stats/size-of.js +18 -1
  6. package/benchmark/stats/stats.d.ts +3 -0
  7. package/benchmark/summarizer/second-phase/process.js +8 -2
  8. package/cli/benchmark-app.d.ts +5 -0
  9. package/cli/benchmark-app.js +49 -6
  10. package/cli/benchmark-helper-app.d.ts +4 -0
  11. package/cli/benchmark-helper-app.js +20 -4
  12. package/cli/common/options.js +13 -4
  13. package/cli/repl/commands/repl-commands.js +2 -0
  14. package/cli/repl/commands/repl-dataflow.d.ts +2 -0
  15. package/cli/repl/commands/repl-dataflow.js +35 -1
  16. package/cli/repl/server/compact.d.ts +2 -2
  17. package/cli/repl/server/compact.js +3 -3
  18. package/cli/repl/server/messages/message-analysis.d.ts +2 -2
  19. package/cli/repl/server/messages/message-analysis.js +2 -2
  20. package/config.d.ts +27 -2
  21. package/config.js +30 -4
  22. package/dataflow/environments/built-in-config.d.ts +5 -2
  23. package/dataflow/environments/built-in-config.js +8 -2
  24. package/dataflow/environments/built-in.d.ts +8 -1
  25. package/dataflow/environments/built-in.js +8 -1
  26. package/dataflow/environments/clone.d.ts +5 -0
  27. package/dataflow/environments/clone.js +5 -0
  28. package/dataflow/environments/default-builtin-config.js +96 -10
  29. package/dataflow/environments/define.d.ts +5 -1
  30. package/dataflow/environments/define.js +36 -10
  31. package/dataflow/environments/environment.js +4 -2
  32. package/dataflow/environments/overwrite.js +4 -0
  33. package/dataflow/environments/remove.d.ts +6 -0
  34. package/dataflow/environments/remove.js +24 -0
  35. package/dataflow/environments/resolve-by-name.js +1 -1
  36. package/dataflow/extractor.d.ts +1 -1
  37. package/dataflow/extractor.js +8 -6
  38. package/dataflow/graph/dataflowgraph-builder.d.ts +76 -6
  39. package/dataflow/graph/dataflowgraph-builder.js +102 -6
  40. package/dataflow/graph/edge.js +4 -1
  41. package/dataflow/graph/graph.d.ts +12 -1
  42. package/dataflow/graph/graph.js +37 -0
  43. package/dataflow/graph/vertex.d.ts +42 -2
  44. package/dataflow/graph/vertex.js +32 -0
  45. package/dataflow/internal/linker.js +3 -1
  46. package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +3 -0
  47. package/dataflow/internal/process/functions/call/argument/unpack-argument.js +4 -10
  48. package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +1 -0
  49. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +55 -45
  50. package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +6 -4
  51. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +27 -8
  52. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +37 -7
  53. package/dataflow/internal/process/functions/call/built-in/built-in-eval.d.ts +10 -0
  54. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +140 -0
  55. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +4 -3
  56. package/dataflow/internal/process/functions/call/built-in/built-in-list.js +51 -17
  57. package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +21 -3
  58. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +3 -0
  59. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +83 -29
  60. package/dataflow/internal/process/functions/call/built-in/built-in-rm.d.ts +7 -0
  61. package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +41 -0
  62. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +20 -6
  63. package/dataflow/internal/process/functions/call/built-in/built-in-vector.d.ts +15 -0
  64. package/dataflow/internal/process/functions/call/built-in/built-in-vector.js +75 -0
  65. package/dataflow/internal/process/functions/call/common.d.ts +1 -1
  66. package/dataflow/internal/process/functions/call/common.js +4 -2
  67. package/dataflow/internal/process/functions/call/named-call-handling.d.ts +2 -0
  68. package/dataflow/internal/process/functions/call/named-call-handling.js +9 -5
  69. package/dataflow/internal/process/process-named-call.d.ts +3 -0
  70. package/dataflow/internal/process/process-named-call.js +3 -0
  71. package/dataflow/processor.d.ts +7 -7
  72. package/documentation/data/server/doc-data-server-messages.js +2 -2
  73. package/documentation/doc-util/doc-cfg.d.ts +11 -2
  74. package/documentation/doc-util/doc-cfg.js +35 -6
  75. package/documentation/doc-util/doc-code.js +10 -2
  76. package/documentation/print-capabilities-markdown.js +1 -1
  77. package/documentation/print-cfg-wiki.d.ts +1 -0
  78. package/documentation/print-cfg-wiki.js +84 -0
  79. package/documentation/print-core-wiki.js +2 -2
  80. package/documentation/print-interface-wiki.js +4 -0
  81. package/documentation/print-query-wiki.js +22 -3
  82. package/package.json +4 -3
  83. package/queries/catalog/call-context-query/call-context-query-executor.js +13 -0
  84. package/queries/catalog/call-context-query/call-context-query-format.d.ts +4 -0
  85. package/queries/catalog/call-context-query/call-context-query-format.js +1 -0
  86. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
  87. package/queries/catalog/dependencies-query/dependencies-query-executor.js +13 -5
  88. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -25
  89. package/queries/catalog/dependencies-query/dependencies-query-format.js +2 -145
  90. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +24 -0
  91. package/queries/catalog/dependencies-query/function-info/function-info.js +10 -0
  92. package/queries/catalog/dependencies-query/function-info/library-functions.d.ts +2 -0
  93. package/queries/catalog/dependencies-query/function-info/library-functions.js +18 -0
  94. package/queries/catalog/dependencies-query/function-info/read-functions.d.ts +2 -0
  95. package/queries/catalog/dependencies-query/function-info/read-functions.js +101 -0
  96. package/queries/catalog/dependencies-query/function-info/source-functions.d.ts +2 -0
  97. package/queries/catalog/dependencies-query/function-info/source-functions.js +11 -0
  98. package/queries/catalog/dependencies-query/function-info/write-functions.d.ts +2 -0
  99. package/queries/catalog/dependencies-query/function-info/write-functions.js +87 -0
  100. package/queries/catalog/location-map-query/location-map-query-executor.d.ts +1 -1
  101. package/queries/catalog/location-map-query/location-map-query-executor.js +38 -3
  102. package/queries/catalog/location-map-query/location-map-query-format.d.ts +10 -1
  103. package/queries/catalog/location-map-query/location-map-query-format.js +5 -1
  104. package/queries/catalog/project-query/project-query-executor.d.ts +3 -0
  105. package/queries/catalog/project-query/project-query-executor.js +17 -0
  106. package/queries/catalog/project-query/project-query-format.d.ts +67 -0
  107. package/queries/catalog/project-query/project-query-format.js +26 -0
  108. package/queries/query.d.ts +60 -1
  109. package/queries/query.js +3 -1
  110. package/r-bridge/data/data.d.ts +2 -2
  111. package/r-bridge/data/data.js +2 -2
  112. package/slicing/static/fingerprint.js +8 -1
  113. package/slicing/static/slice-call.d.ts +1 -1
  114. package/slicing/static/slice-call.js +5 -16
  115. package/slicing/static/slicer-types.d.ts +2 -0
  116. package/slicing/static/static-slicer.d.ts +4 -2
  117. package/slicing/static/static-slicer.js +24 -18
  118. package/slicing/static/visiting-queue.d.ts +7 -1
  119. package/slicing/static/visiting-queue.js +20 -6
  120. package/util/arrays.d.ts +23 -0
  121. package/util/arrays.js +41 -0
  122. package/util/cfg/visitor.d.ts +1 -1
  123. package/util/cfg/visitor.js +2 -2
  124. package/util/{list-access.d.ts → containers.d.ts} +24 -4
  125. package/util/{list-access.js → containers.js} +42 -12
  126. package/util/mermaid/ast.js +12 -1
  127. package/util/mermaid/cfg.js +2 -2
  128. package/util/parallel.d.ts +2 -1
  129. package/util/parallel.js +11 -2
  130. package/util/prefix.d.ts +13 -0
  131. package/util/prefix.js +34 -0
  132. package/util/version.js +1 -1
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processVector = processVector;
4
+ const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
5
+ const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
6
+ const known_call_handling_1 = require("../known-call-handling");
7
+ const config_1 = require("../../../../../../config");
8
+ const containers_1 = require("../../../../../../util/containers");
9
+ /**
10
+ * Process a vector call.
11
+ *
12
+ * Example:
13
+ * ```r
14
+ * c(1, 2, 3, 4)
15
+ * ```
16
+ */
17
+ function processVector(name, args, rootId, data) {
18
+ const fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
19
+ if (!(0, config_1.getConfig)().solver.pointerTracking) {
20
+ return fnCall.information;
21
+ }
22
+ const vectorArgs = [];
23
+ let argIndex = 1;
24
+ for (const arg of args) {
25
+ // Skip invalid argument types
26
+ if (arg === r_function_call_1.EmptyArgument || arg.type !== type_1.RType.Argument || arg.value === undefined) {
27
+ continue;
28
+ }
29
+ if (isPrimitive(arg.value.type)) {
30
+ vectorArgs.push({
31
+ identifier: { index: argIndex++ },
32
+ nodeId: arg.value.info.id,
33
+ });
34
+ }
35
+ else {
36
+ // Check whether argument value can be resolved
37
+ let indicesCollection;
38
+ if (arg.value.type === type_1.RType.Symbol) {
39
+ indicesCollection = (0, containers_1.resolveIndicesByName)(arg.value.lexeme, data.environment);
40
+ }
41
+ else {
42
+ // Check whether argument is nested container
43
+ indicesCollection = fnCall.information.graph.getVertex(arg.value.info.id)?.indicesCollection;
44
+ }
45
+ const flattenedIndices = indicesCollection?.flatMap(indices => indices.indices)
46
+ .map(index => {
47
+ return {
48
+ identifier: { index: argIndex++ },
49
+ nodeId: index.nodeId,
50
+ };
51
+ }) ?? [];
52
+ vectorArgs.push(...flattenedIndices);
53
+ }
54
+ }
55
+ if ((0, config_1.isOverPointerAnalysisThreshold)(vectorArgs.length)) {
56
+ return fnCall.information;
57
+ }
58
+ const indices = {
59
+ indices: vectorArgs,
60
+ isContainer: true,
61
+ };
62
+ // Add resolved indices to vertex
63
+ const vertex = fnCall.information.graph.getVertex(rootId);
64
+ if (vertex) {
65
+ vertex.indicesCollection = [indices];
66
+ }
67
+ return fnCall.information;
68
+ }
69
+ /**
70
+ * Checks whether the passed type is primitive i.e. number, logical or string.
71
+ */
72
+ function isPrimitive(type) {
73
+ return type === type_1.RType.Number || type === type_1.RType.Logical || type === type_1.RType.String;
74
+ }
75
+ //# sourceMappingURL=built-in-vector.js.map
@@ -34,6 +34,6 @@ export interface PatchFunctionCallInput<OtherInfo> {
34
34
  readonly rootId: NodeId;
35
35
  readonly name: RSymbol<OtherInfo & ParentInformation>;
36
36
  readonly data: DataflowProcessorInformation<OtherInfo & ParentInformation>;
37
- readonly argumentProcessResult: readonly (DataflowInformation | undefined)[];
37
+ readonly argumentProcessResult: readonly (Pick<DataflowInformation, 'entryPoint'> | undefined)[];
38
38
  }
39
39
  export declare function patchFunctionCall<OtherInfo>({ nextGraph, rootId, name, data, argumentProcessResult }: PatchFunctionCallInput<OtherInfo>): void;
@@ -64,9 +64,12 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
64
64
  }
65
65
  processedArguments.push(processed);
66
66
  finalEnv = (0, overwrite_1.overwriteEnvironment)(finalEnv, processed.environment);
67
+ finalGraph.mergeWith(processed.graph);
67
68
  // resolve reads within argument, we resolve before adding the `processed.environment` to avoid cyclic dependencies
68
69
  for (const ingoing of [...processed.in, ...processed.unknownReferences]) {
69
- const tryToResolve = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, argEnv, identifier_1.ReferenceType.Unknown) : undefined;
70
+ // check if it is called directly
71
+ const vtx = finalGraph.getVertex(ingoing.nodeId);
72
+ const tryToResolve = ingoing.name ? (0, resolve_by_name_1.resolveByName)(ingoing.name, argEnv, vtx?.tag === vertex_1.VertexType.FunctionCall ? identifier_1.ReferenceType.Function : identifier_1.ReferenceType.Unknown) : undefined;
70
73
  if (tryToResolve === undefined) {
71
74
  remainingReadInArgs.push(ingoing);
72
75
  }
@@ -90,7 +93,6 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
90
93
  }
91
94
  }
92
95
  argEnv = (0, overwrite_1.overwriteEnvironment)(argEnv, processed.environment);
93
- finalGraph.mergeWith(processed.graph);
94
96
  if (arg.type !== type_1.RType.Argument || !arg.name) {
95
97
  callArgs.push({ nodeId: processed.entryPoint, controlDependencies: undefined, type: identifier_1.ReferenceType.Argument });
96
98
  }
@@ -4,4 +4,6 @@ import type { ParentInformation } from '../../../../../r-bridge/lang-4.x/ast/mod
4
4
  import type { RFunctionArgument } from '../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
5
5
  import type { RSymbol } from '../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
6
6
  import type { NodeId } from '../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
7
+ import type { DataflowGraph } from '../../../../graph/graph';
8
+ export declare function markAsOnlyBuiltIn(graph: DataflowGraph, rootId: NodeId): void;
7
9
  export declare function processNamedCall<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.markAsOnlyBuiltIn = markAsOnlyBuiltIn;
3
4
  exports.processNamedCall = processNamedCall;
4
5
  const info_1 = require("../../../../info");
5
6
  const known_call_handling_1 = require("./known-call-handling");
@@ -27,6 +28,13 @@ function processDefaultFunctionProcessor(information, name, args, rootId, data)
27
28
  const call = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: (resolve?.length ?? 0) > 0 ? undefined : 'all' });
28
29
  return mergeInformation(information, call.information);
29
30
  }
31
+ function markAsOnlyBuiltIn(graph, rootId) {
32
+ const v = graph.getVertex(rootId);
33
+ if (v?.tag === vertex_1.VertexType.FunctionCall) {
34
+ v.onlyBuiltin = true;
35
+ v.environment = undefined;
36
+ }
37
+ }
30
38
  function processNamedCall(name, args, rootId, data) {
31
39
  const resolved = (0, resolve_by_name_1.resolveByName)(name.content, data.environment, identifier_1.ReferenceType.Function) ?? [];
32
40
  let defaultProcessor = resolved.length === 0;
@@ -46,11 +54,7 @@ function processNamedCall(name, args, rootId, data) {
46
54
  }
47
55
  else if (information && builtIn) {
48
56
  // mark the function call as built in only
49
- const v = information.graph.getVertex(rootId);
50
- if (v?.tag === vertex_1.VertexType.FunctionCall) {
51
- v.onlyBuiltin = true;
52
- v.environment = undefined;
53
- }
57
+ markAsOnlyBuiltIn(information.graph, rootId);
54
58
  }
55
59
  return information ?? (0, info_1.initializeCleanDataflowInformation)(rootId, data);
56
60
  }
@@ -3,4 +3,7 @@ import type { DataflowInformation } from '../../info';
3
3
  import type { Base, RNode, Location } from '../../../r-bridge/lang-4.x/ast/model/model';
4
4
  import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
5
5
  import type { EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
6
+ /**
7
+ * Helper function for {@link processNamedCall} using the given `functionName` as the name of the function.
8
+ */
6
9
  export declare function processAsNamedCall<OtherInfo>(functionName: RNode<OtherInfo & ParentInformation> & Base<OtherInfo> & Location, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, name: string, args: readonly (RNode<OtherInfo & ParentInformation> | typeof EmptyArgument | undefined)[]): DataflowInformation;
@@ -4,6 +4,9 @@ exports.processAsNamedCall = processAsNamedCall;
4
4
  const named_call_handling_1 = require("./functions/call/named-call-handling");
5
5
  const make_argument_1 = require("./functions/call/argument/make-argument");
6
6
  const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
7
+ /**
8
+ * Helper function for {@link processNamedCall} using the given `functionName` as the name of the function.
9
+ */
7
10
  function processAsNamedCall(functionName, data, name, args) {
8
11
  return (0, named_call_handling_1.processNamedCall)({
9
12
  type: type_1.RType.Symbol,
@@ -10,17 +10,17 @@ import type { KnownParserType, Parser } from '../r-bridge/parser';
10
10
  export interface DataflowProcessorInformation<OtherInfo> {
11
11
  readonly parser: Parser<KnownParserType>;
12
12
  /**
13
- * Initial and frozen ast-information
14
- */
13
+ * Initial and frozen ast-information
14
+ */
15
15
  readonly completeAst: NormalizedAst<OtherInfo>;
16
16
  /**
17
- * Correctly contains pushed local scopes introduced by `function` scopes.
18
- * Will by default *not* contain any symbol-bindings introduced along the way; they have to be decorated when moving up the tree.
19
- */
17
+ * Correctly contains pushed local scopes introduced by `function` scopes.
18
+ * Will by default *not* contain any symbol-bindings introduced along the way; they have to be decorated when moving up the tree.
19
+ */
20
20
  readonly environment: REnvironmentInformation;
21
21
  /**
22
- * Other processors to be called by the given functions
23
- */
22
+ * Other processors to be called by the given functions
23
+ */
24
24
  readonly processors: DataflowProcessors<OtherInfo>;
25
25
  /**
26
26
  * The {@link RParseRequests} that is currently being parsed
@@ -201,10 +201,10 @@ While the context is derived from the \`filename\`, we currently offer no way to
201
201
  })}
202
202
 
203
203
  <a id="analysis-format-compact"></a>
204
- **Retrieve the Output in a compactedForm**
204
+ **Retrieve the Output in a Compacted Form**
205
205
 
206
206
  The default response is formatted as JSON. But this can get very big quickly.
207
- By specifying \`format: "compact"\`, you can retrieve the results heavily compacted (using [msgpack](https://www.npmjs.com/package/@msgpack/msgpack)).
207
+ By specifying \`format: "compact"\`, you can retrieve the results heavily compacted (using [lz-string](https://www.npmjs.com/package/lz-string)).
208
208
  This works with and without the control flow graph as described [above](#analysis-include-cfg).
209
209
 
210
210
  ${await (0, doc_server_message_1.documentServerMessageResponse)({
@@ -1,7 +1,16 @@
1
1
  import type { ControlFlowInformation } from '../../util/cfg/cfg';
2
- import type { RShell } from '../../r-bridge/shell';
3
2
  import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
4
- export declare function getCfg(shell: RShell, code: string): Promise<{
3
+ import type { KnownParser } from '../../r-bridge/parser';
4
+ import type { DataflowInformation } from '../../dataflow/info';
5
+ export declare function getCfg(parser: KnownParser, code: string): Promise<{
5
6
  info: ControlFlowInformation;
6
7
  ast: NormalizedAst;
8
+ dataflow: DataflowInformation;
7
9
  }>;
10
+ export declare function printCfg(cfg: ControlFlowInformation, ast: NormalizedAst, prefix?: string): string;
11
+ export interface PrintCfgOptions {
12
+ readonly showCode?: boolean;
13
+ readonly openCode?: boolean;
14
+ readonly prefix?: string;
15
+ }
16
+ export declare function printCFGCode(parser: KnownParser, code: string, { showCode, openCode, prefix }?: PrintCfgOptions): Promise<string>;
@@ -1,18 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCfg = getCfg;
4
+ exports.printCfg = printCfg;
5
+ exports.printCFGCode = printCFGCode;
4
6
  const cfg_1 = require("../../util/cfg/cfg");
5
- const pipeline_executor_1 = require("../../core/pipeline-executor");
6
7
  const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
7
8
  const retriever_1 = require("../../r-bridge/retriever");
8
- async function getCfg(shell, code) {
9
- const steps = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
10
- parser: shell,
9
+ const time_1 = require("../../util/time");
10
+ const doc_files_1 = require("./doc-files");
11
+ const cfg_2 = require("../../util/mermaid/cfg");
12
+ const doc_code_1 = require("./doc-code");
13
+ async function getCfg(parser, code) {
14
+ const result = await (0, default_pipelines_1.createDataflowPipeline)(parser, {
11
15
  request: (0, retriever_1.requestFromInput)(code)
12
16
  }).allRemainingSteps();
17
+ const cfg = (0, cfg_1.extractCFG)(result.normalize, result.dataflow.graph);
13
18
  return {
14
- info: (0, cfg_1.extractCFG)(steps.normalize, steps.dataflow?.graph),
15
- ast: steps.normalize
19
+ info: cfg,
20
+ ast: result.normalize,
21
+ dataflow: result.dataflow
16
22
  };
17
23
  }
24
+ function printCfg(cfg, ast, prefix = 'flowchart TD\n') {
25
+ return `
26
+ ${(0, doc_code_1.codeBlock)('mermaid', (0, cfg_2.cfgToMermaid)(cfg, ast, prefix))}
27
+ `;
28
+ }
29
+ async function printCFGCode(parser, code, { showCode = true, openCode = false, prefix = 'flowchart BT\n' } = {}) {
30
+ const now = performance.now();
31
+ const res = await getCfg(parser, code);
32
+ const duration = performance.now() - now;
33
+ const metaInfo = `The analysis required _${(0, time_1.printAsMs)(duration)}_ (including the dataflow analysis, normalization, and parsing with the [${parser.name}](${doc_files_1.FlowrWikiBaseRef}/Engines) engine) within the generation environment.`;
34
+ return '\n\n' + printCfg(res.info, res.ast, prefix) + (showCode ? `
35
+ <details${openCode ? ' open' : ''}>
36
+
37
+ <summary style="color:gray">R Code of the CFG</summary>
38
+
39
+ ${metaInfo}
40
+
41
+ ${(0, doc_code_1.codeBlock)('r', code)}
42
+
43
+ </details>
44
+
45
+ ` : '\n(' + metaInfo + ')\n\n');
46
+ }
18
47
  //# sourceMappingURL=doc-cfg.js.map
@@ -4,17 +4,25 @@ exports.codeBlock = codeBlock;
4
4
  exports.codeInline = codeInline;
5
5
  exports.jsonWithLimit = jsonWithLimit;
6
6
  const json_1 = require("../../util/json");
7
+ const environment_1 = require("../../dataflow/environments/environment");
7
8
  function codeBlock(language, code) {
8
9
  return `\n\`\`\`${language}\n${code?.trim() ?? ''}\n\`\`\`\n`;
9
10
  }
10
11
  function codeInline(code) {
11
12
  return `<code>${code}</code>`;
12
13
  }
13
- function jsonWithLimit(object, maxLength = 5_000, tooLongText = '_As the code is pretty long, we inhibit pretty printing and syntax highlighting (JSON):_') {
14
+ function jsonWithLimit(object, maxLength = 5_000, tooLongText = '_As the code is pretty long, we inhibit pretty printing and syntax highlighting (JSON, hiding built-in):_') {
14
15
  const prettyPrinted = JSON.stringify(object, json_1.jsonReplacer, 2);
15
16
  return `
16
17
  ${prettyPrinted.length > maxLength ? tooLongText : ''}
17
- ${codeBlock(prettyPrinted.length > maxLength ? 'text' : 'json', prettyPrinted.length > 5_000 ? JSON.stringify(object, json_1.jsonReplacer) : prettyPrinted)}
18
+ ${codeBlock(prettyPrinted.length > maxLength ? 'text' : 'json', prettyPrinted.length > 5_000 ? JSON.stringify(object, (k, v) => {
19
+ if (typeof v === 'object' && v !== null && 'id' in v && v['id'] === 0 && 'memory' in v && v['memory']) {
20
+ return '<BuiltInEnvironment>';
21
+ }
22
+ else {
23
+ return (0, environment_1.builtInEnvJsonReplacer)(k, v);
24
+ }
25
+ }) : prettyPrinted)}
18
26
  `;
19
27
  }
20
28
  //# sourceMappingURL=doc-code.js.map
@@ -86,7 +86,7 @@ async function printSingleCapability(info, depth, index, capability) {
86
86
  if (capability.url) {
87
87
  nextLine += '\\\nSee ' + (0, strings_1.joinWithLast)(capability.url.map(({ name, href }) => `[${name}](${href})`)) + ' for more info.';
88
88
  }
89
- nextLine += ' Internal ID: `' + capability.id + '`';
89
+ nextLine += ' (internal ID: `' + capability.id + '`)';
90
90
  if (capability.example) {
91
91
  nextLine += `\n${(0, doc_general_1.prefixLines)(typeof capability.example === 'string' ? capability.example : await capability.example(info.parser), nextLineIndent + '> ')}`;
92
92
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const shell_1 = require("../r-bridge/shell");
7
+ const log_1 = require("../../test/functionality/_helper/log");
8
+ const doc_auto_gen_1 = require("./doc-util/doc-auto-gen");
9
+ const doc_code_1 = require("./doc-util/doc-code");
10
+ const doc_types_1 = require("./doc-util/doc-types");
11
+ const path_1 = __importDefault(require("path"));
12
+ const doc_files_1 = require("./doc-util/doc-files");
13
+ const doc_cli_option_1 = require("./doc-util/doc-cli-option");
14
+ const doc_structure_1 = require("./doc-util/doc-structure");
15
+ const doc_issue_1 = require("./doc-util/doc-issue");
16
+ const doc_cfg_1 = require("./doc-util/doc-cfg");
17
+ const visitor_1 = require("../util/cfg/visitor");
18
+ async function getText(shell) {
19
+ const rversion = (await shell.usedRVersion())?.format() ?? 'unknown';
20
+ const types = (0, doc_types_1.getTypesFromFolderAsMermaid)({
21
+ rootFolder: path_1.default.resolve('./src'),
22
+ typeName: 'RNode',
23
+ inlineTypes: doc_types_1.mermaidHide
24
+ });
25
+ return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'control flow graph', rVersion: rversion })}
26
+
27
+ _flowR_ produces two main perspectives of the program: 1) a [normalized version of the AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST)
28
+ and 2) a [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph). However, for further analyses, we also provide an explicit control flow graph
29
+ that is calculated from the normalized AST **and** the dataflow graph to incorporate change in language semantics.
30
+ flowR also uses this CFG for some of its queries (e.g., to link to the last call in a [Call-Context Query](${doc_files_1.FlowrWikiBaseRef}/Query-API))
31
+ but does not incorporate it into its core analysis.
32
+
33
+
34
+ ${(0, doc_structure_1.block)({
35
+ type: 'TIP',
36
+ content: `If you want to investigate the Control Flow Graph,
37
+ you can use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL (see the [Interface wiki page](${doc_files_1.FlowrWikiBaseRef}/Interface) for more information).`
38
+ })}
39
+
40
+ The CFG may be a little bit uncommon compared to the classical CFG with basic blocks. This is mostly due to historical reasons.
41
+ Please [open a new issue](${doc_issue_1.NewIssueUrl}) if you are interested in such a perspective.
42
+
43
+ But for now, let's look at a simple CFG for a program without any branching:
44
+
45
+ ${(0, doc_code_1.codeBlock)('r', 'x <- 2 * 3 + 1')}
46
+
47
+ The corresponding CFG is a directed, labeled graph with two types of edges (control and flow dependencies):
48
+
49
+ ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
50
+
51
+ Every normalized node of the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST) that has any relevance to the
52
+ execution is added and automatically linked using its id (similarly to vertices of the [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph)).
53
+ Higher expressions, such as \`2 * 3\` get an additional node with an artificial id that ends in \`-exit\` to mark whenever their calculation is over.
54
+
55
+ To gain a better understanding, let's have a look at a simple program with a single branching structure:
56
+
57
+ ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
58
+
59
+ Here, you can see the \`if\` node followed by the condition (in this case merely \`u\`) that then splits into two branches for the two possible outcomes.
60
+ The \`if\` structure is terminated by the corresponding \`-exit\` node.
61
+
62
+ For you to compare, the following shows the CFG of an \`if\` without an \`else\` branch:
63
+
64
+ ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
65
+
66
+ The control flow graph also harmonizes with function definitions, and calls:
67
+
68
+ ${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
69
+
70
+ In general, it is probably best to use the ${(0, doc_cli_option_1.getReplCommand)('controlflow*')} command in the REPL to investigate the CFG interactively.
71
+ Have a look at the ${(0, doc_types_1.shortLink)(visitor_1.visitCfgInReverseOrder.name, types.info)} function for a generic CFG visitor.
72
+
73
+ `;
74
+ }
75
+ if (require.main === module) {
76
+ (0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */);
77
+ const shell = new shell_1.RShell();
78
+ void getText(shell).then(str => {
79
+ console.log(str);
80
+ }).finally(() => {
81
+ shell.close();
82
+ });
83
+ }
84
+ //# sourceMappingURL=print-cfg-wiki.js.map
@@ -390,10 +390,10 @@ ${await (0, doc_repl_1.documentReplSession)(shell, [{
390
390
  ### Getting flowR to Talk
391
391
 
392
392
  When using flowR from the CLI, you can use the ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'verbose')} option to get more information about what flowR is doing.
393
- While coding, however, you can use the ${log_1.setMinLevelOfAllLogs.name} function to set the minimum level of logs to be displayed (this works with the ${(0, doc_types_1.shortLink)(log_2.FlowrLogger.name, info)} abstraction).
393
+ While coding, however, you can use the ${(0, doc_types_1.shortLink)(log_1.setMinLevelOfAllLogs.name, info)} function to set the minimum level of logs to be displayed (this works with the ${(0, doc_types_1.shortLink)(log_2.FlowrLogger.name, info)} abstraction).
394
394
  In general, you can configure the levels of individual logs, such as the general \`log\` (obtained with ${(0, doc_types_1.shortLink)('getActiveLog', info)}) or the ${(0, doc_types_1.shortLink)('parseLog', info)}.
395
395
  Please note that flowR makes no guarantees that log outputs are persistent across versions, and it is up to the implementors to provide sensible logging.
396
- If you are an implementor and want to add logging, please make sure that there are no larger runtime impliciations when logging is disabled.
396
+ If you are an implementor and want to add logging, please make sure there are no larger runtime impliciations when logging is disabled.
397
397
  Have a look at the ${(0, doc_types_1.shortLink)(log_2.expensiveTrace.name, info)} function for example, which uses a function to generate the log message only when the log level is reached.
398
398
 
399
399
  `;
@@ -203,12 +203,16 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
203
203
  engines: [{ type: 'r-shell' }],
204
204
  solver: {
205
205
  variables: config_1.VariableResolve.Alias,
206
+ evalStrings: true,
206
207
  pointerTracking: true,
207
208
  resolveSource: {
208
209
  dropPaths: config_1.DropPathsOption.No,
209
210
  ignoreCapitalization: true,
210
211
  inferWorkingDirectory: config_1.InferWorkingDirectory.ActiveScript,
211
212
  searchPath: []
213
+ },
214
+ slicer: {
215
+ threshold: 50
212
216
  }
213
217
  }
214
218
  }, null, 2))}
@@ -62,6 +62,7 @@ It's also possible to filter the results based on the following properties:
62
62
  The \`fileFilter\` property is an object made up of two properties:
63
63
  - **Filter** (\`filter\`): A regular expression that a node's file attribute must match to be considered.
64
64
  - **Include Undefined Files** (\`includeUndefinedFiles\`): If \`fileFilter\` is set, but a node's file attribute is not present, should we include it in the results? Defaults to \`true\`.
65
+ 2. **Ignore Parameter Values** (\`ignoreParameterValues\`): Should we ignore default values for parameters in the results?
65
66
 
66
67
  Re-using the example code from above, the following query attaches all calls to \`mean\` to the kind \`visualize\` and the subkind \`text\`,
67
68
  all calls that start with \`read_\` to the kind \`input\` but only if they are not locally overwritten, and the subkind \`csv-file\`, and links all calls to \`points\` to the last call to \`plot\`:
@@ -122,6 +123,24 @@ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
122
123
  `;
123
124
  }
124
125
  });
126
+ (0, doc_query_1.registerQueryDocumentation)('project', {
127
+ name: 'Project Query',
128
+ type: 'active',
129
+ shortDescription: 'Returns information about the analyzed project',
130
+ functionName: dataflow_query_executor_1.executeDataflowQuery.name,
131
+ functionFile: '../queries/catalog/project-query/project-query-executor.ts',
132
+ buildExplanation: async (shell) => {
133
+ const exampleCode = 'x + 1';
134
+ return `
135
+ This query returns the information about the analyzed project.
136
+ Currently, this is only the list of file paths included.
137
+
138
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
139
+ type: 'project'
140
+ }], { showCode: true, collapseQuery: true })}
141
+ `;
142
+ }
143
+ });
125
144
  (0, doc_query_1.registerQueryDocumentation)('normalized-ast', {
126
145
  name: 'Normalized AST Query',
127
146
  type: 'active',
@@ -405,7 +424,7 @@ print("hello world!")
405
424
  `;
406
425
  return `
407
426
  This query extracts all dependencies from an R script, using a combination of a ${(0, doc_query_1.linkToQueryOfName)('call-context')}
408
- and more advanced tracking in the [Dataflow Graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph).
427
+ and more advanced tracking in the [Dataflow Graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph).
409
428
 
410
429
  In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the loaded library:
411
430
  ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
@@ -428,7 +447,7 @@ In the meantime we offer several properties to overwrite the default behavior (e
428
447
  ${await (0, doc_query_1.showQuery)(shell, longerCode, [{
429
448
  type: 'dependencies',
430
449
  ignoreDefaultFunctions: true,
431
- libraryFunctions: [{ name: 'print', argIdx: 0, argName: 'library', resolveValue: true }],
450
+ libraryFunctions: [{ package: 'base', name: 'print', argIdx: 0, argName: 'library', resolveValue: true }],
432
451
  sourceFunctions: [],
433
452
  readFunctions: [],
434
453
  writeFunctions: []
@@ -464,7 +483,7 @@ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
464
483
  type: 'location-map'
465
484
  }], { showCode: false, collapseQuery: true })}
466
485
 
467
- All locations are given as a ${(0, doc_types_1.shortLink)('SourceRange', types.info)} in the format \`[start-line, start-column, end-line, end-column]\`.
486
+ All locations are given as a ${(0, doc_types_1.shortLink)('SourceRange', types.info)} paired with the file id in the format \`[file-id, [start-line, start-column, end-line, end-column]]\`.
468
487
 
469
488
  `;
470
489
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.2.10",
3
+ "version": "2.2.12",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -33,10 +33,11 @@
33
33
  "wiki:search-api": "ts-node src/documentation/print-search-wiki.ts",
34
34
  "wiki:linting-and-testing": "ts-node src/documentation/print-linting-and-testing-wiki.ts",
35
35
  "wiki:interface": "ts-node src/documentation/print-interface-wiki.ts",
36
+ "wiki:cfg": "ts-node src/documentation/print-cfg-wiki.ts",
36
37
  "gen:readme": "ts-node src/documentation/print-readme.ts",
37
38
  "build": "tsc --project .",
38
39
  "build-dev": "npm run build && npm run build:copy-wasm",
39
- "build:bundle-flowr": "npm run build && esbuild --bundle dist/src/cli/flowr.js --platform=node --bundle --minify --external:clipboardy --target=node22 --outfile=dist/src/cli/flowr.min.js && npm run build:copy-wasm-min",
40
+ "build:bundle-flowr": "npm run build && esbuild --bundle dist/src/cli/flowr.js --platform=node --tree-shaking=true --bundle --minify --external:clipboardy --target=node22 --outfile=dist/src/cli/flowr.min.js && npm run build:copy-wasm-min",
40
41
  "build:copy-wasm": "mkdir -p dist/src/r-bridge/lang-4.x/tree-sitter/ && cp src/r-bridge/lang-4.x/tree-sitter/tree-sitter-r.wasm src/r-bridge/lang-4.x/tree-sitter/tree-sitter.wasm dist/src/r-bridge/lang-4.x/tree-sitter/",
41
42
  "build:copy-wasm-min": "mkdir -p dist/src/cli && cp src/r-bridge/lang-4.x/tree-sitter/tree-sitter-r.wasm src/r-bridge/lang-4.x/tree-sitter/tree-sitter.wasm dist/src/cli",
42
43
  "lint-local": "npx eslint --version && npx eslint src/ test/ --rule \"no-warning-comments: off\"",
@@ -199,12 +200,12 @@
199
200
  "vitest": "^3.0.6"
200
201
  },
201
202
  "dependencies": {
202
- "@msgpack/msgpack": "^3.0.1",
203
203
  "@xmldom/xmldom": "^0.9.7",
204
204
  "clipboardy": "^4.0.0",
205
205
  "command-line-args": "^6.0.1",
206
206
  "command-line-usage": "^7.0.3",
207
207
  "joi": "^17.13.3",
208
+ "lz-string": "^1.5.0",
208
209
  "n-readlines": "^1.0.1",
209
210
  "n3": "^1.23.1",
210
211
  "object-hash": "^3.0.0",
@@ -152,6 +152,16 @@ function doesFilepathMatch(file, filter) {
152
152
  }
153
153
  return filter.filter.test(file);
154
154
  }
155
+ function isParameterDefaultValue(nodeId, ast) {
156
+ let node = ast.idMap.get(nodeId);
157
+ while (node !== undefined) {
158
+ if (node.info.role === "param-value" /* RoleInParent.ParameterDefaultValue */) {
159
+ return true;
160
+ }
161
+ node = node.info.parent ? ast.idMap.get(node.info.parent) : undefined;
162
+ }
163
+ return false;
164
+ }
155
165
  /**
156
166
  * Multi-stage call context query resolve.
157
167
  *
@@ -209,6 +219,9 @@ function executeCallContextQueries({ dataflow: { graph }, ast }, queries) {
209
219
  /* if the call is quoted, we do not want to link to it */
210
220
  continue;
211
221
  }
222
+ else if (query.ignoreParameterValues && isParameterDefaultValue(nodeId, ast)) {
223
+ continue;
224
+ }
212
225
  let linkedIds = undefined;
213
226
  if (cfg && isSubCallQuery(query)) {
214
227
  const linked = Array.isArray(query.linkTo) ? query.linkTo : [query.linkTo];
@@ -41,6 +41,10 @@ export interface DefaultCallContextQueryFormat<RegexType extends RegExp | string
41
41
  * Consider a case like `f <- function_of_interest`, do you want uses of `f` to be included in the results?
42
42
  */
43
43
  readonly includeAliases?: boolean;
44
+ /**
45
+ * Should we ignore default values for parameters in the results?
46
+ */
47
+ readonly ignoreParameterValues?: boolean;
44
48
  /**
45
49
  * Filter that, when set, a node's file attribute must match to be considered
46
50
  */
@@ -32,6 +32,7 @@ exports.CallContextQueryDefinition = {
32
32
  kind: joi_1.default.string().optional().description('The kind of the call, this can be used to group calls together (e.g., linking `plot` to `visualize`). Defaults to `.`'),
33
33
  subkind: joi_1.default.string().optional().description('The subkind of the call, this can be used to uniquely identify the respective call type when grouping the output (e.g., the normalized name, linking `ggplot` to `plot`). Defaults to `.`'),
34
34
  callTargets: joi_1.default.string().valid(...Object.values(identify_link_to_last_call_relation_1.CallTargets)).optional().description('Call targets the function may have. This defaults to `any`. Request this specifically to gain all call targets we can resolve.'),
35
+ ignoreParameterValues: joi_1.default.boolean().optional().description('Should we ignore default values for parameters in the results?'),
35
36
  includeAliases: joi_1.default.boolean().optional().description('Consider a case like `f <- function_of_interest`, do you want uses of `f` to be included in the results?'),
36
37
  fileFilter: joi_1.default.object({
37
38
  fileFilter: joi_1.default.string().required().description('Regex that a node\'s file attribute must match to be considered'),
@@ -109,7 +109,7 @@ function identifyLinkToLastCallRelation(from, cfg, graph, { callName, ignoreIf,
109
109
  if (ignoreIf && ignoreIf(from, graph)) {
110
110
  return found;
111
111
  }
112
- (0, visitor_1.visitInReverseOrder)(cfg, from, node => {
112
+ (0, visitor_1.visitCfgInReverseOrder)(cfg, from, node => {
113
113
  /* we ignore the start id as it cannot be the last call */
114
114
  if (node === from) {
115
115
  return;