@eagleoutice/flowr 2.7.6 → 2.8.0

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 (208) hide show
  1. package/README.md +67 -64
  2. package/cli/wiki.js +1 -1
  3. package/control-flow/extract-cfg.js +3 -3
  4. package/control-flow/useless-loop.d.ts +1 -1
  5. package/control-flow/useless-loop.js +2 -2
  6. package/dataflow/cluster.js +3 -3
  7. package/dataflow/environments/built-in-config.d.ts +8 -4
  8. package/dataflow/environments/built-in.d.ts +27 -14
  9. package/dataflow/environments/built-in.js +27 -12
  10. package/dataflow/environments/default-builtin-config.d.ts +614 -3
  11. package/dataflow/environments/default-builtin-config.js +50 -15
  12. package/dataflow/environments/environment.js +3 -2
  13. package/dataflow/environments/identifier.d.ts +5 -1
  14. package/dataflow/environments/reference-to-maybe.d.ts +2 -2
  15. package/dataflow/environments/reference-to-maybe.js +23 -14
  16. package/dataflow/environments/resolve-by-name.d.ts +6 -2
  17. package/dataflow/environments/resolve-by-name.js +5 -1
  18. package/dataflow/environments/scoping.js +1 -3
  19. package/dataflow/eval/resolve/alias-tracking.js +5 -1
  20. package/dataflow/extractor.js +3 -3
  21. package/dataflow/fn/exceptions-of-function.d.ts +13 -0
  22. package/dataflow/fn/exceptions-of-function.js +47 -0
  23. package/dataflow/fn/higher-order-function.d.ts +1 -1
  24. package/dataflow/fn/higher-order-function.js +3 -3
  25. package/dataflow/fn/recursive-function.d.ts +6 -0
  26. package/dataflow/fn/recursive-function.js +32 -0
  27. package/dataflow/graph/call-graph.d.ts +10 -0
  28. package/dataflow/graph/call-graph.js +209 -0
  29. package/dataflow/graph/dataflowgraph-builder.d.ts +7 -2
  30. package/dataflow/graph/dataflowgraph-builder.js +14 -9
  31. package/dataflow/graph/diff-dataflow-graph.js +96 -2
  32. package/dataflow/graph/graph.d.ts +10 -7
  33. package/dataflow/graph/graph.js +7 -8
  34. package/dataflow/graph/vertex.d.ts +6 -3
  35. package/dataflow/hooks.d.ts +30 -0
  36. package/dataflow/hooks.js +38 -0
  37. package/dataflow/info.d.ts +28 -5
  38. package/dataflow/info.js +66 -31
  39. package/dataflow/internal/linker.d.ts +13 -3
  40. package/dataflow/internal/linker.js +155 -53
  41. package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +4 -0
  42. package/dataflow/internal/process/functions/call/argument/unpack-argument.js +7 -0
  43. package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +1 -1
  44. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +19 -3
  45. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +14 -0
  46. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +30 -0
  47. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -1
  48. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +24 -17
  49. package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +2 -1
  50. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +5 -1
  51. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +59 -21
  52. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -3
  53. package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.d.ts +34 -0
  54. package/dataflow/internal/process/functions/call/built-in/built-in-register-hook.js +92 -0
  55. package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
  56. package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.d.ts +21 -0
  57. package/dataflow/internal/process/functions/call/built-in/built-in-stop-if-not.js +129 -0
  58. package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.d.ts +16 -0
  59. package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +127 -0
  60. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +5 -3
  61. package/dataflow/internal/process/functions/call/common.d.ts +13 -1
  62. package/dataflow/internal/process/functions/call/common.js +33 -2
  63. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +13 -1
  64. package/dataflow/internal/process/functions/call/known-call-handling.js +29 -3
  65. package/dataflow/internal/process/functions/call/named-call-handling.js +2 -1
  66. package/dataflow/internal/process/functions/call/unnamed-call-handling.js +6 -4
  67. package/dataflow/internal/process/functions/process-argument.js +7 -6
  68. package/dataflow/internal/process/functions/process-parameter.js +2 -1
  69. package/dataflow/internal/process/process-named-call.d.ts +2 -2
  70. package/dataflow/internal/process/process-symbol.js +3 -2
  71. package/dataflow/internal/process/process-value.d.ts +3 -2
  72. package/dataflow/internal/process/process-value.js +8 -6
  73. package/dataflow/origin/dfg-get-origin.js +2 -1
  74. package/dataflow/origin/dfg-get-symbol-refs.js +1 -1
  75. package/documentation/doc-readme.d.ts +1 -1
  76. package/documentation/doc-readme.js +6 -6
  77. package/documentation/doc-util/doc-code.js +1 -1
  78. package/documentation/doc-util/doc-dfg.d.ts +1 -0
  79. package/documentation/doc-util/doc-dfg.js +7 -4
  80. package/documentation/doc-util/doc-query.d.ts +1 -0
  81. package/documentation/doc-util/doc-query.js +1 -1
  82. package/documentation/doc-util/doc-repl.d.ts +2 -1
  83. package/documentation/doc-util/doc-repl.js +11 -3
  84. package/documentation/wiki-analyzer.js +2 -0
  85. package/documentation/wiki-dataflow-graph.js +59 -16
  86. package/documentation/wiki-interface.js +33 -5
  87. package/documentation/wiki-mk/doc-context.d.ts +2 -1
  88. package/documentation/wiki-mk/doc-context.js +2 -2
  89. package/documentation/wiki-mk/doc-maker.js +4 -3
  90. package/documentation/wiki-normalized-ast.js +6 -0
  91. package/documentation/wiki-query.js +109 -1
  92. package/linter/linter-rules.d.ts +1 -1
  93. package/linter/rules/seeded-randomness.js +17 -12
  94. package/linter/rules/useless-loop.d.ts +1 -1
  95. package/package.json +9 -9
  96. package/project/cache/flowr-analyzer-cache.d.ts +11 -0
  97. package/project/cache/flowr-analyzer-cache.js +19 -0
  98. package/project/context/flowr-analyzer-dependencies-context.d.ts +6 -1
  99. package/project/context/flowr-analyzer-dependencies-context.js +6 -0
  100. package/project/context/flowr-analyzer-files-context.d.ts +5 -2
  101. package/project/context/flowr-analyzer-files-context.js +24 -17
  102. package/project/context/flowr-file.d.ts +9 -4
  103. package/project/context/flowr-file.js +20 -6
  104. package/project/flowr-analyzer.d.ts +11 -0
  105. package/project/flowr-analyzer.js +6 -0
  106. package/project/plugins/file-plugins/files/flowr-description-file.d.ts +8 -0
  107. package/project/plugins/file-plugins/files/flowr-description-file.js +36 -3
  108. package/project/plugins/file-plugins/files/flowr-jupyter-file.js +1 -1
  109. package/project/plugins/file-plugins/files/flowr-namespace-file.js +1 -1
  110. package/project/plugins/file-plugins/files/flowr-news-file.js +1 -1
  111. package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +1 -1
  112. package/project/plugins/file-plugins/flowr-analyzer-description-file-plugin.js +1 -1
  113. package/project/plugins/file-plugins/flowr-analyzer-file-plugin.d.ts +4 -1
  114. package/project/plugins/file-plugins/flowr-analyzer-file-plugin.js +3 -0
  115. package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.d.ts → flowr-analyzer-namespace-files-plugin.d.ts} +1 -1
  116. package/project/plugins/file-plugins/{flowr-analyzer-namespace-file-plugin.js → flowr-analyzer-namespace-files-plugin.js} +4 -4
  117. package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.d.ts +26 -0
  118. package/project/plugins/file-plugins/flowr-analyzer-test-file-plugin.js +39 -0
  119. package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.d.ts +26 -0
  120. package/project/plugins/file-plugins/flowr-analyzer-vignette-file-plugin.js +39 -0
  121. package/project/plugins/flowr-analyzer-plugin-defaults.js +6 -2
  122. package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +3 -13
  123. package/project/plugins/package-version-plugins/package.d.ts +1 -1
  124. package/project/plugins/package-version-plugins/package.js +3 -3
  125. package/project/plugins/plugin-registry.d.ts +4 -2
  126. package/project/plugins/plugin-registry.js +6 -2
  127. package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.d.ts +11 -0
  128. package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +5 -2
  129. package/queries/catalog/call-context-query/call-context-query-format.d.ts +4 -12
  130. package/queries/catalog/call-graph-query/call-graph-query-executor.d.ts +6 -0
  131. package/queries/catalog/call-graph-query/call-graph-query-executor.js +21 -0
  132. package/queries/catalog/call-graph-query/call-graph-query-format.d.ts +21 -0
  133. package/queries/catalog/call-graph-query/call-graph-query-format.js +32 -0
  134. package/queries/catalog/dataflow-query/dataflow-query-executor.js +4 -3
  135. package/queries/catalog/dependencies-query/dependencies-query-executor.js +29 -3
  136. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
  137. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +8 -1
  138. package/queries/catalog/dependencies-query/function-info/write-functions.js +13 -0
  139. package/queries/catalog/does-call-query/does-call-query-executor.d.ts +6 -0
  140. package/queries/catalog/does-call-query/does-call-query-executor.js +100 -0
  141. package/queries/catalog/does-call-query/does-call-query-format.d.ts +51 -0
  142. package/queries/catalog/does-call-query/does-call-query-format.js +102 -0
  143. package/queries/catalog/files-query/files-query-executor.js +4 -4
  144. package/queries/catalog/files-query/files-query-format.d.ts +2 -1
  145. package/queries/catalog/files-query/files-query-format.js +18 -2
  146. package/queries/catalog/id-map-query/id-map-query-executor.js +4 -3
  147. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.d.ts +18 -0
  148. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-executor.js +56 -0
  149. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +34 -0
  150. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.js +54 -0
  151. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-executor.js +3 -28
  152. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +6 -0
  153. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.js +12 -0
  154. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.d.ts +6 -0
  155. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-executor.js +23 -0
  156. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +28 -0
  157. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.js +44 -0
  158. package/queries/catalog/linter-query/linter-query-format.js +4 -1
  159. package/queries/catalog/location-map-query/location-map-query-executor.js +1 -1
  160. package/queries/catalog/normalized-ast-query/normalized-ast-query-executor.js +4 -3
  161. package/queries/catalog/project-query/project-query-executor.js +9 -3
  162. package/queries/catalog/project-query/project-query-format.d.ts +6 -1
  163. package/queries/catalog/project-query/project-query-format.js +35 -9
  164. package/queries/query.d.ts +34 -2
  165. package/queries/query.js +9 -0
  166. package/r-bridge/data/data.d.ts +10 -5
  167. package/r-bridge/data/data.js +11 -5
  168. package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -7
  169. package/r-bridge/lang-4.x/ast/model/nodes/r-access.d.ts +2 -2
  170. package/r-bridge/lang-4.x/ast/model/nodes/r-argument.d.ts +2 -2
  171. package/r-bridge/lang-4.x/ast/model/nodes/r-binary-op.d.ts +2 -2
  172. package/r-bridge/lang-4.x/ast/model/nodes/r-comment.d.ts +5 -2
  173. package/r-bridge/lang-4.x/ast/model/nodes/r-comment.js +8 -0
  174. package/r-bridge/lang-4.x/ast/model/nodes/r-expression-list.d.ts +2 -2
  175. package/r-bridge/lang-4.x/ast/model/nodes/r-for-loop.d.ts +2 -2
  176. package/r-bridge/lang-4.x/ast/model/nodes/r-function-call.d.ts +3 -3
  177. package/r-bridge/lang-4.x/ast/model/nodes/r-function-definition.d.ts +2 -2
  178. package/r-bridge/lang-4.x/ast/model/nodes/r-if-then-else.d.ts +2 -2
  179. package/r-bridge/lang-4.x/ast/model/nodes/r-parameter.d.ts +2 -2
  180. package/r-bridge/lang-4.x/ast/model/nodes/r-pipe.d.ts +2 -2
  181. package/r-bridge/lang-4.x/ast/model/nodes/r-repeat-loop.d.ts +2 -2
  182. package/r-bridge/lang-4.x/ast/model/nodes/r-unary-op.d.ts +2 -2
  183. package/r-bridge/lang-4.x/ast/model/nodes/r-while-loop.d.ts +2 -2
  184. package/r-bridge/lang-4.x/ast/parser/main/internal/other/normalize-comment.js +0 -1
  185. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +0 -2
  186. package/r-bridge/roxygen2/roxygen-ast.d.ts +218 -0
  187. package/r-bridge/roxygen2/roxygen-ast.js +82 -0
  188. package/r-bridge/roxygen2/roxygen-parse.d.ts +24 -0
  189. package/r-bridge/roxygen2/roxygen-parse.js +214 -0
  190. package/reconstruct/auto-select/magic-comments.js +4 -4
  191. package/slicing/static/slice-call.js +3 -4
  192. package/slicing/static/static-slicer.js +2 -2
  193. package/statistics/features/supported/defined-functions/defined-functions.js +1 -1
  194. package/util/collections/defaultmap.d.ts +3 -3
  195. package/util/mermaid/dfg.js +5 -5
  196. package/util/objects.js +1 -1
  197. package/util/r-author.d.ts +5 -0
  198. package/util/r-author.js +110 -0
  199. package/util/r-license.d.ts +10 -1
  200. package/util/r-license.js +27 -6
  201. package/util/r-version.d.ts +19 -0
  202. package/util/r-version.js +106 -0
  203. package/util/range.d.ts +6 -0
  204. package/util/range.js +7 -0
  205. package/util/simple-df/dfg-ascii.js +2 -2
  206. package/util/text/args.d.ts +9 -0
  207. package/util/text/args.js +65 -0
  208. package/util/version.js +1 -1
