@eagleoutice/flowr 2.2.14 → 2.2.15

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 (83) hide show
  1. package/README.md +4 -4
  2. package/cli/repl/commands/repl-commands.js +1 -1
  3. package/cli/repl/commands/repl-execute.js +2 -1
  4. package/config.js +1 -1
  5. package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
  6. package/control-flow/cfg-dead-code.d.ts +4 -0
  7. package/control-flow/cfg-dead-code.js +81 -0
  8. package/control-flow/cfg-simplification.d.ts +17 -6
  9. package/control-flow/cfg-simplification.js +23 -19
  10. package/control-flow/control-flow-graph.d.ts +2 -1
  11. package/control-flow/control-flow-graph.js +1 -0
  12. package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
  13. package/control-flow/dfg-cfg-guided-visitor.js +1 -1
  14. package/control-flow/extract-cfg.d.ts +1 -1
  15. package/control-flow/extract-cfg.js +60 -57
  16. package/control-flow/semantic-cfg-guided-visitor.d.ts +17 -8
  17. package/control-flow/semantic-cfg-guided-visitor.js +50 -17
  18. package/control-flow/simple-visitor.d.ts +4 -0
  19. package/control-flow/simple-visitor.js +14 -0
  20. package/control-flow/syntax-cfg-guided-visitor.d.ts +2 -2
  21. package/dataflow/environments/built-in-config.d.ts +1 -0
  22. package/dataflow/environments/built-in.d.ts +10 -1
  23. package/dataflow/environments/built-in.js +9 -3
  24. package/dataflow/environments/default-builtin-config.js +1 -1
  25. package/dataflow/environments/resolve-by-name.d.ts +0 -36
  26. package/dataflow/environments/resolve-by-name.js +0 -240
  27. package/dataflow/eval/resolve/alias-tracking.d.ts +87 -0
  28. package/dataflow/eval/resolve/alias-tracking.js +349 -0
  29. package/dataflow/eval/resolve/resolve.d.ts +34 -0
  30. package/dataflow/eval/resolve/resolve.js +93 -0
  31. package/dataflow/eval/values/general.d.ts +27 -0
  32. package/dataflow/eval/values/general.js +73 -0
  33. package/dataflow/eval/values/intervals/interval-constants.d.ts +4 -0
  34. package/dataflow/eval/values/intervals/interval-constants.js +27 -0
  35. package/dataflow/eval/values/logical/logical-constants.d.ts +7 -0
  36. package/dataflow/eval/values/logical/logical-constants.js +31 -0
  37. package/dataflow/eval/values/r-value.d.ts +58 -0
  38. package/dataflow/eval/values/r-value.js +90 -0
  39. package/dataflow/eval/values/scalar/scalar-consatnts.d.ts +15 -0
  40. package/dataflow/eval/values/scalar/scalar-consatnts.js +35 -0
  41. package/dataflow/eval/values/sets/set-constants.d.ts +7 -0
  42. package/dataflow/eval/values/sets/set-constants.js +34 -0
  43. package/dataflow/eval/values/string/string-constants.d.ts +8 -0
  44. package/dataflow/eval/values/string/string-constants.js +40 -0
  45. package/dataflow/eval/values/vectors/vector-constants.d.ts +14 -0
  46. package/dataflow/eval/values/vectors/vector-constants.js +35 -0
  47. package/dataflow/graph/unknown-replacement.d.ts +11 -0
  48. package/dataflow/graph/unknown-replacement.js +12 -0
  49. package/dataflow/graph/unknown-side-effect.d.ts +7 -0
  50. package/dataflow/graph/unknown-side-effect.js +13 -0
  51. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +8 -5
  52. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +4 -2
  53. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +12 -9
  54. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -4
  55. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +9 -2
  56. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +12 -15
  57. package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +23 -0
  58. package/dataflow/internal/process/functions/call/known-call-handling.js +2 -1
  59. package/documentation/doc-util/doc-query.d.ts +6 -3
  60. package/documentation/doc-util/doc-query.js +3 -1
  61. package/documentation/print-cfg-wiki.js +6 -6
  62. package/documentation/print-dataflow-graph-wiki.js +4 -3
  63. package/documentation/print-engines-wiki.js +1 -1
  64. package/documentation/print-query-wiki.js +80 -0
  65. package/linter/rules/1-deprecated-functions.js +1 -1
  66. package/linter/rules/2-file-path-validity.js +1 -1
  67. package/package.json +1 -1
  68. package/queries/catalog/control-flow-query/control-flow-query-executor.d.ts +3 -0
  69. package/queries/catalog/control-flow-query/control-flow-query-executor.js +20 -0
  70. package/queries/catalog/control-flow-query/control-flow-query-format.d.ts +81 -0
  71. package/queries/catalog/control-flow-query/control-flow-query-format.js +34 -0
  72. package/queries/catalog/dependencies-query/dependencies-query-executor.js +33 -32
  73. package/queries/catalog/linter-query/linter-query-format.js +2 -1
  74. package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +3 -3
  75. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -1
  76. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -22
  77. package/queries/query.d.ts +61 -1
  78. package/queries/query.js +2 -0
  79. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +11 -4
  80. package/search/search-executor/search-enrichers.js +5 -2
  81. package/slicing/criterion/parse.d.ts +8 -0
  82. package/slicing/criterion/parse.js +20 -0
  83. package/util/version.js +1 -1
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onReplacementOperator = onReplacementOperator;
4
+ exports.handleReplacementOperator = handleReplacementOperator;
5
+ const handlers = [];
6
+ function onReplacementOperator(handler) {
7
+ handlers.push(handler);
8
+ }
9
+ function handleReplacementOperator(args) {
10
+ handlers.forEach(handler => handler(args));
11
+ }
12
+ //# sourceMappingURL=unknown-replacement.js.map
@@ -0,0 +1,7 @@
1
+ import type { LinkTo } from '../../queries/catalog/call-context-query/call-context-query-format';
2
+ import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
3
+ import type { REnvironmentInformation } from '../environments/environment';
4
+ import type { DataflowGraph } from './graph';
5
+ export type UnknownSideEffectHandler = (graph: DataflowGraph, env: REnvironmentInformation, id: NodeId, target?: LinkTo<RegExp | string>) => void;
6
+ export declare function onUnknownSideEffect(handler: UnknownSideEffectHandler): void;
7
+ export declare function handleUnknownSideEffect(graph: DataflowGraph, env: REnvironmentInformation, id: NodeId, target?: LinkTo<RegExp | string>): void;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onUnknownSideEffect = onUnknownSideEffect;
4
+ exports.handleUnknownSideEffect = handleUnknownSideEffect;
5
+ const handlers = [];
6
+ function onUnknownSideEffect(handler) {
7
+ handlers.push(handler);
8
+ }
9
+ function handleUnknownSideEffect(graph, env, id, target) {
10
+ graph.markIdForUnknownSideEffects(id, target);
11
+ handlers.forEach(handler => handler(graph, env, id, target));
12
+ }
13
+ //# sourceMappingURL=unknown-side-effect.js.map
@@ -10,7 +10,10 @@ const edge_1 = require("../../../../../graph/edge");
10
10
  const identifier_1 = require("../../../../../environments/identifier");
