@eagleoutice/flowr 2.3.0 → 2.4.1

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 (145) hide show
  1. package/README.md +42 -30
  2. package/abstract-interpretation/data-frame/absint-visitor.d.ts +2 -3
  3. package/abstract-interpretation/data-frame/absint-visitor.js +14 -16
  4. package/abstract-interpretation/data-frame/mappers/function-mapper.js +3 -3
  5. package/abstract-interpretation/data-frame/semantics.d.ts +1 -1
  6. package/abstract-interpretation/data-frame/semantics.js +7 -10
  7. package/abstract-interpretation/data-frame/shape-inference.js +2 -8
  8. package/benchmark/slicer.js +7 -5
  9. package/benchmark/stats/size-of.js +3 -3
  10. package/benchmark/summarizer/second-phase/graph.js +1 -1
  11. package/benchmark/summarizer/second-phase/process.js +1 -1
  12. package/cli/benchmark-app.d.ts +1 -0
  13. package/cli/benchmark-app.js +1 -0
  14. package/cli/benchmark-helper-app.d.ts +1 -0
  15. package/cli/benchmark-helper-app.js +4 -3
  16. package/cli/common/options.js +2 -0
  17. package/cli/repl/commands/repl-query.js +1 -1
  18. package/cli/repl/server/connection.js +14 -5
  19. package/control-flow/basic-cfg-guided-visitor.d.ts +1 -2
  20. package/control-flow/basic-cfg-guided-visitor.js +0 -6
  21. package/control-flow/cfg-simplification.d.ts +6 -0
  22. package/control-flow/cfg-simplification.js +18 -9
  23. package/control-flow/control-flow-graph.d.ts +2 -8
  24. package/control-flow/control-flow-graph.js +1 -6
  25. package/control-flow/extract-cfg.d.ts +2 -2
  26. package/control-flow/extract-cfg.js +52 -63
  27. package/core/pipeline-executor.js +0 -8
  28. package/core/steps/all/static-slicing/00-slice.d.ts +7 -1
  29. package/core/steps/all/static-slicing/00-slice.js +9 -3
  30. package/core/steps/pipeline/default-pipelines.d.ts +74 -74
  31. package/dataflow/environments/append.js +1 -1
  32. package/dataflow/environments/built-in-config.d.ts +12 -4
  33. package/dataflow/environments/built-in-config.js +23 -82
  34. package/dataflow/environments/built-in.d.ts +40 -6
  35. package/dataflow/environments/built-in.js +119 -23
  36. package/dataflow/environments/clone.d.ts +3 -2
  37. package/dataflow/environments/clone.js +6 -5
  38. package/dataflow/environments/define.js +1 -2
  39. package/dataflow/environments/diff.js +1 -3
  40. package/dataflow/environments/environment.d.ts +18 -24
  41. package/dataflow/environments/environment.js +25 -37
  42. package/dataflow/environments/overwrite.d.ts +1 -1
  43. package/dataflow/environments/overwrite.js +1 -1
  44. package/dataflow/environments/remove.d.ts +2 -2
  45. package/dataflow/environments/remove.js +3 -4
  46. package/dataflow/environments/resolve-by-name.d.ts +3 -3
  47. package/dataflow/environments/resolve-by-name.js +4 -5
  48. package/dataflow/eval/resolve/alias-tracking.d.ts +12 -12
  49. package/dataflow/eval/resolve/alias-tracking.js +12 -12
  50. package/dataflow/eval/resolve/resolve.js +1 -1
  51. package/dataflow/extractor.js +6 -1
  52. package/dataflow/graph/dataflowgraph-builder.d.ts +3 -1
  53. package/dataflow/graph/dataflowgraph-builder.js +2 -2
  54. package/dataflow/graph/graph.d.ts +2 -1
  55. package/dataflow/graph/graph.js +6 -2
  56. package/dataflow/graph/invert-dfg.d.ts +2 -0
  57. package/dataflow/graph/invert-dfg.js +17 -0
  58. package/dataflow/info.d.ts +1 -1
  59. package/dataflow/internal/linker.js +9 -9
  60. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +1 -1
  61. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -4
  62. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -5
  63. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +9 -7
  64. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +2 -2
  65. package/dataflow/internal/process/functions/call/built-in/built-in-rm.js +1 -1
  66. package/dataflow/processor.d.ts +5 -1
  67. package/documentation/doc-util/doc-env.js +1 -2
  68. package/documentation/doc-util/doc-query.js +1 -1
  69. package/documentation/doc-util/doc-search.js +2 -2
  70. package/documentation/print-cfg-wiki.js +3 -4
  71. package/documentation/print-core-wiki.js +2 -2
  72. package/documentation/print-dataflow-graph-wiki.js +7 -0
  73. package/documentation/print-faq-wiki.js +4 -0
  74. package/documentation/print-linter-wiki.js +32 -4
  75. package/documentation/print-linting-and-testing-wiki.js +13 -1
  76. package/documentation/print-onboarding-wiki.js +4 -0
  77. package/documentation/print-query-wiki.js +12 -3
  78. package/linter/linter-executor.js +1 -2
  79. package/linter/linter-format.d.ts +26 -4
  80. package/linter/linter-format.js +25 -6
  81. package/linter/linter-rules.d.ts +40 -12
  82. package/linter/linter-rules.js +3 -1
  83. package/linter/rules/absolute-path.d.ts +4 -7
  84. package/linter/rules/absolute-path.js +9 -6
  85. package/linter/rules/dataframe-access-validation.d.ts +3 -1
  86. package/linter/rules/dataframe-access-validation.js +3 -1
  87. package/linter/rules/dead-code.d.ts +43 -0
  88. package/linter/rules/dead-code.js +50 -0
  89. package/linter/rules/deprecated-functions.d.ts +3 -2
  90. package/linter/rules/deprecated-functions.js +3 -1
  91. package/linter/rules/file-path-validity.d.ts +4 -4
  92. package/linter/rules/file-path-validity.js +8 -6
  93. package/linter/rules/naming-convention.d.ts +4 -3
  94. package/linter/rules/naming-convention.js +3 -1
  95. package/linter/rules/seeded-randomness.d.ts +4 -3
  96. package/linter/rules/seeded-randomness.js +3 -1
  97. package/linter/rules/unused-definition.d.ts +2 -0
  98. package/linter/rules/unused-definition.js +3 -1
  99. package/package.json +1 -1
  100. package/queries/base-query-format.d.ts +2 -0
  101. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +7 -7
  102. package/queries/catalog/dependencies-query/dependencies-query-executor.js +24 -1
  103. package/queries/catalog/dependencies-query/function-info/function-info.d.ts +9 -5
  104. package/queries/catalog/dependencies-query/function-info/read-functions.js +5 -2
  105. package/queries/catalog/dependencies-query/function-info/write-functions.js +6 -0
  106. package/queries/catalog/linter-query/linter-query-format.js +1 -1
  107. package/queries/catalog/location-map-query/location-map-query-executor.js +7 -5
  108. package/queries/catalog/location-map-query/location-map-query-format.d.ts +3 -0
  109. package/queries/catalog/location-map-query/location-map-query-format.js +1 -0
  110. package/queries/catalog/search-query/search-query-executor.js +1 -1
  111. package/queries/catalog/static-slice-query/static-slice-query-executor.d.ts +1 -1
  112. package/queries/catalog/static-slice-query/static-slice-query-executor.js +3 -2
  113. package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +3 -0
  114. package/queries/catalog/static-slice-query/static-slice-query-format.js +3 -1
  115. package/queries/query-print.d.ts +1 -1
  116. package/queries/query-print.js +0 -1
  117. package/queries/query.d.ts +16 -5
  118. package/queries/query.js +24 -11
  119. package/search/flowr-search-builder.d.ts +6 -6
  120. package/search/flowr-search-executor.d.ts +2 -2
  121. package/search/flowr-search-executor.js +1 -1
  122. package/search/flowr-search.d.ts +13 -8
  123. package/search/flowr-search.js +21 -0
  124. package/search/search-executor/search-enrichers.d.ts +87 -20
  125. package/search/search-executor/search-enrichers.js +44 -5
  126. package/search/search-executor/search-generators.d.ts +4 -4
  127. package/search/search-executor/search-generators.js +12 -7
  128. package/search/search-executor/search-mappers.js +3 -2
  129. package/search/search-executor/search-transformer.d.ts +3 -3
  130. package/search/search-executor/search-transformer.js +2 -2
  131. package/slicing/static/fingerprint.js +1 -2
  132. package/slicing/static/slice-call.d.ts +2 -1
  133. package/slicing/static/slice-call.js +3 -3
  134. package/slicing/static/static-slicer.d.ts +6 -5
  135. package/slicing/static/static-slicer.js +13 -7
  136. package/util/collections/arrays.d.ts +2 -0
  137. package/util/collections/arrays.js +9 -0
  138. package/util/containers.d.ts +1 -0
  139. package/util/containers.js +1 -0
  140. package/util/json.js +1 -4
  141. package/util/mermaid/dfg.js +5 -4
  142. package/util/prefix.d.ts +1 -1
  143. package/util/range.d.ts +1 -0
  144. package/util/range.js +5 -1
  145. package/util/version.js +1 -1