@@ -35,6 +35,21 @@ function processApply(name, args, rootId, data, config) {
35
35
  index = mayFn;
36
36
  }
37
37
  }
38
+ // shift the index to point to the index'd unnamed argument
39
+ let posArgsFound = 0;
40
+ for (let i = 0; i < args.length; i++) {
41
+ const arg = args[i];
42
+ if (arg !== r_function_call_1.EmptyArgument && arg.name) {
43
+ // do nothing
44
+ }
45
+ else if (posArgsFound === index) {
46
+ index = i;
47
+ break;
48
+ }
49
+ else {
50
+ posArgsFound++;
51
+ }
52
+ }
38
53
  /* validate, that we indeed have so many arguments to fill this one :D */
39
54
  if (index >= args.length) {
40
55
  logger_1.dataflowLogger.warn(`Function argument at index ${index} not found, skipping`);
@@ -62,7 +77,8 @@ function processApply(name, args, rootId, data, config) {
62
77
  if (resolveValue) {
63
78
  const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: data.environment, idMap: data.completeAst.idMap, resolve: data.ctx.config.solver.variables, ctx: data.ctx }));
64
79
  if (resolved?.elements.length === 1 && resolved.elements[0].type === 'string') {
65
- functionName = (0, r_value_1.isValue)(resolved.elements[0].value) ? resolved.elements[0].value.str : undefined;
80
+ const r = resolved.elements[0];
81
+ functionName = (0, r_value_1.isValue)(r.value) ? r.value.str : undefined;
66
82
  }