11
11
  const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
12
12
  const unnamed_call_handling_1 = require("../unnamed-call-handling");
13
+ const general_1 = require("../../../../../eval/values/general");
14
+ const r_value_1 = require("../../../../../eval/values/r-value");
13
15
  const log_1 = require("../../../../../../util/log");
16
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
14
17
  function processApply(name, args, rootId, data, config) {
15
18
  const { indexOfFunction = 1, nameOfFunctionArgument, unquoteFunction, resolveInEnvironment, resolveValue } = config;
16
19
  /* as the length is one-based and the argument filter mapping is zero-based, we do not have to subtract 1 */
@@ -54,9 +57,9 @@ function processApply(name, args, rootId, data, config) {
54
57
  else if (val.type === type_1.RType.Symbol) {
55
58
  functionId = val.info.id;
56
59
  if (resolveValue) {
57
- const resolved = (0, resolve_by_name_1.resolveValueOfVariable)(val.content, data.environment);
58
- if (resolved?.length === 1 && typeof resolved[0] === 'string') {
59
- functionName = resolved[0];
60
+ const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: data.environment, idMap: data.completeAst.idMap }));
61
+ if (resolved?.elements.length === 1 && resolved.elements[0].type === 'string') {
62
+ functionName = (0, r_value_1.isValue)(resolved.elements[0].value) ? resolved.elements[0].value.str : undefined;
60
63
  }
61
64
  }
62
65
  else {
@@ -72,7 +75,7 @@ function processApply(name, args, rootId, data, config) {
72
75
  logger_1.dataflowLogger.warn(`Expected symbol or string as function argument at index ${index}, but got ${JSON.stringify(val)} instead.`);
73
76
  return information;
74
77
  }
75
- const allOtherArguments = processedArguments.filter((_, i) => i !== index).map((arg, i) => {
78
+ const allOtherArguments = processedArguments.map((arg, i) => {
76
79
  const counterpart = args[i];
77
80
  if (arg && counterpart !== r_function_call_1.EmptyArgument) {
78
81
  return {
@@ -85,7 +88,7 @@ function processApply(name, args, rootId, data, config) {
85
88
  else {
86
89
  return r_function_call_1.EmptyArgument;
87
90
  }
88
- });
91
+ }).filter((_, i) => i !== index);
89
92
  if (anonymous) {
90
93
  const rootFnId = functionId;
91
94
  functionId = 'anon-' + rootFnId;
@@ -20,6 +20,8 @@ const containers_1 = require("../../../../../../util/containers");
20
20
  const config_1 = require("../../../../../../config");
21
21
  const named_call_handling_1 = require("../named-call-handling");
22
22
  const built_in_1 = require("../../../../../environments/built-in");
23
+ const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
24
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
23
25
  function toReplacementSymbol(target, prefix, superAssignment) {
24
26
  return {
25
27
  type: type_1.RType.Symbol,
@@ -142,7 +144,7 @@ args, rootId, data, config) {
142
144
  name, args: effectiveArgs, rootId, data, forceArgs: config.forceArgs,
143
145
  origin: 'builtin:assignment'
144
146
  }).information;
145
- info.graph.markIdForUnknownSideEffects(rootId);
147
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(info.graph, info.environment, rootId);
146
148
  return info;
147
149
  }
148
150
  function extractSourceAndTarget(args) {
@@ -269,7 +271,7 @@ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignme
269
271
  function processAssignmentToSymbol(config) {
270
272
  const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], target, rootId, data, information, makeMaybe, quoteSource } = config;
271
273
  const referenceType = checkTargetReferenceType(source, sourceArg);
272
- const aliases = (0, resolve_by_name_1.getAliases)([source.info.id], information.graph, information.environment);
274
+ const aliases = (0, alias_tracking_1.getAliases)([source.info.id], information.graph, information.environment);
273
275
  const writeNodes = produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false, aliases);
274
276
  if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
275
277
  log_1.log.warn(`Unexpected write number in assignment: ${JSON.stringify(writeNodes)}`);
@@ -12,9 +12,12 @@ const log_1 = require("../../../../../../util/log");
12
12
  const built_in_source_1 = require("./built-in-source");
13
13
  const edge_1 = require("../../../../../graph/edge");
14
14
  const type_1 = require("../../../../../../r-bridge/lang-4.x/ast/model/type");
15
- const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
16
15
  const append_1 = require("../../../../../environments/append");
17
16
  const assert_1 = require("../../../../../../util/assert");
17
+ const general_1 = require("../../../../../eval/values/general");
18
+ const string_constants_1 = require("../../../../../eval/values/string/string-constants");
19
+ const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
20
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
18
21
  const arrays_1 = require("../../../../../../util/collections/arrays");
19
22
  function processEvalCall(name, args, rootId, data, config) {
20
23
  if (args.length !== 1 || args[0] === r_function_call_1.EmptyArgument || !args[0].value) {
@@ -30,7 +33,7 @@ function processEvalCall(name, args, rootId, data, config) {
30
33
  }
31
34
  if (!(0, config_1.getConfig)().solver.evalStrings) {
32
35
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Skipping eval call ${JSON.stringify(evalArgument)} (disabled in config file)`);
33
- information.graph.markIdForUnknownSideEffects(rootId);
36
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
34
37
  return information;
35
38
  }
36
39
  const code = resolveEvalToCode(evalArgument.value, data.environment, data.completeAst.idMap);
@@ -62,7 +65,7 @@ function processEvalCall(name, args, rootId, data, config) {
62
65
  };
63
66
  }
64
67
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(args)} for eval is currently not supported, skipping`);
65
- information.graph.markIdForUnknownSideEffects(rootId);
68
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
66
69
  return information;
67
70
  }
68
71
  function resolveEvalToCode(evalArgument, env, idMap) {
@@ -77,9 +80,9 @@ function resolveEvalToCode(evalArgument, env, idMap) {
77
80
  return [arg.value.content.str];
78
81
  }
79
82
  else if (arg.value?.type === type_1.RType.Symbol) {
80
- const resolve = (0, resolve_by_name_1.resolveValueOfVariable)(arg.value.content, env, idMap);
81
- if (resolve?.every(r => typeof r === 'object' && r !== null && 'str' in r)) {
82
- return resolve.map(r => r.str);
83
+ const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(arg.value.info.id, { environment: env, idMap: idMap }));
84
+ if (resolved) {
85
+ return (0, string_constants_1.collectStrings)(resolved.elements);
83
86
  }
84
87
  }
85
88
  else if (arg.value?.type === type_1.RType.FunctionCall && arg.value.named && ['paste', 'paste0'].includes(arg.value.functionName.content)) {
@@ -104,9 +107,9 @@ function getAsString(val, env, idMap) {
104
107
  return [val.content.str];
105
108
  }
106
109
  else if (val.type === type_1.RType.Symbol) {
107
- const resolved = (0, resolve_by_name_1.resolveValueOfVariable)(val.content, env, idMap);
108
- if (resolved?.every(r => typeof r === 'object' && r !== null && 'str' in r)) {
109
- return resolved.map(r => r.str);
110
+ const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(val.info.id, { environment: env, idMap: idMap }));
111
+ if (resolved) {
112
+ return (0, string_constants_1.collectStrings)(resolved.elements);
110
113
  }
111
114
  }
112
115
  return undefined;
@@ -7,11 +7,12 @@ const known_call_handling_1 = require("../known-call-handling");
7
7
  const common_1 = require("../common");
8
8
  const unpack_argument_1 = require("../argument/unpack-argument");
9
9
  const logger_1 = require("../../../../../logger");
10
- const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
11
10
  const edge_1 = require("../../../../../graph/edge");
12
11
  const append_1 = require("../../../../../environments/append");
13
12
  const identifier_1 = require("../../../../../environments/identifier");
14
13
  const environment_1 = require("../../../../../environments/environment");
14
+ const general_1 = require("../../../../../eval/values/general");
15
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
15
16
  function processIfThenElse(name, args, rootId, data) {
16
17
  if (args.length !== 2 && args.length !== 3) {
17
18
  logger_1.dataflowLogger.warn(`If-then-else ${name.content} has something different from 2 or 3 arguments, skipping`);
@@ -33,9 +34,9 @@ function processIfThenElse(name, args, rootId, data) {
33
34
  let then;
34
35
  let makeThenMaybe = false;
35
36
  // we should defer this to the abstract interpretation
36
- const values = (0, resolve_by_name_1.resolveValueOfVariable)(condArg?.lexeme, data.environment, data.completeAst.idMap);
37
- const conditionIsAlwaysFalse = values?.every(d => d === false) ?? false;
38
- const conditionIsAlwaysTrue = values?.every(d => d === true) ?? false;
37
+ const values = (0, alias_tracking_1.resolveIdToValue)(condArg?.info.id, { environment: data.environment, idMap: data.completeAst.idMap });
38
+ const conditionIsAlwaysFalse = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === false) ?? false;
39
+ const conditionIsAlwaysTrue = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === true) ?? false;
39
40
  if (!conditionIsAlwaysFalse) {
40
41
  then = (0, processor_1.processDataflowFor)(thenArg, data);
41
42
  if (then.entryPoint) {
@@ -17,6 +17,7 @@ const unpack_argument_1 = require("../argument/unpack-argument");
17
17
  const built_in_access_1 = require("./built-in-access");
18
18
  const built_in_1 = require("../../../../../environments/built-in");
19
19
  const identifier_1 = require("../../../../../environments/identifier");
20
+ const unknown_replacement_1 = require("../../../../../graph/unknown-replacement");
20
21
  function processReplacementFunction(name,
21
22
  /** The last one has to be the value */
22
23
  args, rootId, data, config) {
@@ -60,9 +61,15 @@ args, rootId, data, config) {
60
61
  origin: 'builtin:replacement',
61
62
  link: config.assignRootId ? { origin: [config.assignRootId] } : undefined
62
63
  });
63
- const firstArg = (0, unpack_argument_1.unpackArgument)(args[0])?.info.id;
64
+ const firstArg = (0, unpack_argument_1.unpackArgument)(args[0]);
65
+ (0, unknown_replacement_1.handleReplacementOperator)({
66
+ operator: name.content,
67
+ target: firstArg?.lexeme,
68
+ env: res.environment,
69
+ id: rootId
70
+ });
64
71
  if (firstArg) {
65
- res.graph.addEdge(firstArg, rootId, edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Reads);
72
+ res.graph.addEdge(firstArg.info.id, rootId, edge_1.EdgeType.DefinedBy | edge_1.EdgeType.Reads);
66
73
  }
67
74
  /* a replacement reads all of its call args as well, at least as far as I am aware of */
68
75
  for (const arg of callArgs) {
@@ -23,9 +23,12 @@ const log_1 = require("../../../../../../util/log");
23
23
  const fs_1 = __importDefault(require("fs"));
24
24
  const parser_1 = require("../../../../../../r-bridge/lang-4.x/ast/parser/json/parser");
25
25
  const shell_executor_1 = require("../../../../../../r-bridge/shell-executor");
26
- const resolve_by_name_1 = require("../../../../../environments/resolve-by-name");
27
26
  const assert_1 = require("../../../../../../util/assert");
28
27
  const path_1 = __importDefault(require("path"));
28
+ const general_1 = require("../../../../../eval/values/general");
29
+ const r_value_1 = require("../../../../../eval/values/r-value");
30
+ const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
31
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
29
32
  let sourceProvider = (0, retriever_1.requestProviderFromFile)();
30
33
  function setSourceProvider(provider) {
31
34
  sourceProvider = provider;
@@ -128,7 +131,7 @@ function processSourceCall(name, args, rootId, data, config) {
128
131
  const sourceFileArgument = args[0];
129
132
  if (!config.forceFollow && (0, config_1.getConfig)().ignoreSourceCalls) {
130
133
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Skipping source call ${JSON.stringify(sourceFileArgument)} (disabled in config file)`);
131
- information.graph.markIdForUnknownSideEffects(rootId);
134
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
132
135
  return information;
133
136
  }
134
137
  let sourceFile;
@@ -136,14 +139,8 @@ function processSourceCall(name, args, rootId, data, config) {
136
139
  sourceFile = [(0, retriever_1.removeRQuotes)(sourceFileArgument.lexeme)];
137
140
  }
138
141
  else if (sourceFileArgument !== r_function_call_1.EmptyArgument) {
139
- sourceFile = (0, resolve_by_name_1.resolveValueOfVariable)(sourceFileArgument.value?.lexeme, data.environment, data.completeAst.idMap)?.map(x => {
140
- if (typeof x === 'object' && x && 'str' in x) {
141
- return x.str;
142
- }
143
- else {
144
- return undefined;
145
- }
146
- }).filter(assert_1.isNotUndefined);
142
+ const resolved = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(sourceFileArgument.info.id, { environment: data.environment, idMap: data.completeAst.idMap }));
143
+ sourceFile = resolved?.elements.map(r => r.type === 'string' && (0, r_value_1.isValue)(r.value) ? r.value.str : undefined).filter(assert_1.isNotUndefined);
147
144
  }
148
145
  if (sourceFile && sourceFile.length === 1) {
149
146
  const path = (0, retriever_1.removeRQuotes)(sourceFile[0]);
@@ -158,14 +155,14 @@ function processSourceCall(name, args, rootId, data, config) {
158
155
  const findCount = data.referenceChain.filter(e => e.request === request.request && e.content === request.content).length;
159
156
  if (findCount > limit) {
160
157
  logger_1.dataflowLogger.warn(`Found cycle (>=${limit + 1}) in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
161
- information.graph.markIdForUnknownSideEffects(rootId);
158
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
162
159
  return information;
163
160
  }
164
161
  return sourceRequest(rootId, request, data, information, (0, decorate_1.sourcedDeterministicCountingIdGenerator)((findCount > 0 ? findCount + '::' : '') + path, name.location));
165
162
  }
166
163
  }
167
164
  (0, log_1.expensiveTrace)(logger_1.dataflowLogger, () => `Non-constant argument ${JSON.stringify(sourceFile)} for source is currently not supported, skipping`);
168
- information.graph.markIdForUnknownSideEffects(rootId);
165
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
169
166
  return information;
170
167
  }
171
168
  function sourceRequest(rootId, request, data, information, getId) {
@@ -173,7 +170,7 @@ function sourceRequest(rootId, request, data, information, getId) {
173
170
  /* check if the file exists and if not, fail */
174
171
  if (!fs_1.default.existsSync(request.content)) {
175
172
  logger_1.dataflowLogger.warn(`Failed to analyze sourced file ${JSON.stringify(request)}: file does not exist`);
176
- information.graph.markIdForUnknownSideEffects(rootId);
173
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
177
174
  return information;
178
175
  }
179
176
  }
@@ -195,7 +192,7 @@ function sourceRequest(rootId, request, data, information, getId) {
195
192
  catch (e) {
196
193
  logger_1.dataflowLogger.error(`Failed to analyze sourced file ${JSON.stringify(request)}, skipping: ${e.message}`);
197
194
  logger_1.dataflowLogger.error(e.stack);
198
- information.graph.markIdForUnknownSideEffects(rootId);
195
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, rootId);
199
196
  return information;
200
197
  }
201
198
  // take the entry point as well as all the written references, and give them a control dependency to the source call to show that they are conditional
@@ -229,7 +226,7 @@ function standaloneSourceFile(inputRequest, data, uniqueSourceId, information) {
229
226
  // check if the sourced file has already been dataflow analyzed, and if so, skip it
230
227
  if (data.referenceChain.find(e => e.request === request.request && e.content === request.content)) {
231
228
  logger_1.dataflowLogger.info(`Found loop in dataflow analysis for ${JSON.stringify(request)}: ${JSON.stringify(data.referenceChain)}, skipping further dataflow analysis`);
232
- information.graph.markIdForUnknownSideEffects(uniqueSourceId);
229
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(information.graph, information.environment, uniqueSourceId);
233
230
  return information;
234
231
  }
235
232
  return sourceRequest(uniqueSourceId, request, {
@@ -11,6 +11,8 @@ const logger_1 = require("../../../../../logger");
11
11
  const environment_1 = require("../../../../../environments/environment");
12
12
  const edge_1 = require("../../../../../graph/edge");
13
13
  const identifier_1 = require("../../../../../environments/identifier");
14
+ const general_1 = require("../../../../../eval/values/general");
15
+ const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
14
16
  function processWhileLoop(name, args, rootId, data) {
15
17
  if (args.length !== 2 || args[1] === r_function_call_1.EmptyArgument) {
16
18
  logger_1.dataflowLogger.warn(`While-Loop ${name.content} does not have 2 arguments, skipping`);
@@ -21,6 +23,13 @@ function processWhileLoop(name, args, rootId, data) {
21
23
  logger_1.dataflowLogger.warn(`While-Loop ${name.content} has empty arguments in ${JSON.stringify(args)}, skipping`);
22
24
  return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, origin: 'default' }).information;
23
25
  }
26
+ // we should defer this to the abstract interpretation
27
+ const values = (0, alias_tracking_1.resolveIdToValue)(unpackedArgs[0]?.info.id, { environment: data.environment, idMap: data.completeAst.idMap });
28
+ const conditionIsAlwaysFalse = (0, general_1.valueSetGuard)(values)?.elements.every(d => d.type === 'logical' && d.value === false) ?? false;
29
+ //We don't care about the body if it never executes
30
+ if (conditionIsAlwaysFalse) {
31
+ unpackedArgs.pop();
32
+ }
24
33
  /* we inject the cf-dependency of the while-loop after the condition */
25
34
  const { information, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({
26
35
  name,
@@ -36,10 +45,24 @@ function processWhileLoop(name, args, rootId, data) {
36
45
  }, origin: 'builtin:while-loop'
37
46
  });
38
47
  const [condition, body] = processedArguments;
48
+ // If the condition is always false, we don't include the body
49
+ if (condition !== undefined && conditionIsAlwaysFalse) {
50
+ information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
51
+ return {
52
+ unknownReferences: [],
53
+ in: [{ nodeId: name.info.id, name: name.lexeme, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function }],
54
+ out: condition.out,
55
+ entryPoint: name.info.id,
56
+ exitPoints: [],
57
+ graph: information.graph,
58
+ environment: information.environment
59
+ };
60
+ }
39
61
  (0, assert_1.guard)(condition !== undefined && body !== undefined, () => `While-Loop ${name.content} has no condition or body, impossible!`);
40
62
  const originalDependency = data.controlDependencies;
41
63
  if ((0, info_1.alwaysExits)(condition)) {
42
64
  logger_1.dataflowLogger.warn(`While-Loop ${rootId} forces exit in condition, skipping rest`);
65
+ information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
43
66
  return condition;
44
67
  }
45
68
  const remainingInputs = (0, linker_1.linkInputs)([
@@ -10,6 +10,7 @@ const edge_1 = require("../../../../graph/edge");
10
10
  const logger_1 = require("../../../../logger");
11
11
  const vertex_1 = require("../../../../graph/vertex");
12
12
  const log_1 = require("../../../../../util/log");
13
+ const unknown_side_effect_1 = require("../../../../graph/unknown-side-effect");
13
14
  function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId) {
14
15
  for (const nse of markAsNSE) {
15
16
  if (nse < callArgs.length) {
@@ -46,7 +47,7 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
46
47
  origin: origin === 'default' ? ['function'] : [origin]
47
48
  });
48
49
  if (hasUnknownSideEffect) {
49
- finalGraph.markIdForUnknownSideEffects(rootId);
50
+ (0, unknown_side_effect_1.handleUnknownSideEffect)(finalGraph, data.environment, rootId);
50
51
  }
51
52
  const inIds = remainingReadInArgs;
52
53
  const fnRef = { nodeId: rootId, name: functionCallName, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function };
@@ -1,13 +1,16 @@
1
1
  import type { RShell } from '../../r-bridge/shell';
2
- import type { Queries, SupportedQueryTypes } from '../../queries/query';
2
+ import type { Queries, QueryResults, SupportedQueryTypes } from '../../queries/query';
3
+ import { DEFAULT_DATAFLOW_PIPELINE } from '../../core/steps/pipeline/default-pipelines';
3
4
  import type { SupportedVirtualQueryTypes } from '../../queries/virtual-query/virtual-queries';
4
5
  import type { VirtualCompoundConstraint } from '../../queries/virtual-query/compound-query';
5
- export interface ShowQueryOptions {
6
+ import type { PipelineOutput } from '../../core/steps/pipeline/pipeline';
7
+ export interface ShowQueryOptions<Base extends SupportedQueryTypes> {
6
8
  readonly showCode?: boolean;
7
9
  readonly collapseResult?: boolean;
8
10
  readonly collapseQuery?: boolean;
11
+ readonly addOutput?: (result: QueryResults<Base>, pipeline: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>) => string;
9
12
  }
10
- export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult, collapseQuery }?: ShowQueryOptions): Promise<string>;
13
+ export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult, collapseQuery, addOutput }?: ShowQueryOptions<Base>): Promise<string>;
11
14
  export interface QueryDocumentation {
12
15
  readonly name: string;
13
16
  readonly type: 'virtual' | 'active';
@@ -17,7 +17,7 @@ const doc_dfg_1 = require("./doc-dfg");
17
17
  const doc_code_1 = require("./doc-code");
18
18
  const time_1 = require("../../util/text/time");
19
19
  const query_print_1 = require("../../queries/query-print");
20
- async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery } = {}) {
20
+ async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery, addOutput = () => '' } = {}) {
21
21
  const now = performance.now();
22
22
  const analysis = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
23
23
  parser: shell,
@@ -60,6 +60,8 @@ ${await (0, doc_dfg_1.printDfGraphForCode)(shell, code, { switchCodeAndGraph: tr
60
60
 
61
61
  ${collapseResult ? '</details>' : ''}
62
62
 
63
+ ${addOutput(results, analysis)}
64
+
63
65
  `;
64
66
  }
65
67
  exports.RegisteredQueries = {
@@ -89,10 +89,10 @@ class CollectNumbersSyntaxVisitor extends syntax_cfg_guided_visitor_1.SyntaxAwar
89
89
  class CollectNumbersDataflowVisitor extends dfg_cfg_guided_visitor_1.DataflowAwareCfgGuidedVisitor {
90
90
  numbers = [];
91
91
  constructor(controlFlow, dataflow) {
92
- super({ controlFlow, dataflow, defaultVisitingOrder: 'forward' });
92
+ super({ controlFlow, dfg: dataflow, defaultVisitingOrder: 'forward' });
93
93
  }
94
94
  visitValue(node) {
95
- const astNode = this.config.dataflow.graph.idMap?.get(node.id);
95
+ const astNode = this.config.dfg.idMap?.get(node.id);
96
96
  if ((0, r_number_1.isRNumber)(astNode)) {
97
97
  this.numbers.push(astNode.content);
98
98
  }
@@ -104,7 +104,7 @@ class CollectNumbersDataflowVisitor extends dfg_cfg_guided_visitor_1.DataflowAwa
104
104
  class CollectSourcesSemanticVisitor extends semantic_cfg_guided_visitor_1.SemanticCfgGuidedVisitor {
105
105
  sources = [];
106
106
  constructor(controlFlow, normalizedAst, dataflow) {
107
- super({ controlFlow, normalizedAst, dataflow, defaultVisitingOrder: 'forward' });
107
+ super({ controlFlow, normalizedAst, dfg: dataflow, defaultVisitingOrder: 'forward' });
108
108
  }
109
109
  onAssignmentCall({ source }) {
110
110
  if (source) {
@@ -206,7 +206,7 @@ ${(0, doc_structure_1.section)('Structure of the Control Flow Graph', 2, 'cfg-st
206
206
  You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)}.
207
207
  The ${(0, doc_types_1.shortLink)(control_flow_graph_1.ControlFlowGraph.name, types.info)} class describes everything required to model the control flow graph, with its edge types described by
208
208
  ${(0, doc_types_1.shortLink)('CfgEdge', types.info)} and its vertices by ${(0, doc_types_1.shortLink)('CfgSimpleVertex', types.info)}.
209
- However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the the CFG
209
+ However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the CFG
210
210
  (and is used during the construction of the CFG as well):
211
211
 
212
212
  ${(0, doc_types_1.printHierarchy)({ info: types.info, root: 'ControlFlowInformation', program: types.program, openTop: true })}
@@ -475,7 +475,7 @@ Again, executing it with the CFG and Dataflow of the expression \`x - 1 + 2L * 3
475
475
 
476
476
  ${await (async () => {
477
477
  const res = await (0, doc_cfg_1.getCfg)(shell, 'x - 1 + 2L * 3');
478
- const visitor = new CollectNumbersDataflowVisitor(res.info, res.dataflow);
478
+ const visitor = new CollectNumbersDataflowVisitor(res.info, res.dataflow.graph);
479
479
  visitor.start();
480
480
  const collected = visitor.getNumbers();
481
481
  return collected.map(n => '\n- `' + JSON.stringify(n) + '`').join('');
@@ -500,7 +500,7 @@ Executing it with the CFG and Dataflow of the expression \`x <- 2; 3 -> x; assig
500
500
 
501
501
  ${await (async () => {
502
502
  const res = await (0, doc_cfg_1.getCfg)(shell, 'x <- 2; 3 -> x; assign("x", 42 + 21)');
503
- const visitor = new CollectSourcesSemanticVisitor(res.info, res.ast, res.dataflow);
503
+ const visitor = new CollectSourcesSemanticVisitor(res.info, res.ast, res.dataflow.graph);
504
504
  visitor.start();
505
505
  const collected = visitor.getSources();
506
506
  return collected.map(n => '\n- `' + n + '`').join('');
@@ -34,6 +34,7 @@ const linker_1 = require("../dataflow/internal/linker");
34
34
  const doc_normalized_ast_1 = require("./doc-util/doc-normalized-ast");
35
35
  const dfg_get_origin_1 = require("../dataflow/origin/dfg-get-origin");
36
36
  const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
37
+ const alias_tracking_1 = require("../dataflow/eval/resolve/alias-tracking");
37
38
  const doc_issue_1 = require("./doc-util/doc-issue");
38
39
  const unnamed_call_handling_1 = require("../dataflow/internal/process/functions/call/unnamed-call-handling");
39
40
  const environment_builder_1 = require("../../test/functionality/_helper/dataflow/environment-builder");
@@ -977,7 +978,7 @@ Depending on what you are interested in, there exists a plethora of functions an
977
978
  * The **[Query API](${doc_files_1.FlowrWikiBaseRef}/Query%20API)** provides many functions to query the dataflow graph for specific information (dependencies, calls, slices, clusters, ...)
978
979
  * The **[Search API](${doc_files_1.FlowrWikiBaseRef}/Search%20API)** allows you to search for specific vertices or edges in the dataflow graph or the original program
979
980
  * ${(0, doc_types_1.shortLink)(node_id_1.recoverName.name, vertexType.info)} and ${(0, doc_types_1.shortLink)(node_id_1.recoverContent.name, vertexType.info)} to get the name or content of a vertex in the dataflow graph
980
- * ${(0, doc_types_1.shortLink)(resolve_by_name_1.resolveValueOfVariable.name, vertexType.info)} and ${(0, doc_types_1.shortLink)(resolve_by_name_1.resolveIdToValue.name, vertexType.info)} to resolve the value of a variable or id (if possible, see [below](#dfg-resolving-values))
981
+ * ${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} to resolve the value of a variable or id (if possible, see [below](#dfg-resolving-values))
981
982
  * ${(0, doc_types_1.shortLink)(edge_1.edgeIncludesType.name, vertexType.info)} to check if an edge includes a specific type and ${(0, doc_types_1.shortLink)(edge_1.splitEdgeTypes.name, vertexType.info)} to split the bitmask of edges into its types (see [below](#dfg-resolving-values))
982
983
  * ${(0, doc_types_1.shortLink)(identify_link_to_last_call_relation_1.getValueOfArgument.name, vertexType.info)} to get the (syntactical) value of an argument in a function call
983
984
  * ${(0, doc_types_1.shortLink)(dfg_get_origin_1.getOriginInDfg.name, vertexType.info)} to get information about where a read, call, ... comes from (see [below](#dfg-resolving-values))
@@ -989,8 +990,8 @@ ${(0, doc_structure_1.section)('Resolving Values', 3, 'dfg-resolving-values')}
989
990
  FlowR supports a [configurable](${doc_files_1.FlowrWikiBaseRef}/Interface#configuring-flowr) level of value tracking&mdash;all with the goal of knowing the static value domain of a variable.
990
991
  These capabilities are exposed by the [resolve value Query](${doc_files_1.FlowrWikiBaseRef}/Query-API#resolve-value-query) and backed by two important functions:
991
992
 
992
- ${(0, doc_types_1.shortLink)(resolve_by_name_1.resolveValueOfVariable.name, vertexType.info)} provides an environment-sensitive (see ${(0, doc_types_1.shortLink)('REnvironmentInformation', vertexType.info)})
993
- value resolution, while ${(0, doc_types_1.shortLink)(resolve_by_name_1.resolveIdToValue.name, vertexType.info)} provides a more general, but potentially less precise resolution independent of the current state.
993
+ ${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} provides an environment-sensitive (see ${(0, doc_types_1.shortLink)('REnvironmentInformation', vertexType.info)})
994
+ value resolution depending on if the environment is provided.
994
995
 
995
996
  ${(0, doc_structure_1.section)('Assessing Edges', 3, 'dfg-assess-edge')}
996
997
 
@@ -49,7 +49,7 @@ are exposed with some command line options (e.g., when using the docker image of
49
49
 
50
50
  ${(0, doc_structure_1.block)({
51
51
  type: 'WARNING',
52
- content: 'As the tree-sitter engine is only for parsing, it cannot execute R code.'
52
+ content: 'As the tree-sitter engine is only for parsing, it cannot execute R code. This engine is now the default.'
53
53
  })}
54
54
 
55
55
  In general, there is no need for you to pass custom paths using either
@@ -34,6 +34,8 @@ const flowr_search_builder_1 = require("../search/flowr-search-builder");
34
34
  const vertex_1 = require("../dataflow/graph/vertex");
35
35
  const doc_types_1 = require("./doc-util/doc-types");
36
36
  const path_1 = __importDefault(require("path"));
37
+ const control_flow_query_executor_1 = require("../queries/catalog/control-flow-query/control-flow-query-executor");
38
+ const doc_cfg_1 = require("./doc-util/doc-cfg");
37
39
  (0, doc_query_1.registerQueryDocumentation)('call-context', {
38
40
  name: 'Call-Context Query',
39
41
  type: 'active',
@@ -477,6 +479,84 @@ Here, \`resolveValue\` tells the dependency query to resolve the value of this a
477
479
  `;
478
480
  }
479
481
  });
482
+ (0, doc_query_1.registerQueryDocumentation)('linter', {
483
+ name: 'Linter Query',
484
+ type: 'active',
485
+ shortDescription: 'Lints a given R script for common issues.',
486
+ functionName: dependencies_query_executor_1.executeDependenciesQuery.name,
487
+ functionFile: '../queries/catalog/linter-query/linter-query-executor.ts',
488
+ buildExplanation: async (shell) => {
489
+ const exampleCode = 'read.csv("i_do_not_exist.csv")';
490
+ return `
491
+ This query lints a given R script for common issues, such as missing files, unused variables, and more.
492
+
493
+ In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns all smells detected:
494
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
495
+ type: 'linter'
496
+ }], { showCode: false, collapseQuery: true })}
497
+
498
+ You can also configure which rules to apply and what settings to use for these rules.
499
+ We welcome any feedback and suggestions for new rules on this (consider opening a [new issue](${doc_issue_1.NewIssueUrl})).
500
+ `;
501
+ }
502
+ });
503
+ (0, doc_query_1.registerQueryDocumentation)('control-flow', {
504
+ name: 'Control-Flow Query',
505
+ type: 'active',
506
+ shortDescription: 'Provides the control-flow of the program.',
507
+ functionName: control_flow_query_executor_1.executeControlFlowQuery.name,
508
+ functionFile: '../queries/catalog/control-flow-query/control-flow-query-executor.ts',
509
+ buildExplanation: async (shell) => {
510
+ const exampleCode = 'if(TRUE) 1 else 2';
511
+ return `
512
+ This control-flow query provides you access to the control flow graph.
513
+
514
+ In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the CFG:
515
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
516
+ type: 'control-flow'
517
+ }], { showCode: false, collapseQuery: true, collapseResult: true })}
518
+
519
+ You can also overwrite the simplification passes to tune the perspective. for example, if you want to have basic blocks:
520
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
521
+ type: 'control-flow',
522
+ config: {
523
+ simplificationPasses: ['unique-cf-sets', 'to-basic-blocks']
524
+ }
525
+ }], { showCode: false, collapseResult: true })}
526
+
527
+ this produces:
528
+
529
+ ${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'] })}
530
+
531
+
532
+ If, on the other hand, you want to prune dead code edges:
533
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
534
+ type: 'control-flow',
535
+ config: {
536
+ simplificationPasses: ['unique-cf-sets', 'analyze-dead-code']
537
+ }
538
+ }], { showCode: false, collapseResult: true })}
539
+
540
+ this produces:
541
+
542
+ ${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code'] })}
543
+
544
+
545
+ Or, completely remove dead code:
546
+ ${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
547
+ type: 'control-flow',
548
+ config: {
549
+ simplificationPasses: ['unique-cf-sets', 'analyze-dead-code', 'remove-dead-code']
550
+ }
551
+ }], { showCode: false, collapseResult: true })}
552
+
553
+ this produces:
554
+
555
+ ${await (0, doc_cfg_1.printCfgCode)(shell, exampleCode, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['analyze-dead-code', 'remove-dead-code'] })}
556
+
557
+ `;
558
+ }
559
+ });
480
560
  (0, doc_query_1.registerQueryDocumentation)('location-map', {
481
561
  name: 'Location Map Query',
482
562
  type: 'active',
@@ -46,7 +46,7 @@ exports.R1_DEPRECATED_FUNCTIONS = {
46
46
  '.meta': metadata
47
47
  };
48
48
  },
49
- prettyPrint: result => `Function ${result.function} at ${(0, dfg_1.formatRange)(result.range)}`,
49
+ prettyPrint: result => `Function \`${result.function}\` at ${(0, dfg_1.formatRange)(result.range)}`,
50
50
  defaultConfig: {
51
51
  deprecatedFunctions: ['all_equal', 'arrange_all', 'distinct_all', 'filter_all', 'group_by_all', 'summarise_all', 'mutate_all', 'select_all', 'vars', 'all_vars', 'id', 'failwith', 'select_vars', 'rename_vars', 'select_var', 'current_vars', 'bench_tbls', 'compare_tbls', 'compare_tbls2', 'eval_tbls', 'eval_tbls2', 'location', 'changes', 'combine', 'do', 'funs', 'add_count_', 'add_tally_', 'arrange_', 'count_', 'distinct_', 'do_', 'filter_', 'funs_', 'group_by_', 'group_indices_', 'mutate_', 'tally_', 'transmute_', 'rename_', 'rename_vars_', 'select_', 'select_vars_', 'slice_', 'summarise_', 'summarize_', 'summarise_each', 'src_local', 'tbl_df', 'add_rownames', 'group_nest', 'group_split', 'with_groups', 'nest_by', 'progress_estimated', 'recode', 'sample_n', 'top_n', 'transmute', 'fct_explicit_na', 'aes_', 'aes_auto', 'annotation_logticks', 'is.Coord', 'coord_flip', 'coord_map', 'is.facet', 'fortify', 'is.ggproto', 'guide_train', 'is.ggplot', 'qplot', 'is.theme', 'gg_dep', 'liply', 'isplit2', 'list_along', 'cross', 'invoke', 'at_depth', 'prepend', 'rerun', 'splice', '`%@%`', 'rbernoulli', 'rdunif', 'when', 'update_list', 'map_raw', 'accumulate', 'reduce_right', 'flatten', 'map_dfr', 'as_vector', 'transpose', 'melt_delim', 'melt_fwf', 'melt_table', 'read_table2', 'str_interp', 'as_tibble', 'data_frame', 'tibble_', 'data_frame_', 'lst_', 'as_data_frame', 'as.tibble', 'frame_data', 'trunc_mat', 'is.tibble', 'tidy_names', 'set_tidy_names', 'repair_names', 'extract_numeric', 'complete_', 'drop_na_', 'expand_', 'crossing_', 'nesting_', 'extract_', 'fill_', 'gather_', 'nest_', 'separate_rows_', 'separate_', 'spread_', 'unite_', 'unnest_', 'extract', 'gather', 'nest_legacy', 'separate_rows', 'separate', 'spread',]
52
52
  }
@@ -76,7 +76,7 @@ exports.R2_FILE_PATH_VALIDITY = {
76
76
  '.meta': metadata
77
77
  };
78
78
  },
79
- prettyPrint: result => `Path ${result.filePath} at ${(0, dfg_1.formatRange)(result.range)}`,
79
+ prettyPrint: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)}`,
80
80
  defaultConfig: {
81
81
  additionalReadFunctions: [],
82
82
  additionalWriteFunctions: [],