@eagleoutice/flowr 2.1.7 → 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 (84) hide show
  1. package/README.md +2 -1
  2. package/abstract-interpretation/normalized-ast-fold.d.ts +124 -0
  3. package/abstract-interpretation/normalized-ast-fold.js +178 -0
  4. package/benchmark/summarizer/first-phase/process.js +6 -5
  5. package/cli/repl/commands/repl-dataflow.js +5 -2
  6. package/cli/repl/commands/repl-normalize.js +5 -2
  7. package/cli/repl/commands/repl-query.js +2 -2
  8. package/cli/repl/server/messages/message-query.js +1 -1
  9. package/cli/slicer-app.js +1 -1
  10. package/core/steps/pipeline/pipeline.d.ts +63 -0
  11. package/dataflow/environments/default-builtin-config.js +45 -6
  12. package/dataflow/environments/environment.d.ts +46 -8
  13. package/dataflow/environments/environment.js +24 -1
  14. package/dataflow/environments/identifier.d.ts +49 -7
  15. package/dataflow/environments/identifier.js +11 -2
  16. package/dataflow/environments/resolve-by-name.d.ts +5 -0
  17. package/dataflow/environments/resolve-by-name.js +14 -0
  18. package/dataflow/extractor.js +5 -4
  19. package/dataflow/graph/dataflowgraph-builder.d.ts +6 -0
  20. package/dataflow/graph/dataflowgraph-builder.js +8 -0
  21. package/dataflow/graph/edge.d.ts +10 -4
  22. package/dataflow/graph/edge.js +12 -5
  23. package/dataflow/graph/graph.d.ts +41 -3
  24. package/dataflow/graph/graph.js +39 -34
  25. package/dataflow/graph/vertex.d.ts +66 -7
  26. package/dataflow/graph/vertex.js +15 -0
  27. package/dataflow/info.d.ts +79 -11
  28. package/dataflow/info.js +20 -0
  29. package/dataflow/internal/linker.d.ts +4 -2
  30. package/dataflow/internal/linker.js +12 -5
  31. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -0
  32. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -3
  33. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -1
  34. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +16 -0
  35. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +83 -6
  36. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +17 -7
  37. package/dataflow/internal/process/functions/call/common.js +1 -1
  38. package/documentation/doc-util/doc-dfg.d.ts +2 -2
  39. package/documentation/doc-util/doc-dfg.js +11 -16
  40. package/documentation/doc-util/doc-normalized-ast.js +1 -1
  41. package/documentation/doc-util/doc-types.d.ts +1 -1
  42. package/documentation/doc-util/doc-types.js +21 -0
  43. package/documentation/print-capabilities-markdown.js +1 -1
  44. package/documentation/print-dataflow-graph-wiki.js +44 -7
  45. package/documentation/print-linting-and-testing-wiki.js +60 -26
  46. package/documentation/print-normalized-ast-wiki.js +107 -5
  47. package/documentation/print-query-wiki.js +8 -1
  48. package/package.json +17 -3
  49. package/queries/catalog/call-context-query/call-context-query-executor.js +23 -2
  50. package/queries/catalog/call-context-query/call-context-query-format.d.ts +29 -2
  51. package/queries/catalog/call-context-query/call-context-query-format.js +7 -1
  52. package/queries/catalog/call-context-query/cascade-action.d.ts +8 -0
  53. package/queries/catalog/call-context-query/cascade-action.js +13 -0
  54. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -1
  55. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +41 -4
  56. package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -0
  57. package/queries/query.d.ts +4 -4
  58. package/queries/query.js +17 -5
  59. package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
  60. package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +5 -1
  61. package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +6 -1
  62. package/r-bridge/lang-4.x/ast/model/processing/node-id.js +6 -1
  63. package/r-bridge/lang-4.x/ast/model/processing/visitor.d.ts +1 -1
  64. package/r-bridge/lang-4.x/ast/model/processing/visitor.js +1 -1
  65. package/r-bridge/lang-4.x/ast/parser/json/format.js +2 -2
  66. package/reconstruct/reconstruct.js +1 -1
  67. package/slicing/static/slice-call.d.ts +7 -2
  68. package/slicing/static/slice-call.js +33 -44
  69. package/slicing/static/static-slicer.d.ts +5 -1
  70. package/slicing/static/static-slicer.js +22 -8
  71. package/slicing/static/visiting-queue.d.ts +4 -4
  72. package/slicing/static/visiting-queue.js +5 -3
  73. package/statistics/output/print-stats.js +2 -1
  74. package/statistics/summarizer/post-process/histogram.js +2 -1
  75. package/statistics/summarizer/post-process/post-process-output.js +2 -1
  76. package/statistics/summarizer/second-phase/process.js +3 -3
  77. package/util/arrays.d.ts +1 -1
  78. package/util/arrays.js +3 -3
  79. package/util/assert.d.ts +1 -1
  80. package/util/assert.js +3 -2
  81. package/util/cfg/cfg.js +4 -2
  82. package/util/mermaid/cfg.js +1 -1
  83. package/util/summarizer.js +2 -2
  84. package/util/version.js +1 -1