67
83
  }
68
84
  else {
@@ -102,7 +118,7 @@ function processApply(name, args, rootId, data, config) {
102
118
  name: functionName,
103
119
  /* can never be a direct built-in-call */
104
120
  onlyBuiltin: false,
105
- cds: data.controlDependencies,
121
+ controlDependencies: data.controlDependencies,
106
122
  args: allOtherArguments, // same reference
107
123
  origin: ['function']
108
124
  }, data.ctx.env.makeCleanEnv());
@@ -151,7 +167,7 @@ function processApply(name, args, rootId, data, config) {
151
167
  args: allOtherArguments,
152
168
  environment: resolveInEnvironment === 'global' ? undefined : data.environment,
153
169
  onlyBuiltin: resolveInEnvironment === 'global',
154
- cds: data.controlDependencies,
170
+ controlDependencies: data.controlDependencies,
155
171
  origin: ['function']
156
172
  });
157
173
  }
@@ -22,6 +22,20 @@ export interface AssignmentConfiguration extends ForceArguments {
22
22
  readonly indicesCollection?: ContainerIndicesCollection;
23
23
  readonly mayHaveMoreArgs?: boolean;
24
24
  }
25
+ export interface ExtendedAssignmentConfiguration extends AssignmentConfiguration {
26
+ readonly source: {
27
+ idx?: number;
28
+ name: string;
29
+ };
30
+ readonly target: {
31
+ idx?: number;
32
+ name: string;
33
+ };
34
+ }
35
+ /**
36
+ * In contrast to `processAssignment`, this function allows more flexible handling of assignment-like functions.
37
+ */
38
+ export declare function processAssignmentLike<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: ExtendedAssignmentConfiguration): DataflowInformation;
25
39
  /**
26
40
  * Processes an assignment, i.e., `<target> <- <source>`.
27
41
  * Handling it as a function call \`&lt;-\` `(<target>, <source>)`.
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processAssignmentLike = processAssignmentLike;
3
4
  exports.processAssignment = processAssignment;
4
5
  exports.markAsAssignment = markAsAssignment;
5
6
  const known_call_handling_1 = require("../known-call-handling");
@@ -8,6 +9,7 @@ const unpack_argument_1 = require("../argument/unpack-argument");
8
9
  const process_named_call_1 = require("../../../process-named-call");
9
10
  const make_argument_1 = require("../argument/make-argument");
10
11
  const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
12
+ const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
11
13
  const logger_1 = require("../../../../../logger");
12
14
  const identifier_1 = require("../../../../../environments/identifier");
13
15
  const overwrite_1 = require("../../../../../environments/overwrite");
@@ -69,6 +71,30 @@ function tryReplacementPassingIndices(rootId, functionName, data, name, args, in
69
71
  (0, named_call_handling_1.markAsOnlyBuiltIn)(info.graph, functionName.info.id);
70
72
  return info;
71
73
  }
74
+ /**
75
+ * In contrast to `processAssignment`, this function allows more flexible handling of assignment-like functions.
76
+ */
77
+ function processAssignmentLike(name,
78
+ /* we expect them to be ordered in the sense that we have (source, target): `<source> <- <target>` */
79
+ args, rootId, data, config) {
80
+ const argsWithNames = new Map();
81
+ const argsWithoutNames = [];
82
+ for (const arg of args) {
83
+ const name = arg !== r_function_call_1.EmptyArgument ? arg.name?.content : undefined;
84
+ if (name !== undefined) {
85
+ argsWithNames.set(name, arg);
86
+ }
87
+ else {
88
+ argsWithoutNames.push(arg);
89
+ }
90
+ }
91
+ const source = argsWithNames.get(config.source.name) ?? (config.source.idx !== undefined ? argsWithoutNames[config.source.idx] : undefined);
92
+ const target = argsWithNames.get(config.target.name) ?? (config.target.idx !== undefined ? argsWithoutNames[config.target.idx] : undefined);
93
+ if (source && target) {
94
+ args = [target, source];
95
+ }
96
+ return processAssignment(name, args, rootId, data, { ...config, mayHaveMoreArgs: true });
97
+ }
72
98
  /**
73
99
  * Processes an assignment, i.e., `<target> <- <source>`.
74
100
  * Handling it as a function call \`&lt;-\` `(<target>, <source>)`.
@@ -338,6 +364,10 @@ function processAssignmentToSymbol(config) {
338
364
  if (quoteSource) {
339
365
  information.graph.addEdge(rootId, source.info.id, edge_1.EdgeType.NonStandardEvaluation);
340
366
  }
367
+ else {
368
+ // we read the source
369
+ information.graph.addEdge(rootId, source.info.id, edge_1.EdgeType.Reads);
370
+ }
341
371
  return {
342
372
  ...information,
343
373
  unknownReferences: [],
@@ -53,7 +53,7 @@ function processEvalCall(name, args, rootId, data, config) {
53
53
  result.push(r);
54
54
  // add a returns edge from the eval to the result
55
55
  for (const e of r.exitPoints) {
56
- information.graph.addEdge(rootId, e, edge_1.EdgeType.Returns);
56
+ information.graph.addEdge(rootId, e.nodeId, edge_1.EdgeType.Returns);
57
57
  }
58
58
  }
59
59
  return {
@@ -64,6 +64,7 @@ function processEvalCall(name, args, rootId, data, config) {
64
64
  in: information.in.concat(result.flatMap(r => r.in)),
65
65
  unknownReferences: information.unknownReferences.concat(result.flatMap(r => r.unknownReferences)),
66
66
  exitPoints: information.exitPoints.concat(result.flatMap(r => r.exitPoints)),
67
+ hooks: information.hooks.concat(result.flatMap(r => r.hooks)),
67
68
  };
68
69
  }
69
70
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(args)} for eval is currently not supported, skipping`);
@@ -47,12 +47,6 @@ function linkReadNameToWriteIfPossible(read, environments, listEnvironments, rem
47
47
  }
48
48
  }
49
49
  }
50
- function processNextExpression(currentElement, environment, listEnvironments, remainingRead, nextGraph) {
51
- // all inputs that have not been written until now are read!
52
- for (const read of currentElement.in.concat(currentElement.unknownReferences)) {
53
- linkReadNameToWriteIfPossible(read, environment, listEnvironments, remainingRead, nextGraph);
54
- }
55
- }
56
50
  function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextGraph, localDefs) {
57
51
  for (const { functionCall, called } of calledEnvs) {
58
52
  let callDependencies = null;
@@ -87,7 +81,7 @@ function updateSideEffectsForCalledFunctions(calledEnvs, inputEnvironment, nextG
87
81
  };
88
82
  }
89
83
  if (callDependencies === null) {
90
- callDependencies = nextGraph.getVertex(functionCall, true)?.cds;
84
+ callDependencies = nextGraph.getVertex(functionCall, true)?.controlDependencies;
91
85
  }
92
86
  inputEnvironment = (0, overwrite_1.overwriteEnvironment)(inputEnvironment, environment, callDependencies);
93
87
  }
@@ -108,11 +102,11 @@ function processExpressionList(name, args, rootId, data) {
108
102
  const nextGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
109
103
  let out = [];
110
104
  const exitPoints = [];
111
- let expressionCounter = 0;
105
+ const activeCdsAtStart = data.controlDependencies;
106
+ const invertExitCds = [];
112
107
  const processedExpressions = [];
113
108
  let defaultReturnExpr = undefined;
114
109
  for (const expression of expressions) {
115
- (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `processing expression ${++expressionCounter} of ${expressions.length}`);
116
110
  if (expression === undefined) {
117
111
  processedExpressions.push(undefined);
118
112
  continue;
@@ -126,16 +120,25 @@ function processExpressionList(name, args, rootId, data) {
126
120
  // if the expression contained next or break anywhere before the next loop, the "overwrite" should be an "append", because we do not know if the rest is executed
127
121
  // update the environments for the next iteration with the previous writes
128
122
  if (exitPoints.length > 0) {
129
- processed.out = (0, reference_to_maybe_1.makeAllMaybe)(processed.out, nextGraph, processed.environment, true);
130
- processed.in = (0, reference_to_maybe_1.makeAllMaybe)(processed.in, nextGraph, processed.environment, false);
123
+ processed.out = (0, reference_to_maybe_1.makeAllMaybe)(processed.out, nextGraph, processed.environment, true, invertExitCds);
124
+ processed.in = (0, reference_to_maybe_1.makeAllMaybe)(processed.in, nextGraph, processed.environment, false, invertExitCds);
131
125
  processed.unknownReferences = (0, reference_to_maybe_1.makeAllMaybe)(processed.unknownReferences, nextGraph, processed.environment, false);
132
126
  }
133
- (0, info_1.addNonDefaultExitPoints)(exitPoints, processed.exitPoints);
134
127
  out = out.concat(processed.out);
135
- (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `expression ${expressionCounter} of ${expressions.length} has ${processed.unknownReferences.length} unknown nodes`);
136
- processNextExpression(processed, environment, listEnvironments, remainingRead, nextGraph);
137
- environment = exitPoints.length > 0 ? (0, overwrite_1.overwriteEnvironment)(environment, processed.environment) : processed.environment;
128
+ // all inputs that have not been written until now are read!
129
+ for (const read of processed.in.concat(processed.unknownReferences)) {
130
+ linkReadNameToWriteIfPossible(read, environment, listEnvironments, remainingRead, nextGraph);
131
+ }
138
132
  const calledEnvs = (0, linker_1.linkFunctionCalls)(nextGraph, data.completeAst.idMap, processed.graph);
133
+ for (const c of calledEnvs) {
134
+ if (c.propagateExitPoints.length > 0) {
135
+ for (const exit of c.propagateExitPoints) {
136
+ processed.exitPoints.push(exit);
137
+ }
138
+ }
139
+ }
140
+ (0, info_1.addNonDefaultExitPoints)(exitPoints, invertExitCds, activeCdsAtStart, processed.exitPoints);
141
+ environment = exitPoints.length > 0 ? (0, overwrite_1.overwriteEnvironment)(environment, processed.environment) : processed.environment;
139
142
  // if the called function has global redefinitions, we have to keep them within our environment
140
143
  environment = updateSideEffectsForCalledFunctions(calledEnvs, environment, nextGraph, processed.out);
141
144
  for (const { nodeId } of processed.out) {
@@ -149,10 +152,13 @@ function processExpressionList(name, args, rootId, data) {
149
152
  }
150
153
  }
151
154
  if (defaultReturnExpr) {
152
- exitPoints.push({
155
+ exitPoints.push(data.controlDependencies ? {
153
156
  type: 0 /* ExitPointType.Default */,
