@eagleoutice/flowr 2.0.17 → 2.0.19

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.
@@ -46,11 +46,11 @@ const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipeli
46
46
  const graph_1 = require("../../../dataflow/graph/graph");
47
47
  const tmp = __importStar(require("tmp"));
48
48
  const fs_1 = __importDefault(require("fs"));
49
- const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
50
49
  const magic_comments_1 = require("../../../reconstruct/auto-select/magic-comments");
51
50
  const lineage_1 = require("./messages/lineage");
52
51
  const lineage_2 = require("../commands/lineage");
53
52
  const assert_1 = require("../../../util/assert");
53
+ const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
54
54
  /**
55
55
  * Each connection handles a single client, answering to its requests.
56
56
  * There is no need to construct this class manually, {@link FlowRServer} will do it for you.
@@ -221,7 +221,7 @@ class FlowRServerConnection {
221
221
  }
222
222
  fileInformation.pipeline.updateRequest({
223
223
  criterion: request.criterion,
224
- autoSelectIf: request.noMagicComments ? auto_select_defaults_1.autoSelectLibrary : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.autoSelectLibrary)
224
+ autoSelectIf: request.noMagicComments ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect)
225
225
  });
226
226
  void fileInformation.pipeline.allRemainingSteps(true).then(results => {
227
227
  (0, send_1.sendMessage)(this.socket, {
package/cli/slicer-app.js CHANGED
@@ -12,8 +12,8 @@ const json_1 = require("../util/json");
12
12
  const script_1 = require("./common/script");
13
13
  const slicer_1 = require("../benchmark/slicer");
14
14
  const print_1 = require("../benchmark/stats/print");
15
- const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
16
15
  const magic_comments_1 = require("../reconstruct/auto-select/magic-comments");
16
+ const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
17
17
  const options = (0, script_1.processCommandLineArgs)('slicer', ['input', 'criterion'], {
18
18
  subtitle: 'Slice R code based on a given slicing criterion',
19
19
  examples: [
@@ -30,7 +30,7 @@ async function getSlice() {
30
30
  (0, assert_1.guard)(options.criterion !== undefined, 'a slicing criterion must be given');
31
31
  await slicer.init(options['input-is-text']
32
32
  ? { request: 'text', content: options.input }
33
- : { request: 'file', content: options.input }, options['no-magic-comments'] ? auto_select_defaults_1.autoSelectLibrary : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.autoSelectLibrary));
33
+ : { request: 'file', content: options.input }, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
34
34
  let mappedSlices = [];
35
35
  let reconstruct = undefined;
36
36
  const doSlicing = options.criterion.trim() !== '';
@@ -18,6 +18,7 @@ const built_in_expression_list_1 = require("../internal/process/functions/call/b
18
18
  const built_in_get_1 = require("../internal/process/functions/call/built-in/built-in-get");
19
19
  const built_in_library_1 = require("../internal/process/functions/call/built-in/built-in-library");
20
20
  const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
21
+ const built_in_apply_1 = require("../internal/process/functions/call/built-in/built-in-apply");
21
22
  exports.BuiltIn = 'built-in';
22
23
  function defaultBuiltInProcessor(name, args, rootId, data, config) {
23
24
  const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
@@ -67,14 +68,16 @@ function registerReplacementFunctions(standardConfig, assignments, ...prefixes)
67
68
  for (const prefix of prefixes) {
68
69
  const effectiveName = `${prefix}${assignment}`;
69
70
  (0, assert_1.guard)(!exports.BuiltInMemory.has(effectiveName), `Built-in ${effectiveName} already defined`);
70
- exports.BuiltInMemory.set(effectiveName, [{
71
+ const d = [{
71
72
  kind: 'built-in-function',
72
73
  definedAt: exports.BuiltIn,
73
74
  processor: (name, args, rootId, data) => (0, built_in_replacement_1.processReplacementFunction)(name, args, rootId, data, { ...standardConfig, assignmentOperator: assignment }),
74
75
  name: effectiveName,
75
76
  controlDependencies: undefined,
76
77
  nodeId: exports.BuiltIn
77
- }]);
78
+ }];
79
+ exports.BuiltInMemory.set(effectiveName, d);
80
+ exports.EmptyBuiltInMemory.set(effectiveName, d);
78
81
  }
79
82
  }
80
83
  }
@@ -106,7 +109,10 @@ registerBuiltInConstant(true, 'T', true);
106
109
  registerBuiltInConstant(true, 'FALSE', false);
107
110
  registerBuiltInConstant(true, 'F', false);
108
111
  registerSimpleFunctions('~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':', 'list', 'c', 'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max', 'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean', 'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'plot', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix', 'do.call', 'rbind', 'nrow', 'ncol', 'tryCatch', 'expression', 'factor', 'missing', 'as.data.frame', 'data.frame', 'na.omit', 'rownames', 'names', 'order', 'length', 'any', 'dim', 'matrix', 'cbind', 'nchar', 't');
109
- registerBuiltInFunctions(true, ['apply', 'lapply', 'sapply', 'tapply', 'mapply'], defaultBuiltInProcessor, { forceArgs: [false, true] });
112
+ registerBuiltInFunctions(true, ['lapply', 'sapply', 'vapply', 'mapply'], built_in_apply_1.processApply, { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' });
113
+ /* functool wrappers */
114
+ registerBuiltInFunctions(true, ['Lapply', 'Sapply', 'Vapply', 'Mapply'], built_in_apply_1.processApply, { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' });
115
+ registerBuiltInFunctions(true, ['apply', 'tapply', 'Tapply'], built_in_apply_1.processApply, { indexOfFunction: 2, nameOfFunctionArgument: 'FUN' });
110
116
  registerBuiltInFunctions(true, ['print'], defaultBuiltInProcessor, { returnsNthArgument: 0, forceArgs: 'all' });
111
117
  registerBuiltInFunctions(true, ['('], defaultBuiltInProcessor, { returnsNthArgument: 0 });
112
118
  registerBuiltInFunctions(true, ['load', 'load_all', 'setwd', 'set.seed'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: [true] });
@@ -121,7 +127,7 @@ registerBuiltInFunctions(true, ['[', '[['], built_in_access_1.processAccess, { t
121
127
  registerBuiltInFunctions(true, ['$', '@'], built_in_access_1.processAccess, { treatIndicesAsString: true });
122
128
  registerBuiltInFunctions(true, ['if', 'ifelse'], built_in_if_then_else_1.processIfThenElse, {});
123
129
  registerBuiltInFunctions(true, ['get'], built_in_get_1.processGet, {});
124
- registerBuiltInFunctions(false, ['library'], built_in_library_1.processLibrary, {});
130
+ registerBuiltInFunctions(false, ['library', 'require'], built_in_library_1.processLibrary, {});
125
131
  registerBuiltInFunctions(true, ['<-', '='], built_in_assignment_1.processAssignment, { canBeReplacement: true });
126
132
  registerBuiltInFunctions(true, [':=', 'assign'], built_in_assignment_1.processAssignment, {});
127
133
  registerBuiltInFunctions(true, ['delayedAssign'], built_in_assignment_1.processAssignment, { quoteSource: true });
@@ -138,6 +144,12 @@ registerBuiltInFunctions(true, ['repeat'], built_in_repeat_loop_1.processRepeatL
138
144
  registerBuiltInFunctions(true, ['while'], built_in_while_loop_1.processWhileLoop, {});
139
145
  registerBuiltInFunctions(true, ['options'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: 'all' });
140
146
  registerBuiltInFunctions(true, ['on.exit', 'sys.on.exit'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
147
+ /* library and require is handled above */
148
+ registerBuiltInFunctions(true, ['requireNamespace', 'loadNamespace', 'attachNamespace', 'asNamespace'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
149
+ /* downloader and installer functions (R, devtools, BiocManager) */
150
+ registerBuiltInFunctions(true, ['library.dynam', 'install.packages', 'install', 'install_github', 'install_gitlab', 'install_bitbucket', 'install_url', 'install_git', 'install_svn', 'install_local', 'install_version', 'update_packages'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
151
+ /* weird env attachments */
152
+ registerBuiltInFunctions(true, ['attach'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
141
153
  /* they are all mapped to `<-` but we separate super assignments */
142
154
  registerReplacementFunctions({ makeMaybe: true }, ['<-', '<<-'], '[', '[[', '$', '@', 'names', 'dimnames', 'attributes', 'attr', 'class', 'levels', 'rownames', 'colnames');
143
155
  //# sourceMappingURL=built-in.js.map
@@ -1,7 +1,7 @@
1
1
  import type { DataflowGraphEdge } from './edge';
2
2
  import { EdgeType } from './edge';
3
3
  import type { DataflowInformation } from '../info';
4
- import type { DataflowGraphVertexArgument, DataflowGraphVertexInfo } from './vertex';
4
+ import type { DataflowGraphVertexArgument, DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from './vertex';
5
5
  import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
6
6
  import type { IdentifierDefinition, IdentifierReference } from '../environments/identifier';
7
7
  import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
@@ -141,6 +141,11 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
141
141
  * @param reference - The reference to the vertex to mark as definition
142
142
  */
143
143
  setDefinitionOfVertex(reference: IdentifierReference): void;
144
+ /**
145
+ * Marks a vertex in the graph to be a function call with the new information
146
+ * @param info - The information about the new function call node
147
+ */
148
+ updateToFunctionCall(info: DataflowGraphVertexFunctionCall): void;
144
149
  /** If you do not pass the `to` node, this will just mark the node as maybe */
145
150
  addControlDependency(from: NodeId, to?: NodeId, when?: boolean): this;
146
151
  /** Marks the given node as having unknown side effects */
@@ -282,6 +282,16 @@ class DataflowGraph {
282
282
  this.vertexInformation.set(reference.nodeId, { ...vertex, tag: 'variable-definition' });
283
283
  }
284
284
  }
285
+ /**
286
+ * Marks a vertex in the graph to be a function call with the new information
287
+ * @param info - The information about the new function call node
288
+ */
289
+ updateToFunctionCall(info) {
290
+ const vertex = this.getVertex(info.id, true);
291
+ (0, assert_1.guard)(vertex !== undefined, () => `node must be defined for ${JSON.stringify(info.id)} to update it to a function call`);
292
+ (0, assert_1.guard)(vertex.tag === "use" /* VertexType.Use */, () => `node must be a use node for ${JSON.stringify(info.id)} to update it to a function call`);
293
+ this.vertexInformation.set(info.id, { ...vertex, ...info, tag: "function-call" /* VertexType.FunctionCall */ });
294
+ }
285
295
  /** If you do not pass the `to` node, this will just mark the node as maybe */
286
296
  addControlDependency(from, to, when) {
287
297
  to = to ? (0, node_id_1.normalizeIdToNumberIfPossible)(to) : undefined;
@@ -6,6 +6,12 @@ const known_call_handling_1 = require("../known-call-handling");
6
6
  const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
7
7
  const logger_1 = require("../../../../../logger");
8
8
  const environment_1 = require("../../../../../environments/environment");
9
+ const built_in_1 = require("../../../../../environments/built-in");
10
+ const built_in_assignment_1 = require("./built-in-assignment");
11
+ function tableAssignmentProcessor(name, args, rootId, data, outInfo) {
12
+ outInfo.definitionRootNodes.push(rootId);
13
+ return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
14
+ }
9
15
  function processAccess(name, args, rootId, data, config) {
10
16
  if (args.length < 2) {
11
17
  logger_1.dataflowLogger.warn(`Access ${name.content} has less than 2 arguments, skipping`);
@@ -15,7 +21,26 @@ function processAccess(name, args, rootId, data, config) {
15
21
  (0, assert_1.guard)(head !== r_function_call_1.EmptyArgument, () => `Access ${name.content} has no source, impossible!`);
16
22
  let fnCall;
17
23
  if (!config.treatIndicesAsString) {
24
+ /* within an access operation which treats its fields, we redefine the table assignment ':=' as a trigger if this is to be treated as a definition */
25
+ // do we have a local definition that needs to be recovered?
26
+ const existing = data.environment.current.memory.get(':=');
27
+ const outInfo = { definitionRootNodes: [] };
28
+ data.environment.current.memory.set(':=', [{
29
+ kind: 'built-in-function',
30
+ definedAt: built_in_1.BuiltIn,
31
+ controlDependencies: undefined,
32
+ processor: (name, args, rootId, data) => tableAssignmentProcessor(name, args, rootId, data, outInfo),
33
+ name: ':=',
34
+ nodeId: built_in_1.BuiltIn
35
+ }]);
18
36
  fnCall = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
37
+ /* recover the environment */
38
+ if (existing !== undefined) {
39
+ data.environment.current.memory.set(':=', existing);
40
+ }
41
+ if (head.value && outInfo.definitionRootNodes.length > 0) {
42
+ (0, built_in_assignment_1.markAsAssignment)(fnCall.information, { kind: 'variable', name: head.value.lexeme ?? '', nodeId: head.value.info.id, definedAt: rootId, controlDependencies: [] }, outInfo.definitionRootNodes, rootId);
43
+ }
19
44
  }
20
45
  else {
21
46
  const newArgs = [...args];
@@ -47,10 +72,7 @@ function processAccess(name, args, rootId, data, config) {
47
72
  if (arg !== undefined) {
48
73
  info.graph.addEdge(name.info.id, arg.entryPoint, { type: 1 /* EdgeType.Reads */ });
49
74
  }
50
- if (config.treatIndicesAsString) {
51
- // everything but the first is disabled here
52
- break;
53
- }
75
+ /* we include the read edges to the constant arguments as well so that they are included if necessary */
54
76
  }
55
77
  return {
56
78
  ...info,
@@ -0,0 +1,14 @@
1
+ import type { DataflowProcessorInformation } from '../../../../../processor';
2
+ import type { DataflowInformation } from '../../../../../info';
3
+ import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
4
+ import type { ParentInformation } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/decorate';
5
+ import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
6
+ import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
7
+ import type { MergeableRecord } from '../../../../../../util/objects';
8
+ export interface BuiltInApplyConfiguration extends MergeableRecord {
9
+ /** the 0-based index of the argument which is the actual function passed, defaults to 1 */
10
+ readonly indexOfFunction?: number;
11
+ /** does the argument have a name that it can be given by as well? */
12
+ readonly nameOfFunctionArgument?: string;
13
+ }
14
+ export declare function processApply<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, { indexOfFunction, nameOfFunctionArgument }: BuiltInApplyConfiguration): DataflowInformation;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processApply = void 0;
4
+ const known_call_handling_1 = require("../known-call-handling");
5
+ const r_function_call_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
6
+ const logger_1 = require("../../../../../logger");
7
+ function processApply(name, args, rootId, data, { indexOfFunction = 1, nameOfFunctionArgument }) {
8
+ /* as the length is one-based and the argument filter mapping is zero-based, we do not have to subtract 1 */
9
+ const forceArgsMask = new Array(indexOfFunction).fill(false);
10
+ forceArgsMask.push(true);
11
+ const { information, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({
12
+ name, args, rootId, data, forceArgs: forceArgsMask
13
+ });
14
+ let index = indexOfFunction;
15
+ /* search, if one of the arguments actually contains the argument name if given in the config */
16
+ if (nameOfFunctionArgument !== undefined) {
17
+ const mayFn = args.findIndex(arg => arg !== r_function_call_1.EmptyArgument && arg.name && arg.name.content === nameOfFunctionArgument);
18
+ if (mayFn >= 0) {
19
+ index = mayFn;
20
+ }
21
+ }
22
+ /* validate, that we indeed have so many arguments to fill this one :D */
23
+ if (index >= args.length) {
24
+ logger_1.dataflowLogger.warn(`Function argument at index ${index} not found, skipping`);
25
+ return information;
26
+ }
27
+ const arg = args[index];
28
+ if (arg === r_function_call_1.EmptyArgument || arg?.value?.type !== "RSymbol" /* RType.Symbol */) {
29
+ logger_1.dataflowLogger.warn(`Expected symbol as argument at index ${index}, but got ${JSON.stringify(arg)} instead.`);
30
+ return information;
31
+ }
32
+ const functionSymbol = arg.value;
33
+ const allOtherArguments = processedArguments.filter((_, i) => i !== index).map((arg, i) => {
34
+ const counterpart = args[i];
35
+ if (arg && counterpart !== r_function_call_1.EmptyArgument && counterpart.name) {
36
+ return {
37
+ name: counterpart.name.content,
38
+ controlDependencies: data.controlDependencies,
39
+ nodeId: arg.entryPoint
40
+ };
41
+ }
42
+ else {
43
+ return r_function_call_1.EmptyArgument;
44
+ }
45
+ });
46
+ const applyCallId = functionSymbol.info.id;
47
+ /* identify it as a full-blown function call :) */
48
+ information.graph.updateToFunctionCall({
49
+ tag: "function-call" /* VertexType.FunctionCall */,
50
+ id: applyCallId,
51
+ name: functionSymbol.content,
52
+ args: allOtherArguments,
53
+ environment: data.environment,
54
+ onlyBuiltin: false,
55
+ controlDependencies: data.controlDependencies
56
+ });
57
+ for (const arg of processedArguments) {
58
+ if (arg) {
59
+ information.graph.addEdge(applyCallId, arg.entryPoint, { type: 64 /* EdgeType.Argument */ });
60
+ }
61
+ }
62
+ return information;
63
+ }
64
+ exports.processApply = processApply;
65
+ //# sourceMappingURL=built-in-apply.js.map
@@ -5,7 +5,10 @@ import type { RNode } from '../../../../../../r-bridge/lang-4.x/ast/model/model'
5
5
  import type { RSymbol } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
6
6
  import type { RFunctionArgument } from '../../../../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
7
7
  import type { NodeId } from '../../../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
8
+ import type { IdentifierDefinition } from '../../../../../environments/identifier';
8
9
  import type { ForceArguments } from '../common';
10
+ import type { REnvironmentInformation } from '../../../../../environments/environment';
11
+ import type { DataflowGraph } from '../../../../../graph/graph';
9
12
  export interface AssignmentConfiguration extends ForceArguments {
10
13
  readonly superAssignment?: boolean;
11
14
  readonly swapSourceAndTarget?: boolean;
@@ -20,7 +23,7 @@ export interface AssignmentConfiguration extends ForceArguments {
20
23
  */
21
24
  export declare function processAssignment<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, config: AssignmentConfiguration): DataflowInformation;
22
25
  export interface AssignmentToSymbolParameters<OtherInfo> extends AssignmentConfiguration {
23
- readonly name: RSymbol<OtherInfo & ParentInformation>;
26
+ readonly nameOfAssignmentFunction: string;
24
27
  readonly source: RNode<OtherInfo & ParentInformation>;
25
28
  readonly args: [DataflowInformation, DataflowInformation];
26
29
  readonly target: RSymbol<OtherInfo & ParentInformation>;
@@ -28,3 +31,16 @@ export interface AssignmentToSymbolParameters<OtherInfo> extends AssignmentConfi
28
31
  readonly data: DataflowProcessorInformation<OtherInfo>;
29
32
  readonly information: DataflowInformation;
30
33
  }
34
+ /**
35
+ * Consider a call like `x <- v`
36
+ * @param information - the information to define the assignment within
37
+ * @param nodeToDefine - `x`
38
+ * @param sourceIds - `v`
39
+ * @param rootIdOfAssignment - `<-`
40
+ * @param quoteSource - whether to quote the source (i.e., define `x` without a direct reference to `v`)
41
+ * @param superAssignment - whether this is a super assignment (i.e., `<<-`)
42
+ */
43
+ export declare function markAsAssignment(information: {
44
+ environment: REnvironmentInformation;
45
+ graph: DataflowGraph;
46
+ }, nodeToDefine: IdentifierDefinition, sourceIds: readonly NodeId[], rootIdOfAssignment: NodeId, quoteSource?: boolean, superAssignment?: boolean): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processAssignment = void 0;
3
+ exports.markAsAssignment = exports.processAssignment = void 0;
4
4
  const known_call_handling_1 = require("../known-call-handling");
5
5
  const assert_1 = require("../../../../../../util/assert");
6
6
  const log_1 = require("../../../../../../util/log");
@@ -15,7 +15,7 @@ function toReplacementSymbol(target, prefix, superAssignment) {
15
15
  return {
16
16
  type: "RSymbol" /* RType.Symbol */,
17
17
  info: target.info,
18
- /* they are all mapped to <- in R, but we mark super as well */
18
+ /* they are all mapped to `<-` in R, but we mark super as well */
19
19
  content: `${prefix}${superAssignment ? '<<-' : '<-'}`,
20
20
  lexeme: target.lexeme,
21
21
  location: target.location,
@@ -44,7 +44,7 @@ args, rootId, data, config) {
44
44
  const res = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, reverseOrder: !config.swapSourceAndTarget, forceArgs: config.forceArgs });
45
45
  return processAssignmentToSymbol({
46
46
  ...config,
47
- name,
47
+ nameOfAssignmentFunction: name.content,
48
48
  source,
49
49
  target,
50
50
  args: getEffectiveOrder(config, res.processedArguments),
@@ -110,7 +110,7 @@ function processAssignmentToString(target, args, name, rootId, data, config, sou
110
110
  });
111
111
  return processAssignmentToSymbol({
112
112
  ...config,
113
- name,
113
+ nameOfAssignmentFunction: name.content,
114
114
  source,
115
115
  target: symbol,
116
116
  args: getEffectiveOrder(config, res.processedArguments),
@@ -122,10 +122,38 @@ function processAssignmentToString(target, args, name, rootId, data, config, sou
122
122
  function checkFunctionDef(source, sourceInfo) {
123
123
  return sourceInfo.graph.getVertex(source.info.id)?.tag === "function-definition" /* VertexType.FunctionDefinition */;
124
124
  }
125
+ /**
126
+ * Consider a call like `x <- v`
127
+ * @param information - the information to define the assignment within
128
+ * @param nodeToDefine - `x`
129
+ * @param sourceIds - `v`
130
+ * @param rootIdOfAssignment - `<-`
131
+ * @param quoteSource - whether to quote the source (i.e., define `x` without a direct reference to `v`)
132
+ * @param superAssignment - whether this is a super assignment (i.e., `<<-`)
133
+ */
134
+ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignment, quoteSource, superAssignment) {
135
+ information.environment = (0, define_1.define)(nodeToDefine, superAssignment, information.environment);
136
+ information.graph.setDefinitionOfVertex(nodeToDefine);
137
+ if (!quoteSource) {
138
+ for (const sourceId of sourceIds) {
139
+ information.graph.addEdge(nodeToDefine, sourceId, { type: 2 /* EdgeType.DefinedBy */ });
140
+ }
141
+ }
142
+ information.graph.addEdge(nodeToDefine, rootIdOfAssignment, { type: 2 /* EdgeType.DefinedBy */ });
143
+ // kinda dirty, but we have to remove existing read edges for the symbol, added by the child
144
+ const out = information.graph.outgoingEdges(nodeToDefine.nodeId);
145
+ for (const [id, edge] of (out ?? [])) {
146
+ edge.types &= ~1 /* EdgeType.Reads */;
147
+ if (edge.types == 0) {
148
+ out?.delete(id);
149
+ }
150
+ }
151
+ }
152
+ exports.markAsAssignment = markAsAssignment;
125
153
  /**
126
154
  * Helper function whenever it is known that the _target_ of an assignment is a (single) symbol (i.e. `x <- ...`, but not `names(x) <- ...`).
127
155
  */
128
- function processAssignmentToSymbol({ name, source, args: [targetArg, sourceArg], target, rootId, data, information, superAssignment, makeMaybe, quoteSource }) {
156
+ function processAssignmentToSymbol({ nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, superAssignment, makeMaybe, quoteSource }) {
129
157
  const isFunctionDef = checkFunctionDef(source, sourceArg);
130
158
  const writeNodes = produceWrittenNodes(rootId, targetArg, isFunctionDef, data, makeMaybe ?? false);
131
159
  if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
@@ -133,25 +161,12 @@ function processAssignmentToSymbol({ name, source, args: [targetArg, sourceArg],
133
161
  }
134
162
  // we drop the first arg which we use to pass along arguments :D
135
163
  const readFromSourceWritten = sourceArg.out.slice(1);
136
- const readTargets = [{ nodeId: rootId, name: name.content, controlDependencies: data.controlDependencies }, ...sourceArg.unknownReferences, ...sourceArg.in, ...targetArg.in.filter(i => i.nodeId !== target.info.id), ...readFromSourceWritten];
164
+ const readTargets = [{ nodeId: rootId, name: nameOfAssignmentFunction, controlDependencies: data.controlDependencies }, ...sourceArg.unknownReferences, ...sourceArg.in, ...targetArg.in.filter(i => i.nodeId !== target.info.id), ...readFromSourceWritten];
137
165
  const writeTargets = [...writeNodes, ...writeNodes, ...readFromSourceWritten];
138
166
  information.environment = (0, overwrite_1.overwriteEnvironment)(targetArg.environment, sourceArg.environment);
139
167
  // install assigned variables in environment
140
168
  for (const write of writeNodes) {
141
- information.environment = (0, define_1.define)(write, superAssignment, information.environment);
142
- information.graph.setDefinitionOfVertex(write);
143
- if (!quoteSource) {
144
- information.graph.addEdge(write, source.info.id, { type: 2 /* EdgeType.DefinedBy */ });
145
- }
146
- information.graph.addEdge(write, rootId, { type: 2 /* EdgeType.DefinedBy */ });
147
- // kinda dirty, but we have to remove existing read edges for the symbol, added by the child
148
- const out = information.graph.outgoingEdges(write.nodeId);
149
- for (const [id, edge] of (out ?? [])) {
150
- edge.types &= ~1 /* EdgeType.Reads */;
151
- if (edge.types == 0) {
152
- out?.delete(id);
153
- }
154
- }
169
+ markAsAssignment(information, write, [source.info.id], rootId, quoteSource, superAssignment);
155
170
  }
156
171
  information.graph.addEdge(rootId, targetArg.entryPoint, { type: 8 /* EdgeType.Returns */ });
157
172
  if (quoteSource) {
@@ -5,16 +5,16 @@ const known_call_handling_1 = require("../known-call-handling");
5
5
  const logger_1 = require("../../../../../logger");
6
6
  const unpack_argument_1 = require("../argument/unpack-argument");
7
7
  const make_argument_1 = require("../argument/make-argument");
8
- /* we currently do not mark this as an unknown side effect, as we can enable/disable this with a toggle */
9
8
  function processLibrary(name, args, rootId, data) {
9
+ /* we do not really know what loading the library does and what side effects it causes, hence we mark it as an unknown side effect */
10
10
  if (args.length !== 1) {
11
11
  logger_1.dataflowLogger.warn(`Currently only one-arg library-likes are allows (for ${name.content}), skipping`);
12
- return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
12
+ return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, hasUnknownSideEffect: true }).information;
13
13
  }
14
14
  const nameToLoad = (0, unpack_argument_1.unpackArgument)(args[0]);
15
15
  if (nameToLoad === undefined || nameToLoad.type !== "RSymbol" /* RType.Symbol */) {
16
16
  logger_1.dataflowLogger.warn('No library name provided, skipping');
17
- return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data }).information;
17
+ return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, hasUnknownSideEffect: true }).information;
18
18
  }
19
19
  // treat as a function call but convert the first argument to a string
20
20
  const newArg = {
@@ -27,7 +27,10 @@ function processLibrary(name, args, rootId, data) {
27
27
  str: nameToLoad.content
28
28
  }
29
29
  };
30
- return (0, known_call_handling_1.processKnownFunctionCall)({ name, args: (0, make_argument_1.wrapArgumentsUnnamed)([newArg], data.completeAst.idMap), rootId, data }).information;
30
+ return (0, known_call_handling_1.processKnownFunctionCall)({
31
+ name, args: (0, make_argument_1.wrapArgumentsUnnamed)([newArg], data.completeAst.idMap), rootId, data,
32
+ hasUnknownSideEffect: true
33
+ }).information;
31
34
  }
32
35
  exports.processLibrary = processLibrary;
33
36
  //# sourceMappingURL=built-in-library.js.map
@@ -13,15 +13,19 @@ export interface ProcessKnownFunctionCallInput<OtherInfo> extends ForceArguments
13
13
  readonly args: readonly (RNode<OtherInfo & ParentInformation> | RFunctionArgument<OtherInfo & ParentInformation>)[];
14
14
  readonly rootId: NodeId;
15
15
  readonly data: DataflowProcessorInformation<OtherInfo & ParentInformation>;
16
+ /** should arguments be processed from right to left? This does not affect the order recorded in the call but of the environments */
16
17
  readonly reverseOrder?: boolean;
17
18
  /** which arguments are to be marked as {@link EdgeType#NonStandardEvaluation|non-standard-evaluation}? */
18
19
  readonly markAsNSE?: readonly number[];
20
+ /** allows passing a data processor in-between each argument */
19
21
  readonly patchData?: (data: DataflowProcessorInformation<OtherInfo & ParentInformation>, arg: number) => DataflowProcessorInformation<OtherInfo & ParentInformation>;
22
+ /** Does the call have a side effect that we do not know a lot about which may have further consequences? */
23
+ readonly hasUnknownSideEffect?: boolean;
20
24
  }
21
25
  export interface ProcessKnownFunctionCallResult {
22
26
  readonly information: DataflowInformation;
23
27
  readonly processedArguments: readonly (DataflowInformation | undefined)[];
24
28
  readonly fnRef: IdentifierReference;
25
29
  }
26
- export declare function markNonStandardEvaluationEdges(markAsNSE: readonly number[] | undefined, callArgs: readonly (DataflowInformation | undefined)[], finalGraph: DataflowGraph, rootId: NodeId): void;
27
- export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData }: ProcessKnownFunctionCallInput<OtherInfo>): ProcessKnownFunctionCallResult;
30
+ export declare function markNonStandardEvaluationEdges(markAsNSE: readonly number[], callArgs: readonly (DataflowInformation | undefined)[], finalGraph: DataflowGraph, rootId: NodeId): void;
31
+ export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>): ProcessKnownFunctionCallResult;
@@ -5,10 +5,8 @@ const processor_1 = require("../../../../processor");
5
5
  const common_1 = require("./common");
6
6
  const graph_1 = require("../../../../graph/graph");
7
7
  const logger_1 = require("../../../../logger");
8
+ const log_1 = require("../../../../../util/log");
8
9
  function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId) {
9
- if (markAsNSE === undefined) {
10
- return;
11
- }
12
10
  for (const nse of markAsNSE) {
13
11
  if (nse < callArgs.length) {
14
12
  const arg = callArgs[nse];
@@ -22,14 +20,16 @@ function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId)
22
20
  }
23
21
  }
24
22
  exports.markNonStandardEvaluationEdges = markNonStandardEvaluationEdges;
25
- function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d }) {
23
+ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }) {
26
24
  const functionName = (0, processor_1.processDataflowFor)(name, data);
27
25
  const finalGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
28
26
  const functionCallName = name.content;
29
- logger_1.dataflowLogger.debug(`Using ${rootId} (name: ${functionCallName}) as root for the named function call`);
27
+ (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Processing known function call ${functionCallName} with ${args.length} arguments`);
30
28
  const processArgs = reverseOrder ? [...args].reverse() : args;
31
29
  const { finalEnv, callArgs, remainingReadInArgs, processedArguments } = (0, common_1.processAllArguments)({ functionName, args: processArgs, data, finalGraph, functionRootId: rootId, patchData, forceArgs });
32
- markNonStandardEvaluationEdges(markAsNSE, processedArguments, finalGraph, rootId);
30
+ if (markAsNSE) {
31
+ markNonStandardEvaluationEdges(markAsNSE, processedArguments, finalGraph, rootId);
32
+ }
33
33
  finalGraph.addVertex({
34
34
  tag: "function-call" /* VertexType.FunctionCall */,
35
35
  id: rootId,
@@ -40,6 +40,9 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
40
40
  controlDependencies: data.controlDependencies,
41
41
  args: reverseOrder ? [...callArgs].reverse() : callArgs
42
42
  });
43
+ if (hasUnknownSideEffect) {
44
+ finalGraph.markIdForUnknownSideEffects(rootId);
45
+ }
43
46
  const inIds = remainingReadInArgs;
44
47
  const fnRef = { nodeId: rootId, name: functionCallName, controlDependencies: data.controlDependencies, call: true };
45
48
  inIds.push(fnRef);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.0.17",
3
+ "version": "2.0.19",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -231,6 +231,11 @@ export declare const flowrCapabilities: {
231
231
  readonly id: "local-equal-assignment";
232
232
  readonly supported: "fully";
233
233
  readonly description: "_Handle `x = 3`, `x$y := 3`, ..._";
234
+ }, {
235
+ readonly name: "Local Table Assignment";
236
+ readonly id: "local-table-assignment";
237
+ readonly supported: "fully";
238
+ readonly description: "_Handle `x[,a:=3,]`, ..._";
234
239
  }, {
235
240
  readonly name: "Super Left Assignment";
236
241
  readonly id: "super-left-assignment";
@@ -288,6 +288,12 @@ exports.flowrCapabilities = {
288
288
  supported: 'fully',
289
289
  description: '_Handle `x = 3`, `x$y := 3`, ..._'
290
290
  },
291
+ {
292
+ name: 'Local Table Assignment',
293
+ id: 'local-table-assignment',
294
+ supported: 'fully',
295
+ description: '_Handle `x[,a:=3,]`, ..._'
296
+ },
291
297
  {
292
298
  name: 'Super Left Assignment',
293
299
  id: 'super-left-assignment',
@@ -34,7 +34,7 @@ exports.OperatorDatabase = {
34
34
  '%in%': { name: 'matching operator', stringUsedInRAst: '%in%', stringUsedInternally: '%in%', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'operation', capabilities: ['binary-operator', 'infix-calls', 'special-operator', 'function-calls'] },
35
35
  /* assignment */
36
36
  '<-': { name: 'left assignment', stringUsedInRAst: "LEFT_ASSIGN" /* RawRType.LeftAssign */, stringUsedInternally: '<-', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'local-left-assignment', 'function-calls'] },
37
- ':=': { name: 'left assignment', stringUsedInRAst: "LEFT_ASSIGN" /* RawRType.LeftAssign */, stringUsedInternally: ':=', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'local-equal-assignment', 'function-calls'] },
37
+ ':=': { name: 'left assignment', stringUsedInRAst: "LEFT_ASSIGN" /* RawRType.LeftAssign */, stringUsedInternally: ':=', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'local-table-assignment', 'function-calls'] },
38
38
  '<<-': { name: 'left global assignment', stringUsedInRAst: "LEFT_ASSIGN" /* RawRType.LeftAssign */, stringUsedInternally: '<<-', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'super-left-assignment', 'function-calls'] },
39
39
  '->': { name: 'right assignment', stringUsedInRAst: "RIGHT_ASSIGN" /* RawRType.RightAssign */, stringUsedInternally: '->', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'local-right-assignment', 'function-calls'] },
40
40
  '->>': { name: 'right global assignment', stringUsedInRAst: "RIGHT_ASSIGN" /* RawRType.RightAssign */, stringUsedInternally: '->>', writtenAs: 'infix', arity: 2 /* OperatorArity.Binary */, usedAs: 'assignment', capabilities: ['binary-operator', 'infix-calls', 'assignment-functions', 'super-right-assignment', 'function-calls'] },
@@ -1,4 +1,4 @@
1
- import type { NoInfo, RNode } from '../../r-bridge/lang-4.x/ast/model/model';
1
+ import type { RNode } from '../../r-bridge/lang-4.x/ast/model/model';
2
2
  import type { ParentInformation, NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
3
3
  /**
4
4
  * The structure of the predicate that should be used to determine
@@ -14,8 +14,3 @@ export type AutoSelectPredicate = (node: RNode<ParentInformation>, fullAst: Norm
14
14
  * A variant of the {@link AutoSelectPredicate} which does not select any additional statements (~&gt; false)
15
15
  */
16
16
  export declare function doNotAutoSelect(_node: RNode): boolean;
17
- /**
18
- * A variant of the {@link AutoSelectPredicate} which does its best
19
- * to select any kind of library import automatically.
20
- */
21
- export declare function autoSelectLibrary<Info = NoInfo>(node: RNode<Info>): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.autoSelectLibrary = exports.doNotAutoSelect = void 0;
3
+ exports.doNotAutoSelect = void 0;
4
4
  /**
5
5
  * A variant of the {@link AutoSelectPredicate} which does not select any additional statements (~&gt; false)
6
6
  */
@@ -8,16 +8,4 @@ function doNotAutoSelect(_node) {
8
8
  return false;
9
9
  }
10
10
  exports.doNotAutoSelect = doNotAutoSelect;
11
- const libraryFunctionCall = /^(library|require|((require|load|attach)Namespace))$/;
12
- /**
13
- * A variant of the {@link AutoSelectPredicate} which does its best
14
- * to select any kind of library import automatically.
15
- */
16
- function autoSelectLibrary(node) {
17
- if (node.type !== "RFunctionCall" /* RType.FunctionCall */ || !node.named) {
18
- return false;
19
- }
20
- return libraryFunctionCall.test(node.functionName.content);
21
- }
22
- exports.autoSelectLibrary = autoSelectLibrary;
23
11
  //# sourceMappingURL=auto-select-defaults.js.map
@@ -424,7 +424,7 @@ function removeOuterExpressionListIfApplicable(result, linesWithAutoSelected) {
424
424
  *
425
425
  * @returns The number of lines for which `autoSelectIf` triggered, as well as the reconstructed code itself.
426
426
  */
427
- function reconstructToCode(ast, selection, autoSelectIf = auto_select_defaults_1.autoSelectLibrary) {
427
+ function reconstructToCode(ast, selection, autoSelectIf = auto_select_defaults_1.doNotAutoSelect) {
428
428
  if (exports.reconstructLogger.settings.minLevel <= 1 /* LogLevel.Trace */) {
429
429
  exports.reconstructLogger.trace(`reconstruct ast with ids: ${JSON.stringify([...selection])}`);
430
430
  }
package/util/version.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.flowrVersion = void 0;
4
4
  const semver_1 = require("semver");
5
5
  // this is automatically replaced with the current version by release-it
6
- const version = '2.0.17';
6
+ const version = '2.0.19';
7
7
  function flowrVersion() {
8
8
  return new semver_1.SemVer(version);
9
9
  }