@eagleoutice/flowr 2.1.8 → 2.1.9

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 (65) hide show
  1. package/benchmark/summarizer/first-phase/process.js +6 -5
  2. package/cli/repl/commands/repl-dataflow.js +5 -2
  3. package/cli/repl/commands/repl-normalize.js +5 -2
  4. package/cli/repl/commands/repl-query.js +2 -2
  5. package/cli/repl/server/messages/message-query.js +1 -1
  6. package/dataflow/environments/default-builtin-config.js +45 -6
  7. package/dataflow/environments/environment.d.ts +46 -8
  8. package/dataflow/environments/environment.js +24 -1
  9. package/dataflow/environments/identifier.d.ts +49 -7
  10. package/dataflow/environments/identifier.js +11 -2
  11. package/dataflow/extractor.js +5 -4
  12. package/dataflow/graph/dataflowgraph-builder.d.ts +6 -0
  13. package/dataflow/graph/dataflowgraph-builder.js +8 -0
  14. package/dataflow/graph/edge.d.ts +10 -4
  15. package/dataflow/graph/edge.js +12 -5
  16. package/dataflow/graph/graph.d.ts +41 -3
  17. package/dataflow/graph/graph.js +39 -34
  18. package/dataflow/graph/vertex.d.ts +66 -7
  19. package/dataflow/graph/vertex.js +15 -0
  20. package/dataflow/info.d.ts +79 -11
  21. package/dataflow/info.js +20 -0
  22. package/dataflow/internal/linker.d.ts +4 -2
  23. package/dataflow/internal/linker.js +12 -5
  24. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -0
  25. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -3
  26. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +16 -0
  27. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +83 -6
  28. package/dataflow/internal/process/functions/call/common.js +1 -1
  29. package/documentation/doc-util/doc-dfg.d.ts +0 -1
  30. package/documentation/doc-util/doc-dfg.js +1 -14
  31. package/documentation/print-capabilities-markdown.js +1 -1
  32. package/documentation/print-dataflow-graph-wiki.js +26 -7
  33. package/documentation/print-linting-and-testing-wiki.js +60 -26
  34. package/documentation/print-query-wiki.js +1 -1
  35. package/package.json +17 -3
  36. package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
  37. package/queries/catalog/call-context-query/call-context-query-format.d.ts +13 -0
  38. package/queries/catalog/call-context-query/call-context-query-format.js +3 -1
  39. package/queries/catalog/call-context-query/cascade-action.d.ts +8 -0
  40. package/queries/catalog/call-context-query/cascade-action.js +13 -0
  41. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -1
  42. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +41 -4
  43. package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -0
  44. package/queries/query.d.ts +4 -4
  45. package/queries/query.js +17 -5
  46. package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
  47. package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +5 -1
  48. package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +6 -1
  49. package/r-bridge/lang-4.x/ast/model/processing/node-id.js +6 -1
  50. package/slicing/static/slice-call.d.ts +7 -2
  51. package/slicing/static/slice-call.js +33 -44
  52. package/slicing/static/static-slicer.d.ts +5 -1
  53. package/slicing/static/static-slicer.js +22 -8
  54. package/slicing/static/visiting-queue.d.ts +4 -4
  55. package/slicing/static/visiting-queue.js +5 -3
  56. package/statistics/output/print-stats.js +2 -1
  57. package/statistics/summarizer/post-process/histogram.js +2 -1
  58. package/statistics/summarizer/post-process/post-process-output.js +2 -1
  59. package/statistics/summarizer/second-phase/process.js +3 -3
  60. package/util/arrays.d.ts +1 -1
  61. package/util/arrays.js +3 -3
  62. package/util/cfg/cfg.js +4 -2
  63. package/util/mermaid/cfg.js +1 -1
  64. package/util/summarizer.js +2 -2
  65. package/util/version.js +1 -1
@@ -6,6 +6,9 @@ import Joi from 'joi';
6
6
  import type { PipelineOutput } from '../../../core/steps/pipeline/pipeline';
7
7
  import type { DEFAULT_DATAFLOW_PIPELINE } from '../../../core/steps/pipeline/default-pipelines';
8
8
  import { CallTargets } from './identify-link-to-last-call-relation';
9
+ import type { DataflowGraph } from '../../../dataflow/graph/graph';
10
+ import type { DataflowGraphVertexInfo } from '../../../dataflow/graph/vertex';
11
+ import type { CascadeAction } from './cascade-action';
9
12
  export interface FileFilter<FilterType> {
10
13
  /**
11
14
  * Regex that a node's file attribute must match to be considered
@@ -52,6 +55,16 @@ interface LinkToLastCall<CallName extends RegExp | string = RegExp | string> ext
52
55
  readonly type: 'link-to-last-call';
53
56
  /** Regex regarding the function name of the last call. Similar to {@link DefaultCallContextQueryFormat#callName}, strings are interpreted as a `RegExp`. */
54
57
  readonly callName: CallName;
58
+ /**
59
+ * Should we ignore this (source) call?
60
+ * Currently, there is no well working serialization for this.
61
+ */
62
+ readonly ignoreIf?: (id: NodeId, graph: DataflowGraph) => boolean;
63
+ /**
64
+ * Should we continue searching after the link was created?
65
+ * Currently, there is no well working serialization for this.
66
+ */
67
+ readonly cascadeIf?: (target: DataflowGraphVertexInfo, from: NodeId, graph: DataflowGraph) => CascadeAction;
55
68
  }