154
157
  nodeId: defaultReturnExpr.entryPoint,
155
158
  controlDependencies: data.controlDependencies
159
+ } : {
160
+ type: 0 /* ExitPointType.Default */,
161
+ nodeId: defaultReturnExpr.entryPoint
156
162
  });
157
163
  }
158
164
  const ingoing = remainingRead.values().toArray().flat();
@@ -186,7 +192,8 @@ function processExpressionList(name, args, rootId, data) {
186
192
  graph: nextGraph,
187
193
  /* if we have no group, we take the last evaluated expr */
188
194
  entryPoint: meId,
189
- exitPoints: exitPoints
195
+ exitPoints: exitPoints,
196
+ hooks: processedExpressions.flatMap(p => p?.hooks ?? []),
190
197
  };
191
198
  }
192
199
  //# sourceMappingURL=built-in-expression-list.js.map
@@ -73,7 +73,8 @@ function processForLoop(name, args, rootId, data) {
73
73
  graph: nextGraph,
74
74
  entryPoint: name.info.id,
75
75
  exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
76
- environment: outEnvironment
76
+ environment: outEnvironment,
77
+ hooks: variable.hooks.concat(vector.hooks, body.hooks),
77
78
  };
78
79
  }
79
80
  //# sourceMappingURL=built-in-for-loop.js.map