@@ -7,19 +7,22 @@
7
7
  import type { Identifier, IdentifierDefinition, IdentifierReference } from './identifier';
8
8
  import type { DataflowGraph } from '../graph/graph';
9
9
  import type { ControlDependency } from '../info';
10
+ /**
11
+ * Marks the reference as maybe (i.e., as controlled by a set of {@link IdentifierReference#controlDependencies|control dependencies}).
12
+ */
10
13
  export declare function makeReferenceMaybe(ref: IdentifierReference, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference;
11
14
  export declare function makeAllMaybe(references: readonly IdentifierReference[] | undefined, graph: DataflowGraph, environments: REnvironmentInformation, includeDefs: boolean, defaultCd?: ControlDependency | undefined): IdentifierReference[];
12
15
  export type EnvironmentMemory = Map<Identifier, IdentifierDefinition[]>;
16
+ /** A single entry/scope within an {@link REnvironmentInformation} */
13
17
  export interface IEnvironment {
14
- /** unique and internally generated identifier -- will not be used for comparison but assists debugging for tracking identities */
18
+ /** Unique and internally generated identifier -- will not be used for comparison but helps with debugging for tracking identities */
15
19
  readonly id: number;
16
20
  /** Lexical parent of the environment, if any (can be manipulated by R code) */
17
21
  parent: IEnvironment;
18
- /**
19
- * Maps to exactly one definition of an identifier if the source is known, otherwise to a list of all possible definitions
20
- */
22
+ /** Maps to exactly one definition of an identifier if the source is known, otherwise to a list of all possible definitions */
21
23
  memory: EnvironmentMemory;
22
24
  }
25
+ /** @see REnvironmentInformation */
23
26
  export declare class Environment implements IEnvironment {
24
27
  readonly id: number;
25
28
  parent: IEnvironment;
@@ -27,11 +30,26 @@ export declare class Environment implements IEnvironment {
27
30
  constructor(parent: IEnvironment);
28
31
  }
29
32
  /**
30
- * First of all, yes, R stores its environments differently, potentially even with a different differentiation between
31
- * the `baseenv`, the `emptyenv`and other default environments. Yet, during dataflow we want sometimes to know more (static
32
- * reference information) and sometimes know less (to be honest we do not want that,
33
+ * An environment describes a ({@link IEnvironment#parent|scoped}) mapping of names to their definitions ({@link EnvironmentMemory}).
34
+ *
35
+ * First, yes, R stores its environments differently, potentially even with another differentiation between
36
+ * the `baseenv`, the `emptyenv`, and other default environments (see https://adv-r.hadley.nz/environments.html).
37
+ * Yet, during the dataflow analysis, we want sometimes to know more (static {@link IdentifierDefinition|reference information})
38
+ * and sometimes know less (to be honest, we do not want that,
33
39
  * but statically determining all attached environments is theoretically impossible --- consider attachments by user input).
34
- * One example would be maps holding a potential list of all definitions of a variable, if we do not know the execution path (like with `if(x) A else B`).
40
+ *
41
+ * One important environment is the {@link BuiltInEnvironment} which contains the default definitions for R's built-in functions and constants.
42
+ * Please use {@link initializeCleanEnvironments} to initialize the environments (which includes the built-ins).
43
+ * During serialization, you may want to rely on the {@link builtInEnvJsonReplacer} to avoid the huge built-in environment.
44
+ *
45
+ *
46
+ * @see {@link define} - to define a new {@link IdentifierDefinition|identifier definition} within an environment
47
+ * @see {@link resolveByName} - to resolve an {@link Identifier|identifier/name} to its {@link IdentifierDefinition|definitions} within an environment
48
+ * @see {@link makeReferenceMaybe} - to attach control dependencies to a reference
49
+ * @see {@link pushLocalEnvironment} - to create a new local scope
50
+ * @see {@link popLocalEnvironment} - to remove the current local scope
51
+ * @see {@link appendEnvironment} - to append an environment to the current one
52
+ * @see {@link overwriteEnvironment} - to overwrite the definitions in the current environment with those of another one
35
53
  */
36
54
  export interface REnvironmentInformation {
37
55
  /** The currently active environment (the stack is represented by the currently active {@link IEnvironment#parent}). Environments are maintained within the dataflow graph. */
@@ -39,7 +57,27 @@ export interface REnvironmentInformation {
39
57
  /** nesting level of the environment, will be `0` for the global/root environment */
40
58
  readonly level: number;
41
59
  }
60
+ /**
61
+ * The built-in {@link REnvironmentInformation|environment} is the root of all environments.
62
+ *
63
+ * For its default content (when not overwritten by a flowR config),
64
+ * see the {@link DefaultBuiltinConfig}.
65
+ */
42
66
  export declare const BuiltInEnvironment: Environment;
67
+ /**
68
+ * The twin of the {@link BuiltInEnvironment} but with less built ins defined for
69
+ * cases in which we want some commonly overwritten variables to remain open.
70
+ * If you do not know if you need the empty environment, you do not need the empty environment (right now).
71
+ *
72
+ * @see {@link BuiltInEnvironment}
73
+ */
43
74
  export declare const EmptyBuiltInEnvironment: IEnvironment;
75
+ /**
76
+ * Initialize a new {@link REnvironmentInformation|environment} with the built-ins.
77
+ * See {@link EmptyBuiltInEnvironment} for the case `fullBuiltIns = false`.
78
+ */
44
79
  export declare function initializeCleanEnvironments(fullBuiltIns?: boolean): REnvironmentInformation;
80
+ /**
81
+ * Helps to serialize an environment, but replaces the built-in environment with a placeholder.
82
+ */
45
83
  export declare function builtInEnvJsonReplacer(k: unknown, v: unknown): unknown;
@@ -9,6 +9,9 @@ const identifier_1 = require("./identifier");
9
9
  const built_in_1 = require("./built-in");
10
10
  const resolve_by_name_1 = require("./resolve-by-name");
11
11
  const json_1 = require("../../util/json");
12
+ /**
13
+ * Marks the reference as maybe (i.e., as controlled by a set of {@link IdentifierReference#controlDependencies|control dependencies}).
14
+ */
12
15
  function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = undefined) {
13
16
  const node = graph.get(ref.nodeId, true);
14
17
  if (includeDefs) {
@@ -42,6 +45,7 @@ function makeAllMaybe(references, graph, environments, includeDefs, defaultCd =
42
45
  return references.map(ref => makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd));
43
46
  }
44
47
  let environmentIdCounter = 0;
48
+ /** @see REnvironmentInformation */
45
49
  class Environment {
46
50
  id = environmentIdCounter++;
47
51
  parent;
@@ -52,14 +56,30 @@ class Environment {
52
56
  }
53
57
  }
54
58
  exports.Environment = Environment;
55
- /* the built-in environment is the root of all environments */
59
+ /**
60
+ * The built-in {@link REnvironmentInformation|environment} is the root of all environments.
61
+ *
62
+ * For its default content (when not overwritten by a flowR config),
63
+ * see the {@link DefaultBuiltinConfig}.
64
+ */
56
65
  exports.BuiltInEnvironment = new Environment(undefined);
57
66
  exports.BuiltInEnvironment.memory = undefined;
67
+ /**
68
+ * The twin of the {@link BuiltInEnvironment} but with less built ins defined for
69
+ * cases in which we want some commonly overwritten variables to remain open.
70
+ * If you do not know if you need the empty environment, you do not need the empty environment (right now).
71
+ *
72
+ * @see {@link BuiltInEnvironment}
73
+ */
58
74
  exports.EmptyBuiltInEnvironment = {
59
75
  id: exports.BuiltInEnvironment.id,
60
76
  memory: undefined,
61
77
  parent: undefined
62
78
  };
79
+ /**
80
+ * Initialize a new {@link REnvironmentInformation|environment} with the built-ins.
81
+ * See {@link EmptyBuiltInEnvironment} for the case `fullBuiltIns = false`.
82
+ */
63
83
  function initializeCleanEnvironments(fullBuiltIns = true) {
64
84
  exports.BuiltInEnvironment.memory ??= built_in_1.BuiltInMemory;
65
85
  exports.EmptyBuiltInEnvironment.memory ??= built_in_1.EmptyBuiltInMemory;
@@ -68,6 +88,9 @@ function initializeCleanEnvironments(fullBuiltIns = true) {
68
88
  level: 0
69
89
  };
70
90
  }
91
+ /**
92
+ * Helps to serialize an environment, but replaces the built-in environment with a placeholder.
93
+ */
71
94
  function builtInEnvJsonReplacer(k, v) {
72
95
  if (v === exports.BuiltInEnvironment) {
73
96
  return '<BuiltInEnvironment>';
@@ -5,9 +5,17 @@ export type Identifier = string & {
5
5
  __brand?: 'identifier';
6
6
  };
7
7
  /**
8
- * Each reference only has exactly one reference type, stored as the respective number.
9
- * However, when checking we may want to allow for one of several types,
8
+ * Each reference has exactly one reference type, stored as the respective number.
9
+ * However, when checking, we may want to allow for one of several types,
10
10
  * allowing the combination of the respective bitmasks.
11
+ *
12
+ * Having reference types is important as R separates a variable definition from
13
+ * a function when resolving an {@link Identifier|identifier}.
14
+ * In `c <- 3; print(c(1, 2))` the call to `c` works normally (as the vector constructor),
15
+ * while writing `c <- function(...) ..1` overshadows the built-in and causes `print` to only output the first element.
16
+ *
17
+ * @see {@link isReferenceType} - for checking if a (potentially joint) reference type contains a certain type
18
+ * @see {@link ReferenceTypeReverseMapping} - for debugging
11
19
  */
12
20
  export declare enum ReferenceType {
13
21
  /** The identifier type is unknown */
@@ -27,19 +35,38 @@ export declare enum ReferenceType {
27
35
  /** The identifier is defined by a built-in function */
28
36
  BuiltInFunction = 128
29
37
  }
38
+ /** Reverse mapping of the reference types so you can get the name from the bitmask (useful for debugging) */
30
39
  export declare const ReferenceTypeReverseMapping: Map<ReferenceType, string>;
31
40
  /**
32
41
  * Check if the reference types have an overlapping type!
33
42
  */
34
43
  export declare function isReferenceType(t: ReferenceType, target: ReferenceType): boolean;
44
+ /**
45
+ * Describes all types of reference (definitions) that can appear within a graph (i.e., that are not built-in like the
46
+ * default definition for the assignment operator `<-`).
47
+ *
48
+ * @see {@link InGraphIdentifierDefinition} - for the definition of an identifier within the graph
49
+ */
35
50
  export type InGraphReferenceType = Exclude<ReferenceType, ReferenceType.BuiltInConstant | ReferenceType.BuiltInFunction>;
36
51
  /**
37
- * Something like `a` in `b <- a`.
38
- * Without any surrounding information, `a` will produce the identifier reference `a`.
39
- * Similarly, `b` will create a reference.
52
+ * An identifier reference points to a variable like `a` in `b <- a`.
53
+ * Without any surrounding code, `a` will produce the identifier reference `a`.
54
+ * Similarly, `b` will create a reference (although it will be an {@link IdentifierDefinition|identifier definition}
55
+ * which adds even more information).
56
+ *
57
+ * In general,
58
+ * references are merely pointers (with meta-information) to a vertex in the {@link DataflowGraph|dataflow graph}.
59
+ * In the context of the extractor, for example,
60
+ * they indicate the references that are currently (during the analysis at this given node)
61
+ * {@link DataflowInformation#in|read (`in`)}, {@link DataflowInformation#out|written (`out`)},
62
+ * or {@link DataflowInformation#unknownReferences|unknown (`unknownReferences`)}.
63
+ *
64
+ * @see {@link InGraphIdentifierDefinition}
40
65
  */
41
66
  export interface IdentifierReference {
42
- /** Node which represents the reference in the AST */
67
+ /**
68
+ * The id of the node which represents the reference in the {@link NormalizedAst|normalized AST} and the {@link DataflowGraph|dataflow graph}.
69
+ */
43
70
  readonly nodeId: NodeId;
44
71
  /** Name the reference is identified by (e.g., the name of the variable), undefined if the reference is "artificial" (e.g., anonymous) */
45
72
  readonly name: Identifier | undefined;
@@ -51,13 +78,28 @@ export interface IdentifierReference {
51
78
  */
52
79
  controlDependencies: ControlDependency[] | undefined;
53
80
  }
81
+ /**
82
+ * The definition of an {@link Identifier|identifier} within the {@link DataflowGraph|graph}.
83
+ * This extends on the {@link IdentifierReference}
84
+ * by adding the {@link NodeId} of the definition
85
+ * (and using `type` to mark the object type).
86
+ *
87
+ * Within a code snippet like `a <- 3`, the symbol processor will first create an
88
+ * {@link IdentifierReference|identifier reference} for `a` to reference the use
89
+ * and then promote it to an {@link InGraphIdentifierDefinition|identifier definition}.
90
+ *
91
+ * @see {@link IdentifierReference}
92
+ */
54
93
  interface InGraphIdentifierDefinition extends IdentifierReference {
55
94
  readonly type: InGraphReferenceType;
56
95
  /** The assignment (or whatever, like `assign` function call) node which ultimately defined this identifier */
57
96
  readonly definedAt: NodeId;
58
97
  }
59
98
  /**
60
- * Stores the definition of an identifier within an {@link IEnvironment}
99
+ * Stores the definition of an identifier within an {@link IEnvironment}.
100
+ *
101
+ * {@link BuiltInIdentifierDefinition} and {@link BuiltInIdentifierConstant} are used for built-in functions and constants only,
102
+ * so the most important one for your day-to-day R script is the {@link InGraphIdentifierDefinition}.
61
103
  */
62
104
  export type IdentifierDefinition = InGraphIdentifierDefinition | BuiltInIdentifierDefinition | BuiltInIdentifierConstant;
63
105
  export {};
@@ -3,9 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ReferenceTypeReverseMapping = exports.ReferenceType = void 0;
4
4
  exports.isReferenceType = isReferenceType;
5
5
  /**
6
- * Each reference only has exactly one reference type, stored as the respective number.
7
- * However, when checking we may want to allow for one of several types,
6
+ * Each reference has exactly one reference type, stored as the respective number.
7
+ * However, when checking, we may want to allow for one of several types,
8
8
  * allowing the combination of the respective bitmasks.
9
+ *
10
+ * Having reference types is important as R separates a variable definition from
11
+ * a function when resolving an {@link Identifier|identifier}.
12
+ * In `c <- 3; print(c(1, 2))` the call to `c` works normally (as the vector constructor),
13
+ * while writing `c <- function(...) ..1` overshadows the built-in and causes `print` to only output the first element.
14
+ *
15
+ * @see {@link isReferenceType} - for checking if a (potentially joint) reference type contains a certain type
16
+ * @see {@link ReferenceTypeReverseMapping} - for debugging
9
17
  */
10
18
  var ReferenceType;
11
19
  (function (ReferenceType) {
@@ -26,6 +34,7 @@ var ReferenceType;
26
34
  /** The identifier is defined by a built-in function */
27
35
  ReferenceType[ReferenceType["BuiltInFunction"] = 128] = "BuiltInFunction";
28
36
  })(ReferenceType || (exports.ReferenceType = ReferenceType = {}));
37
+ /** Reverse mapping of the reference types so you can get the name from the bitmask (useful for debugging) */
29
38
  exports.ReferenceTypeReverseMapping = new Map(Object.entries(ReferenceType).map(([k, v]) => [v, k]));
30
39
  /**
31
40
  * Check if the reference types have an overlapping type!
@@ -13,3 +13,8 @@ import { ReferenceType } from './identifier';
13
13
  */
14
14
  export declare function resolveByName(name: Identifier, environment: REnvironmentInformation, target?: ReferenceType): IdentifierDefinition[] | undefined;
15
15
  export declare function resolvesToBuiltInConstant(name: Identifier | undefined, environment: REnvironmentInformation, wantedValue: unknown): Ternary;
16
+ export interface ResolveResult<T = unknown> {
17
+ value: T;
18
+ from: ReferenceType;
19
+ }
20
+ export declare function resolveToConstants(name: Identifier | undefined, environment: REnvironmentInformation): ResolveResult[] | undefined;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveByName = resolveByName;
4
4
  exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
5
+ exports.resolveToConstants = resolveToConstants;
5
6
  const environment_1 = require("./environment");
6
7
  const identifier_1 = require("./identifier");
7
8
  const info_1 = require("../info");
@@ -80,4 +81,17 @@ function resolvesToBuiltInConstant(name, environment, wantedValue) {
80
81
  return some ? 1 /* Ternary.Maybe */ : 2 /* Ternary.Never */;
81
82
  }
82
83
  }
84
+ function resolveToConstants(name, environment) {
85
+ if (name === undefined) {
86
+ return undefined;
87
+ }
88
+ const definitions = resolveByName(name, environment, identifier_1.ReferenceType.Constant);
89
+ if (definitions === undefined) {
90
+ return undefined;
91
+ }
92
+ return definitions.map(def => ({
93
+ value: def.value,
94
+ from: def.type
95
+ }));
96
+ }
83
97
  //# sourceMappingURL=resolve-by-name.js.map
@@ -20,6 +20,7 @@ const built_in_source_1 = require("./internal/process/functions/call/built-in/bu
20
20
  const cfg_1 = require("../util/cfg/cfg");
21
21
  const edge_1 = require("./graph/edge");
22
22
  const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
23
+ const built_in_function_definition_1 = require("./internal/process/functions/call/built-in/built-in-function-definition");
23
24
  exports.processors = {
24
25
  [type_1.RType.Number]: process_value_1.processValue,
25
26
  [type_1.RType.String]: process_value_1.processValue,
@@ -56,11 +57,9 @@ function resolveLinkToSideEffects(ast, graph) {
56
57
  if (typeof s !== 'object') {
57
58
  continue;
58
59
  }
59
- if (!cfg) {
60
- cfg = (0, cfg_1.extractCFG)(ast).graph;
61
- }
60
+ cfg ??= (0, cfg_1.extractCFG)(ast).graph;
62
61
  /* this has to change whenever we add a new link to relations because we currently offer no abstraction for the type */
63
- const potentials = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(s.id, cfg, graph, s.linkTo.callName);
62
+ const potentials = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(s.id, cfg, graph, s.linkTo);
64
63
  for (const pot of potentials) {
65
64
  graph.addEdge(s.id, pot, edge_1.EdgeType.Reads);
66
65
  }
@@ -92,6 +91,8 @@ function produceDataFlowGraph(request, ast) {
92
91
  df = (0, built_in_source_1.standaloneSourceFile)(request[i], dfData, `root-${i}`, df);
93
92
  }
94
93
  }
94
+ // finally, resolve linkages
95
+ (0, built_in_function_definition_1.updateNestedFunctionCalls)(df.graph, df.environment);
95
96
  resolveLinkToSideEffects(ast, df.graph);
96
97
  return df;
97
98
  }
@@ -114,6 +114,12 @@ export declare class DataflowGraphBuilder extends DataflowGraph {
114
114
  * @see reads for parameters.
115
115
  */
116
116
  definesOnCall(from: NodeId, to: DataflowGraphEdgeTarget): this;
117
+ /**
118
+ * Adds a **defined-by-on-call edge** with from as definition, and to as variable.
119
+ *
120
+ * @see reads for parameters.
121
+ */
122
+ definedByOnCall(from: NodeId, to: DataflowGraphEdgeTarget): this;
117
123
  /**
118
124
  * Adds an **argument edge** (E9) with from as function call, and to as argument.
119
125
  *
@@ -212,6 +212,14 @@ class DataflowGraphBuilder extends graph_1.DataflowGraph {
212
212
  definesOnCall(from, to) {
213
213
  return this.edgeHelper(from, to, edge_1.EdgeType.DefinesOnCall);
214
214
  }
215
+ /**
216
+ * Adds a **defined-by-on-call edge** with from as definition, and to as variable.
217
+ *
218
+ * @see reads for parameters.
219
+ */
220
+ definedByOnCall(from, to) {
221
+ return this.edgeHelper(from, to, edge_1.EdgeType.DefinedByOnCall);
222
+ }
215
223
  /**
216
224
  * Adds an **argument edge** (E9) with from as function call, and to as argument.
217
225
  *
@@ -19,9 +19,15 @@ export declare enum EdgeType {
19
19
  Calls = 4,
20
20
  /** The source returns target on call */
21
21
  Returns = 8,
22
- /** The edge determines that source (probably argument) defines the target (probably parameter), currently automatically created by `addEdge` */
22
+ /**
23
+ * The edge determines that source (probably argument) defines the target (probably parameter).
24
+ * This may also link a function call to definitions it causes to be active (as part of the closure) of the called function definition.
25
+ */
23
26
  DefinesOnCall = 16,
24
- /** Inverse of `defines-on-call` currently only needed to get better results when slicing complex function calls */
27
+ /**
28
+ * Usually the inverse of `defines-on-call` (in the context of arguments and parameters).
29
+ * This may also link an open read (within a function) to the definition that is active at the call site.
30
+ */
25
31
  DefinedByOnCall = 32,
26
32
  /** Formal used as argument to a function call */
27
33
  Argument = 64,
@@ -57,8 +63,8 @@ export declare const enum TraverseEdge {
57
63
  Never = 0,
58
64
  /** Traverse the edge as a side effect */
59
65
  SideEffect = 1,
60
- /** Traverse this edge if the definition is relevant */
61
- DefinedByOnCall = 2,
66
+ /** Traverse this edge if the definition is relevant (i.e., if two matching edges trigger this state) */
67
+ OnlyIfBoth = 2,
62
68
  /** Always traverse this edge */
63
69
  Always = 3
64
70
  }
@@ -22,9 +22,15 @@ var EdgeType;
22
22
  EdgeType[EdgeType["Calls"] = 4] = "Calls";
23
23
  /** The source returns target on call */
24
24
  EdgeType[EdgeType["Returns"] = 8] = "Returns";
25
- /** The edge determines that source (probably argument) defines the target (probably parameter), currently automatically created by `addEdge` */
25
+ /**
26
+ * The edge determines that source (probably argument) defines the target (probably parameter).
27
+ * This may also link a function call to definitions it causes to be active (as part of the closure) of the called function definition.
28
+ */
26
29
  EdgeType[EdgeType["DefinesOnCall"] = 16] = "DefinesOnCall";
27
- /** Inverse of `defines-on-call` currently only needed to get better results when slicing complex function calls */
30
+ /**
31
+ * Usually the inverse of `defines-on-call` (in the context of arguments and parameters).
32
+ * This may also link an open read (within a function) to the definition that is active at the call site.
33
+ */
28
34
  EdgeType[EdgeType["DefinedByOnCall"] = 32] = "DefinedByOnCall";
29
35
  /** Formal used as argument to a function call */
30
36
  EdgeType[EdgeType["Argument"] = 64] = "Argument";
@@ -89,13 +95,14 @@ function edgeIncludesType(type, types) {
89
95
  function edgeDoesNotIncludeType(type, types) {
90
96
  return (types & type) === 0;
91
97
  }
92
- const alwaysTraverseEdgeTypes = EdgeType.Reads | EdgeType.DefinedBy | EdgeType.Argument | EdgeType.Calls | EdgeType.DefinesOnCall;
98
+ const alwaysTraverseEdgeTypes = EdgeType.Reads | EdgeType.DefinedBy | EdgeType.Argument | EdgeType.Calls;
99
+ const definedByOnCallTypes = EdgeType.DefinesOnCall | EdgeType.DefinedByOnCall;
93
100
  function shouldTraverseEdge(types) {
94
101
  if (edgeIncludesType(types, alwaysTraverseEdgeTypes)) {
95
102
  return 3 /* TraverseEdge.Always */;
96
103
  }
97
- else if (edgeIncludesType(types, EdgeType.DefinedByOnCall)) {
98
- return 2 /* TraverseEdge.DefinedByOnCall */;
104
+ else if (edgeIncludesType(types, definedByOnCallTypes)) {
105
+ return 2 /* TraverseEdge.OnlyIfBoth */;
99
106
  }
100
107
  else if (edgeIncludesType(types, EdgeType.SideEffectOnCall)) {
101
108
  return 1 /* TraverseEdge.SideEffect */;
@@ -1,5 +1,4 @@
1
- import type { DataflowGraphEdge } from './edge';
2
- import { EdgeType } from './edge';
1
+ import type { DataflowGraphEdge, EdgeType } from './edge';
3
2
  import type { DataflowInformation } from '../info';
4
3
  import type { DataflowGraphVertexArgument, DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from './vertex';
5
4
  import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
@@ -7,30 +6,56 @@ import type { IdentifierDefinition, IdentifierReference } from '../environments/
7
6
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
7
  import type { AstIdMap } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
9
8
  import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
9
+ /**
10
+ * Describes the information we store per function body.
11
+ * The {@link DataflowFunctionFlowInformation#exitPoints} are stored within the enclosing {@link DataflowGraphVertexFunctionDefinition} vertex.
12
+ */
10
13
  export type DataflowFunctionFlowInformation = Omit<DataflowInformation, 'graph' | 'exitPoints'> & {
11
14
  graph: Set<NodeId>;
12
15
  };
13
16
  /**
17
+ * A reference with a name, e.g. `a` and `b` in the following function call:
18
+ *
14
19
  * ```r
15
20
  * foo(a = 3, b = 2)
16
21
  * ```
22
+ *
23
+ * @see #isNamedArgument
24
+ * @see PositionalFunctionArgument
17
25
  */
18
26
  export interface NamedFunctionArgument extends IdentifierReference {
19
27
  readonly name: string;
20
28
  }
21
29
  /**
30
+ * A reference which does not have a name, like the references to the arguments `3` and `2` in the following:
31
+ *
22
32
  * ```r
23
33
  * foo(3, 2)
24
34
  * ```
35
+ *
36
+ * @see #isPositionalArgument
37
+ * @see NamedFunctionArgument
25
38
  */
26
39
  export interface PositionalFunctionArgument extends Omit<IdentifierReference, 'name'> {
27
40
  readonly name?: undefined;
28
41
  }
29
42
  /** Summarizes either named (`foo(a = 3, b = 2)`), unnamed (`foo(3, 2)`), or empty (`foo(,)`) arguments within a function. */
30
43
  export type FunctionArgument = NamedFunctionArgument | PositionalFunctionArgument | typeof EmptyArgument;
44
+ /**
45
+ * Check if the given argument is a {@link PositionalFunctionArgument}.
46
+ */
31
47
  export declare function isPositionalArgument(arg: FunctionArgument): arg is PositionalFunctionArgument;
48
+ /**
49
+ * Check if the given argument is a {@link NamedFunctionArgument}.
50
+ */
32
51
  export declare function isNamedArgument(arg: FunctionArgument): arg is NamedFunctionArgument;
52
+ /**
53
+ * Returns the reference of a non-empty argument.
54
+ */
33
55
  export declare function getReferenceOfArgument(arg: FunctionArgument): NodeId | undefined;
56
+ /**
57
+ * A reference that is enough to indicate start and end points of an edge within the dataflow graph.
58
+ */
34
59
  type ReferenceForEdge = Pick<IdentifierReference, 'nodeId' | 'controlDependencies'> | IdentifierDefinition;
35
60
  /**
36
61
  * Maps the edges target to the edge information
@@ -41,11 +66,20 @@ export type OutgoingEdges<Edge extends DataflowGraphEdge = DataflowGraphEdge> =
41
66
  * In other words, it maps the source to the edge information.
42
67
  */
43
68
  export type IngoingEdges<Edge extends DataflowGraphEdge = DataflowGraphEdge> = Map<NodeId, Edge>;
69
+ /**
70
+ * The structure of the serialized {@link DataflowGraph}.
71
+ */
44
72
  export interface DataflowGraphJson {
45
73
  readonly rootVertices: NodeId[];
46
74
  readonly vertexInformation: [NodeId, DataflowGraphVertexInfo][];
47
75
  readonly edgeInformation: [NodeId, [NodeId, DataflowGraphEdge][]][];
48
76
  }
77
+ /**
78
+ * An unknown side effect describes something that we cannot handle correctly (in all cases).
79
+ * For example, `eval` will be marked as an unknown side effect as we have no idea of how it will affect the program.
80
+ * Linked side effects are used whenever we know that a call may be affected by another one in a way that we cannot
81
+ * grasp from the dataflow perspective (e.g., an indirect dependency based on the currently active graphic device).
82
+ */
49
83
  export type UnknownSidEffect = NodeId | {
50
84
  id: NodeId;
51
85
  linkTo: LinkTo<RegExp>;
@@ -60,6 +94,11 @@ export type UnknownSidEffect = NodeId | {
60
94
  * However, this does not have to hold during the construction as edges may point from or to vertices which are yet to be constructed.
61
95
  *
62
96
  * All methods return the modified graph to allow for chaining.
97
+ *
98
+ * @see {@link DataflowGraph#addEdge|`addEdge`} - to add an edge to the graph
99
+ * @see {@link DataflowGraph#addVertex|`addVertex`} - to add a vertex to the graph
100
+ * @see {@link DataflowGraph#fromJson|`fromJson`} - to construct a dataflow graph object from a deserialized JSON object.
101
+ * @see {@link emptyGraph} - to create an empty graph (useful in tests)
63
102
  */
64
103
  export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo, Edge extends DataflowGraphEdge = DataflowGraphEdge> {
65
104
  private static DEFAULT_ENVIRONMENT;
@@ -144,7 +183,6 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
144
183
  addEdge(from: ReferenceForEdge, to: ReferenceForEdge, type: EdgeType): this;
145
184
  /** {@inheritDoc} */
146
185
  addEdge(from: NodeId | ReferenceForEdge, to: NodeId | ReferenceForEdge, type: EdgeType): this;
147
- private installEdge;
148
186
  /**
149
187
  * Merges the other graph into *this* one (in-place). The return value is only for convenience.
150
188
  *