56
69
  export type LinkTo<CallName extends RegExp | string> = LinkToLastCall<CallName>;
57
70
  export interface SubCallContextQueryFormat<CallName extends RegExp | string = RegExp | string> extends DefaultCallContextQueryFormat<CallName> {
@@ -32,7 +32,9 @@ exports.CallContextQueryDefinition = {
32
32
  }).optional().description('Filter that, when set, a node\'s file attribute must match to be considered'),
33
33
  linkTo: joi_1.default.object({
34
34
  type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
35
- callName: joi_1.default.string().required().description('Regex regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression.')
35
+ callName: joi_1.default.string().required().description('Regex regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression.'),
36
+ ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
37
+ cascadeIf: joi_1.default.function().optional().description('Should we continue searching after the link was created? Currently, there is no well working serialization for this.')
36
38
  }).optional().description('Links the current call to the last call of the given kind. This way, you can link a call like `points` to the latest graphics plot etc.')
37
39
  }).description('Call context query used to find calls in the dataflow graph')
38
40
  };
@@ -0,0 +1,8 @@
1
+ export declare enum CascadeAction {
2
+ /** The action is to start the cascade */
3
+ Stop = "stop",
4
+ /** The action is to continue the cascade */
5
+ Continue = "continue",
6
+ /** The action is to skip the current node */
7
+ Skip = "skip"
8
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CascadeAction = void 0;
4
+ var CascadeAction;
5
+ (function (CascadeAction) {
6
+ /** The action is to start the cascade */
7
+ CascadeAction["Stop"] = "stop";
8
+ /** The action is to continue the cascade */
9
+ CascadeAction["Continue"] = "continue";
10
+ /** The action is to skip the current node */
11
+ CascadeAction["Skip"] = "skip";
12
+ })(CascadeAction || (exports.CascadeAction = CascadeAction = {}));
13
+ //# sourceMappingURL=cascade-action.js.map
@@ -1,6 +1,10 @@
1
1
  import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
2
2
  import type { ControlFlowGraph } from '../../../util/cfg/cfg';
3
3
  import type { DataflowGraph } from '../../../dataflow/graph/graph';
4
+ import type { DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
5
+ import { RType } from '../../../r-bridge/lang-4.x/ast/model/type';
6
+ import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
7
+ import type { LinkTo } from './call-context-query-format';
4
8
  export declare enum CallTargets {
5
9
  /** call targets a function that is not defined locally (e.g., the call targets a library function) */
6
10
  OnlyGlobal = "global",
@@ -14,4 +18,10 @@ export declare enum CallTargets {
14
18
  Any = "any"
15
19
  }
16
20
  export declare function satisfiesCallTargets(id: NodeId, graph: DataflowGraph, callTarget: CallTargets): NodeId[] | 'no';
17
- export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, linkTo: RegExp): NodeId[];
21
+ export declare function getValueOfArgument<Types extends readonly RType[] = readonly RType[]>(graph: DataflowGraph, call: DataflowGraphVertexFunctionCall | undefined, argument: {
22
+ name?: string;
23
+ index: number;
24
+ }, additionalAllowedTypes?: Types): (RNodeWithParent & {
25
+ type: Types[number];
26
+ }) | undefined;
27
+ export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, ignoreIf, cascadeIf }: LinkTo<RegExp>): NodeId[];
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CallTargets = void 0;
4
4
  exports.satisfiesCallTargets = satisfiesCallTargets;
5
+ exports.getValueOfArgument = getValueOfArgument;
5
6
  exports.identifyLinkToLastCallRelation = identifyLinkToLastCallRelation;
7
+ const graph_1 = require("../../../dataflow/graph/graph");
6
8
  const visitor_1 = require("../../../util/cfg/visitor");
7
9
  const vertex_1 = require("../../../dataflow/graph/vertex");
8
10
  const edge_1 = require("../../../dataflow/graph/edge");
