@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
@@ -14,7 +14,11 @@ exports.LocationMapQueryDefinition = {
14
14
  asciiSummarizer: (formatter, _processed, queryResults, result) => {
15
15
  const out = queryResults;
16
16
  result.push(`Query: ${(0, ansi_1.bold)('location-map', formatter)} (${(0, time_1.printAsMs)(out['.meta'].timing, 0)})`);
17
- result.push(`Id List: {${(0, query_print_1.summarizeIdsIfTooLong)(formatter, [...Object.keys(out.map)])}}`);
17
+ result.push('File List:');
18
+ for (const [id, file] of Object.entries(out.map.files)) {
19
+ result.push(` ╰ ${id}: \`${file}\``);
20
+ }
21
+ result.push(` ╰ Id List: {${(0, query_print_1.summarizeIdsIfTooLong)(formatter, [...Object.keys(out.map.ids)])}}`);
18
22
  return true;
19
23
  },
20
24
  schema: joi_1.default.object({
@@ -0,0 +1,3 @@
1
+ import type { ProjectQuery, ProjectQueryResult } from './project-query-format';
2
+ import type { BasicQueryData } from '../../base-query-format';
3
+ export declare function executeProjectQuery({ dataflow }: BasicQueryData, queries: readonly ProjectQuery[]): ProjectQueryResult;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeProjectQuery = executeProjectQuery;
4
+ const log_1 = require("../../../util/log");
5
+ function executeProjectQuery({ dataflow }, queries) {
6
+ if (queries.length !== 1) {
7
+ log_1.log.warn('Id-Map query expects only up to one query, but got', queries.length);
8
+ }
9
+ return {
10
+ '.meta': {
11
+ /* there is no sense in measuring a get */
12
+ timing: 0
13
+ },
14
+ files: dataflow.graph.sourced
15
+ };
16
+ }
17
+ //# sourceMappingURL=project-query-executor.js.map
@@ -0,0 +1,67 @@
1
+ import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
2
+ import { executeProjectQuery } from './project-query-executor';
3
+ import Joi from 'joi';
4
+ export interface ProjectQuery extends BaseQueryFormat {
5
+ readonly type: 'project';
6
+ }
7
+ export interface ProjectQueryResult extends BaseQueryResult {
8
+ readonly files: (string | '<inline>')[];
9
+ }
10
+ export declare const ProjectQueryDefinition: {
11
+ readonly executor: typeof executeProjectQuery;
12
+ readonly asciiSummarizer: (formatter: import("../../../util/ansi").OutputFormatter, _processed: import("../../../core/steps/pipeline/pipeline").PipelineOutput<import("../../../core/steps/pipeline/pipeline").Pipeline<{
13
+ readonly name: "parse";
14
+ readonly humanReadableName: "parse with R shell";
15
+ readonly description: "Parse the given R code into an AST";
16
+ readonly processor: (_results: unknown, input: Partial<import("../../../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../../../r-bridge/parser").ParseStepOutput<string>>;
17
+ readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
18
+ readonly printer: {
19
+ readonly 0: typeof import("../../../core/print/print").internalPrinter;
20
+ readonly 2: {
21
+ (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
22
+ (value: any, replacer?: (number | string)[] | null, space?: string | number): string;
23
+ };
24
+ readonly 5: ({ parsed }: import("../../../r-bridge/parser").ParseStepOutput<string>, config: import("../../../util/quads").QuadSerializationConfiguration) => string;
25
+ };
26
+ readonly dependencies: readonly [];
27
+ readonly requiredInput: import("../../../r-bridge/parser").ParseRequiredInput<string>;
28
+ } | {
29
+ readonly name: "normalize";
30
+ readonly humanReadableName: "normalize";
31
+ readonly description: "Normalize the AST to flowR's AST";
32
+ readonly processor: (results: {
33
+ parse?: import("../../../r-bridge/parser").ParseStepOutput<string>;
34
+ }, input: Partial<import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../../r-bridge/lang-4.x/ast/model/model").RNode<import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
35
+ readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
36
+ readonly printer: {
37
+ readonly 0: typeof import("../../../core/print/print").internalPrinter;
38
+ readonly 2: typeof import("../../../core/print/normalize-printer").normalizedAstToJson;
39
+ readonly 5: typeof import("../../../core/print/normalize-printer").normalizedAstToQuads;
40
+ readonly 3: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaid;
41
+ readonly 4: typeof import("../../../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
42
+ };
43
+ readonly dependencies: readonly ["parse"];
44
+ readonly requiredInput: import("../../../core/steps/all/core/10-normalize").NormalizeRequiredInput;
45
+ } | {
46
+ readonly humanReadableName: "dataflow";
47
+ readonly processor: (results: {
48
+ normalize?: import("../../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
49
+ }, input: {
50
+ request?: import("../../../r-bridge/retriever").RParseRequests;
51
+ parser?: import("../../../r-bridge/parser").Parser<import("../../../r-bridge/parser").KnownParserType>;
52
+ }) => import("../../../dataflow/info").DataflowInformation;
53
+ readonly requiredInput: {};
54
+ readonly name: "dataflow";
55
+ readonly description: "Construct the dataflow graph";
56
+ readonly executed: import("../../../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
57
+ readonly printer: {
58
+ readonly 0: typeof import("../../../core/print/print").internalPrinter;
59
+ readonly 2: typeof import("../../../core/print/dataflow-printer").dataflowGraphToJson;
60
+ readonly 5: typeof import("../../../core/print/dataflow-printer").dataflowGraphToQuads;
61
+ readonly 3: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaid;
62
+ readonly 4: typeof import("../../../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
63
+ };
64
+ readonly dependencies: readonly ["normalize"];
65
+ }>>, queryResults: BaseQueryResult, result: string[]) => true;
66
+ readonly schema: Joi.ObjectSchema<any>;
67
+ };
@@ -0,0 +1,26 @@
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
+ exports.ProjectQueryDefinition = void 0;
7
+ const project_query_executor_1 = require("./project-query-executor");
8
+ const ansi_1 = require("../../../util/ansi");
9
+ const time_1 = require("../../../util/time");
10
+ const joi_1 = __importDefault(require("joi"));
11
+ exports.ProjectQueryDefinition = {
12
+ executor: project_query_executor_1.executeProjectQuery,
13
+ asciiSummarizer: (formatter, _processed, queryResults, result) => {
14
+ const out = queryResults;
15
+ result.push(`Query: ${(0, ansi_1.bold)('project', formatter)} (${(0, time_1.printAsMs)(out['.meta'].timing, 0)})`);
16
+ result.push(` ╰ Contains ${out.files.length} file${out.files.length === 1 ? '' : 's'}`);
17
+ for (const file of out.files) {
18
+ result.push(` ╰ \`${file}\``);
19
+ }
20
+ return true;
21
+ },
22
+ schema: joi_1.default.object({
23
+ type: joi_1.default.string().valid('project').required().description('The type of the query.'),
24
+ }).description('The project query provides information on the analyzed project.')
25
+ };
26
+ //# sourceMappingURL=project-query-format.js.map
@@ -19,7 +19,8 @@ import type { SearchQuery } from './catalog/search-query/search-query-format';
19
19
  import type { HappensBeforeQuery } from './catalog/happens-before-query/happens-before-query-format';
20
20
  import type { ResolveValueQuery } from './catalog/resolve-value-query/resolve-value-query-format';
21
21
  import type { DataflowLensQuery } from './catalog/dataflow-lens-query/dataflow-lens-query-format';
22
- export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | DataflowLensQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery | ResolveValueQuery;
22
+ import type { ProjectQuery } from './catalog/project-query/project-query-format';
23
+ export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | DataflowLensQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery | ResolveValueQuery | ProjectQuery;
23
24
  export type QueryArgumentsWithType<QueryType extends BaseQueryFormat['type']> = Query & {
24
25
  type: QueryType;
25
26
  };
@@ -686,6 +687,64 @@ export declare const SupportedQueries: {
686
687
  }>>, queryResults: BaseQueryResult, result: string[]) => true;
687
688
  readonly schema: Joi.ObjectSchema<any>;
688
689
  };
690
+ readonly project: {
691
+ readonly executor: typeof import("./catalog/project-query/project-query-executor").executeProjectQuery;
692
+ readonly asciiSummarizer: (formatter: OutputFormatter, _processed: PipelineOutput<import("../core/steps/pipeline/pipeline").Pipeline<{
693
+ readonly name: "parse";
694
+ readonly humanReadableName: "parse with R shell";
695
+ readonly description: "Parse the given R code into an AST";
696
+ readonly processor: (_results: unknown, input: Partial<import("../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../r-bridge/parser").ParseStepOutput<string>>;
697
+ readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
698
+ readonly printer: {
699
+ readonly 0: typeof import("../core/print/print").internalPrinter;
700
+ readonly 2: {
701
+ (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
702
+ (value: any, replacer?: (number | string)[] | null, space?: string | number): string;
703
+ };
704
+ readonly 5: ({ parsed }: import("../r-bridge/parser").ParseStepOutput<string>, config: import("../util/quads").QuadSerializationConfiguration) => string;
705
+ };
706
+ readonly dependencies: readonly [];
707
+ readonly requiredInput: import("../r-bridge/parser").ParseRequiredInput<string>;
708
+ } | {
709
+ readonly name: "normalize";
710
+ readonly humanReadableName: "normalize";
711
+ readonly description: "Normalize the AST to flowR's AST";
712
+ readonly processor: (results: {
713
+ parse?: import("../r-bridge/parser").ParseStepOutput<string>;
714
+ }, input: Partial<import("../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../r-bridge/lang-4.x/ast/model/model").RNode<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
715
+ readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
716
+ readonly printer: {
717
+ readonly 0: typeof import("../core/print/print").internalPrinter;
718
+ readonly 2: typeof import("../core/print/normalize-printer").normalizedAstToJson;
719
+ readonly 5: typeof import("../core/print/normalize-printer").normalizedAstToQuads;
720
+ readonly 3: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaid;
721
+ readonly 4: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
722
+ };
723
+ readonly dependencies: readonly ["parse"];
724
+ readonly requiredInput: import("../core/steps/all/core/10-normalize").NormalizeRequiredInput;
725
+ } | {
726
+ readonly humanReadableName: "dataflow";
727
+ readonly processor: (results: {
728
+ normalize?: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
729
+ }, input: {
730
+ request?: import("../r-bridge/retriever").RParseRequests;
731
+ parser?: import("../r-bridge/parser").Parser<import("../r-bridge/parser").KnownParserType>;
732
+ }) => import("../dataflow/info").DataflowInformation;
733
+ readonly requiredInput: {};
734
+ readonly name: "dataflow";
735
+ readonly description: "Construct the dataflow graph";
736
+ readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
737
+ readonly printer: {
738
+ readonly 0: typeof import("../core/print/print").internalPrinter;
739
+ readonly 2: typeof import("../core/print/dataflow-printer").dataflowGraphToJson;
740
+ readonly 5: typeof import("../core/print/dataflow-printer").dataflowGraphToQuads;
741
+ readonly 3: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaid;
742
+ readonly 4: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
743
+ };
744
+ readonly dependencies: readonly ["normalize"];
745
+ }>>, queryResults: BaseQueryResult, result: string[]) => true;
746
+ readonly schema: Joi.ObjectSchema<any>;
747
+ };
689
748
  };
690
749
  export type SupportedQueryTypes = keyof typeof SupportedQueries;
691
750
  export type QueryResult<Type extends Query['type']> = ReturnType<typeof SupportedQueries[Type]['executor']>;
package/queries/query.js CHANGED
@@ -27,6 +27,7 @@ const search_query_format_1 = require("./catalog/search-query/search-query-forma
27
27
  const happens_before_query_format_1 = require("./catalog/happens-before-query/happens-before-query-format");
28
28
  const resolve_value_query_format_1 = require("./catalog/resolve-value-query/resolve-value-query-format");
29
29
  const dataflow_lens_query_format_1 = require("./catalog/dataflow-lens-query/dataflow-lens-query-format");
30
+ const project_query_format_1 = require("./catalog/project-query/project-query-format");
30
31
  exports.SupportedQueries = {
31
32
  'call-context': call_context_query_format_1.CallContextQueryDefinition,
32
33
  'config': config_query_format_1.ConfigQueryDefinition,
@@ -41,7 +42,8 @@ exports.SupportedQueries = {
41
42
  'location-map': location_map_query_format_1.LocationMapQueryDefinition,
42
43
  'search': search_query_format_1.SearchQueryDefinition,
43
44
  'happens-before': happens_before_query_format_1.HappensBeforeQueryDefinition,
44
- 'resolve-value': resolve_value_query_format_1.ResolveValueQueryDefinition
45
+ 'resolve-value': resolve_value_query_format_1.ResolveValueQueryDefinition,
46
+ 'project': project_query_format_1.ProjectQueryDefinition
45
47
  };
46
48
  function executeQueriesOfSameType(data, ...queries) {
47
49
  (0, assert_1.guard)(queries.length > 0, 'At least one query must be provided');
@@ -149,7 +149,7 @@ export declare const flowrCapabilities: {
149
149
  }, {
150
150
  readonly name: "Resolve Arguments";
151
151
  readonly id: "resolve-arguments";
152
- readonly supported: "partially";
152
+ readonly supported: "fully";
153
153
  readonly description: "_Correctly bind arguments (including [`pmatch`](https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/pmatch))._ Currently, we do not have a correct implementation for `pmatch`. Furthermore, more tests would be nice.";
154
154
  }, {
155
155
  readonly name: "Side-Effects in Argument";
@@ -418,7 +418,7 @@ export declare const flowrCapabilities: {
418
418
  }, {
419
419
  readonly name: "Internal and Primitive Functions";
420
420
  readonly id: "built-in-internal-and-primitive-functions";
421
- readonly supported: "not";
421
+ readonly supported: "partially";
422
422
  readonly description: "_Handle `.Internal`, `.Primitive`, ..._ In general we can not handle them as they refer to non-R code. We currently do not support them when used with the function.";
423
423
  }, {
424
424
  readonly name: "Options";
@@ -200,7 +200,7 @@ ${await (0, doc_dfg_1.printDfGraphForCode)(parser, code, { simplified: true })}
200
200
  {
201
201
  name: 'Resolve Arguments',
202
202
  id: 'resolve-arguments',
203
- supported: 'partially',
203
+ supported: 'fully',
204
204
  description: '_Correctly bind arguments (including [`pmatch`](https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/pmatch))._ Currently, we do not have a correct implementation for `pmatch`. Furthermore, more tests would be nice.'
205
205
  },
206
206
  {
@@ -532,7 +532,7 @@ ${await (0, doc_dfg_1.printDfGraphForCode)(parser, code, { simplified: true })}
532
532
  {
533
533
  name: 'Internal and Primitive Functions',
534
534
  id: 'built-in-internal-and-primitive-functions',
535
- supported: 'not',
535
+ supported: 'partially',
536
536
  description: '_Handle `.Internal`, `.Primitive`, ..._ In general we can not handle them as they refer to non-R code. We currently do not support them when used with the function.'
537
537
  },
538
538
  {
@@ -9,7 +9,14 @@ const object_hash_1 = __importDefault(require("object-hash"));
9
9
  const environment_1 = require("../../dataflow/environments/environment");
10
10
  const built_in_1 = require("../../dataflow/environments/built-in");
11
11
  function envFingerprint(env) {
12
- return (0, object_hash_1.default)(env, { excludeKeys: key => key === 'id', replacer: (v) => (v === environment_1.BuiltInEnvironment || v === built_in_1.EmptyBuiltInMemory) ? undefined : v });
12
+ return (0, object_hash_1.default)(env, {
13
+ algorithm: 'md5',
14
+ excludeKeys: key => key === 'id' || key === 'value',
15
+ respectFunctionProperties: false,
16
+ respectFunctionNames: false,
17
+ ignoreUnknown: true,
18
+ replacer: (v) => (v === environment_1.BuiltInEnvironment || v === built_in_1.EmptyBuiltInMemory) ? undefined : v
19
+ });
13
20
  }
14
21
  function fingerprint(id, envFingerprint, onlyForSideEffects) {
15
22
  return `${id}-${envFingerprint}-${onlyForSideEffects ? '0' : '1'}`;
@@ -8,7 +8,7 @@ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-i
8
8
  /**
9
9
  * Returns the function call targets (definitions) by the given caller
10
10
  */
11
- export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
11
+ export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation, queue: VisitingQueue): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
12
12
  /** returns the new threshold hit count */
13
13
  export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowGraph: DataflowGraph, queue: VisitingQueue): void;
14
14
  /** Returns true if we found at least one return edge */
@@ -16,7 +16,7 @@ const static_slicer_1 = require("./static-slicer");
16
16
  /**
17
17
  * Returns the function call targets (definitions) by the given caller
18
18
  */
19
- function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment) {
19
+ function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment, queue) {
20
20
  // bind with call-local environments during slicing
21
21
  const outgoingEdges = dataflowGraph.get(callerInfo.id, true);
22
22
  (0, assert_1.guard)(outgoingEdges !== undefined, () => `outgoing edges of id: ${callerInfo.id} must be in graph but can not be found, keep in slice to be sure`);
@@ -30,7 +30,7 @@ function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment) {
30
30
  functionCallDefs.push(target);
31
31
  }
32
32
  }
33
- const functionCallTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set(functionCallDefs), dataflowGraph);
33
+ const functionCallTargets = queue.memoizeCallTargets(functionCallDefs.join(';'), () => (0, linker_1.getAllLinkedFunctionDefinitions)(new Set(functionCallDefs), dataflowGraph));
34
34
  return [functionCallTargets, activeEnvironment];
35
35
  }
36
36
  function includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowGraph) {
@@ -38,22 +38,11 @@ function includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironm
38
38
  if (!valueRoot) {
39
39
  return;
40
40
  }
41
- const callTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set([valueRoot]), dataflowGraph);
41
+ const callTargets = queue.memoizeCallTargets(valueRoot, () => (0, linker_1.getAllLinkedFunctionDefinitions)(new Set([valueRoot]), dataflowGraph));
42
42
  linkCallTargets(false, callTargets, activeEnvironment, (0, fingerprint_1.envFingerprint)(activeEnvironment), queue);
43
43
  }
44
44
  function linkCallTargets(onlyForSideEffects, functionCallTargets, activeEnvironment, activeEnvironmentFingerprint, queue) {
45
45
  for (const functionCallTarget of functionCallTargets) {
46
- // all those linked within the scopes of other functions are already linked when exiting a function definition
47
- /* for(const openIn of (functionCallTarget as DataflowGraphVertexFunctionDefinition).subflow.in) {
48
- // only if the outgoing path does not already have a defined by linkage
49
- const defs = openIn.name ? resolveByName(openIn.name, activeEnvironment, openIn.type) : undefined;
50
- if(defs === undefined) {
51
- continue;
52
- }
53
- for(const def of defs.filter(d => d.nodeId !== BuiltIn)) {
54
- queue.add(def.nodeId, baseEnvironment, baseEnvPrint, onlyForSideEffects);
55
- }
56
- }*/
57
46
  for (const exitPoint of functionCallTarget.exitPoints) {
58
47
  queue.add(exitPoint, activeEnvironment, activeEnvironmentFingerprint, onlyForSideEffects);
59
48
  }
@@ -62,7 +51,7 @@ function linkCallTargets(onlyForSideEffects, functionCallTargets, activeEnvironm
62
51
  /** returns the new threshold hit count */
63
52
  function sliceForCall(current, callerInfo, dataflowGraph, queue) {
64
53
  const baseEnvironment = current.baseEnvironment;
65
- const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowGraph, callerInfo, current.baseEnvironment);
54
+ const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowGraph, callerInfo, current.baseEnvironment, queue);
66
55
  const activeEnvironmentFingerprint = (0, fingerprint_1.envFingerprint)(activeEnvironment);
67
56
  if (functionCallTargets.size === 0) {
68
57
  /*
@@ -91,7 +80,7 @@ function handleReturns(from, queue, currentEdges, baseEnvFingerprint, baseEnviro
91
80
  queue.add(target, baseEnvironment, baseEnvFingerprint, false);
92
81
  }
93
82
  else if ((0, edge_1.edgeIncludesType)(edge.types, edge_1.EdgeType.DefinesOnCall | edge_1.EdgeType.DefinedByOnCall | edge_1.EdgeType.Argument)) {
94
- (0, static_slicer_1.updatePotentialAddition)(queue, from, target, baseEnvironment);
83
+ (0, static_slicer_1.updatePotentialAddition)(queue, from, target, baseEnvironment, baseEnvFingerprint);
95
84
  }
96
85
  }
97
86
  return true;
@@ -9,6 +9,8 @@ export interface NodeToSlice {
9
9
  readonly id: NodeId;
10
10
  /** used for calling context, etc. */
11
11
  readonly baseEnvironment: REnvironmentInformation;
12
+ /** the fingerprint of the environment */
13
+ readonly envFingerprint: string;
12
14
  /** if we add a function call, we may need it only for its side effects (e.g., a redefinition of a global variable), if so, 'returns' links will not be traced */
13
15
  readonly onlyForSideEffects: boolean;
14
16
  }
@@ -1,4 +1,5 @@
1
1
  import type { SliceResult } from './slicer-types';
2
+ import type { Fingerprint } from './fingerprint';
2
3
  import { VisitingQueue } from './visiting-queue';
3
4
  import type { DataflowGraph } from '../../dataflow/graph/graph';
4
5
  import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
@@ -15,6 +16,7 @@ export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogOb
15
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
17
  * @param criteria - The criterias to slice on.
17
18
  * @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
+ * @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.
18
20
  */
19
- export declare function staticSlicing(graph: DataflowGraph, { idMap }: NormalizedAst, criteria: SlicingCriteria, threshold?: number): Readonly<SliceResult>;
20
- export declare function updatePotentialAddition(queue: VisitingQueue, id: NodeId, target: NodeId, baseEnvironment: REnvironmentInformation): void;
21
+ export declare function staticSlicing(graph: DataflowGraph, { idMap }: NormalizedAst, criteria: SlicingCriteria, threshold?: number, cache?: Map<Fingerprint, Set<NodeId>>): Readonly<SliceResult>;
22
+ export declare function updatePotentialAddition(queue: VisitingQueue, id: NodeId, target: NodeId, baseEnvironment: REnvironmentInformation, envFingerprint: string): void;
@@ -12,6 +12,7 @@ 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 config_1 = require("../../config");
15
16
  exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
16
17
  /**
17
18
  * This returns the ids to include in the static backward slice, when slicing with the given seed id's (must be at least one).
@@ -22,12 +23,13 @@ exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
22
23
  * @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
24
  * @param criteria - The criterias to slice on.
24
25
  * @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.
26
+ * @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.
25
27
  */
26
- function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
28
+ function staticSlicing(graph, { idMap }, criteria, threshold = (0, config_1.getConfig)().solver.slicer?.threshold ?? 75, cache) {
27
29
  (0, assert_1.guard)(criteria.length > 0, 'must have at least one seed id to calculate slice');
28
30
  const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria, idMap);
29
31
  (0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
30
- const queue = new visiting_queue_1.VisitingQueue(threshold);
32
+ const queue = new visiting_queue_1.VisitingQueue(threshold, cache);
31
33
  let minNesting = Number.MAX_SAFE_INTEGER;
32
34
  const sliceSeedIds = new Set();
33
35
  // every node ships the call environment which registers the calling environment
@@ -44,15 +46,15 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
44
46
  * include all the implicit side effects that we have to consider as we are unable to narrow them down
45
47
  */
46
48
  for (const id of graph.unknownSideEffects) {
47
- if (typeof id !== 'object') { /* otherwise, their target is just missing */
49
+ if (typeof id !== 'object') {
50
+ /* otherwise, their target is just missing */
48
51
  queue.add(id, emptyEnv, basePrint, true);
49
52
  }
50
53
  }
51
54
  }
52
55
  while (queue.nonEmpty()) {
53
56
  const current = queue.next();
54
- const { baseEnvironment, id, onlyForSideEffects } = current;
55
- const baseEnvFingerprint = (0, fingerprint_1.envFingerprint)(baseEnvironment);
57
+ const { baseEnvironment, id, onlyForSideEffects, envFingerprint: baseEnvFingerprint } = current;
56
58
  const currentInfo = graph.get(id, true);
57
59
  if (currentInfo === undefined) {
58
60
  exports.slicerLogger.warn(`id: ${id} must be in graph but can not be found, keep in slice to be sure`);
@@ -78,29 +80,32 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
78
80
  }
79
81
  }
80
82
  for (const [target, { types }] of currentEdges) {
81
- if ((0, edge_1.edgeIncludesType)(types, edge_1.EdgeType.NonStandardEvaluation)) {
82
- continue;
83
- }
84
83
  const t = (0, edge_1.shouldTraverseEdge)(types);
85
- if (t === 3 /* TraverseEdge.Always */) {
86
- queue.add(target, baseEnvironment, baseEnvFingerprint, false);
87
- }
88
- else if (t === 2 /* TraverseEdge.OnlyIfBoth */) {
89
- updatePotentialAddition(queue, id, target, baseEnvironment);
90
- }
91
- else if (t === 1 /* TraverseEdge.SideEffect */) {
92
- queue.add(target, baseEnvironment, baseEnvFingerprint, true);
84
+ switch (t) {
85
+ case 0 /* TraverseEdge.Never */:
86
+ continue;
87
+ case 3 /* TraverseEdge.Always */:
88
+ queue.add(target, baseEnvironment, baseEnvFingerprint, false);
89
+ continue;
90
+ case 2 /* TraverseEdge.OnlyIfBoth */:
91
+ updatePotentialAddition(queue, id, target, baseEnvironment, baseEnvFingerprint);
92
+ continue;
93
+ case 1 /* TraverseEdge.SideEffect */:
94
+ queue.add(target, baseEnvironment, baseEnvFingerprint, true);
95
+ continue;
96
+ default:
97
+ (0, assert_1.assertUnreachable)(t);
93
98
  }
94
99
  }
95
100
  }
96
101
  return { ...queue.status(), decodedCriteria };
97
102
  }
98
- function updatePotentialAddition(queue, id, target, baseEnvironment) {
103
+ function updatePotentialAddition(queue, id, target, baseEnvironment, envFingerprint) {
99
104
  const n = queue.potentialAdditions.get(target);
100
105
  if (n) {
101
106
  const [addedBy, { baseEnvironment, onlyForSideEffects }] = n;
102
107
  if (addedBy !== id) {
103
- queue.add(target, baseEnvironment, (0, fingerprint_1.envFingerprint)(baseEnvironment), onlyForSideEffects);
108
+ queue.add(target, baseEnvironment, envFingerprint, onlyForSideEffects);
104
109
  queue.potentialAdditions.delete(target);
105
110
  }
106
111
  }
@@ -108,6 +113,7 @@ function updatePotentialAddition(queue, id, target, baseEnvironment) {
108
113
  queue.potentialAdditions.set(target, [id, {
109
114
  id: target,
110
115
  baseEnvironment,
116
+ envFingerprint,
111
117
  onlyForSideEffects: false
112
118
  }]);
113
119
  }
@@ -1,14 +1,19 @@
1
+ import type { Fingerprint } from './fingerprint';
1
2
  import type { NodeToSlice, SliceResult } from './slicer-types';
2
3
  import type { REnvironmentInformation } from '../../dataflow/environments/environment';
3
4
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
5
+ import type { DataflowGraphVertexInfo } from '../../dataflow/graph/vertex';
4
6
  export declare class VisitingQueue {
5
7
  private readonly threshold;
6
8
  private timesHitThreshold;
7
9
  private readonly seen;
10
+ private readonly seenByCache;
8
11
  private readonly idThreshold;
9
12
  private readonly queue;
13
+ private readonly cache?;
10
14
  potentialAdditions: Map<NodeId, [NodeId, NodeToSlice]>;
11
- constructor(threshold: number);
15
+ private cachedCallTargets;
16
+ constructor(threshold: number, cache?: Map<Fingerprint, Set<NodeId>>);
12
17
  /**
13
18
  * Adds a node to the queue if it has not been seen before.
14
19
  * @param target - the node to add
@@ -20,5 +25,6 @@ export declare class VisitingQueue {
20
25
  next(): NodeToSlice;
21
26
  nonEmpty(): boolean;
22
27
  hasId(id: NodeId): boolean;
28
+ memoizeCallTargets(id: NodeId, targets: () => Set<DataflowGraphVertexInfo>): Set<DataflowGraphVertexInfo>;
23
29
  status(): Readonly<Pick<SliceResult, 'timesHitThreshold' | 'result'>>;
24
30
  }
@@ -2,19 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VisitingQueue = void 0;
4
4
  const fingerprint_1 = require("./fingerprint");
5
- const static_slicer_1 = require("./static-slicer");
6
- const assert_1 = require("../../util/assert");
7
5
  class VisitingQueue {
8
6
  threshold;
9
7
  timesHitThreshold = 0;
10
8
  seen = new Map();
9
+ seenByCache = new Set();
11
10
  idThreshold = new Map();
12
11
  queue = [];
12
+ cache = new Map();
13
13
  // the set of potential additions holds nodes which may be added if a second edge deems them relevant (e.g., found with the `defined-by-on-call` edge)
14
14
  // additionally it holds which node id added the addition so we can separate their inclusion on the structure
15
15
  potentialAdditions = new Map();
16
- constructor(threshold) {
16
+ cachedCallTargets = new Map();
17
+ constructor(threshold, cache) {
17
18
  this.threshold = threshold;
19
+ this.cache = cache;
18
20
  }
19
21
  /**
20
22
  * Adds a node to the queue if it has not been seen before.
@@ -26,16 +28,22 @@ class VisitingQueue {
26
28
  add(target, env, envFingerprint, onlyForSideEffects) {
27
29
  const idCounter = this.idThreshold.get(target) ?? 0;
28
30
  if (idCounter > this.threshold) {
29
- static_slicer_1.slicerLogger.warn(`id: ${target} has been visited ${idCounter} times, skipping`);
30
31
  this.timesHitThreshold++;
31
32
  return;
32
33
  }
33
34
  /* we do not include the in call part in the fingerprint as it is 'deterministic' from the source position */
34
35
  const print = (0, fingerprint_1.fingerprint)(target, envFingerprint, onlyForSideEffects);
35
36
  if (!this.seen.has(print)) {
37
+ const cached = this.cache?.get(print);
38
+ if (cached) {
39
+ this.seenByCache.add(target);
40
+ for (const id of cached) {
41
+ this.queue.push({ id, baseEnvironment: env, envFingerprint, onlyForSideEffects });
42
+ }
43
+ }
36
44
  this.idThreshold.set(target, idCounter + 1);
37
45
  this.seen.set(print, target);
38
- this.queue.push({ id: target, baseEnvironment: env, onlyForSideEffects });
46
+ this.queue.push({ id: target, baseEnvironment: env, envFingerprint, onlyForSideEffects });
39
47
  }
40
48
  }
41
49
  next() {
@@ -47,10 +55,16 @@ class VisitingQueue {
47
55
  hasId(id) {
48
56
  return this.idThreshold.has(id);
49
57
  }
58
+ memoizeCallTargets(id, targets) {
59
+ if (!this.cachedCallTargets.has(id)) {
60
+ this.cachedCallTargets.set(id, targets());
61
+ }
62
+ return this.cachedCallTargets.get(id);
63
+ }
50
64
  status() {
51
65
  return {
52
66
  timesHitThreshold: this.timesHitThreshold,
53
- result: new Set([...this.seen.values()].filter(assert_1.isNotUndefined))
67
+ result: new Set([...this.seen.values(), ...this.seenByCache])
54
68
  };
55
69
  }
56
70
  }
package/util/arrays.d.ts CHANGED
@@ -65,3 +65,26 @@ export declare function arraySum(arr: readonly number[]): number;
65
65
  */
66
66
  export declare function array2bag<T>(arr: T[]): Map<T, number>;
67
67
  export declare function arrayEqual<T>(a: readonly T[] | undefined, b: readonly T[] | undefined): boolean;
68
+ /**
69
+ * Samples elements from a list such that the distance between the sampled elements is as equal as possible.
70
+ *
71
+ * If the number of elements to sample is greater or equal to the number of elements in the list, the list is returned as is.
72
+ * If the number of elements to sample is less than or equal to 0, an empty list is returned.
73
+ *
74
+ * @param list - list of elements
75
+ * @param sampleCount - number of elements to sample
76
+ * @param rounding - rounding mode to use for the index calculation
77
+ * @returns - a list of elements equidistantly sampled from the input list
78
+ */
79
+ export declare function equidistantSampling<T>(list: readonly T[], sampleCount: number, rounding?: 'floor' | 'ceil'): T[];
80
+ /**
81
+ * Returns the cartesian product of the given arrays.
82
+ * @example
83
+ *
84
+ * ```ts
85
+ * cartesianProduct([1, 2], ['a', 'b', 'c'], [true, false])
86
+ * // -> [[1, 'a', true], [1, 'a', false], [1, 'b', true], [1, 'b', false], [1, 'c', true], [1, 'c', false], [2, 'a', true], [2, 'a', false], [2, 'b', true], [2, 'b', false], [2, 'c', true], [2, 'c', false]]
87
+ * ```
88
+ *
89
+ */
90
+ export declare function cartesianProduct<T>(...arrays: T[][]): T[][];