@@ -2,13 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Enrichments = exports.Enrichment = void 0;
4
4
  exports.enrichmentContent = enrichmentContent;
5
- exports.enrich = enrich;
5
+ exports.enrichElement = enrichElement;
6
+ const objects_1 = require("../../util/objects");
6
7
  const vertex_1 = require("../../dataflow/graph/vertex");
7
8
  const identify_link_to_last_call_relation_1 = require("../../queries/catalog/call-context-query/identify-link-to-last-call-relation");
8
9
  const assert_1 = require("../../util/assert");
9
10
  const extract_cfg_1 = require("../../control-flow/extract-cfg");
10
11
  const dfg_get_origin_1 = require("../../dataflow/origin/dfg-get-origin");
11
12
  const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
13
+ const cfg_simplification_1 = require("../../control-flow/cfg-simplification");
12
14
  /**
13
15
  * An enumeration that stores the names of the available enrichments that can be applied to a set of search elements.
14
16
  * See {@link FlowrSearchBuilder.with} for more information on how to apply enrichments.
@@ -17,6 +19,8 @@ var Enrichment;
17
19
  (function (Enrichment) {
18
20
  Enrichment["CallTargets"] = "call-targets";
19
21
  Enrichment["LastCall"] = "last-call";
22
+ Enrichment["CfgInformation"] = "cfg-information";
23
+ Enrichment["QueryData"] = "query-data";
20
24
  })(Enrichment || (exports.Enrichment = Enrichment = {}));
21
25
  /**
22
26
  * The registry of enrichments that are currently supported by the search.
@@ -24,7 +28,7 @@ var Enrichment;
24
28
  */