@@ -12,7 +12,11 @@ import type { ReadOnlyFlowrAnalyzerContext } from '../../../../../../project/con
12
12
  */
13
13
  export declare function processFunctionDefinition<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;
14
14
  /**
15
- *
15
+ * Retrieve the active environment when entering a function definition or call
16
+ * @param callerEnvironment - environment at the call site / function definition site
17
+ * @param baseEnvironment - base environment within the function definition / call
18
+ * @param ctx - analyzer context
19
+ * @returns active environment within the function definition / call
16
20
  */
17
21
  export declare function retrieveActiveEnvironment(callerEnvironment: REnvironmentInformation | undefined, baseEnvironment: REnvironmentInformation, ctx: ReadOnlyFlowrAnalyzerContext): REnvironmentInformation;
18
22
  /**
@@ -5,6 +5,7 @@ exports.retrieveActiveEnvironment = retrieveActiveEnvironment;
5
5
  exports.updateNestedFunctionClosures = updateNestedFunctionClosures;
6
6
  exports.updateNestedFunctionCalls = updateNestedFunctionCalls;
7
7
  const processor_1 = require("../../../../../processor");
8
+ const info_1 = require("../../../../../info");
8
9
  const linker_1 = require("../../../../linker");
9
10
  const known_call_handling_1 = require("../known-call-handling");
10
11
  const unpack_argument_1 = require("../argument/unpack-argument");
@@ -20,6 +21,8 @@ const resolve_by_name_1 = require("../../../../../environments/resolve-by-name")
20
21
  const edge_1 = require("../../../../../graph/edge");
21
22
  const log_1 = require("../../../../../../util/log");
22
23
  const built_in_1 = require("../../../../../environments/built-in");
24
+ const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
25
+ const hooks_1 = require("../../../../../hooks");
23
26
  /**
24
27
  * Process a function definition, i.e., `function(a, b) { ... }`
25
28
  */
