@eagleoutice/flowr 1.4.1 → 1.4.2

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 (133) hide show
  1. package/README.md +3 -3
  2. package/abstract-interpretation/processor.js +9 -3
  3. package/benchmark/slicer.d.ts +0 -3
  4. package/benchmark/slicer.js +4 -16
  5. package/benchmark/stats/print.js +0 -2
  6. package/benchmark/stats/stats.d.ts +2 -3
  7. package/benchmark/stats/stats.js +1 -1
  8. package/cli/benchmark-app.d.ts +1 -0
  9. package/cli/benchmark-app.js +21 -6
  10. package/cli/benchmark-helper-app.d.ts +2 -0
  11. package/cli/benchmark-helper-app.js +15 -6
  12. package/cli/common/options.js +4 -1
  13. package/cli/common/scripts-info.d.ts +1 -0
  14. package/cli/common/scripts-info.js +15 -1
  15. package/cli/export-quads-app.js +1 -5
  16. package/cli/repl/commands/cfg.js +2 -2
  17. package/cli/repl/commands/commands.d.ts +3 -1
  18. package/cli/repl/commands/commands.js +67 -28
  19. package/cli/repl/commands/dataflow.js +2 -2
  20. package/cli/repl/commands/normalize.js +2 -2
  21. package/cli/repl/commands/parse.js +12 -12
  22. package/cli/repl/commands/quit.js +4 -1
  23. package/cli/repl/core.d.ts +4 -2
  24. package/cli/repl/core.js +63 -7
  25. package/cli/repl/execute.d.ts +1 -1
  26. package/cli/repl/execute.js +3 -3
  27. package/cli/repl/server/connection.js +3 -8
  28. package/cli/repl/server/net.js +2 -2
  29. package/cli/statistics-helper-app.js +0 -1
  30. package/cli/summarizer-app.js +1 -2
  31. package/config.d.ts +16 -0
  32. package/config.js +75 -0
  33. package/core/input.d.ts +1 -1
  34. package/core/output.d.ts +1 -2
  35. package/core/print/parse-printer.d.ts +1 -2
  36. package/core/print/parse-printer.js +6 -4
  37. package/core/slicer.js +4 -8
  38. package/core/steps.d.ts +7 -24
  39. package/core/steps.js +5 -12
  40. package/dataflow/environments/environment.js +8 -0
  41. package/dataflow/environments/register.js +1 -0
  42. package/dataflow/extractor.d.ts +2 -2
  43. package/dataflow/extractor.js +10 -2
  44. package/dataflow/internal/process/functions/function-call.js +7 -1
  45. package/dataflow/internal/process/functions/source.d.ts +8 -0
  46. package/dataflow/internal/process/functions/source.js +81 -0
  47. package/dataflow/processor.d.ts +10 -1
  48. package/flowr.d.ts +2 -0
  49. package/flowr.js +14 -9
  50. package/package.json +41 -18
  51. package/r-bridge/lang-4.x/ast/index.d.ts +1 -0
  52. package/r-bridge/lang-4.x/ast/index.js +3 -0
  53. package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +2 -0
  54. package/r-bridge/lang-4.x/ast/model/processing/decorate.js +6 -1
  55. package/r-bridge/lang-4.x/ast/parser/json/format.d.ts +14 -0
  56. package/r-bridge/lang-4.x/ast/parser/json/format.js +26 -0
  57. package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +7 -0
  58. package/r-bridge/lang-4.x/ast/parser/json/parser.js +57 -0
  59. package/r-bridge/lang-4.x/ast/parser/xml/data.d.ts +0 -3
  60. package/r-bridge/lang-4.x/ast/parser/xml/index.d.ts +0 -2
  61. package/r-bridge/lang-4.x/ast/parser/xml/index.js +0 -2
  62. package/r-bridge/lang-4.x/ast/parser/xml/input-format.d.ts +5 -1
  63. package/r-bridge/lang-4.x/ast/parser/xml/input-format.js +7 -10
  64. package/r-bridge/lang-4.x/ast/parser/xml/internal/access.js +2 -2
  65. package/r-bridge/lang-4.x/ast/parser/xml/internal/control/if-then-else.js +1 -1
  66. package/r-bridge/lang-4.x/ast/parser/xml/internal/control/if-then.js +2 -2
  67. package/r-bridge/lang-4.x/ast/parser/xml/internal/expression/expression.js +4 -4
  68. package/r-bridge/lang-4.x/ast/parser/xml/internal/functions/argument.js +2 -2
  69. package/r-bridge/lang-4.x/ast/parser/xml/internal/functions/call.js +4 -4
  70. package/r-bridge/lang-4.x/ast/parser/xml/internal/functions/definition.js +2 -2
  71. package/r-bridge/lang-4.x/ast/parser/xml/internal/functions/parameter.js +2 -2
  72. package/r-bridge/lang-4.x/ast/parser/xml/internal/index.d.ts +0 -1
  73. package/r-bridge/lang-4.x/ast/parser/xml/internal/index.js +0 -1
  74. package/r-bridge/lang-4.x/ast/parser/xml/internal/loops/break.js +2 -2
  75. package/r-bridge/lang-4.x/ast/parser/xml/internal/loops/for.js +3 -6
  76. package/r-bridge/lang-4.x/ast/parser/xml/internal/loops/next.js +2 -2
  77. package/r-bridge/lang-4.x/ast/parser/xml/internal/loops/repeat.js +2 -2
  78. package/r-bridge/lang-4.x/ast/parser/xml/internal/loops/while.js +2 -2
  79. package/r-bridge/lang-4.x/ast/parser/xml/internal/meta.d.ts +6 -11
  80. package/r-bridge/lang-4.x/ast/parser/xml/internal/meta.js +15 -23
  81. package/r-bridge/lang-4.x/ast/parser/xml/internal/operators/binary.js +6 -6
  82. package/r-bridge/lang-4.x/ast/parser/xml/internal/operators/unary.js +3 -3
  83. package/r-bridge/lang-4.x/ast/parser/xml/internal/other/comment.js +2 -2
  84. package/r-bridge/lang-4.x/ast/parser/xml/internal/other/line-directive.js +2 -2
  85. package/r-bridge/lang-4.x/ast/parser/xml/internal/structure/elements.js +3 -3
  86. package/r-bridge/lang-4.x/ast/parser/xml/internal/structure/root.js +3 -4
  87. package/r-bridge/lang-4.x/ast/parser/xml/internal/structure/single-element.js +2 -2
  88. package/r-bridge/lang-4.x/ast/parser/xml/internal/values/number.js +2 -2
  89. package/r-bridge/lang-4.x/ast/parser/xml/internal/values/string.js +2 -2
  90. package/r-bridge/lang-4.x/ast/parser/xml/internal/values/symbol.js +4 -4
  91. package/r-bridge/lang-4.x/values.d.ts +0 -1
  92. package/r-bridge/lang-4.x/values.js +14 -6
  93. package/r-bridge/retriever.d.ts +25 -21
  94. package/r-bridge/retriever.js +73 -23
  95. package/r-bridge/shell-executor.d.ts +3 -17
  96. package/r-bridge/shell-executor.js +9 -78
  97. package/r-bridge/shell.d.ts +5 -27
  98. package/r-bridge/shell.js +31 -92
  99. package/statistics/features/supported/assignments/post-process.js +6 -6
  100. package/statistics/features/supported/comments/post-process.js +2 -2
  101. package/statistics/features/supported/data-access/post-process.js +4 -4
  102. package/statistics/features/supported/defined-functions/post-process.js +4 -4
  103. package/statistics/features/supported/expression-list/post-process.js +3 -3
  104. package/statistics/features/supported/loops/post-process.js +3 -3
  105. package/statistics/features/supported/used-functions/post-process.js +5 -5
  106. package/statistics/features/supported/used-packages/post-process.js +5 -5
  107. package/statistics/features/supported/values/post-process.js +3 -3
  108. package/statistics/features/supported/variables/post-process.js +3 -3
  109. package/statistics/output/ansi.js +1 -1
  110. package/statistics/statistics.js +7 -8
  111. package/util/args.d.ts +8 -4
  112. package/util/args.js +11 -4
  113. package/util/cfg/visitor.js +1 -1
  114. package/util/files.d.ts +6 -0
  115. package/util/files.js +11 -1
  116. package/util/log.js +3 -0
  117. package/util/summarizer/benchmark/first-phase/input.d.ts +2 -1
  118. package/util/summarizer/benchmark/first-phase/input.js +20 -4
  119. package/util/summarizer/benchmark/first-phase/process.d.ts +2 -1
  120. package/util/summarizer/benchmark/first-phase/process.js +14 -5
  121. package/util/summarizer/benchmark/second-phase/graph.js +1 -1
  122. package/util/summarizer/benchmark/second-phase/process.d.ts +2 -0
  123. package/util/summarizer/benchmark/second-phase/process.js +48 -11
  124. package/util/summarizer/benchmark/summarizer.d.ts +0 -4
  125. package/util/summarizer/benchmark/summarizer.js +16 -7
  126. package/util/summarizer/statistics/first-phase/process.js +8 -8
  127. package/util/summarizer/statistics/post-process/post-process-output.js +4 -5
  128. package/r-bridge/lang-4.x/ast/parser/xml/config.d.ts +0 -25
  129. package/r-bridge/lang-4.x/ast/parser/xml/config.js +0 -16
  130. package/r-bridge/lang-4.x/ast/parser/xml/internal/xml-to-json.d.ts +0 -9
  131. package/r-bridge/lang-4.x/ast/parser/xml/internal/xml-to-json.js +0 -51
  132. package/r-bridge/lang-4.x/ast/parser/xml/parser.d.ts +0 -17
  133. package/r-bridge/lang-4.x/ast/parser/xml/parser.js +0 -30
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  [![flowR logo](https://raw.githubusercontent.com/wiki/Code-Inspect/flowr/img/flowR.png)](https://github.com/Code-Inspect/flowr/wiki)\
2
- [![QA (and potentially deploy)](https://github.com/Code-Inspect/flowr/actions/workflows/qa.yaml/badge.svg)](https://github.com/Code-Inspect/flowr/actions/workflows/qa.yaml) [![codecov](https://codecov.io/gh/Code-Inspect/flowr/graph/badge.svg)](https://codecov.io/gh/Code-Inspect/flowr) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/eagleoutice/flowr?logo=docker&logoColor=white&label=dockerhub)](https://hub.docker.com/r/eagleoutice/flowr) [![latest tag](https://badgen.net/github/tag/Code-Inspect/flowr?label=latest&color=purple)](https://github.com/Code-Inspect/flowr/releases/latest)
2
+ [![QA (and potentially deploy)](https://github.com/Code-Inspect/flowr/actions/workflows/qa.yaml/badge.svg)](https://github.com/Code-Inspect/flowr/actions/workflows/qa.yaml) [![codecov](https://codecov.io/gh/Code-Inspect/flowr/graph/badge.svg)](https://codecov.io/gh/Code-Inspect/flowr) [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/eagleoutice/flowr?logo=docker&logoColor=white&label=dockerhub)](https://hub.docker.com/r/eagleoutice/flowr) [![latest tag](https://badgen.net/github/tag/Code-Inspect/flowr?label=latest&color=purple)](https://github.com/Code-Inspect/flowr/releases/latest) [![Marketplace](https://badgen.net/vs-marketplace/v/code-inspect.vscode-flowr)](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr)
3
3
 
4
4
 
5
- *flowR* is a static [dataflow analyzer](https://en.wikipedia.org/wiki/Data-flow_analysis) and [program slicer](https://github.com/Code-Inspect/flowr/wiki/Terminology#program-slice) for the [*R*](https://www.r-project.org/) programming language (currently tested for versions `4.x`).
5
+ *flowR* is a static [dataflow analyzer](https://en.wikipedia.org/wiki/Data-flow_analysis) and [program slicer](https://github.com/Code-Inspect/flowr/wiki/Terminology#program-slice) for the [*R*](https://www.r-project.org/) programming language (currently tested for versions `4.x`). It is available as a [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr) and as a [docker image](https://hub.docker.com/r/eagleoutice/flowr).
6
6
 
7
7
  ## ⭐ Getting Started
8
8
 
9
- To get started with _flowR_, please check out the [Overview](https://github.com/Code-Inspect/flowr/wiki/Overview). The [Setup](https://github.com/Code-Inspect/flowr/wiki/Setup) wiki page explains how you can download and setup _flowR_ on your system. With docker 🐳️, the following line should be enough (and drop you directly into the REPL):
9
+ To get started with _flowR_, please check out the [Overview](https://github.com/Code-Inspect/flowr/wiki/Overview). The [Setup](https://github.com/Code-Inspect/flowr/wiki/Setup) wiki page explains how you can download and setup _flowR_ on your system. For Visual Studio Code, please see the [marketplace entry](https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr). With docker 🐳️, the following line should be enough (and drop you directly into the REPL):
10
10
 
11
11
  ```shell
12
12
  docker run -it --rm eagleoutice/flowr
@@ -11,9 +11,15 @@ const log_1 = require("../util/log");
11
11
  exports.aiLogger = log_1.log.getSubLogger({ name: 'abstract-interpretation' });
12
12
  class Stack {
13
13
  backingStore = [];
14
- size() { return this.backingStore.length; }
15
- peek() { return this.backingStore[this.size() - 1]; }
16
- pop() { return this.backingStore.pop(); }
14
+ size() {
15
+ return this.backingStore.length;
16
+ }
17
+ peek() {
18
+ return this.backingStore[this.size() - 1];
19
+ }
20
+ pop() {
21
+ return this.backingStore.pop();
22
+ }
17
23
  push(item) {
18
24
  this.backingStore.push(item);
19
25
  return item;
@@ -15,8 +15,6 @@ export declare const benchmarkLogger: import("tslog").Logger<import("tslog").ILo
15
15
  export interface BenchmarkSlicerStats extends MergeableRecord {
16
16
  /** the measurements obtained during the benchmark */
17
17
  stats: SlicerStats;
18
- /** the used token map when translating what was parsed from R */
19
- tokenMap: Record<string, string>;
20
18
  /** the initial and unmodified AST produced by the R side/the 'parse' step */
21
19
  parse: string;
22
20
  /** the normalized AST produced by the 'normalization' step, including its parent decoration */
@@ -52,7 +50,6 @@ export declare class BenchmarkSlicer {
52
50
  private readonly shell;
53
51
  private stats;
54
52
  private loadedXml;
55
- private tokenMap;
56
53
  private dataflow;
57
54
  private ai;
58
55
  private normalizedAst;
@@ -29,11 +29,10 @@ exports.benchmarkLogger = log_1.log.getSubLogger({ name: 'benchmark' });
29
29
  class BenchmarkSlicer {
30
30
  /** Measures all data that is recorded *once* per slicer (complete setup up to the dataflow graph creation) */
31
31
  commonMeasurements = new stopwatch_1.Measurements();
32
- perSliceMeasurements = new Map;
32
+ perSliceMeasurements = new Map();
33
33
  shell;
34
34
  stats;
35
35
  loadedXml;
36
- tokenMap;
37
36
  dataflow;
38
37
  ai;
39
38
  normalizedAst;
@@ -44,7 +43,6 @@ class BenchmarkSlicer {
44
43
  constructor() {
45
44
  this.totalStopwatch = this.commonMeasurements.start('total');
46
45
  this.shell = this.commonMeasurements.measure('initialize R session', () => new r_bridge_1.RShell());
47
- this.commonMeasurements.measure('inject home path', () => this.shell.tryToInjectHomeLibPath());
48
46
  }
49
47
  /**
50
48
  * Initialize the slicer on the given request.
@@ -52,24 +50,15 @@ class BenchmarkSlicer {
52
50
  */
53
51
  async init(request) {
54
52
  (0, assert_1.guard)(this.stats === undefined, 'cannot initialize the slicer twice');
55
- await this.commonMeasurements.measureAsync('ensure installation of xmlparsedata', () => this.shell.ensurePackageInstalled('xmlparsedata', true));
56
- this.tokenMap = await this.commonMeasurements.measureAsync('retrieve token map',
57
- // with this being the first time, there is no preexisting caching!
58
- () => this.shell.tokenMap());
59
53
  this.stepper = new core_1.SteppingSlicer({
60
54
  shell: this.shell,
61
- request: {
62
- ...request,
63
- ensurePackageInstalled: true
64
- },
55
+ request: { ...request },
65
56
  stepOfInterest: core_1.LAST_STEP,
66
- criterion: [],
67
- tokenMap: this.tokenMap
57
+ criterion: []
68
58
  });
69
59
  this.loadedXml = await this.measureCommonStep('parse', 'retrieve AST from R code');
70
60
  this.normalizedAst = await this.measureCommonStep('normalize', 'normalize R AST');
71
61
  this.dataflow = await this.measureCommonStep('dataflow', 'produce dataflow information');
72
- this.ai = await this.measureCommonStep('ai', 'run abstract interpretation');
73
62
  this.stepper.switchToSliceStage();
74
63
  await this.calculateStatsAfterInit(request);
75
64
  }
@@ -210,8 +199,7 @@ class BenchmarkSlicer {
210
199
  stats: this.stats,
211
200
  parse: this.loadedXml,
212
201
  dataflow: this.dataflow,
213
- normalize: this.normalizedAst,
214
- tokenMap: this.tokenMap,
202
+ normalize: this.normalizedAst
215
203
  };
216
204
  }
217
205
  /**
@@ -72,7 +72,6 @@ function stats2string(stats) {
72
72
  let result = `
73
73
  Request: ${JSON.stringify(stats.request)}
74
74
  Shell init time: ${print(stats.commonMeasurements, 'initialize R session')}
75
- Retrieval of token map: ${print(stats.commonMeasurements, 'retrieve token map')}
76
75
  AST retrieval: ${print(stats.commonMeasurements, 'retrieve AST from R code')}
77
76
  AST normalization: ${print(stats.commonMeasurements, 'normalize R AST')}
78
77
  Dataflow creation: ${print(stats.commonMeasurements, 'produce dataflow information')}
@@ -117,7 +116,6 @@ function ultimateStats2String(stats) {
117
116
  return `
118
117
  Summarized: ${stats.totalRequests} requests and ${stats.totalSlices} slices
119
118
  Shell init time: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('initialize R session'))}
120
- Retrieval of token map: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('retrieve token map'))}
121
119
  AST retrieval: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('retrieve AST from R code'))}
122
120
  AST normalization: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('normalize R AST'))}
123
121
  Dataflow creation: ${formatSummarizedTimeMeasure(stats.commonMeasurements.get('produce dataflow information'))}
@@ -1,7 +1,6 @@
1
- import type { SingleSlicingCriterion, SlicingCriteria } from '../../slicing';
1
+ import type { ReconstructionResult, SingleSlicingCriterion, SlicingCriteria } from '../../slicing';
2
2
  import type { NodeId, RParseRequestFromFile, RParseRequestFromText } from '../../r-bridge';
3
- import type { ReconstructionResult } from '../../slicing';
4
- export declare const CommonSlicerMeasurements: readonly ["initialize R session", "inject home path", "ensure installation of xmlparsedata", "retrieve token map", "retrieve AST from R code", "normalize R AST", "produce dataflow information", "run abstract interpretation", "close R session", "total"];
3
+ export declare const CommonSlicerMeasurements: readonly ["initialize R session", "retrieve AST from R code", "normalize R AST", "produce dataflow information", "close R session", "total"];
5
4
  export type CommonSlicerMeasurements = typeof CommonSlicerMeasurements[number];
6
5
  export declare const PerSliceMeasurements: readonly ["static slicing", "reconstruct code", "total"];
7
6
  export type PerSliceMeasurements = typeof PerSliceMeasurements[number];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PerSliceMeasurements = exports.CommonSlicerMeasurements = void 0;
4
- exports.CommonSlicerMeasurements = ['initialize R session', 'inject home path', 'ensure installation of xmlparsedata', 'retrieve token map', 'retrieve AST from R code', 'normalize R AST', 'produce dataflow information', 'run abstract interpretation', 'close R session', 'total'];
4
+ exports.CommonSlicerMeasurements = ['initialize R session', 'retrieve AST from R code', 'normalize R AST', 'produce dataflow information', 'close R session', 'total'];
5
5
  exports.PerSliceMeasurements = ['static slicing', 'reconstruct code', 'total'];
6
6
  //# sourceMappingURL=stats.js.map
@@ -6,4 +6,5 @@ export interface BenchmarkCliOptions {
6
6
  slice: string;
7
7
  parallel: number;
8
8
  limit?: number;
9
+ runs?: number;
9
10
  }
@@ -9,6 +9,7 @@ const parallel_1 = require("../util/parallel");
9
9
  const assert_1 = require("../util/assert");
10
10
  const fs_1 = __importDefault(require("fs"));
11
11
  const common_1 = require("./common");
12
+ const path_1 = __importDefault(require("path"));
12
13
  const options = (0, common_1.processCommandLineArgs)('benchmark', [], {
13
14
  subtitle: 'Slice given files with additional benchmark information',
14
15
  examples: [
@@ -21,15 +22,17 @@ if (options.input.length === 0) {
21
22
  process.exit(0);
22
23
  }
23
24
  (0, assert_1.guard)(options.slice === 'all' || options.slice === 'no', 'slice must be either all or no');
25
+ (0, assert_1.guard)(options.runs === undefined || options.runs > 0, 'runs must be greater than zero');
24
26
  function removeIfExists(summarizedRaw) {
25
27
  if (fs_1.default.existsSync(summarizedRaw)) {
26
28
  console.log(`Removing existing ${summarizedRaw}`);
27
- fs_1.default.unlinkSync(summarizedRaw);
29
+ fs_1.default.rmSync(summarizedRaw, { recursive: true });
28
30
  }
29
31
  }
30
32
  async function benchmark() {
31
33
  removeIfExists(options.output);
32
- console.log(`Writing output continuously to ${options.output}`);
34
+ fs_1.default.mkdirSync(options.output);
35
+ console.log(`Storing output in ${options.output}`);
33
36
  console.log(`Using ${options.parallel} parallel executors`);
34
37
  // we do not use the limit argument to be able to pick the limit randomly
35
38
  const files = [];
@@ -43,10 +46,22 @@ async function benchmark() {
43
46
  }
44
47
  const limit = options.limit ?? files.length;
45
48
  const verboseAdd = options.verbose ? ['--verbose'] : [];
46
- const pool = new parallel_1.LimitedThreadPool(`${__dirname}/benchmark-helper-app`, files.map(f => [f.content, '--output', options.output, '--slice', options.slice, ...verboseAdd]), limit, options.parallel);
47
- await pool.run();
48
- const stats = pool.getStats();
49
- console.log(`Benchmarked ${stats.counter} files, skipped ${stats.skipped.length} files due to errors`);
49
+ const args = files.map((f, i) => [
50
+ '--input', f.content,
51
+ '--file-id', `${i}`,
52
+ '--output', path_1.default.join(options.output, `${path_1.default.parse(f.content).name}.json`),
53
+ '--slice', options.slice, ...verboseAdd
54
+ ]);
55
+ const runs = options.runs ?? 1;
56
+ for (let i = 1; i <= runs; i++) {
57
+ console.log(`Run ${i} of ${runs}`);
58
+ const pool = new parallel_1.LimitedThreadPool(`${__dirname}/benchmark-helper-app`,
59
+ // we reverse here "for looks", since the helper pops from the end, and we want file ids to be ascending :D
60
+ args.map(a => [...a, '--run-num', `${i}`]).reverse(), limit, options.parallel);
61
+ await pool.run();
62
+ const stats = pool.getStats();
63
+ console.log(`Run ${i} of ${runs}: Benchmarked ${stats.counter} files, skipped ${stats.skipped.length} files due to errors`);
64
+ }
50
65
  }
51
66
  void benchmark();
52
67
  //# sourceMappingURL=benchmark-app.js.map
@@ -2,6 +2,8 @@ export interface SingleBenchmarkCliOptions {
2
2
  verbose: boolean;
3
3
  help: boolean;
4
4
  input?: string;
5
+ 'file-id'?: number;
6
+ 'run-num'?: number;
5
7
  slice: string;
6
8
  output?: string;
7
9
  }
@@ -25,7 +25,10 @@ async function benchmark() {
25
25
  // we do not use the limit argument to be able to pick the limit randomly
26
26
  (0, assert_1.guard)(options.input !== undefined, 'No input file given');
27
27
  (0, assert_1.guard)(options.output !== undefined, 'No output file given');
28
- console.log(`[${options.input}] Appending output to ${options.output}`);
28
+ (0, assert_1.guard)((options['file-id'] === undefined) === (options['run-num'] === undefined), 'When giving a file-id or run-num, both have to be given');
29
+ // prefix for printing to console, includes file id and run number if present
30
+ const prefix = `[${options.input}${options['file-id'] !== undefined ? ` (file ${options['file-id']}, run ${options['run-num']})` : ''}]`;
31
+ console.log(`${prefix} Appending output to ${options.output}`);
29
32
  // ensure the file exists
30
33
  const fileStat = fs_1.default.statSync(options.input);
31
34
  (0, assert_1.guard)(fileStat.isFile(), `File ${options.input} does not exist or is no file`);
@@ -35,21 +38,27 @@ async function benchmark() {
35
38
  await slicer.init(request);
36
39
  // ${escape}1F${escape}1G${escape}2K for line reset
37
40
  if (options.slice === 'all') {
38
- const count = await slicer.sliceForAll(slicing_1.DefaultAllVariablesFilter, (i, total, arr) => console.log(`[${options.input}] Slicing ${i + 1}/${total} [${JSON.stringify(arr[i])}]`));
39
- console.log(`[${options.input}] Completed Slicing`);
41
+ const count = await slicer.sliceForAll(slicing_1.DefaultAllVariablesFilter, (i, total, arr) => console.log(`${prefix} Slicing ${i + 1}/${total} [${JSON.stringify(arr[i])}]`));
42
+ console.log(`${prefix} Completed Slicing`);
40
43
  (0, assert_1.guard)(count > 0, `No possible slices found for ${options.input}, skipping in count`);
41
44
  }
42
45
  else {
43
- console.log(`[${options.input}] Skipping Slicing due to --slice=${options.slice}`);
46
+ console.log(`${prefix} Skipping Slicing due to --slice=${options.slice}`);
44
47
  }
45
48
  const { stats } = slicer.finish();
49
+ const output = {
50
+ filename: options.input,
51
+ 'file-id': options['file-id'],
52
+ 'run-num': options['run-num'],
53
+ stats
54
+ };
46
55
  // append line by line
47
- fs_1.default.appendFileSync(options.output, `${JSON.stringify({ filename: options.input, stats }, json_1.jsonReplacer)}\n`);
56
+ fs_1.default.appendFileSync(options.output, `${JSON.stringify(output, json_1.jsonReplacer)}\n`);
48
57
  }
49
58
  catch (e) {
50
59
  if (e instanceof Error) {
51
60
  if (!e.message.includes('unable to parse R')) {
52
- console.log(`[${options.input}] Non R-Side error : ${e.message}`);
61
+ console.log(`${prefix} Non R-Side error : ${e.message}`);
53
62
  }
54
63
  }
55
64
  slicer.ensureSessionClosed(); // ensure finish
@@ -15,15 +15,18 @@ exports.benchmarkOptions = [
15
15
  { name: 'verbose', alias: 'v', type: Boolean, description: 'Run with verbose logging [do not use for the real benchmark as this affects the time measurements, but only to find errors]' },
16
16
  { name: 'help', alias: 'h', type: Boolean, description: 'Print this usage guide' },
17
17
  { name: 'limit', alias: 'l', type: Number, description: 'Limit the number of files to process (if given, this will choose these files randomly and add the chosen names to the output' },
18
+ { name: 'runs', alias: 'r', type: Number, description: 'The amount of benchmark runs that should be done, out of which an average will be calculated' },
18
19
  { name: 'input', alias: 'i', type: String, description: 'Pass a folder or file as src to read from', multiple: true, defaultOption: true, defaultValue: [], typeLabel: '{underline files/folders}' },
19
20
  { name: 'parallel', alias: 'p', type: String, description: 'Number of parallel executors (defaults to {italic max(cpu.count-1, 1)})', defaultValue: Math.max(os_1.default.cpus().length - 1, 1), typeLabel: '{underline number}' },
20
21
  { name: 'slice', alias: 's', type: String, description: 'Automatically slice for *all* variables (default) or *no* slicing and only parsing/dataflow construction', defaultValue: 'all', typeLabel: '{underline all/no}' },
21
- { name: 'output', alias: 'o', type: String, description: `File to write all the measurements to in a per-file-basis (defaults to {italic benchmark-${StartTimeString}.json})`, defaultValue: `benchmark-${StartTimeString}.json`, typeLabel: '{underline file}' }
22
+ { name: 'output', alias: 'o', type: String, description: `Directory to write all the measurements to in a per-file-basis (defaults to {italic benchmark-${StartTimeString}})`, defaultValue: `benchmark-${StartTimeString}`, typeLabel: '{underline file}' }
22
23
  ];
23
24
  exports.benchmarkHelperOptions = [
24
25
  { name: 'verbose', alias: 'v', type: Boolean, description: 'Run with verbose logging [do not use for the real benchmark as this affects the time measurements, but only to find errors]' },
25
26
  { name: 'help', alias: 'h', type: Boolean, description: 'Print this usage guide' },
26
27
  { name: 'input', alias: 'i', type: String, description: 'Pass a single file as src to read from', multiple: false, defaultOption: true, typeLabel: '{underline file}' },
28
+ { name: 'file-id', alias: 'd', type: Number, description: 'A numeric file id that can be used to match an input and run-num to a file' },
29
+ { name: 'run-num', alias: 'r', type: Number, description: 'The n-th time that the file with the given file-id is being benchmarked' },
27
30
  { name: 'slice', alias: 's', type: String, description: 'Automatically slice for *all* variables (default) or *no* slicing and only parsing/dataflow construction', defaultValue: 'all', typeLabel: '{underline all/no}' },
28
31
  { name: 'output', alias: 'o', type: String, description: 'File to write the measurements to (appends a single line in JSON format)', typeLabel: '{underline file}' },
29
32
  ];
@@ -21,4 +21,5 @@ export interface HelperScriptInformation extends BaseScriptInformation {
21
21
  }
22
22
  export type ScriptInformation = MasterScriptInformation | HelperScriptInformation;
23
23
  export declare const scripts: Record<"slicer" | "benchmark" | "stats" | "summarizer" | "export-quads" | "stats-helper" | "benchmark-helper", ScriptInformation>;
24
+ export declare function getValidOptionsForCompletion(options: readonly OptionDefinition[], prevArgs: readonly string[]): string[];
24
25
  export {};
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.scripts = void 0;
3
+ exports.getValidOptionsForCompletion = exports.scripts = void 0;
4
4
  const options_1 = require("./options");
5
+ const commands_1 = require("../repl/commands");
5
6
  /**
6
7
  * We hold `_scripts` internally, as the modifiable variant and export the readonly scripts
7
8
  */
@@ -66,4 +67,17 @@ const _scripts = {
66
67
  }
67
68
  };
68
69
  exports.scripts = _scripts;
70
+ function getValidOptionsForCompletion(options, prevArgs) {
71
+ return options.filter(o => canAddOption(o, prevArgs)).flatMap(o => {
72
+ const args = [(0, commands_1.asOptionName)(o.name)];
73
+ if (o.alias) {
74
+ args.push((0, commands_1.asOptionName)(o.alias));
75
+ }
76
+ return args;
77
+ });
78
+ }
79
+ exports.getValidOptionsForCompletion = getValidOptionsForCompletion;
80
+ function canAddOption(option, prevArgs) {
81
+ return option.multiple || !prevArgs.includes((0, commands_1.asOptionName)(option.name)) && (!option.alias || !prevArgs.includes((0, commands_1.asOptionName)(option.alias)));
82
+ }
69
83
  //# sourceMappingURL=scripts-info.js.map
@@ -17,12 +17,8 @@ const options = (0, common_1.processCommandLineArgs)('export-quads', [], {
17
17
  ]
18
18
  });
19
19
  const shell = new r_bridge_1.RShell();
20
- shell.tryToInjectHomeLibPath();
21
20
  async function writeQuadForSingleFile(request, output) {
22
- const normalized = await (0, r_bridge_1.retrieveNormalizedAstFromRCode)({
23
- ...request,
24
- ensurePackageInstalled: true
25
- }, shell);
21
+ const normalized = await (0, r_bridge_1.retrieveNormalizedAstFromRCode)(request, shell);
26
22
  const serialized = (0, quads_1.serialize2quads)(normalized.ast, { context: request.content });
27
23
  log_1.log.info(`Appending quads to ${output}`);
28
24
  fs_1.default.appendFileSync(output, serialized);
@@ -13,7 +13,7 @@ async function controlflow(shell, remainingLine) {
13
13
  }).allRemainingSteps();
14
14
  }
15
15
  exports.controlflowCommand = {
16
- description: 'Get mermaid code for the control-flow graph of R code, start with \'file://\' to indicate a file',
16
+ description: `Get mermaid code for the control-flow graph of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
17
17
  usageExample: ':controlflow',
18
18
  aliases: ['cfg', 'cf'],
19
19
  script: false,
@@ -24,7 +24,7 @@ exports.controlflowCommand = {
24
24
  }
25
25
  };
26
26
  exports.controlflowStarCommand = {
27
- description: 'Get a mermaid url of the control-flow graph of R code, start with \'file://\' to indicate a file',
27
+ description: `Get a mermaid url of the control-flow graph of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
28
28
  usageExample: ':controlflow',
29
29
  aliases: ['cfg*', 'cf*'],
30
30
  script: false,
@@ -3,9 +3,11 @@ export declare const helpCommand: ReplCommand;
3
3
  /**
4
4
  * The names of all commands including their aliases (but without the leading `:`)
5
5
  */
6
- export declare const commandNames: string[];
6
+ export declare function getCommandNames(): string[];
7
7
  /**
8
8
  * Get the command for a given command name or alias.
9
9
  * @param command - The name of the command (without the leading `:`)
10
10
  */
11
11
  export declare function getCommand(command: string): ReplCommand | undefined;
12
+ export declare function asOptionName(argument: string): string;
13
+ export declare function longestCommandName(): number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCommand = exports.commandNames = exports.helpCommand = void 0;
3
+ exports.longestCommandName = exports.asOptionName = exports.getCommand = exports.getCommandNames = exports.helpCommand = void 0;
4
4
  const quit_1 = require("./quit");
5
5
  const common_1 = require("../../common");
6
6
  const execute_1 = require("../execute");
@@ -28,16 +28,17 @@ exports.helpCommand = {
28
28
  usageExample: ':help',
29
29
  aliases: ['h', '?'],
30
30
  fn: output => {
31
+ initCommandMapping();
31
32
  output.stdout(`
32
33
  You can always just enter R expressions which get evaluated right away:
33
34
  ${prompt_1.rawPrompt} ${(0, statistics_1.bold)('1 + 1', output.formatter)}
34
35
  ${(0, statistics_1.italic)('[1] 2', output.formatter)}
35
36
 
36
37
  Besides that, you can use the following commands. The scripts ${(0, statistics_1.italic)('can', output.formatter)} accept further arguments. There are the following basic commands:
37
- ${Array.from(Object.entries(commands)).filter(([, { script }]) => !script).map(c => printHelpForScript(c, output.formatter)).join('\n')}
38
+ ${Array.from(Object.entries(commands())).filter(([, { script }]) => !script).map(c => printHelpForScript(c, output.formatter)).join('\n')}
38
39
 
39
40
  Furthermore, you can directly call the following scripts which accept arguments. If you are unsure, try to add ${(0, statistics_1.italic)('--help', output.formatter)} after the command.
40
- ${Array.from(Object.entries(commands)).filter(([, { script }]) => script).map(([command, { description }]) => ` ${(0, statistics_1.bold)(padCmd(':' + command), output.formatter)}${description}`).join('\n')}
41
+ ${Array.from(Object.entries(commands())).filter(([, { script }]) => script).map(([command, { description }]) => ` ${(0, statistics_1.bold)(padCmd(':' + command), output.formatter)}${description}`).join('\n')}
41
42
 
42
43
  You can combine commands by separating them with a semicolon ${(0, statistics_1.bold)(';', output.formatter)}.
43
44
  `);
@@ -46,7 +47,7 @@ You can combine commands by separating them with a semicolon ${(0, statistics_1.
46
47
  /**
47
48
  * All commands that should be available in the REPL.
48
49
  */
49
- const commands = {
50
+ const _commands = {
50
51
  'help': exports.helpCommand,
51
52
  'quit': quit_1.quitCommand,
52
53
  'version': version_1.versionCommand,
@@ -59,45 +60,83 @@ const commands = {
59
60
  'controlflow': cfg_1.controlflowCommand,
60
61
  'controlflow*': cfg_1.controlflowStarCommand
61
62
  };
62
- for (const [script, { target, description, type }] of Object.entries(common_1.scripts)) {
63
- if (type === 'master script') {
64
- commands[script] = {
65
- description,
66
- aliases: [],
67
- script: true,
68
- usageExample: `:${script} --help`,
69
- fn: async (output, _s, remainingLine) => {
70
- await (0, execute_1.waitOnScript)(`${__dirname}/../../${target}`, (0, args_1.splitAtEscapeSensitive)(remainingLine), stdio => (0, execute_1.stdioCaptureProcessor)(stdio, msg => output.stdout(msg), msg => output.stderr(msg)));
71
- }
72
- };
63
+ let commandsInitialized = false;
64
+ function commands() {
65
+ if (commandsInitialized) {
66
+ return _commands;
73
67
  }
68
+ commandsInitialized = true;
69
+ for (const [script, { target, description, type }] of Object.entries(common_1.scripts)) {
70
+ if (type === 'master script') {
71
+ _commands[script] = {
72
+ description,
73
+ aliases: [],
74
+ script: true,
75
+ usageExample: `:${script} --help`,
76
+ fn: async (output, _s, remainingLine) => {
77
+ await (0, execute_1.waitOnScript)(`${__dirname}/../../${target}`, (0, args_1.splitAtEscapeSensitive)(remainingLine), stdio => (0, execute_1.stdioCaptureProcessor)(stdio, msg => output.stdout(msg), msg => output.stderr(msg)));
78
+ }
79
+ };
80
+ }
81
+ }
82
+ return _commands;
74
83
  }
75
84
  /**
76
85
  * The names of all commands including their aliases (but without the leading `:`)
77
86
  */
78
- exports.commandNames = [];
87
+ function getCommandNames() {
88
+ if (commandNames === undefined) {
89
+ initCommandMapping();
90
+ }
91
+ return commandNames;
92
+ }
93
+ exports.getCommandNames = getCommandNames;
94
+ let commandNames = undefined;
79
95
  // maps command names or aliases to the actual command name
80
- const commandMapping = {};
81
- for (const [command, { aliases }] of Object.entries(commands)) {
82
- (0, assert_1.guard)(commandMapping[command] === undefined, `Command ${command} is already registered!`);
83
- commandMapping[command] = command;
84
- for (const alias of aliases) {
85
- (0, assert_1.guard)(commandMapping[alias] === undefined, `Command (alias) ${alias} is already registered!`);
86
- commandMapping[alias] = command;
96
+ let commandMapping = undefined;
97
+ function initCommandMapping() {
98
+ commandMapping = {};
99
+ commandNames = [];
100
+ for (const [command, { aliases }] of Object.entries(commands())) {
101
+ (0, assert_1.guard)(commandMapping[command] === undefined, `Command ${command} is already registered!`);
102
+ commandMapping[command] = command;
103
+ for (const alias of aliases) {
104
+ (0, assert_1.guard)(commandMapping[alias] === undefined, `Command (alias) ${alias} is already registered!`);
105
+ commandMapping[alias] = command;
106
+ }
107
+ commandNames.push(command);
108
+ commandNames.push(...aliases);
87
109
  }
88
- exports.commandNames.push(command);
89
- exports.commandNames.push(...aliases);
90
110
  }
91
111
  /**
92
112
  * Get the command for a given command name or alias.
93
113
  * @param command - The name of the command (without the leading `:`)
94
114
  */
95
115
  function getCommand(command) {
96
- return commands[commandMapping[command]];
116
+ if (commandMapping === undefined) {
117
+ initCommandMapping();
118
+ }
119
+ return commands()[commandMapping[command]];
97
120
  }
98
121
  exports.getCommand = getCommand;
99
- const longestKey = Array.from(Object.keys(commands), k => k.length).reduce((p, n) => Math.max(p, n), 0);
122
+ function asOptionName(argument) {
123
+ if (argument.length == 1) {
124
+ return `-${argument}`;
125
+ }
126
+ else {
127
+ return `--${argument}`;
128
+ }
129
+ }
130
+ exports.asOptionName = asOptionName;
131
+ let _longestCommandName = undefined;
132
+ function longestCommandName() {
133
+ if (_longestCommandName === undefined) {
134
+ _longestCommandName = Array.from(Object.keys(commands()), k => k.length).reduce((p, n) => Math.max(p, n), 0);
135
+ }
136
+ return _longestCommandName;
137
+ }
138
+ exports.longestCommandName = longestCommandName;
100
139
  function padCmd(string) {
101
- return String(string).padEnd(longestKey + 2, ' ');
140
+ return String(string).padEnd(longestCommandName() + 2, ' ');
102
141
  }
103
142
  //# sourceMappingURL=commands.js.map
@@ -12,7 +12,7 @@ async function dataflow(shell, remainingLine) {
12
12
  }).allRemainingSteps();
13
13
  }
14
14
  exports.dataflowCommand = {
15
- description: 'Get mermaid code for the dataflow graph of R code, start with \'file://\' to indicate a file',
15
+ description: `Get mermaid code for the dataflow graph of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
16
16
  usageExample: ':dataflow',
17
17
  aliases: ['d', 'df'],
18
18
  script: false,
@@ -22,7 +22,7 @@ exports.dataflowCommand = {
22
22
  }
23
23
  };
24
24
  exports.dataflowStarCommand = {
25
- description: 'Get a mermaid url of the dataflow graph of R code, start with \'file://\' to indicate a file',
25
+ description: `Get a mermaid url of the dataflow graph of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
26
26
  usageExample: ':dataflow*',
27
27
  aliases: ['d*', 'df*'],
28
28
  script: false,
@@ -12,7 +12,7 @@ async function normalize(shell, remainingLine) {
12
12
  }).allRemainingSteps();
13
13
  }
14
14
  exports.normalizeCommand = {
15
- description: 'Get mermaid code for the normalized AST of R code, start with \'file://\' to indicate a file',
15
+ description: `Get mermaid code for the normalized AST of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
16
16
  usageExample: ':normalize',
17
17
  aliases: ['n'],
18
18
  script: false,
@@ -22,7 +22,7 @@ exports.normalizeCommand = {
22
22
  }
23
23
  };
24
24
  exports.normalizeStarCommand = {
25
- description: 'Get a mermaid url of the normalized AST of R code, start with \'file://\' to indicate a file',
25
+ description: `Get a mermaid url of the normalized AST of R code, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
26
26
  usageExample: ':normalize',
27
27
  aliases: ['n*'],
28
28
  script: false,
@@ -4,8 +4,9 @@ exports.parseCommand = void 0;
4
4
  const r_bridge_1 = require("../../../r-bridge");
5
5
  const internal_1 = require("../../../r-bridge/lang-4.x/ast/parser/xml/internal");
6
6
  const core_1 = require("../../../core");
7
- const objects_1 = require("../../../util/objects");
8
- function toDepthMap(xml, config) {
7
+ const format_1 = require("../../../r-bridge/lang-4.x/ast/parser/json/format");
8
+ const parser_1 = require("../../../r-bridge/lang-4.x/ast/parser/json/parser");
9
+ function toDepthMap(xml) {
9
10
  const root = (0, r_bridge_1.getKeysGuarded)(xml, "exprlist" /* RawRType.ExpressionList */);
10
11
  const visit = [{ depth: 0, node: root }];
11
12
  const result = [];
@@ -14,7 +15,7 @@ function toDepthMap(xml, config) {
14
15
  if (current === undefined) {
15
16
  continue;
16
17
  }
17
- const children = current.node[config.childrenName] ?? [];
18
+ const children = current.node[r_bridge_1.childrenKey] ?? [];
18
19
  result.push({ ...current, leaf: children.length === 0 });
19
20
  children.reverse();
20
21
  const nextDepth = current.depth + 1;
@@ -62,7 +63,7 @@ function retrieveLocationString(locationRaw) {
62
63
  return ` (${extracted.start.line}:${extracted.start.column}─${extracted.end.line}:${extracted.end.column})`;
63
64
  }
64
65
  }
65
- function depthListToTextTree(list, config, f) {
66
+ function depthListToTextTree(list, f) {
66
67
  let result = '';
67
68
  const deadDepths = new Set();
68
69
  let i = 0;
@@ -72,13 +73,13 @@ function depthListToTextTree(list, config, f) {
72
73
  result += initialIndentation(i, depth, deadDepths, nextDepth, list, f);
73
74
  result += f.reset();
74
75
  const raw = (0, internal_1.objectWithArrUnwrap)(node);
75
- const content = raw[config.contentName];
76
- const locationRaw = raw[config.attributeName];
76
+ const content = raw[r_bridge_1.contentKey];
77
+ const locationRaw = raw[r_bridge_1.attributesKey];
77
78
  let location = '';
78
79
  if (locationRaw !== undefined) {
79
80
  location = retrieveLocationString(locationRaw);
80
81
  }
81
- const type = (0, internal_1.getTokenType)(config.tokenMap, node);
82
+ const type = (0, internal_1.getTokenType)(node);
82
83
  if (leaf) {
83
84
  const suffix = `${f.format(content ? JSON.stringify(content) : '', { style: 1 /* FontStyles.Bold */ })}${f.format(location, { style: 3 /* FontStyles.Italic */ })}`;
84
85
  result += `${type} ${suffix}`;
@@ -91,7 +92,7 @@ function depthListToTextTree(list, config, f) {
91
92
  return result;
92
93
  }
93
94
  exports.parseCommand = {
94
- description: 'Prints ASCII Art of the parsed, unmodified AST, start with \'file://\' to indicate a file',
95
+ description: `Prints ASCII Art of the parsed, unmodified AST, start with '${r_bridge_1.fileProtocol}' to indicate a file`,
95
96
  usageExample: ':parse',
96
97
  aliases: ['p'],
97
98
  script: false,
@@ -99,11 +100,10 @@ exports.parseCommand = {
99
100
  const result = await new core_1.SteppingSlicer({
100
101
  stepOfInterest: 'parse',
101
102
  shell,
102
- request: (0, r_bridge_1.requestFromInput)(remainingLine.trim())
103
+ request: (0, r_bridge_1.requestFromInput)((0, r_bridge_1.removeRQuotes)(remainingLine.trim()))
103
104
  }).allRemainingSteps();
104
- const config = (0, objects_1.deepMergeObject)(r_bridge_1.DEFAULT_XML_PARSER_CONFIG, { tokenMap: await shell.tokenMap() });
105
- const object = await (0, internal_1.xlm2jsonObject)(config, result.parse);
106
- output.stdout(depthListToTextTree(toDepthMap(object, config), config, output.formatter));
105
+ const object = (0, parser_1.convertPreparedParsedData)((0, format_1.prepareParsedData)(result.parse));
106
+ output.stdout(depthListToTextTree(toDepthMap(object), output.formatter));
107
107
  }
108
108
  };
109
109
  //# sourceMappingURL=parse.js.map