25
29
  exports.Enrichments = {
26
30
  [Enrichment.CallTargets]: {
27
- enrich: (e, data, args, prev) => {
31
+ enrichElement: (e, _s, data, args, prev) => {
28
32
  // we don't resolve aliases here yet!
29
33
  const content = { targets: [] };
30
34
  const callVertex = data.dataflow.graph.getVertex(e.node.info.id);
@@ -65,7 +69,7 @@ exports.Enrichments = {
65
69
  mapper: ({ targets }) => targets.map(t => t).filter(t => t.node !== undefined)
66
70
  },
67
71
  [Enrichment.LastCall]: {
68
- enrich: (e, data, args, prev) => {
72
+ enrichElement: (e, _s, data, args, prev) => {
69
73
  (0, assert_1.guard)(args && args.length, `${Enrichment.LastCall} enrichment requires at least one argument`);
70
74
  const content = prev ?? { linkedIds: [] };
71
75
  const vertex = data.dataflow.graph.get(e.node.info.id);
@@ -86,6 +90,41 @@ exports.Enrichments = {
86
90
  },
87
91
  mapper: ({ linkedIds }) => linkedIds
88
92
  },
93
+ [Enrichment.CfgInformation]: {
94
+ enrichElement: (e, search, _data, _args, prev) => {
95
+ const searchContent = search.enrichmentContent(Enrichment.CfgInformation);
96
+ return {
97
+ ...prev,
98
+ isRoot: searchContent.cfg.graph.rootIds().has(e.node.info.id),
99
+ isReachable: searchContent.reachableNodes?.has(e.node.info.id)
100
+ };
101
+ },
102
+ enrichSearch: (_search, data, args, prev) => {
103
+ args = {
104
+ forceRefresh: false,
105
+ checkReachable: false,
106
+ simplificationPasses: cfg_simplification_1.DefaultCfgSimplificationOrder,
107
+ ...args
108
+ };
109
+ // short-circuit if we already have a cfg stored
110
+ if (!args.forceRefresh && prev?.simpleCfg) {
111
+ return prev;
112
+ }
113
+ const content = {
114
+ ...prev,
115
+ cfg: (0, extract_cfg_1.extractCfg)(data.normalize, data.config, data.dataflow.graph, args.simplificationPasses),
116
+ };
117
+ if (args.checkReachable) {
118
+ content.reachableNodes = (0, cfg_simplification_1.cfgFindAllReachable)(content.cfg);
119
+ }
120
+ return content;
121
+ }
122
+ },
123
+ [Enrichment.QueryData]: {
124
+ // the query data enrichment is just a "pass-through" that passes the query data to the underlying search
125
+ enrichElement: (_e, _search, _data, args, prev) => (args ?? prev),
126
+ enrichSearch: (_search, _data, args, prev) => (0, objects_1.deepMergeObject)(prev, args)
127
+ }
89
128
  };
90
129
  /**
91
130
  * Returns the content of the given enrichment type from a {@link FlowrSearchElement}.
@@ -96,14 +135,14 @@ exports.Enrichments = {
96
135
  function enrichmentContent(e, enrichment) {
97
136
  return e?.enrichments?.[enrichment];
98
137
  }
99
- function enrich(e, data, enrichment, args) {
138
+ function enrichElement(e, s, data, enrichment, args) {
100
139
  const enrichmentData = exports.Enrichments[enrichment];
101
140
  const prev = e?.enrichments;
102
141
  return {
103
142
  ...e,
104
143
  enrichments: {
105
144
  ...prev ?? {},
106
- [enrichment]: enrichmentData.enrich(e, data, args, prev?.[enrichment])
145
+ [enrichment]: enrichmentData.enrichElement?.(e, s, data, args, prev?.[enrichment])
107
146
  }
108
147
  };
109
148
  }
@@ -1,10 +1,10 @@
1
- import type { FlowrSearchElement, FlowrSearchElementFromQuery, FlowrSearchGeneratorNodeBase, FlowrSearchGetFilter, FlowrSearchInput } from '../flowr-search';
1
+ import type { FlowrSearchElement, FlowrSearchGeneratorNodeBase, FlowrSearchGetFilter, FlowrSearchInput } from '../flowr-search';
2
2
  import { FlowrSearchElements } from '../flowr-search';
3
3
  import type { Pipeline } from '../../core/steps/pipeline/pipeline';
4
4
  import type { TailTypesOrUndefined } from '../../util/collections/arrays';
5
5
  import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
6
6
  import type { SlicingCriteria } from '../../slicing/criterion/parse';
7
- import type { Query } from '../../queries/query';
7
+ import type { SynchronousQuery } from '../../queries/query';
8
8
  /**
9
9
  * This is a union of all possible generator node types
10
10
  */
@@ -33,8 +33,8 @@ declare function generateFrom(data: FlowrSearchInput<Pipeline>, args: {
33
33
  from: FlowrSearchElement<ParentInformation> | FlowrSearchElement<ParentInformation>[];
34
34
  }): FlowrSearchElements<ParentInformation>;
35
35
  declare function generateFromQuery(data: FlowrSearchInput<Pipeline>, args: {
36
- from: readonly Query[];
37
- }): FlowrSearchElements<ParentInformation, FlowrSearchElementFromQuery<ParentInformation>[]>;
36
+ from: readonly SynchronousQuery[];
37
+ }): FlowrSearchElements<ParentInformation, FlowrSearchElement<ParentInformation>[]>;
38
38
  declare function generateCriterion(data: FlowrSearchInput<Pipeline>, args: {
39
39
  criterion: SlicingCriteria;
40
40
  }): FlowrSearchElements<ParentInformation>;
@@ -6,6 +6,7 @@ const flowr_search_1 = require("../flowr-search");
6
6
  const parse_1 = require("../../slicing/criterion/parse");
7
7
  const assert_1 = require("../../util/assert");
8
8
  const query_1 = require("../../queries/query");
9
+ const search_enrichers_1 = require("./search-enrichers");
9
10
  /**
10
11
  * All supported generators!
11
12
  */
@@ -55,22 +56,26 @@ function generateFrom(data, args) {
55
56
  return new flowr_search_1.FlowrSearchElements(Array.isArray(args.from) ? args.from : [args.from]);
56
57
  }
57
58
  function generateFromQuery(data, args) {
58
- const nodes = new Set();
59
59
  const result = (0, query_1.executeQueries)({ ast: data.normalize, dataflow: data.dataflow, config: data.config }, args.from);
60
+ // collect involved nodes
61
+ const nodesByQuery = new Map();
60
62
  for (const [query, content] of Object.entries(result)) {
61
63
  if (query === '.meta') {
62
64
  continue;
63
65
  }
66
+ const nodes = new Set();
64
67
  const queryDef = query_1.SupportedQueries[query];
65
68
  for (const node of queryDef.flattenInvolvedNodes(content)) {
66
- nodes.add({
67
- node: data.normalize.idMap.get(node),
68
- query: query,
69
- queryResult: content
70
- });
69
+ nodes.add({ node: data.normalize.idMap.get(node) });
71
70
  }
71
+ nodesByQuery.set(query, nodes);
72
72
  }
73
- return new flowr_search_1.FlowrSearchElements([...nodes]);
73
+ // enrich elements with query data
74
+ const elements = new flowr_search_1.FlowrSearchElements([...nodesByQuery].flatMap(([_, nodes]) => [...nodes])).enrich(data, search_enrichers_1.Enrichment.QueryData, { queries: result });
75
+ return elements.mutate(s => s.map(e => {
76
+ const [query, _] = [...nodesByQuery].find(([_, nodes]) => nodes.has(e));
77
+ return (0, search_enrichers_1.enrichElement)(e, elements, data, search_enrichers_1.Enrichment.QueryData, { query });
78
+ }));
74
79
  }
75
80
  function generateCriterion(data, args) {
76
81
  return new flowr_search_1.FlowrSearchElements(args.criterion.map(c => ({ node: data.normalize.idMap.get((0, parse_1.slicingCriterionToId)(c, data.normalize.idMap)) })));
@@ -10,8 +10,9 @@ var Mapper;
10
10
  const Mappers = {
11
11
  [Mapper.Enrichment]: {
12
12
  mapper: (e, _data, enrichment) => {
13
- const data = (0, search_enrichers_1.enrichmentContent)(e, enrichment);
14
- return data !== undefined ? search_enrichers_1.Enrichments[enrichment].mapper(data) : [];
13
+ const enrichmentData = search_enrichers_1.Enrichments[enrichment];
14
+ const content = (0, search_enrichers_1.enrichmentContent)(e, enrichment);
15
+ return content !== undefined ? enrichmentData.mapper?.(content) ?? [] : [];
15
16
  }
16
17
  }
17
18
  };
@@ -4,7 +4,7 @@ import type { LastOfArray, Tail2TypesOrUndefined, TailOfArray } from '../../util
4
4
  import type { FlowrFilterExpression } from '../flowr-search-filters';
5
5
  import type { FlowrSearchGeneratorNode } from './search-generators';
6
6
  import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
7
- import type { EnrichedFlowrSearchElement, Enrichment, EnrichmentArguments } from './search-enrichers';
7
+ import type { Enrichment, EnrichmentElementArguments } from './search-enrichers';
8
8
  import type { Mapper, MapperArguments } from './search-mappers';
9
9
  /**
10
10
  * This is a union of all possible transformer node types
@@ -57,8 +57,8 @@ declare function getFilter<Elements extends FlowrSearchElement<ParentInformation
57
57
  }): CascadeEmpty<Elements, Elements | []>;
58
58
  declare function getWith<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { info, args }: {
59
59
  info: Enrichment;
60
- args?: EnrichmentArguments<Enrichment>;
61
- }): FlowrSearchElements<ParentInformation, EnrichedFlowrSearchElement<ParentInformation>[]>;
60
+ args?: EnrichmentElementArguments<Enrichment>;
61
+ }): FlowrSearchElements<ParentInformation, FlowrSearchElement<ParentInformation>[]>;
62
62
  declare function getMap<Elements extends FlowrSearchElement<ParentInformation>[], FSE extends FlowrSearchElements<ParentInformation, Elements>>(data: FlowrSearchInput<Pipeline>, elements: FSE, { mapper, args }: {
63
63
  mapper: Mapper;
64
64
  args: MapperArguments<Mapper>;
@@ -96,7 +96,7 @@ function getFilter(data, elements, { filter }) {
96
96
  return elements.mutate(e => e.filter(e => (0, flowr_search_filters_1.evalFilter)(filter, { element: e, normalize: data.normalize, dataflow: data.dataflow })));
97
97
  }
98
98
  function getWith(data, elements, { info, args }) {
99
- return elements.mutate(elements => elements.map(e => (0, search_enrichers_1.enrich)(e, data, info, args)));
99
+ return elements.enrich(data, info, args).mutate(s => s.map(e => (0, search_enrichers_1.enrichElement)(e, elements, data, info, args)));
100
100
  }
101
101
  function getMap(data, elements, { mapper, args }) {
102
102
  return elements.mutate(elements => elements.flatMap(e => (0, search_mappers_1.map)(e, data, mapper, args)));
@@ -105,7 +105,7 @@ function getMerge(
105
105
  /* search has to be unknown because it is a recursive type */
106
106
  data, elements, other) {
107
107
  const resultOther = (0, flowr_search_executor_1.runSearch)(other, data);
108
- return elements.addAll(resultOther);
108
+ return elements.addAll([...resultOther.getElements()]);
109
109
  }
110
110
  function getUnique(data, elements) {
111
111
  return elements.mutate(e => e.reduce((acc, cur) => {
@@ -7,7 +7,6 @@ exports.envFingerprint = envFingerprint;
7
7
  exports.fingerprint = fingerprint;
8
8
  const object_hash_1 = __importDefault(require("object-hash"));
9
9
  const environment_1 = require("../../dataflow/environments/environment");
10
- const built_in_1 = require("../../dataflow/environments/built-in");
11
10
  function envFingerprint(env) {
12
11
  return (0, object_hash_1.default)(env, {
13
12
  algorithm: 'md5',
@@ -15,7 +14,7 @@ function envFingerprint(env) {
15
14
  respectFunctionProperties: false,
16
15
  respectFunctionNames: false,
17
16
  ignoreUnknown: true,
18
- replacer: (v) => (v === environment_1.BuiltInEnvironment || v === built_in_1.EmptyBuiltInMemory) ? undefined : v
17
+ replacer: (v) => (0, environment_1.isDefaultBuiltInEnvironment)(v) ? undefined : v
19
18
  });
20
19
  }
21
20
  function fingerprint(id, envFingerprint, onlyForSideEffects) {
@@ -5,11 +5,12 @@ import type { DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from '.
5
5
  import type { REnvironmentInformation } from '../../dataflow/environments/environment';
6
6
  import type { DataflowGraph, OutgoingEdges } from '../../dataflow/graph/graph';
7
7
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
+ import type { DataflowInformation } from '../../dataflow/info';
8
9
  /**
9
10
  * Returns the function call targets (definitions) by the given caller
10
11
  */
11
12
  export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation, queue: VisitingQueue): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
12
13
  /** returns the new threshold hit count */
13
- export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowGraph: DataflowGraph, queue: VisitingQueue): void;
14
+ export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowInformation: DataflowInformation, queue: VisitingQueue): void;
14
15
  /** Returns true if we found at least one return edge */
15
16
  export declare function handleReturns(from: NodeId, queue: VisitingQueue, currentEdges: OutgoingEdges, baseEnvFingerprint: Fingerprint, baseEnvironment: REnvironmentInformation): boolean;
@@ -59,9 +59,9 @@ function linkCallTargets(onlyForSideEffects, functionCallTargets, activeEnvironm
59
59
  }
60
60
  }
61
61
  /** returns the new threshold hit count */
62
- function sliceForCall(current, callerInfo, dataflowGraph, queue) {
62
+ function sliceForCall(current, callerInfo, dataflowInformation, queue) {
63
63
  const baseEnvironment = current.baseEnvironment;
64
- const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowGraph, callerInfo, current.baseEnvironment, queue);
64
+ const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowInformation.graph, callerInfo, current.baseEnvironment, queue);
65
65
  const activeEnvironmentFingerprint = (0, fingerprint_1.envFingerprint)(activeEnvironment);
66
66
  if (functionCallTargets.size === 0) {
67
67
  /*
@@ -69,7 +69,7 @@ function sliceForCall(current, callerInfo, dataflowGraph, queue) {
69
69
  * hence, we add a new flag and add all argument values to the queue causing directly
70
70
  */
71
71
  for (const arg of callerInfo.args) {
72
- includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowGraph);
72
+ includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowInformation.graph);
73
73
  }
74
74
  return;
75
75
  }
@@ -1,22 +1,23 @@
1
1
  import type { SliceResult } from './slicer-types';
2
2
  import type { Fingerprint } from './fingerprint';
3
3
  import { VisitingQueue } from './visiting-queue';
4
- import type { DataflowGraph } from '../../dataflow/graph/graph';
5
4
  import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
6
5
  import type { SlicingCriteria } from '../criterion/parse';
7
6
  import type { REnvironmentInformation } from '../../dataflow/environments/environment';
8
7
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
+ import { SliceDirection } from '../../core/steps/all/static-slicing/00-slice';
9
+ import type { DataflowInformation } from '../../dataflow/info';
9
10
  export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogObj>;
10
11
  /**
11
- * This returns the ids to include in the static backward slice, when slicing with the given seed id's (must be at least one).
12
+ * This returns the ids to include in the static slice of the given type, when slicing with the given seed id's (must be at least one).
12
13
  * <p>
13
14
  * The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
14
15
  *
15
- * @param graph - The dataflow graph to conduct the slicing on.
16
- * @param ast - The normalized AST of the code (used to get static nesting information of the lexemes in case of control flow dependencies that may have no effect on the slicing scope).
16
+ * @param info - The dataflow information used for slicing.
17
17
  * @param criteria - The criteria to slice on.
18
+ * @param direction - The direction to slice in.
18
19
  * @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
19
20
  * @param cache - A cache to store the results of the slice. If provided, the slice may use this cache to speed up the slicing process.
20
21
  */
21
- export declare function staticSlicing(graph: DataflowGraph, { idMap }: NormalizedAst, criteria: SlicingCriteria, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
22
+ export declare function staticSlice(info: DataflowInformation, { idMap }: NormalizedAst, criteria: SlicingCriteria, direction: SliceDirection, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
22
23
  export declare function updatePotentialAddition(queue: VisitingQueue, id: NodeId, target: NodeId, baseEnvironment: REnvironmentInformation, envFingerprint: string): void;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.slicerLogger = void 0;
4
- exports.staticSlicing = staticSlicing;
4
+ exports.staticSlice = staticSlice;
5
5
  exports.updatePotentialAddition = updatePotentialAddition;
6
6
  const assert_1 = require("../../util/assert");
7
7
  const log_1 = require("../../util/log");
@@ -12,22 +12,28 @@ const parse_1 = require("../criterion/parse");
12
12
  const environment_1 = require("../../dataflow/environments/environment");
13
13
  const vertex_1 = require("../../dataflow/graph/vertex");
14
14
  const edge_1 = require("../../dataflow/graph/edge");
15
+ const _00_slice_1 = require("../../core/steps/all/static-slicing/00-slice");
16
+ const invert_dfg_1 = require("../../dataflow/graph/invert-dfg");
15
17
  exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
16
18
  /**
17
- * This returns the ids to include in the static backward slice, when slicing with the given seed id's (must be at least one).
19
+ * This returns the ids to include in the static slice of the given type, when slicing with the given seed id's (must be at least one).
18
20
  * <p>
19
21
  * The returned ids can be used to {@link reconstructToCode|reconstruct the slice to R code}.
20
22
  *
21
- * @param graph - The dataflow graph to conduct the slicing on.
22
- * @param ast - The normalized AST of the code (used to get static nesting information of the lexemes in case of control flow dependencies that may have no effect on the slicing scope).
23
+ * @param info - The dataflow information used for slicing.
23
24
  * @param criteria - The criteria to slice on.
25
+ * @param direction - The direction to slice in.
24
26
  * @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
25
27
  * @param cache - A cache to store the results of the slice. If provided, the slice may use this cache to speed up the slicing process.
26
28
  */
27
- function staticSlicing(graph, { idMap }, criteria, threshold = 75, cache) {
29
+ function staticSlice(info, { idMap }, criteria, direction, threshold = 75, cache) {
28
30
  (0, assert_1.guard)(criteria.length > 0, 'must have at least one seed id to calculate slice');
29
31
  const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria, idMap);
30
- (0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
32
+ (0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating ${direction} slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
33
+ let { graph } = info;
34
+ if (direction === _00_slice_1.SliceDirection.Forward) {
35
+ graph = (0, invert_dfg_1.invertDfg)(graph);
36
+ }
31
37
  const queue = new visiting_queue_1.VisitingQueue(threshold, cache);
32
38
  let minNesting = Number.MAX_SAFE_INTEGER;
33
39
  const sliceSeedIds = new Set();
@@ -71,7 +77,7 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75, cache) {
71
77
  }
72
78
  if (!onlyForSideEffects) {
73
79
  if (currentVertex.tag === vertex_1.VertexType.FunctionCall && !currentVertex.onlyBuiltin) {
74
- (0, slice_call_1.sliceForCall)(current, currentVertex, graph, queue);
80
+ (0, slice_call_1.sliceForCall)(current, currentVertex, info, queue);
75
81
  }
76
82
  const ret = (0, slice_call_1.handleReturns)(id, queue, currentEdges, baseEnvFingerprint, baseEnvironment);
77
83
  if (ret) {
@@ -88,3 +88,5 @@ export declare function equidistantSampling<T>(list: readonly T[], sampleCount:
88
88
  *
89
89
  */
90
90
  export declare function cartesianProduct<T>(...arrays: T[][]): T[][];
91
+ /** merge two arrays, removing duplicates */
92
+ export declare function uniqueArrayMerge<T>(left: readonly T[], right: readonly T[]): T[];
@@ -10,6 +10,7 @@ exports.array2bag = array2bag;
10
10
  exports.arrayEqual = arrayEqual;
11
11
  exports.equidistantSampling = equidistantSampling;
12
12
  exports.cartesianProduct = cartesianProduct;
13
+ exports.uniqueArrayMerge = uniqueArrayMerge;
13
14
  const assert_1 = require("../assert");
14
15
  /**
15
16
  * Splits the array every time the given predicate fires.
@@ -215,4 +216,12 @@ function equidistantSampling(list, sampleCount, rounding = 'ceil') {
215
216
  function cartesianProduct(...arrays) {
216
217
  return arrays.reduce((a, b) => a.flatMap(x => b.map(y => x.concat(y))), [[]]);
217
218
  }
219
+ /** merge two arrays, removing duplicates */
220
+ function uniqueArrayMerge(left, right) {
221
+ const result = new Set(left);
222
+ for (const elem of right) {
223
+ result.add(elem);
224
+ }
225
+ return Array.from(result);
226
+ }
218
227
  //# sourceMappingURL=arrays.js.map
@@ -17,6 +17,7 @@ export declare function getAccessOperands<OtherInfo>(args: readonly RFunctionArg
17
17
  *
18
18
  * @param name - Name to resolve
19
19
  * @param environment - Environment in which name is resolved
20
+ * @param builtInEnvironment - Built-in environment
20
21
  * @returns The indicesCollection of the resolved definitions
21
22
  */
22
23
  export declare function resolveIndicesByName(name: Identifier, environment: REnvironmentInformation): ContainerIndices[] | undefined;
@@ -24,6 +24,7 @@ function getAccessOperands(args) {
24
24
  *
25
25
  * @param name - Name to resolve
26
26
  * @param environment - Environment in which name is resolved
27
+ * @param builtInEnvironment - Built-in environment
27
28
  * @returns The indicesCollection of the resolved definitions
28
29
  */
29
30
  function resolveIndicesByName(name, environment) {
package/util/json.js CHANGED
@@ -46,12 +46,9 @@ function bigStringify(obj, current, send) {
46
46
  if (obj === undefined || obj === null) {
47
47
  return current + 'null';
48
48
  }
49
- else if (obj === environment_1.BuiltInEnvironment) {
49
+ else if ((0, environment_1.isDefaultBuiltInEnvironment)(obj)) {
50
50
  return current + '<BuiltInEnvironment>';
51
51
  }
52
- else if (obj === environment_1.EmptyBuiltInEnvironment) {
53
- return current + '<EmptyBuiltInEnvironment>';
54
- }
55
52
  else if (Array.isArray(obj)) {
56
53
  let str = current + '[';
57
54
  for (let i = 0; i < obj.length; i++) {
@@ -6,7 +6,6 @@ exports.graphToMermaid = graphToMermaid;
6
6
  exports.graphToMermaidUrl = graphToMermaidUrl;
7
7
  exports.diffGraphsToMermaid = diffGraphsToMermaid;
8
8
  exports.diffGraphsToMermaidUrl = diffGraphsToMermaidUrl;
9
- const assert_1 = require("../assert");
10
9
  const mermaid_1 = require("./mermaid");
11
10
  const graph_1 = require("../../dataflow/graph/graph");
12
11
  const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
@@ -14,7 +13,6 @@ const identifier_1 = require("../../dataflow/environments/identifier");
14
13
  const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
15
14
  const edge_1 = require("../../dataflow/graph/edge");
16
15
  const vertex_1 = require("../../dataflow/graph/vertex");
17
- const environment_1 = require("../../dataflow/environments/environment");
18
16
  const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
19
17
  const built_in_1 = require("../../dataflow/environments/built-in");
20
18
  /**
@@ -135,7 +133,7 @@ function printEnvironmentToLines(env) {
135
133
  if (env === undefined) {
136
134
  return ['??'];
137
135
  }
138
- else if (env.id === environment_1.BuiltInEnvironment.id) {
136
+ else if (env.builtInEnv) {
139
137
  return ['Built-in'];
140
138
  }
141
139
  const lines = [...printEnvironmentToLines(env.parent), `${env.id}${'-'.repeat(40)}`];
@@ -176,7 +174,10 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
176
174
  mermaid.nodeLines.push(` style ${idPrefix}${id} stroke:red,stroke-width:5px; `);
177
175
  }
178
176
  const edges = mermaid.rootGraph.get((0, node_id_1.normalizeIdToNumberIfPossible)(id), true);
179
- (0, assert_1.guard)(edges !== undefined, `node ${id} must be found`);
177
+ if (edges === undefined) {
178
+ mermaid.nodeLines.push(' %% No edges found for ' + id);
179
+ return;
180
+ }
180
181
  const artificialCdEdges = (info.cds ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
181
182
  // eslint-disable-next-line prefer-const
182
183
  for (let [target, edge] of [...edges[1], ...artificialCdEdges]) {
package/util/prefix.d.ts CHANGED
@@ -10,4 +10,4 @@
10
10
  * findByPrefixIfUnique('', { 'hello', 'hell' }) // => undefined (empty prefix)
11
11
  * ```
12
12
  */
13
- export declare function findByPrefixIfUnique(prefix: string, keys: readonly string[]): string | undefined;
13
+ export declare function findByPrefixIfUnique(prefix: string, keys: readonly string[] | MapIterator<string>): string | undefined;
package/util/range.d.ts CHANGED
@@ -68,3 +68,4 @@ export declare function rangeCompare([r1sl, r1sc, ,]: SourceRange, [r2sl, r2sc,
68
68
  * Checks if the first range is a subset of the second range.
69
69
  */
70
70
  export declare function rangeIsSubsetOf([r1sl, r1sc, r1el, r1ec]: SourceRange, [r2sl, r2sc, r2el, r2ec]: SourceRange): boolean;
71
+ export declare function combineRanges(...ranges: SourceRange[]): SourceRange[];
package/util/range.js CHANGED
@@ -9,6 +9,7 @@ exports.rangesOverlap = rangesOverlap;
9
9
  exports.addRanges = addRanges;
10
10
  exports.rangeCompare = rangeCompare;
11
11
  exports.rangeIsSubsetOf = rangeIsSubsetOf;
12
+ exports.combineRanges = combineRanges;
12
13
  const assert_1 = require("./assert");
13
14
  function getRangeStart(p) {
14
15
  return p === undefined ? undefined : [p[0], p[1]];
@@ -70,6 +71,9 @@ function rangeCompare([r1sl, r1sc, ,], [r2sl, r2sc, ,]) {
70
71
  * Checks if the first range is a subset of the second range.
71
72
  */
72
73
  function rangeIsSubsetOf([r1sl, r1sc, r1el, r1ec], [r2sl, r2sc, r2el, r2ec]) {
73
- return r1sl >= r2sl && r1sc >= r2sc && r1el <= r2el && r1ec <= r2ec;
74
+ return (r1sl > r2sl || r1sl === r2sl && r1sc >= r2sc) && (r1el < r2el || r1sl === r2sl && r1ec <= r2ec);
75
+ }
76
+ function combineRanges(...ranges) {
77
+ return ranges.filter(range => !ranges.some(other => range !== other && rangeIsSubsetOf(range, other)));
74
78
  }
75
79
  //# sourceMappingURL=range.js.map
package/util/version.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flowrVersion = flowrVersion;
4
4
  const semver_1 = require("semver");
5
5
  // this is automatically replaced with the current version by release-it
6
- const version = '2.3.0';
6
+ const version = '2.4.1';
7
7
  function flowrVersion() {
8
8
  return new semver_1.SemVer(version);
9
9
  }