@@ -31,19 +34,23 @@ function processFunctionDefinition(name, args, rootId, data) {
31
34
  /* we remove the last argument, as it is the body */
32
35
  const parameters = args.slice(0, -1);
33
36
  const bodyArg = (0, unpack_argument_1.unpackNonameArg)(args[args.length - 1]);
34
- (0, assert_1.guard)(bodyArg !== undefined, () => `Function Definition ${JSON.stringify(args)} has missing body! This is bad!`);
37
+ (0, assert_1.guard)(bodyArg !== undefined, () => `Function Definition ${JSON.stringify(args)} has no body! This is bad!`);
35
38
  const originalEnvironment = data.environment;
36
39
  // within a function def we do not pass on the outer binds as they could be overwritten when called
37
40
  data = prepareFunctionEnvironment(data);
38
41
  const subgraph = new graph_1.DataflowGraph(data.completeAst.idMap);
39
42
  let readInParameters = [];
43
+ const paramIds = [];
40
44
  for (const param of parameters) {
41
- (0, assert_1.guard)(param !== r_function_call_1.EmptyArgument, () => `Empty argument in function definition ${name.content}, ${JSON.stringify(args)}`);
45
+ (0, assert_1.guard)(param !== r_function_call_1.EmptyArgument, () => `Empty param arg in function definition ${name.content}, ${JSON.stringify(args)}`);
42
46
  const processed = (0, processor_1.processDataflowFor)(param, data);
47
+ if (param.value?.type === type_1.RType.Parameter) {
48
+ paramIds.push(param.value.name.info.id);
49
+ }
43
50
  subgraph.mergeWith(processed.graph);
44
51
  const read = processed.in.concat(processed.unknownReferences);
45
52
  (0, linker_1.linkInputs)(read, data.environment, readInParameters, subgraph, false);
46
- data = { ...data, environment: (0, overwrite_1.overwriteEnvironment)(data.environment, processed.environment) };
53
+ data.environment = (0, overwrite_1.overwriteEnvironment)(data.environment, processed.environment);
47
54
  }
48
55
  const paramsEnvironments = data.environment;
49
56
  const body = (0, processor_1.processDataflowFor)(bodyArg, data);
@@ -51,7 +58,7 @@ function processFunctionDefinition(name, args, rootId, data) {
51
58
  // This is the correct behavior, even if someone uses non-`=` arguments in functions.
52
59
  const bodyEnvironment = body.environment;
53
60
  readInParameters = findPromiseLinkagesForParameters(subgraph, readInParameters, paramsEnvironments, body);
54
- const readInBody = [...body.in, ...body.unknownReferences];
61
+ const readInBody = body.in.concat(body.unknownReferences);
55
62
  // there is no uncertainty regarding the arguments, as if a function header is executed, so is its body
56
63
  const remainingRead = (0, linker_1.linkInputs)(readInBody, paramsEnvironments, readInParameters.slice(), body.graph, true /* functions do not have to be called */);
57
64
  // functions can be called multiple times,
@@ -59,7 +66,7 @@ function processFunctionDefinition(name, args, rootId, data) {
59
66
  /* theoretically, we should just check if there is a global effect-write somewhere within */
60
67
  if (remainingRead.length > 0) {
61
68
  const nameIdShares = (0, linker_1.produceNameSharedIdMap)(remainingRead);
62
- const definedInLocalEnvironment = new Set([...bodyEnvironment.current.memory.values()].flat().map(d => d.nodeId));
69
+ const definedInLocalEnvironment = new Set(Array.from(bodyEnvironment.current.memory.values()).flat().map(d => d.nodeId));
63
70
  // Everything that is in body.out but not within the local environment populated for the function scope is a potential escape ~> global definition
64
71
  const globalBodyOut = body.out.filter(d => !definedInLocalEnvironment.has(d.nodeId));
65
72
  (0, linker_1.linkCircularRedefinitionsWithinALoop)(body.graph, nameIdShares, globalBodyOut);
@@ -72,28 +79,50 @@ function processFunctionDefinition(name, args, rootId, data) {
72
79
  tag: vertex_1.VertexType.Use,
73
80
  id: read.nodeId,
74
81
  environment: undefined,
75
- cds: undefined
82
+ controlDependencies: undefined
76
83
  }, data.ctx.env.makeCleanEnv());
77
84
  }
78
85
  }
86
+ const compactedHooks = (0, hooks_1.compactHookStates)(body.hooks);
87
+ const exitHooks = (0, hooks_1.getHookInformation)(compactedHooks, hooks_1.KnownHooks.OnFnExit);
79
88
  const flow = {
80
89
  unknownReferences: [],
81
90
  in: remainingRead,
82
91
  out: [],
83
92
  entryPoint: body.entryPoint,
84
93
  graph: new Set(subgraph.rootIds()),
85
- environment: outEnvironment
94
+ environment: outEnvironment,
95
+ hooks: compactedHooks
86
96
  };
87
97
  updateNestedFunctionClosures(subgraph, outEnvironment, name.info.id);
88
98
  const exitPoints = body.exitPoints;
99
+ const readParams = {};
100
+ for (const paramId of paramIds) {
101
+ const ingoing = subgraph.ingoingEdges(paramId);
102
+ readParams[paramId] = ingoing?.values().some(({ types }) => (0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.Reads)) ?? false;
103
+ }
104
+ let afterHookExitPoints = exitPoints?.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 0 /* ExitPointType.Default */ || e.type === 4 /* ExitPointType.Error */) ?? [];
105
+ for (const hook of exitHooks) {
106
+ const vert = subgraph.getVertex(hook.id);
107
+ if (vert?.tag !== vertex_1.VertexType.FunctionDefinition) {
108
+ continue;
109
+ }
110
+ // call all hooks
111
+ subgraph.addEdge(rootId, hook.id, edge_1.EdgeType.Calls);
112
+ const hookExitPoints = vert.exitPoints.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 4 /* ExitPointType.Error */);
113
+ if (hookExitPoints.length > 0) {
114
+ afterHookExitPoints = (0, info_1.overwriteExitPoints)(afterHookExitPoints, hookExitPoints);
115
+ }
116
+ }
89
117
  const graph = new graph_1.DataflowGraph(data.completeAst.idMap).mergeWith(subgraph, false);
90
118
  graph.addVertex({
91
119
  tag: vertex_1.VertexType.FunctionDefinition,
92
120
  id: name.info.id,
93
121
  environment: (0, scoping_1.popLocalEnvironment)(outEnvironment),
94
- cds: data.controlDependencies,
122
+ controlDependencies: data.controlDependencies,
123
+ params: readParams,
95
124
  subflow: flow,
96
- exitPoints: exitPoints?.filter(e => e.type === 1 /* ExitPointType.Return */ || e.type === 0 /* ExitPointType.Default */).map(e => e.nodeId) ?? []
125
+ exitPoints: afterHookExitPoints
97
126
  }, data.ctx.env.makeCleanEnv());