@@ -10,6 +12,9 @@ const resolve_by_name_1 = require("../../../dataflow/environments/resolve-by-nam
10
12
  const identifier_1 = require("../../../dataflow/environments/identifier");
11
13
  const built_in_1 = require("../../../dataflow/environments/built-in");
12
14
  const assert_1 = require("../../../util/assert");
15
+ const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
16
+ const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
17
+ const cascade_action_1 = require("./cascade-action");
13
18
  var CallTargets;
14
19
  (function (CallTargets) {
15
20
  /** call targets a function that is not defined locally (e.g., the call targets a library function) */
@@ -74,8 +79,36 @@ function satisfiesCallTargets(id, graph, callTarget) {
74
79
  (0, assert_1.assertUnreachable)(callTarget);
75
80
  }
76
81
  }
77
- function identifyLinkToLastCallRelation(from, cfg, graph, linkTo) {
82
+ function getValueOfArgument(graph, call, argument, additionalAllowedTypes) {
83
+ if (!call) {
84
+ return undefined;
85
+ }
86
+ const totalIndex = argument.name ? call.args.findIndex(arg => arg !== r_function_call_1.EmptyArgument && arg.name === argument.name) : -1;
87
+ let refAtIndex;
88
+ if (totalIndex < 0) {
89
+ const references = call.args.filter(arg => arg !== r_function_call_1.EmptyArgument && !arg.name).map(graph_1.getReferenceOfArgument);
90
+ refAtIndex = references[argument.index];
91
+ }
92
+ else {
93
+ const arg = call.args[totalIndex];
94
+ refAtIndex = (0, graph_1.getReferenceOfArgument)(arg);
95
+ }
96
+ if (refAtIndex === undefined) {
97
+ return undefined;
98
+ }
99
+ let valueNode = graph.idMap?.get(refAtIndex);
100
+ if (valueNode?.type === type_1.RType.Argument) {
101
+ valueNode = valueNode.value;
102
+ }
103
+ if (valueNode) {
104
+ return !additionalAllowedTypes || additionalAllowedTypes.includes(valueNode.type) ? valueNode : undefined;
105
+ }
106
+ }
107
+ function identifyLinkToLastCallRelation(from, cfg, graph, { callName, ignoreIf, cascadeIf }) {
78
108
  const found = [];
109
+ if (ignoreIf && ignoreIf(from, graph)) {
110
+ return found;
111
+ }
79
112
  (0, visitor_1.visitInReverseOrder)(cfg, from, node => {
80
113
  /* we ignore the start id as it cannot be the last call */
81
114
  if (node === from) {
@@ -85,13 +118,17 @@ function identifyLinkToLastCallRelation(from, cfg, graph, linkTo) {
85
118
  if (vertex === undefined || vertex[0].tag !== vertex_1.VertexType.FunctionCall) {
86
119
  return;
87
120
  }
88
- if (linkTo.test(vertex[0].name)) {
121
+ if (callName.test(vertex[0].name)) {
122
+ const act = cascadeIf ? cascadeIf(vertex[0], from, graph) : cascade_action_1.CascadeAction.Stop;
123
+ if (act === cascade_action_1.CascadeAction.Skip) {
124
+ return;
125
+ }
89
126
  const tar = satisfiesCallTargets(vertex[0].id, graph, CallTargets.MustIncludeGlobal);
90
127
  if (tar === 'no') {
91
- return true;
128
+ return act === cascade_action_1.CascadeAction.Stop;
92
129
  }
93
130
  found.push(node);
94
- return true;
131
+ return act === cascade_action_1.CascadeAction.Stop;
95
132
  }
96
133
  });
97
134
  return found;
@@ -83,6 +83,8 @@ exports.ReadFunctions = [
83
83
  { name: 'read.ssd', argIdx: 0, argName: 'file' },
84
84
  { name: 'read.systat', argIdx: 0, argName: 'file' },
85
85
  { name: 'read.xport', argIdx: 0, argName: 'file' },
86
+ // car
87
+ { name: 'Import', argIdx: 0, argName: 'file' },
86
88
  ];
87
89
  exports.WriteFunctions = [
88
90
  { name: 'save', argIdx: 0, argName: '...' },
@@ -138,6 +140,8 @@ exports.WriteFunctions = [
138
140
  { name: 'tiff', argIdx: 0, argName: 'file' },
139
141
  { name: 'X11', argIdx: 0, argName: 'file' },
140
142
  { name: 'quartz', argIdx: 0, argName: 'file' },
143
+ // car
144
+ { name: 'Export', argIdx: 0, argName: 'file' },
141
145
  ];
142
146
  function printResultSection(title, infos, result, sectionSpecifics) {
143
147
  if (infos.length <= 0) {
@@ -450,9 +450,9 @@ type OmitFromValues<T, K extends string | number | symbol> = {
450
450
  export type QueryResultsWithoutMeta<Queries extends Query> = OmitFromValues<Omit<QueryResults<Queries['type']>, '.meta'>, '.meta'>;
451
451
  export type Queries<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>> = readonly (QueryArgumentsWithType<Base> | VirtualQueryArgumentsWithType<Base, VirtualArguments>)[];
452
452
  export declare function executeQueries<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(data: BasicQueryData, queries: Queries<Base, VirtualArguments>): QueryResults<Base>;
453
- export declare const SupportedQueriesSchema: Joi.AlternativesSchema<any>;
453
+ export declare function SupportedQueriesSchema(): Joi.AlternativesSchema<any>;
454
454
  export declare const CompoundQuerySchema: Joi.ObjectSchema<any>;
455
- export declare const VirtualQuerySchema: Joi.AlternativesSchema<any>;
456
- export declare const AnyQuerySchema: Joi.AlternativesSchema<any>;
457
- export declare const QueriesSchema: Joi.ArraySchema<any[]>;
455
+ export declare function VirtualQuerySchema(): Joi.AlternativesSchema<any>;
456
+ export declare function AnyQuerySchema(): Joi.AlternativesSchema<any>;
457
+ export declare function QueriesSchema(): Joi.ArraySchema<any[]>;
458
458
  export {};
package/queries/query.js CHANGED
@@ -3,9 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.QueriesSchema = exports.AnyQuerySchema = exports.VirtualQuerySchema = exports.CompoundQuerySchema = exports.SupportedQueriesSchema = exports.SupportedQueries = void 0;
6
+ exports.CompoundQuerySchema = exports.SupportedQueries = void 0;
7
7
  exports.executeQueriesOfSameType = executeQueriesOfSameType;
8
8
  exports.executeQueries = executeQueries;
9
+ exports.SupportedQueriesSchema = SupportedQueriesSchema;
10
+ exports.VirtualQuerySchema = VirtualQuerySchema;
11
+ exports.AnyQuerySchema = AnyQuerySchema;
12
+ exports.QueriesSchema = QueriesSchema;
9
13
  const call_context_query_format_1 = require("./catalog/call-context-query/call-context-query-format");
10
14
  const assert_1 = require("../util/assert");
11
15
  const virtual_queries_1 = require("./virtual-query/virtual-queries");
@@ -74,14 +78,22 @@ function executeQueries(data, queries) {
74
78
  };
75
79
  return results;
76
80
  }
77
- exports.SupportedQueriesSchema = joi_1.default.alternatives(Object.values(exports.SupportedQueries).map(q => q.schema)).description('Supported queries');
81
+ function SupportedQueriesSchema() {
82
+ return joi_1.default.alternatives(Object.values(exports.SupportedQueries).map(q => q.schema)).description('Supported queries');
83
+ }
78
84
  exports.CompoundQuerySchema = joi_1.default.object({
79
85
  type: joi_1.default.string().valid('compound').required().description('The type of the query.'),
80
86
  query: joi_1.default.string().required().description('The query to run on the file analysis information.'),
81
87
  commonArguments: joi_1.default.object().required().description('Common arguments for all queries.'),
82
88
  arguments: joi_1.default.array().items(joi_1.default.object()).required().description('Arguments for each query.')
83
89
  }).description('Compound query used to combine queries of the same type');
84
- exports.VirtualQuerySchema = joi_1.default.alternatives(exports.CompoundQuerySchema).description('Virtual queries (used for structure)');
85
- exports.AnyQuerySchema = joi_1.default.alternatives(exports.SupportedQueriesSchema, exports.VirtualQuerySchema).description('Any query');
86
- exports.QueriesSchema = joi_1.default.array().items(exports.AnyQuerySchema).description('Queries to run on the file analysis information (in the form of an array)');
90
+ function VirtualQuerySchema() {
91
+ return joi_1.default.alternatives(exports.CompoundQuerySchema).description('Virtual queries (used for structure)');
92
+ }
93
+ function AnyQuerySchema() {
94
+ return joi_1.default.alternatives(SupportedQueriesSchema(), VirtualQuerySchema()).description('Any query');
95
+ }
96
+ function QueriesSchema() {
97
+ return joi_1.default.array().items(AnyQuerySchema()).description('Queries to run on the file analysis information (in the form of an array)');
98
+ }
87
99
  //# sourceMappingURL=query.js.map
@@ -145,6 +145,9 @@ export type ROther<Info> = RComment<Info> | RLineDirective<Info>;
145
145
  * All other subtypes (like {@link RLoopConstructs}) listed above
146
146
  * can be used to restrict the kind of node. They do not have to be
147
147
  * exclusive, some nodes can appear in multiple subtypes.
148
+ *
149
+ * @see {@link recoverName} - to receive the name/lexeme from such a node
150
+ * @see {@link recoverContent} - for a more rigorous approach to get the content of a node within a {@link DataflowGraph|dataflow graph}
148
151
  */
149
152
  export type RNode<Info = NoInfo> = RExpressionList<Info> | RFunctions<Info> | ROther<Info> | RConstructs<Info> | RNamedAccess<Info> | RIndexAccess<Info> | RUnaryOp<Info> | RBinaryOp<Info> | RSingleNode<Info> | RPipe<Info>;
150
153
  export type OtherInfoNode = RNode | RDelimiter;
@@ -1,7 +1,11 @@
1
1
  import type { Leaf, Location, NoInfo } from '../model';
2
2
  import type { RType } from '../type';
3
3
  import type { RNumberValue } from '../../../convert-values';
4
- /** includes numeric, integer, and complex */
4
+ /**
5
+ * A number like `3`, `-2.14`, `1L`, or `2i`.
6
+ * Includes numeric, integer, and complex.
7
+ * See {@link RNumberValue} for more information.
8
+ */
5
9
  export interface RNumber<Info = NoInfo> extends Leaf<Info>, Location {
6
10
  readonly type: RType.Number;
7
11
  content: RNumberValue;
@@ -7,7 +7,12 @@ export type NodeId<T extends string | number = string | number> = T & {
7
7
  /** used so that we do not have to store strings for the default numeric ids */
8
8
  export declare function normalizeIdToNumberIfPossible(id: NodeId): NodeId;
9
9
  /**
10
- * Recovers the lexeme of a node from its id in the idmap.
10
+ * Recovers the lexeme of a {@link RNode|node} from its id in the {@link AstIdMap|id map}.
11
+ *
12
+ * @see {@link recoverContent} - to recover the content of a node
11
13
  */
12
14
  export declare function recoverName(id: NodeId, idMap?: AstIdMap): string | undefined;
15
+ /**
16
+ * Recovers the content of a {@link RNode|node} from its id in the {@link DataflowGraph|dataflow graph}.
17
+ */
13
18
  export declare function recoverContent(id: NodeId, graph: DataflowGraph): string | undefined;
@@ -15,11 +15,16 @@ function normalizeIdToNumberIfPossible(id) {
15
15
  return id;
16
16
  }
17
17
  /**
18
- * Recovers the lexeme of a node from its id in the idmap.
18
+ * Recovers the lexeme of a {@link RNode|node} from its id in the {@link AstIdMap|id map}.
19
+ *
20
+ * @see {@link recoverContent} - to recover the content of a node
19
21
  */
20
22
  function recoverName(id, idMap) {
21
23
  return idMap?.get(id)?.lexeme;
22
24
  }
25
+ /**
26
+ * Recovers the content of a {@link RNode|node} from its id in the {@link DataflowGraph|dataflow graph}.
27
+ */
23
28
  function recoverContent(id, graph) {
24
29
  const vertex = graph.getVertex(id);
25
30
  if (vertex === undefined) {
@@ -1,10 +1,15 @@
1
1
  import type { NodeToSlice } from './slicer-types';
2
2
  import type { VisitingQueue } from './visiting-queue';
3
3
  import type { Fingerprint } from './fingerprint';
4
- import type { DataflowGraphVertexFunctionCall } from '../../dataflow/graph/vertex';
4
+ import type { DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from '../../dataflow/graph/vertex';
5
5
  import type { REnvironmentInformation } from '../../dataflow/environments/environment';
6
6
  import type { DataflowGraph, OutgoingEdges } from '../../dataflow/graph/graph';
7
+ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
+ /**
9
+ * Returns the function call targets (definitions) by the given caller
10
+ */
11
+ export declare function getAllFunctionCallTargets(dataflowGraph: DataflowGraph, callerInfo: DataflowGraphVertexFunctionCall, baseEnvironment: REnvironmentInformation): [Set<DataflowGraphVertexInfo>, REnvironmentInformation];
7
12
  /** returns the new threshold hit count */
8
13
  export declare function sliceForCall(current: NodeToSlice, callerInfo: DataflowGraphVertexFunctionCall, dataflowGraph: DataflowGraph, queue: VisitingQueue): void;
9
14
  /** Returns true if we found at least one return edge */
10
- export declare function handleReturns(queue: VisitingQueue, currentEdges: OutgoingEdges, baseEnvFingerprint: Fingerprint, baseEnvironment: REnvironmentInformation): boolean;
15
+ export declare function handleReturns(from: NodeId, queue: VisitingQueue, currentEdges: OutgoingEdges, baseEnvFingerprint: Fingerprint, baseEnvironment: REnvironmentInformation): boolean;
@@ -1,31 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAllFunctionCallTargets = getAllFunctionCallTargets;
3
4
  exports.sliceForCall = sliceForCall;
4
5
  exports.handleReturns = handleReturns;
5
6
  const assert_1 = require("../../util/assert");
6
7
  const fingerprint_1 = require("./fingerprint");
7
8
  const linker_1 = require("../../dataflow/internal/linker");
8
- const environment_1 = require("../../dataflow/environments/environment");
9
- const scoping_1 = require("../../dataflow/environments/scoping");
10
- const overwrite_1 = require("../../dataflow/environments/overwrite");
11
9
  const graph_1 = require("../../dataflow/graph/graph");
12
10
  const built_in_1 = require("../../dataflow/environments/built-in");
13
11
  const resolve_by_name_1 = require("../../dataflow/environments/resolve-by-name");
14
12
  const edge_1 = require("../../dataflow/graph/edge");
15
13
  const identifier_1 = require("../../dataflow/environments/identifier");
16
- function retrieveActiveEnvironment(callerInfo, baseEnvironment) {
17
- let callerEnvironment = callerInfo.environment;
18
- let level = callerEnvironment?.level ?? 0;
19
- if (baseEnvironment.level !== level) {
20
- while (baseEnvironment.level < level) {
21
- baseEnvironment = (0, scoping_1.pushLocalEnvironment)(baseEnvironment);
22
- }
23
- while (baseEnvironment.level > level) {
24
- callerEnvironment = (0, scoping_1.pushLocalEnvironment)(callerEnvironment ?? (0, environment_1.initializeCleanEnvironments)(true));
25
- level = callerEnvironment.level;
14
+ const built_in_function_definition_1 = require("../../dataflow/internal/process/functions/call/built-in/built-in-function-definition");
15
+ const static_slicer_1 = require("./static-slicer");
16
+ /**
17
+ * Returns the function call targets (definitions) by the given caller
18
+ */
19
+ function getAllFunctionCallTargets(dataflowGraph, callerInfo, baseEnvironment) {
20
+ // bind with call-local environments during slicing
21
+ const outgoingEdges = dataflowGraph.get(callerInfo.id, true);
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`);
23
+ // lift baseEnv on the same level
24
+ const activeEnvironment = (0, built_in_function_definition_1.retrieveActiveEnvironment)(callerInfo.environment, baseEnvironment);
25
+ const name = callerInfo.name;
26
+ (0, assert_1.guard)(name !== undefined, () => `name of id: ${callerInfo.id} can not be found in id map`);
27
+ const functionCallDefs = (0, resolve_by_name_1.resolveByName)(name, activeEnvironment, identifier_1.ReferenceType.Unknown)?.filter(d => d.definedAt !== built_in_1.BuiltIn)?.map(d => d.nodeId) ?? [];
28
+ for (const [target, outgoingEdge] of outgoingEdges[1].entries()) {
29
+ if ((0, edge_1.edgeIncludesType)(outgoingEdge.types, edge_1.EdgeType.Calls)) {
30
+ functionCallDefs.push(target);
26
31
  }
27
32
  }
28
- return (0, overwrite_1.overwriteEnvironment)(baseEnvironment, callerEnvironment);
33
+ const functionCallTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set(functionCallDefs), dataflowGraph);
34
+ return [functionCallTargets, activeEnvironment];
29
35
  }
30
36
  function includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowGraph) {
31
37
  const valueRoot = (0, graph_1.getReferenceOfArgument)(arg);
@@ -33,20 +39,21 @@ function includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironm
33
39
  return;
34
40
  }
35
41
  const callTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set([valueRoot]), dataflowGraph);
36
- linkCallTargets(false, callTargets, baseEnvironment, (0, fingerprint_1.envFingerprint)(baseEnvironment), activeEnvironment, (0, fingerprint_1.envFingerprint)(activeEnvironment), queue);
42
+ linkCallTargets(false, callTargets, activeEnvironment, (0, fingerprint_1.envFingerprint)(activeEnvironment), queue);
37
43
  }
38
- function linkCallTargets(onlyForSideEffects, functionCallTargets, baseEnvironment, baseEnvPrint, activeEnvironment, activeEnvironmentFingerprint, queue) {
44
+ function linkCallTargets(onlyForSideEffects, functionCallTargets, activeEnvironment, activeEnvironmentFingerprint, queue) {
39
45
  for (const functionCallTarget of functionCallTargets) {
40
46
  // all those linked within the scopes of other functions are already linked when exiting a function definition
41
- for (const openIn of functionCallTarget.subflow.in) {
42
- const defs = openIn.name ? (0, resolve_by_name_1.resolveByName)(openIn.name, activeEnvironment, openIn.type) : undefined;
43
- if (defs === undefined) {
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) {
44
51
  continue;
45
52
  }
46
- for (const def of defs.filter(d => d.nodeId !== built_in_1.BuiltIn)) {
53
+ for(const def of defs.filter(d => d.nodeId !== BuiltIn)) {
47
54
  queue.add(def.nodeId, baseEnvironment, baseEnvPrint, onlyForSideEffects);
48
55
  }
49
- }
56
+ }*/
50
57
  for (const exitPoint of functionCallTarget.exitPoints) {
51
58
  queue.add(exitPoint, activeEnvironment, activeEnvironmentFingerprint, onlyForSideEffects);
52
59
  }
@@ -54,23 +61,9 @@ function linkCallTargets(onlyForSideEffects, functionCallTargets, baseEnvironmen
54
61
  }
55
62
  /** returns the new threshold hit count */
56
63
  function sliceForCall(current, callerInfo, dataflowGraph, queue) {
57
- // bind with call-local environments during slicing
58
- const outgoingEdges = dataflowGraph.get(callerInfo.id, true);
59
- (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`);
60
- // lift baseEnv on the same level
61
64
  const baseEnvironment = current.baseEnvironment;
62
- const baseEnvPrint = (0, fingerprint_1.envFingerprint)(baseEnvironment);
63
- const activeEnvironment = retrieveActiveEnvironment(callerInfo, baseEnvironment);
65
+ const [functionCallTargets, activeEnvironment] = getAllFunctionCallTargets(dataflowGraph, callerInfo, current.baseEnvironment);
64
66
  const activeEnvironmentFingerprint = (0, fingerprint_1.envFingerprint)(activeEnvironment);
65
- const name = callerInfo.name;
66
- (0, assert_1.guard)(name !== undefined, () => `name of id: ${callerInfo.id} can not be found in id map`);
67
- const functionCallDefs = (0, resolve_by_name_1.resolveByName)(name, activeEnvironment, identifier_1.ReferenceType.Unknown)?.filter(d => d.definedAt !== built_in_1.BuiltIn)?.map(d => d.nodeId) ?? [];
68
- for (const [target, outgoingEdge] of outgoingEdges[1].entries()) {
69
- if ((0, edge_1.edgeIncludesType)(outgoingEdge.types, edge_1.EdgeType.Calls)) {
70
- functionCallDefs.push(target);
71
- }
72
- }
73
- const functionCallTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set(functionCallDefs), dataflowGraph);
74
67
  if (functionCallTargets.size === 0) {
75
68
  /*
76
69
  * if we do not have any call to resolve this function, we have to assume that every function passed is actually called!
@@ -81,10 +74,10 @@ function sliceForCall(current, callerInfo, dataflowGraph, queue) {
81
74
  }
82
75
  return;
83
76
  }
84
- linkCallTargets(current.onlyForSideEffects, functionCallTargets, baseEnvironment, baseEnvPrint, activeEnvironment, activeEnvironmentFingerprint, queue);
77
+ linkCallTargets(current.onlyForSideEffects, functionCallTargets, activeEnvironment, activeEnvironmentFingerprint, queue);
85
78
  }
86
79
  /** Returns true if we found at least one return edge */
87
- function handleReturns(queue, currentEdges, baseEnvFingerprint, baseEnvironment) {
80
+ function handleReturns(from, queue, currentEdges, baseEnvFingerprint, baseEnvironment) {
88
81
  const e = [...currentEdges.entries()];
89
82
  const found = e.filter(([_, edge]) => (0, edge_1.edgeIncludesType)(edge.types, edge_1.EdgeType.Returns));
90
83
  if (found.length === 0) {
@@ -97,12 +90,8 @@ function handleReturns(queue, currentEdges, baseEnvFingerprint, baseEnvironment)
97
90
  if ((0, edge_1.edgeIncludesType)(edge.types, edge_1.EdgeType.Reads)) {
98
91
  queue.add(target, baseEnvironment, baseEnvFingerprint, false);
99
92
  }
100
- else if ((0, edge_1.edgeIncludesType)(edge.types, edge_1.EdgeType.Argument)) {
101
- queue.potentialArguments.set(target, {
102
- id: target,
103
- baseEnvironment,
104
- onlyForSideEffects: false
105
- });
93
+ 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);
106
95
  }
107
96
  }
108
97
  return true;
@@ -1,7 +1,10 @@
1
1
  import type { SliceResult } from './slicer-types';
2
+ import { VisitingQueue } from './visiting-queue';
2
3
  import type { DataflowGraph } from '../../dataflow/graph/graph';
3
4
  import type { NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
4
5
  import type { SlicingCriteria } from '../criterion/parse';
6
+ import type { REnvironmentInformation } from '../../dataflow/environments/environment';
7
+ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
5
8
  export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogObj>;
6
9
  /**
7
10
  * This returns the ids to include in the static backward slice, when slicing with the given seed id's (must be at least one).
@@ -10,7 +13,8 @@ export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogOb
10
13
  *
11
14
  * @param graph - The dataflow graph to conduct the slicing on.
12
15
  * @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).
13
- * @param criteria - The criteras to slice on.
16
+ * @param criteria - The criterias to slice on.
14
17
  * @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.
15
18
  */
16
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;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.slicerLogger = void 0;
4
4
  exports.staticSlicing = staticSlicing;
5
+ exports.updatePotentialAddition = updatePotentialAddition;
5
6
  const assert_1 = require("../../util/assert");
6
7
  const log_1 = require("../../util/log");
7
8
  const fingerprint_1 = require("./fingerprint");
@@ -19,7 +20,7 @@ exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
19
20
  *
20
21
  * @param graph - The dataflow graph to conduct the slicing on.
21
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).
22
- * @param criteria - The criteras to slice on.
23
+ * @param criteria - The criterias to slice on.
23
24
  * @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.
24
25
  */
25
26
  function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
@@ -71,7 +72,7 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
71
72
  if (currentVertex.tag === vertex_1.VertexType.FunctionCall && !currentVertex.onlyBuiltin) {
72
73
  (0, slice_call_1.sliceForCall)(current, currentVertex, graph, queue);
73
74
  }
74
- const ret = (0, slice_call_1.handleReturns)(queue, currentEdges, baseEnvFingerprint, baseEnvironment);
75
+ const ret = (0, slice_call_1.handleReturns)(id, queue, currentEdges, baseEnvFingerprint, baseEnvironment);
75
76
  if (ret) {
76
77
  continue;
77
78
  }
@@ -84,12 +85,8 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
84
85
  if (t === 3 /* TraverseEdge.Always */) {
85
86
  queue.add(target, baseEnvironment, baseEnvFingerprint, false);
86
87
  }
87
- else if (t === 2 /* TraverseEdge.DefinedByOnCall */) {
88
- const n = queue.potentialArguments.get(target);
89
- if (n) {
90
- queue.add(target, n.baseEnvironment, (0, fingerprint_1.envFingerprint)(n.baseEnvironment), n.onlyForSideEffects);
91
- queue.potentialArguments.delete(target);
92
- }
88
+ else if (t === 2 /* TraverseEdge.OnlyIfBoth */) {
89
+ updatePotentialAddition(queue, id, target, baseEnvironment);
93
90
  }
94
91
  else if (t === 1 /* TraverseEdge.SideEffect */) {
95
92
  queue.add(target, baseEnvironment, baseEnvFingerprint, true);
@@ -98,4 +95,21 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
98
95
  }
99
96
  return { ...queue.status(), decodedCriteria };
100
97
  }
98
+ function updatePotentialAddition(queue, id, target, baseEnvironment) {
99
+ const n = queue.potentialAdditions.get(target);
100
+ if (n) {
101
+ const [addedBy, { baseEnvironment, onlyForSideEffects }] = n;
102
+ if (addedBy !== id) {
103
+ queue.add(target, baseEnvironment, (0, fingerprint_1.envFingerprint)(baseEnvironment), onlyForSideEffects);
104
+ queue.potentialAdditions.delete(target);
105
+ }
106
+ }
107
+ else {
108
+ queue.potentialAdditions.set(target, [id, {
109
+ id: target,
110
+ baseEnvironment,
111
+ onlyForSideEffects: false
112
+ }]);
113
+ }
114
+ }
101
115
  //# sourceMappingURL=static-slicer.js.map
@@ -4,10 +4,10 @@ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-i
4
4
  export declare class VisitingQueue {
5
5
  private readonly threshold;
6
6
  private timesHitThreshold;
7
- private seen;
8
- private idThreshold;
9
- private queue;
10
- potentialArguments: Map<NodeId, NodeToSlice>;
7
+ private readonly seen;
8
+ private readonly idThreshold;
9
+ private readonly queue;
10
+ potentialAdditions: Map<NodeId, [NodeId, NodeToSlice]>;
11
11
  constructor(threshold: number);
12
12
  /**
13
13
  * Adds a node to the queue if it has not been seen before.
@@ -3,14 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VisitingQueue = void 0;
4
4
  const fingerprint_1 = require("./fingerprint");
5
5
  const static_slicer_1 = require("./static-slicer");
6
+ const assert_1 = require("../../util/assert");
6
7
  class VisitingQueue {
7
8
  threshold;
8
9
  timesHitThreshold = 0;
9
10
  seen = new Map();
10
11
  idThreshold = new Map();
11
12
  queue = [];
12
- // the set of potential arguments holds arguments which may be added if found with the `defined-by-on-call` edge
13
- potentialArguments = new Map();
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
+ // additionally it holds which node id added the addition so we can separate their inclusion on the structure
15
+ potentialAdditions = new Map();
14
16
  constructor(threshold) {
15
17
  this.threshold = threshold;
16
18
  }
@@ -48,7 +50,7 @@ class VisitingQueue {
48
50
  status() {
49
51
  return {
50
52
  timesHitThreshold: this.timesHitThreshold,
51
- result: new Set(this.seen.values())
53
+ result: new Set([...this.seen.values()].filter(assert_1.isNotUndefined))
52
54
  };
53
55
  }
54
56
  }
@@ -7,9 +7,10 @@ exports.printFeatureStatisticsEntry = printFeatureStatisticsEntry;
7
7
  const ansi_1 = require("../../util/ansi");
8
8
  const json_1 = require("../../util/json");
9
9
  const feature_1 = require("../features/feature");
10
+ const arrays_1 = require("../../util/arrays");
10
11
  function minMaxAvgAndMedian(data) {
11
12
  data = data.sort((a, b) => a - b);
12
- const sum = data.reduce((a, b) => a + b, 0);
13
+ const sum = (0, arrays_1.arraySum)(data);
13
14
  return {
14
15
  sum,
15
16
  min: data[0],
@@ -11,6 +11,7 @@ const bimap_1 = require("../../../util/bimap");
11
11
  const defaultmap_1 = require("../../../util/defaultmap");
12
12
  const assert_1 = require("../../../util/assert");
13
13
  const summarizer_1 = require("../../../util/summarizer");
14
+ const arrays_1 = require("../../../util/arrays");
14
15
  /**
15
16
  * Produces column-wise histogram-information based on a {@link ClusterReport}.
16
17
  *
@@ -79,7 +80,7 @@ function histograms2table(histograms, countAsDensity = false) {
79
80
  (0, assert_1.guard)(histograms.length > 0, 'there must be at least one histogram to convert to a table');
80
81
  const mostBins = guardForLargestBinSize(histograms);
81
82
  const header = ['bin', 'from', 'to', ...histograms.map(h => JSON.stringify(h.name))];
82
- const sums = histograms.map(h => h.bins.reduce((a, b) => a + b, 0));
83
+ const sums = histograms.map(h => (0, arrays_1.arraySum)(h.bins));
83
84
  const rows = [];
84
85
  for (let binIndex = 0; binIndex < mostBins; binIndex++) {
85
86
  const row = new Array(histograms.length + 3);