98
127
  return {
99
128
  /* nothing escapes a function definition, but the function itself, will be forced in assignment: { nodeId: functionDefinition.info.id, scope: data.activeScope, used: 'always', name: functionDefinition.info.id as string } */
@@ -103,13 +132,16 @@ function processFunctionDefinition(name, args, rootId, data) {
103
132
  exitPoints: [],
104
133
  entryPoint: name.info.id,
105
134
  graph,
106
- environment: originalEnvironment
135
+ environment: originalEnvironment,
136
+ hooks: []
107
137
  };
108
138
  }
109
- // this is no longer necessary when we update environments to be back to front (e.g., with a list of environments)
110
- // this favors the bigger environment
111
139
  /**
112
- *
140
+ * Retrieve the active environment when entering a function definition or call
141
+ * @param callerEnvironment - environment at the call site / function definition site
142
+ * @param baseEnvironment - base environment within the function definition / call
143
+ * @param ctx - analyzer context
144
+ * @returns active environment within the function definition / call
113
145
  */
114
146
  function retrieveActiveEnvironment(callerEnvironment, baseEnvironment, ctx) {
115
147
  callerEnvironment ??= ctx.env.makeCleanEnv();
@@ -168,9 +200,10 @@ function updateNestedFunctionCalls(graph, outEnvironment) {
168
200
  // track *all* function definitions - including those nested within the current graph,
169
201
  // try to resolve their 'in' by only using the lowest scope which will be popped after this definition
170
202
  for (const [id, { onlyBuiltin, environment, name }] of graph.verticesOfType(vertex_1.VertexType.FunctionCall)) {
171
- if (!name || onlyBuiltin) {
203
+ if (onlyBuiltin || !name) {
172
204
  continue;
173
205
  }
206
+ let effectiveEnvironment = outEnvironment;
174
207
  // only the call environment counts!
175
208
  if (environment) {
176
209
  while (outEnvironment.level > environment.level) {
@@ -179,16 +212,21 @@ function updateNestedFunctionCalls(graph, outEnvironment) {
179
212
  while (outEnvironment.level < environment.level) {
180
213
  outEnvironment = (0, scoping_1.pushLocalEnvironment)(outEnvironment);
181
214
  }
215
+ effectiveEnvironment = (0, overwrite_1.overwriteEnvironment)(outEnvironment, environment);
182
216
  }
183
- const effectiveEnvironment = environment ? (0, overwrite_1.overwriteEnvironment)(outEnvironment, environment) : outEnvironment;
184
- const targets = (0, linker_1.getAllFunctionCallTargets)(id, graph, effectiveEnvironment);
217
+ const targets = new Set((0, linker_1.getAllFunctionCallTargets)(id, graph, effectiveEnvironment));
185
218
  for (const target of targets) {
219
+ if ((0, built_in_1.isBuiltIn)(target)) {
220
+ graph.addEdge(id, target, edge_1.EdgeType.Calls);
221
+ continue;
222
+ }
186
223
  const targetVertex = graph.getVertex(target);
187
- if (targetVertex?.tag !== vertex_1.VertexType.FunctionDefinition) {
188
- // support reads on symbols
189
- if (targetVertex?.tag === vertex_1.VertexType.Use) {
190
- graph.addEdge(id, target, edge_1.EdgeType.Reads);
191
- }
224
+ // support reads on symbols
225
+ if (targetVertex?.tag === vertex_1.VertexType.Use) {
226
+ graph.addEdge(id, target, edge_1.EdgeType.Reads);
227
+ continue;
228
+ }
229
+ else if (targetVertex?.tag !== vertex_1.VertexType.FunctionDefinition) {
192
230
  continue;
193
231
  }
194
232
  graph.addEdge(id, target, edge_1.EdgeType.Calls);
@@ -76,8 +76,8 @@ function processIfThenElse(name, args, rootId, data) {
76
76
  else {
77
77
  finalEnvironment = (0, append_1.appendEnvironment)(thenEnvironment, otherwise ? otherwise.environment : cond.environment);
78
78
  }
79
- const cdTrue = { id: rootId, when: true };
80
- const cdFalse = { id: rootId, when: false };
79
+ const cdTrue = [{ id: rootId, when: true }];
80
+ const cdFalse = [{ id: rootId, when: false }];
81
81
  // again within an if-then-else we consider all actives to be read
82
82
  const ingoing = cond.in.concat(makeThenMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(then?.in, nextGraph, finalEnvironment, false, cdTrue) : then?.in ?? [], makeOtherwiseMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(otherwise?.in, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.in ?? [], cond.unknownReferences, makeThenMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(then?.unknownReferences, nextGraph, finalEnvironment, false, cdTrue) : then?.unknownReferences ?? [], makeOtherwiseMaybe ? (0, reference_to_maybe_1.makeAllMaybe)(otherwise?.unknownReferences, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.unknownReferences ?? []);
83
83
  // we assign all with a maybe marker
@@ -102,7 +102,8 @@ function processIfThenElse(name, args, rootId, data) {
102
102
  exitPoints,
103
103
  entryPoint: rootId,
104
104
  environment: finalEnvironment,
105
- graph: nextGraph
105
+ graph: nextGraph,
106
+ hooks: cond.hooks.concat(then?.hooks ?? [], otherwise?.hooks ?? []),
106
107
  };
107
108
  }
108
109
  //# sourceMappingURL=built-in-if-then-else.js.map
@@ -0,0 +1,34 @@
1
+ import { type DataflowProcessorInformation } from '../../../../../processor';
2
+ import type { DataflowInformation } from '../../../../../info';
3
+ import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
4
+ import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
5
+ import { type RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
6
+ import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
7
+ import type { KnownHooks } from '../../../../../hooks';
8
+ export interface RegisterHookConfig {
9
+ /** name of the hook to register, 'fn-exit' if it triggers on exit */
10
+ hook: KnownHooks;
11
+ args: {
12
+ /** the expression to register as hook */
13
+ expr: {
14
+ idx?: number;
15
+ name: string;
16
+ };
17
+ /** argument to control whether to add or replace the current hook */
18
+ add?: {
19
+ idx?: number;
20
+ name: string;
21
+ default: boolean;
22
+ };
23
+ /** argument to control whether to run the hook before or after other hooks */
24
+ after?: {
25
+ idx?: number;
26
+ name: string;
27
+ default: boolean;
28
+ };
29
+ };
30
+ }
31
+ /**
32
+ * Process a hook such as `on.exit`
33
+ */
34
+ export declare function processRegisterHook<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: RegisterHookConfig): DataflowInformation;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processRegisterHook = processRegisterHook;
4
+ const known_call_handling_1 = require("../known-call-handling");
5
+ const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
6
+ const linker_1 = require("../../../../linker");
7
+ const common_1 = require("../common");
8
+ const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
9
+ const range_1 = require("../../../../../../util/range");
10
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
11
+ const general_1 = require("../../../../../eval/values/general");
12
+ const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
13
+ /**
14
+ * Process a hook such as `on.exit`
15
+ */
16
+ function processRegisterHook(name, args, rootId, data, config) {
17
+ const params = {
18
+ [config.args.expr.name]: 'expr',
19
+ };
20
+ if (config.args.add) {
21
+ params[config.args.add.name] = 'add';
22
+ }
23
+ if (config.args.after) {
24
+ params[config.args.after.name] = 'after';
25
+ }
26
+ params['...'] = '...';
27
+ const argMaps = (0, linker_1.pMatch)((0, common_1.convertFnArguments)(args), params);
28
+ const exprIds = new Set(argMaps.entries().filter(([, v]) => v === 'expr').map(([k]) => k));
29
+ const addIds = config.args.add ? new Set(argMaps.entries().filter(([, v]) => v === 'add').map(([k]) => k)) : new Set();
30
+ const afterIds = config.args.after ? new Set(argMaps.entries().filter(([, v]) => v === 'after').map(([k]) => k)) : new Set();
31
+ const wrappedFunctions = new Set();
32
+ // we automatically transform the expr to a function definition that takes no arguments
33
+ const transformed = args.map(arg => {
34
+ if (arg === r_function_call_1.EmptyArgument) {
35
+ return r_function_call_1.EmptyArgument;
36
+ }
37
+ else if (exprIds.has(arg.info.id) && arg.value) {
38
+ const val = arg.value;
39
+ const wrapId = `${val.info.id}-hook-fn`;
40
+ wrappedFunctions.add(wrapId);
41
+ const wrapped = {
42
+ type: type_1.RType.FunctionDefinition,
43
+ location: val.location ?? (0, range_1.invalidRange)(),
44
+ parameters: [],
45
+ body: val,
46
+ lexeme: 'function',
47
+ info: {
48
+ ...val.info,
49
+ id: wrapId,
50
+ }
51
+ };
52
+ data.completeAst.idMap.set(wrapId, wrapped);
53
+ return {
54
+ ...arg,
55
+ value: wrapped
56
+ };
57
+ }
58
+ else {
59
+ return arg;
60
+ }
61
+ });
62
+ const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args: transformed, rootId, data, origin: 'builtin:register-hook' });
63
+ const resolveArgs = {
64
+ graph: res.information.graph,
65
+ environment: res.information.environment,
66
+ resolve: data.ctx.config.solver.variables,
67
+ ctx: data.ctx,
68
+ idMap: data.completeAst.idMap,
69
+ full: true
70
+ };
71
+ const shouldAdd = addIds.size === 0 ? config.args.add?.default :
72
+ Array.from(addIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
73
+ .some(v => v.type === 'logical' && v.value !== false);
74
+ const shouldBeAfter = afterIds.size === 0 ? config.args.after?.default :
75
+ Array.from(afterIds).flatMap(id => (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(id, resolveArgs))?.elements ?? [])
76
+ .some(v => v.type === 'logical' && v.value !== false);
77
+ const info = res.information;
78
+ const hooks = Array.from(wrappedFunctions, id => ({
79
+ type: config.hook,
80
+ id,
81
+ cds: data.controlDependencies,
82
+ add: shouldAdd,
83
+ after: shouldBeAfter
84
+ }));
85
+ info.hooks.push(...hooks);
86
+ if (data.environment.level <= 1) {
87
+ // if we are at the root level, we need to assume that the hook can cause unknown side-effects
88
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(info.graph, info.environment, rootId);
89
+ }
90
+ return info;
91
+ }
92
+ //# sourceMappingURL=built-in-register-hook.js.map
@@ -27,6 +27,7 @@ function processRepeatLoop(name, args, rootId, data) {
27
27
  args: unpacked ? [unpacked] : args,
28
28
  rootId,
29
29
  data,
30
+ forceArgs: 'all',
30
31
  patchData: (d, i) => {
31
32
  if (i === 0) {
32
33
  return { ...d, controlDependencies: [...d.controlDependencies ?? [], { id: name.info.id }] };
@@ -0,0 +1,21 @@
1
+ import type { DataflowProcessorInformation } from '../../../../../processor';
2
+ import type { DataflowInformation } from '../../../../../info';
3
+ import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
4
+ import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
5
+ import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
6
+ import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
7
+ /**
8
+ * Processes a built-in 'stopifnot' function call.
9
+ * This is special in that it may take a number of boolean expressions either via `...` or
10
+ * via `exprs` for which each expression is now evaluated individually:
11
+ * @example
12
+ * ```r
13
+ * stopifnot(exprs = {
14
+ * all.equal(pi, 3.1415927)
15
+ * 2 < 2
16
+ * all(1:10 < 12)
17
+ * "a" < "b"
18
+ * })
19
+ * ```
20
+ */
21
+ export declare function processStopIfNot<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>): DataflowInformation;