@eagleoutice/flowr 1.3.11 → 1.3.13

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 (125) hide show
  1. package/cli/common/scripts-info.d.ts +1 -1
  2. package/package.json +3 -4
  3. package/benchmark/benchmark-slicer.js +0 -223
  4. package/core/pipeline-executor.js +0 -221
  5. package/core/stepping-slicer.js +0 -160
  6. package/core/steps/all/00-parse.js +0 -19
  7. package/core/steps/all/10-normalize.js +0 -21
  8. package/core/steps/all/20-dataflow.js +0 -21
  9. package/core/steps/all/30-slice.js +0 -16
  10. package/core/steps/all/40-reconstruct.js +0 -16
  11. package/core/steps/all/core/00-parse.js +0 -24
  12. package/core/steps/all/core/10-normalize.js +0 -46
  13. package/core/steps/all/core/20-dataflow.js +0 -39
  14. package/core/steps/all/static-slicing/00-slice.js +0 -21
  15. package/core/steps/all/static-slicing/10-reconstruct.js +0 -21
  16. package/core/steps/index.js +0 -21
  17. package/core/steps/input.js +0 -3
  18. package/core/steps/output.js +0 -3
  19. package/core/steps/pipeline/create.js +0 -130
  20. package/core/steps/pipeline/default.js +0 -15
  21. package/core/steps/pipeline/dependency-checker.js +0 -76
  22. package/core/steps/pipeline/index.js +0 -20
  23. package/core/steps/pipeline/invalid-pipeline-error.js +0 -14
  24. package/core/steps/pipeline/pipeline.js +0 -28
  25. package/core/steps/step.js +0 -8
  26. package/core/steps/steps-provider.js +0 -3
  27. package/core/steps/steps.js +0 -35
  28. package/dataflow/common/environments/append.js +0 -48
  29. package/dataflow/common/environments/environment.js +0 -165
  30. package/dataflow/common/environments/index.js +0 -23
  31. package/dataflow/common/environments/overwrite.js +0 -82
  32. package/dataflow/common/environments/register.js +0 -49
  33. package/dataflow/common/environments/resolve-by-name.js +0 -35
  34. package/dataflow/common/environments/scopes.js +0 -6
  35. package/dataflow/common/environments/scoping.js +0 -27
  36. package/dataflow/graph/equal.js +0 -127
  37. package/dataflow/v1/extractor.js +0 -60
  38. package/dataflow/v1/graph/diff.js +0 -206
  39. package/dataflow/v1/graph/edge.js +0 -32
  40. package/dataflow/v1/graph/graph.js +0 -298
  41. package/dataflow/v1/graph/index.js +0 -21
  42. package/dataflow/v1/graph/quads.js +0 -27
  43. package/dataflow/v1/graph/vertex.js +0 -3
  44. package/dataflow/v1/index.js +0 -24
  45. package/dataflow/v1/internal/info.js +0 -16
  46. package/dataflow/v1/internal/linker.js +0 -255
  47. package/dataflow/v1/internal/process/access.js +0 -54
  48. package/dataflow/v1/internal/process/expression-list.js +0 -154
  49. package/dataflow/v1/internal/process/functions/argument.js +0 -46
  50. package/dataflow/v1/internal/process/functions/exit-points.js +0 -125
  51. package/dataflow/v1/internal/process/functions/function-call.js +0 -99
  52. package/dataflow/v1/internal/process/functions/function-definition.js +0 -176
  53. package/dataflow/v1/internal/process/functions/parameter.js +0 -47
  54. package/dataflow/v1/internal/process/if-then-else.js +0 -57
  55. package/dataflow/v1/internal/process/loops/for-loop.js +0 -54
  56. package/dataflow/v1/internal/process/loops/repeat-loop.js +0 -21
  57. package/dataflow/v1/internal/process/loops/while-loop.js +0 -31
  58. package/dataflow/v1/internal/process/operators/assignment.js +0 -129
  59. package/dataflow/v1/internal/process/operators/non-assignment-binary-op.js +0 -25
  60. package/dataflow/v1/internal/process/operators/pipe.js +0 -46
  61. package/dataflow/v1/internal/process/operators/unary-op.js +0 -10
  62. package/dataflow/v1/internal/process/symbol.js +0 -21
  63. package/dataflow/v1/internal/process/uninteresting-leaf.js +0 -9
  64. package/dataflow/v1/processor.js +0 -20
  65. package/dataflow/v2/entry.js +0 -11
  66. package/flowr-1.3.7.tgz +0 -0
  67. package/r-bridge/lang-4.x/ast/parser/xml/common/config.js +0 -16
  68. package/r-bridge/lang-4.x/ast/parser/xml/common/input-format.js +0 -42
  69. package/r-bridge/lang-4.x/ast/parser/xml/common/meta.js +0 -118
  70. package/r-bridge/lang-4.x/ast/parser/xml/common/xml-to-json.js +0 -58
  71. package/r-bridge/lang-4.x/ast/parser/xml/v1/data.js +0 -3
  72. package/r-bridge/lang-4.x/ast/parser/xml/v1/hooks.js +0 -136
  73. package/r-bridge/lang-4.x/ast/parser/xml/v1/index.js +0 -22
  74. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/access.js +0 -107
  75. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/control/if-then-else.js +0 -32
  76. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/control/if-then.js +0 -46
  77. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/control/index.js +0 -19
  78. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/expression/expression.js +0 -65
  79. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/expression/index.js +0 -18
  80. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/functions/argument.js +0 -74
  81. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/functions/call.js +0 -149
  82. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/functions/definition.js +0 -60
  83. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/functions/index.js +0 -20
  84. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/functions/parameter.js +0 -64
  85. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/index.js +0 -27
  86. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/break.js +0 -24
  87. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/for.js +0 -72
  88. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/index.js +0 -22
  89. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/next.js +0 -24
  90. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/repeat.js +0 -42
  91. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/loops/while.js +0 -45
  92. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/operators/binary.js +0 -162
  93. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/operators/index.js +0 -20
  94. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/operators/special.js +0 -24
  95. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/operators/unary.js +0 -59
  96. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/other/comment.js +0 -34
  97. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/other/index.js +0 -18
  98. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/other/line-directive.js +0 -55
  99. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/structure/elements.js +0 -159
  100. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/structure/index.js +0 -20
  101. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/structure/root.js +0 -34
  102. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/structure/single-element.js +0 -64
  103. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/values/index.js +0 -20
  104. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/values/number.js +0 -56
  105. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/values/string.js +0 -41
  106. package/r-bridge/lang-4.x/ast/parser/xml/v1/internal/values/symbol.js +0 -56
  107. package/r-bridge/lang-4.x/ast/parser/xml/v1/normalize.js +0 -30
  108. package/r-bridge/lang-4.x/ast/parser/xml/v2/data.js +0 -3
  109. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/access.js +0 -95
  110. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/expression.js +0 -99
  111. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/functions/argument.js +0 -71
  112. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/operators/binary.js +0 -30
  113. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/operators/index.js +0 -19
  114. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/operators/unary.js +0 -35
  115. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/other/comment.js +0 -25
  116. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/other/index.js +0 -18
  117. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/other/line-directive.js +0 -38
  118. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/root.js +0 -26
  119. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/single-element.js +0 -63
  120. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/values/index.js +0 -18
  121. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/values/number.js +0 -46
  122. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/values/string.js +0 -33
  123. package/r-bridge/lang-4.x/ast/parser/xml/v2/internal/values/symbol.js +0 -63
  124. package/r-bridge/lang-4.x/ast/parser/xml/v2/normalize.js +0 -25
  125. package/util/summarizer/benchmark/benchmark-summarizer.js +0 -208
@@ -20,5 +20,5 @@ export interface HelperScriptInformation extends BaseScriptInformation {
20
20
  masterScripts: string[];
21
21
  }
22
22
  export type ScriptInformation = MasterScriptInformation | HelperScriptInformation;
23
- export declare const scripts: Record<"slicer" | "benchmark" | "summarizer" | "export-quads" | "stats" | "stats-helper" | "benchmark-helper", ScriptInformation>;
23
+ export declare const scripts: Record<"slicer" | "benchmark" | "stats" | "summarizer" | "export-quads" | "stats-helper" | "benchmark-helper", ScriptInformation>;
24
24
  export {};
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "1.3.11",
3
+ "version": "1.3.13",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
- "main": "dist/src/flowr.js",
6
5
  "types": "dist/src/index.d.ts",
7
6
  "repository": {
8
7
  "type": "git",
@@ -337,7 +336,6 @@
337
336
  "@types/n-readlines": "^1.0.6",
338
337
  "@types/n3": "^1.16.4",
339
338
  "@types/object-hash": "^3.0.6",
340
- "@types/semver": "^7.5.6",
341
339
  "@types/tmp": "^0.2.6",
342
340
  "@types/xml2js": "^0.4.14",
343
341
  "@typescript-eslint/eslint-plugin": "^6.13.2",
@@ -355,7 +353,6 @@
355
353
  "mocha-multi-reporters": "^1.5.1",
356
354
  "nyc": "^15.1.0",
357
355
  "release-it": "^17.0.1",
358
- "ts-essentials": "^9.4.1",
359
356
  "ts-node": "^10.9.2",
360
357
  "typedoc": "^0.25.4",
361
358
  "typedoc-plugin-missing-exports": "^2.1.0",
@@ -364,6 +361,7 @@
364
361
  "typescript": "^5.3.3"
365
362
  },
366
363
  "dependencies": {
364
+ "@types/semver": "^7.5.6",
367
365
  "@types/tar": "^6.1.10",
368
366
  "@xmldom/xmldom": "^0.8.10",
369
367
  "command-line-args": "^5.2.1",
@@ -377,6 +375,7 @@
377
375
  "semver": "^7.5.4",
378
376
  "tar": "^6.2.0",
379
377
  "tmp": "^0.2.1",
378
+ "ts-essentials": "^9.4.1",
380
379
  "tslog": "^4.9.2",
381
380
  "xml2js": "^0.6.2",
382
381
  "xpath-ts2": "^1.4.2"
@@ -1,223 +0,0 @@
1
- "use strict";
2
- /**
3
- * Provides a top-level slicer that can be used to slice code *and* retrieve stats.
4
- * @module
5
- */
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.BenchmarkSlicer = exports.benchmarkLogger = void 0;
11
- const r_bridge_1 = require("../r-bridge");
12
- const stopwatch_1 = require("./stopwatch");
13
- const assert_1 = require("../util/assert");
14
- const slicing_1 = require("../slicing");
15
- const fs_1 = __importDefault(require("fs"));
16
- const log_1 = require("../util/log");
17
- const core_1 = require("../core");
18
- const strings_1 = require("../util/strings");
19
- exports.benchmarkLogger = log_1.log.getSubLogger({ name: 'benchmark' });
20
- /**
21
- * A slicer that can be used to slice exactly one file (multiple times).
22
- * It holds its own {@link RShell} instance, maintains a cached dataflow and keeps measurements.
23
- *
24
- * Make sure to call {@link init} to initialize the slicer, before calling {@link slice}.
25
- * After slicing, call {@link finish} to close the R session and retrieve the stats.
26
- *
27
- * @note Under the hood, the benchmark slicer maintains a {@link SteppingSlicer}.
28
- */
29
- class BenchmarkSlicer {
30
- /** Measures all data that is recorded *once* per slicer (complete setup up to the dataflow graph creation) */
31
- commonMeasurements = new stopwatch_1.Measurements();
32
- perSliceMeasurements = new Map;
33
- shell;
34
- stats;
35
- loadedXml;
36
- tokenMap;
37
- dataflow;
38
- normalizedAst;
39
- totalStopwatch;
40
- finished = false;
41
- // Yes this is dirty, but we know that we assign the stepper during the initialization and this saves us from having to check for nullability every time
42
- stepper = null;
43
- constructor() {
44
- this.totalStopwatch = this.commonMeasurements.start('total');
45
- this.shell = this.commonMeasurements.measure('initialize R session', () => new r_bridge_1.RShell());
46
- this.commonMeasurements.measure('inject home path', () => this.shell.tryToInjectHomeLibPath());
47
- }
48
- /**
49
- * Initialize the slicer on the given request.
50
- * Can only be called once for each instance.
51
- */
52
- async init(request) {
53
- (0, assert_1.guard)(this.stats === undefined, 'cannot initialize the slicer twice');
54
- await this.commonMeasurements.measureAsync('ensure installation of xmlparsedata', () => this.shell.ensurePackageInstalled('xmlparsedata', true));
55
- this.tokenMap = await this.commonMeasurements.measureAsync('retrieve token map',
56
- // with this being the first time, there is no preexisting caching!
57
- () => this.shell.tokenMap());
58
- this.stepper = new core_1.SteppingSlicer({
59
- shell: this.shell,
60
- request: {
61
- ...request,
62
- ensurePackageInstalled: true
63
- },
64
- stepOfInterest: core_1.LAST_STEP,
65
- criterion: [],
66
- tokenMap: this.tokenMap
67
- });
68
- this.loadedXml = await this.measureCommonStep('parse', 'retrieve AST from R code');
69
- this.normalizedAst = await this.measureCommonStep('normalize', 'normalize R AST');
70
- this.dataflow = await this.measureCommonStep('dataflow', 'produce dataflow information');
71
- this.stepper.switchToSliceStage();
72
- await this.calculateStatsAfterInit(request);
73
- }
74
- async calculateStatsAfterInit(request) {
75
- const loadedContent = request.request === 'text' ? request.content : fs_1.default.readFileSync(request.content, 'utf-8');
76
- // retrieve number of R tokens - flowr_parsed should still contain the last parsed code
77
- const numberOfRTokens = await (0, r_bridge_1.retrieveNumberOfRTokensOfLastParse)(this.shell);
78
- (0, assert_1.guard)(this.normalizedAst !== undefined, 'normalizedAst should be defined after initialization');
79
- (0, assert_1.guard)(this.dataflow !== undefined, 'dataflow should be defined after initialization');
80
- // collect dataflow graph size
81
- const vertices = [...this.dataflow.graph.vertices(true)];
82
- let numberOfEdges = 0;
83
- let numberOfCalls = 0;
84
- let numberOfDefinitions = 0;
85
- for (const [n, info] of vertices) {
86
- const outgoingEdges = this.dataflow.graph.outgoingEdges(n);
87
- numberOfEdges += outgoingEdges?.size ?? 0;
88
- if (info.tag === 'function-call') {
89
- numberOfCalls++;
90
- }
91
- else if (info.tag === 'function-definition') {
92
- numberOfDefinitions++;
93
- }
94
- }
95
- this.stats = {
96
- commonMeasurements: new Map(),
97
- perSliceMeasurements: this.perSliceMeasurements,
98
- request,
99
- input: {
100
- numberOfLines: loadedContent.split('\n').length,
101
- numberOfCharacters: loadedContent.length,
102
- numberOfNonWhitespaceCharacters: (0, strings_1.withoutWhitespace)(loadedContent).length,
103
- numberOfRTokens: numberOfRTokens,
104
- numberOfNormalizedTokens: [...(0, r_bridge_1.collectAllIds)(this.normalizedAst.ast)].length
105
- },
106
- dataflow: {
107
- numberOfNodes: [...this.dataflow.graph.vertices(true)].length,
108
- numberOfEdges: numberOfEdges,
109
- numberOfCalls: numberOfCalls,
110
- numberOfFunctionDefinitions: numberOfDefinitions
111
- }
112
- };
113
- }
114
- /**
115
- * Slice for the given {@link SlicingCriteria}.
116
- * @see SingleSlicingCriterion
117
- *
118
- * @returns The per slice stats retrieved for this slicing criteria
119
- */
120
- async slice(...slicingCriteria) {
121
- exports.benchmarkLogger.trace(`try to slice for criteria ${JSON.stringify(slicingCriteria)}`);
122
- this.guardActive();
123
- (0, assert_1.guard)(!this.perSliceMeasurements.has(slicingCriteria), 'do not slice the same criteria combination twice');
124
- const measurements = new stopwatch_1.Measurements();
125
- const stats = {
126
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
127
- measurements: undefined,
128
- slicingCriteria: [],
129
- numberOfDataflowNodesSliced: 0,
130
- timesHitThreshold: 0,
131
- reconstructedCode: {
132
- code: '',
133
- autoSelected: 0
134
- }
135
- };
136
- this.perSliceMeasurements.set(slicingCriteria, stats);
137
- this.stepper.updateCriterion(slicingCriteria);
138
- const totalStopwatch = measurements.start('total');
139
- const slicedOutput = await this.measureSliceStep('slice', measurements, 'static slicing');
140
- stats.slicingCriteria = slicedOutput.decodedCriteria;
141
- stats.reconstructedCode = await this.measureSliceStep('reconstruct', measurements, 'reconstruct code');
142
- totalStopwatch.stop();
143
- exports.benchmarkLogger.debug(`Produced code for ${JSON.stringify(slicingCriteria)}: ${stats.reconstructedCode.code}`);
144
- const results = this.stepper.getResults(false);
145
- if (exports.benchmarkLogger.settings.minLevel >= 3 /* LogLevel.Info */) {
146
- exports.benchmarkLogger.info(`mapped slicing criteria: ${slicedOutput.decodedCriteria.map(c => {
147
- const node = results.normalize.idMap.get(c.id);
148
- return `\n- id: ${c.id}, location: ${JSON.stringify(node?.location)}, lexeme: ${JSON.stringify(node?.lexeme)}`;
149
- }).join('')}`);
150
- }
151
- // if it is not in the dataflow graph it was kept to be safe and should not count to the included nodes
152
- stats.numberOfDataflowNodesSliced = [...slicedOutput.result].filter(id => results.dataflow.graph.hasNode(id, false)).length;
153
- stats.timesHitThreshold = slicedOutput.timesHitThreshold;
154
- stats.measurements = measurements.get();
155
- return {
156
- stats,
157
- slice: slicedOutput,
158
- code: stats.reconstructedCode
159
- };
160
- }
161
- /** Bridging the gap between the new internal and the old names for the benchmarking */
162
- async measureCommonStep(expectedStep, keyToMeasure) {
163
- const { result } = await this.commonMeasurements.measureAsync(keyToMeasure, () => this.stepper.nextStep(expectedStep));
164
- return result;
165
- }
166
- async measureSliceStep(expectedStep, measure, keyToMeasure) {
167
- const { result } = await measure.measureAsync(keyToMeasure, () => this.stepper.nextStep(expectedStep));
168
- return result;
169
- }
170
- guardActive() {
171
- (0, assert_1.guard)(this.stats !== undefined && !this.finished, 'need to call init before, and can not do after finish!');
172
- }
173
- /**
174
- * Call {@link slice} for all slicing criteria that match the given filter.
175
- * See {@link collectAllSlicingCriteria} for details.
176
- * <p>
177
- * the `report` function will be called *before* each individual slice is performed.
178
- *
179
- * @returns The number of slices that were produced
180
- *
181
- * @see collectAllSlicingCriteria
182
- * @see SlicingCriteriaFilter
183
- */
184
- async sliceForAll(filter, report = () => { }) {
185
- this.guardActive();
186
- let count = 0;
187
- const allCriteria = [...(0, slicing_1.collectAllSlicingCriteria)(this.normalizedAst.ast, filter)];
188
- for (const slicingCriteria of allCriteria) {
189
- report(count, allCriteria.length, allCriteria);
190
- await this.slice(...slicingCriteria);
191
- count++;
192
- }
193
- return count;
194
- }
195
- /**
196
- * Retrieves the final stats and closes the shell session.
197
- * Can be called multiple times to retrieve the stored stats, but will only close the session once (the first time).
198
- */
199
- finish() {
200
- (0, assert_1.guard)(this.stats !== undefined, 'need to call init before finish');
201
- if (!this.finished) {
202
- this.commonMeasurements.measure('close R session', () => this.shell.close());
203
- this.totalStopwatch.stop();
204
- this.finished = true;
205
- }
206
- this.stats.commonMeasurements = this.commonMeasurements.get();
207
- return {
208
- stats: this.stats,
209
- parse: this.loadedXml,
210
- dataflow: this.dataflow,
211
- normalize: this.normalizedAst,
212
- tokenMap: this.tokenMap,
213
- };
214
- }
215
- /**
216
- * Only call in case of an error - if the session must be closed and the benchmark itself is to be considered failed/dead.
217
- */
218
- ensureSessionClosed() {
219
- this.shell.close();
220
- }
221
- }
222
- exports.BenchmarkSlicer = BenchmarkSlicer;
223
- //# sourceMappingURL=benchmark-slicer.js.map
@@ -1,221 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PipelineExecutor = void 0;
4
- const assert_1 = require("../util/assert");
5
- /**
6
- * The pipeline executor allows to execute arbitrary {@link Pipeline|pipelines} in a step-by-step fashion.
7
- * If you are not yet in the possession of a {@link Pipeline|pipeline}, you can use the {@link createPipeline} function
8
- * to create one for yourself, based on the steps that you want to execute.
9
- *
10
- * Those steps are split into two phases or "stages" (which is the name that we will use in the following), represented
11
- * by the {@link PipelineStepStage} type. These allow us to separate things that have to be done
12
- * once per-file, e.g., actually parsing the AST, from those, that we need to repeat 'once per request' (whatever this
13
- * request may be). In other words, what can be cached between operations and what can not.
14
- *
15
- * Furthermore, this executor follows an iterable fashion to be *as flexible as possible*
16
- * (e.g., to be instrumented with measurements). So, you can use the pipeline executor like this:
17
- *
18
- * ```ts
19
- * const stepper = new PipelineExecutor( ... )
20
- * while(stepper.hasNextStep()) {
21
- * await stepper.nextStep()
22
- * }
23
- *
24
- * stepper.switchToRequestStage()
25
- *
26
- * while(stepper.hasNextStep()) {
27
- * await stepper.nextStep()
28
- * }
29
- *
30
- * const result = stepper.getResults()
31
- * ```
32
- *
33
- * Of course, you might think, that this is rather overkill if you simply want to receive the result.
34
- * And this is true. Therefore, if you do not want to perform some kind of magic in-between steps, you can use the
35
- * **{@link allRemainingSteps}** function like this:
36
- *
37
- * ```ts
38
- * const stepper = new PipelineExecutor( ... )
39
- * const result = await stepper.allRemainingSteps()
40
- * ```
41
- *
42
- * As the name suggest, you can combine this name with previous calls to {@link nextStep} to only execute the remaining
43
- * steps in case, for whatever reason you only want to instrument some steps.
44
- *
45
- * By default, the {@link PipelineExecutor} does not offer an automatic way to repeat requests (mostly to prevent accidental errors).
46
- * However, you can use the
47
- * **{@link updateRequest}** function to reset the request steps and re-execute them for a new request. This allows something like the following:
48
- *
49
- * ```ts
50
- * const stepper = new PipelineExecutor( ... )
51
- * const result = await stepper.allRemainingSteps()
52
- *
53
- * stepper.updateRequest( ... )
54
- * const result2 = await stepper.allRemainingSteps()
55
- * ```
56
- *
57
- * **Example - Slicing With the Pipeline Executor**:
58
- *
59
- * Suppose, you want to... you know _slice_ a file (which was, at one point the origin of flowR), then you can
60
- * either create a pipeline yourself with the respective steps, or you can use the {@link DEFAULT_SLICING_PIPELINE} (and friends).
61
- * With it, slicing essentially becomes 'easy-as-pie':
62
- *
63
- * ```ts
64
- * const slicer = new PipelineExecutor(DEFAULT_SLICING_PIPELINE, {
65
- * shell: new RShell(),
66
- * // of course, the criterion and request given here are just examples, you can use whatever you want to slice!
67
- * criterion: ['2@b'],
68
- * request: requestFromInput('b <- 3; x <- 5\ncat(b)'),
69
- * })
70
- * const result = await slicer.allRemainingSteps()
71
- * ```
72
- *
73
- * But now, we want to slice for `x` in the first line as well! We can do that by adding:
74
- *
75
- * ```ts
76
- * stepper.updateRequest({ criterion: ['1@x'] })
77
- * const result2 = await stepper.allRemainingSteps()
78
- * ```
79
- *
80
- * @note Even though using the pipeline executor introduces a small performance overhead, we consider
81
- * it to be the baseline for performance benchmarking. It may very well be possible to squeeze out a little bit more by
82
- * directly constructing the steps in the right order. However, we consider this to be negligible when compared with the time required
83
- * for, for example, the dataflow analysis of larger files.
84
- *
85
- * @see PipelineExecutor#allRemainingSteps
86
- * @see PipelineExecutor#nextStep
87
- */
88
- class PipelineExecutor {
89
- pipeline;
90
- length;
91
- input;
92
- output = {};
93
- currentExecutionStage = 0 /* PipelineStepStage.OncePerFile */;
94
- stepCounter = 0;
95
- /**
96
- * Construct a new pipeline executor.
97
- * The required additional input is specified by the {@link IPipelineStep#requiredInput|required input configuration} of each step in the `pipeline`.
98
- *
99
- * @param pipeline - The {@link Pipeline} to execute, probably created with {@link createPipeline}.
100
- * @param input - External {@link PipelineInput|configuration and input} required to execute the given pipeline.
101
- */
102
- constructor(pipeline, input) {
103
- this.pipeline = pipeline;
104
- this.length = pipeline.order.length;
105
- this.input = input;
106
- }
107
- /**
108
- * Retrieve the current {@link PipelineStepStage|stage} the pipeline executor is in.
109
- *
110
- * @see currentExecutionStage
111
- * @see switchToRequestStage
112
- * @see PipelineStepStage
113
- */
114
- getCurrentStage() {
115
- return this.currentExecutionStage;
116
- }
117
- /**
118
- * Switch to the next {@link PipelineStepStage|stage} of the pipeline executor.
119
- *
120
- * This will fail if either a step change is currently not valid (as not all steps have been executed),
121
- * or if there is no next stage (i.e., the pipeline is already completed or in the last stage).
122
- *
123
- * @see PipelineExecutor
124
- * @see getCurrentStage
125
- */
126
- switchToRequestStage() {
127
- (0, assert_1.guard)(this.stepCounter === this.pipeline.firstStepPerRequest, 'First need to complete all steps before switching');
128
- (0, assert_1.guard)(this.currentExecutionStage === 0 /* PipelineStepStage.OncePerFile */, 'Cannot switch to next stage, already in per-request stage.');
129
- this.currentExecutionStage = 1 /* PipelineStepStage.OncePerRequest */;
130
- }
131
- /**
132
- * Returns the results of the pipeline.
133
- *
134
- * @param intermediate - Normally you can only receive the results *after* the stepper completed the step of interested.
135
- * However, if you pass `true` to this parameter, you can also receive the results *before* the {@link PipelineExecutor|pipeline executor}
136
- * completed, although the typing system then can not guarantee which of the steps have already happened.
137
- */
138
- getResults(intermediate = false) {
139
- (0, assert_1.guard)(intermediate || this.stepCounter >= this.length, 'Without the intermediate flag, the pipeline must be completed before providing access to the results.');
140
- return this.output;
141
- }
142
- /**
143
- * Returns true only if
144
- * 1) there are more {@link IPipelineStep|steps} to-do for the current {@link PipelineStepStage|stage} and
145
- * 2) we have not yet reached the end of the {@link Pipeline|pipeline}.
146
- */
147
- hasNextStep() {
148
- return (this.stepCounter < this.length && this.currentExecutionStage !== 0 /* PipelineStepStage.OncePerFile */)
149
- || this.stepCounter < this.pipeline.firstStepPerRequest;
150
- }
151
- /**
152
- * Execute the next {@link IPipelineStep|step} and return the name of the {@link IPipelineStep|step} that was executed,
153
- * so you can guard if the {@link IPipelineStep|step} differs from what you are interested in.
154
- * Furthermore, it returns the {@link IPipelineStep|step's} result.
155
- *
156
- * @param expectedStepName - A safeguard if you want to retrieve the result.
157
- * If given, it causes the execution to fail if the next step is not the one you expect.
158
- *
159
- * _Without `expectedStepName`, please refrain from accessing the result, as you have no safeguards if the pipeline changes._
160
- */
161
- async nextStep(expectedStepName) {
162
- const [step, result] = this._doNextStep(expectedStepName);
163
- const awaitedResult = await result;
164
- this.output[step] = awaitedResult;
165
- this.stepCounter++;
166
- return { name: step, result: awaitedResult };
167
- }
168
- _doNextStep(expectedStepName) {
169
- const step = this.pipeline.steps.get(this.pipeline.order[this.stepCounter]);
170
- (0, assert_1.guard)(step !== undefined, () => `Cannot execute next step, step ${this.pipeline.order[this.stepCounter]} does not exist.`);
171
- if (expectedStepName !== undefined) {
172
- (0, assert_1.guard)(step.name === expectedStepName, () => `Cannot execute next step, expected step ${JSON.stringify(expectedStepName)} but got ${step.name}.`);
173
- }
174
- return [step.name, step.processor(this.output, this.input)];
175
- }
176
- /**
177
- * This only makes sense if you have already run a request and want to re-use the per-file results for a new one.
178
- * (or if for whatever reason you did not pass information for the pipeline with the constructor).
179
- *
180
- * @param newRequestData - Data for the new request
181
- */
182
- updateRequest(newRequestData) {
183
- const requestStep = this.pipeline.firstStepPerRequest;
184
- (0, assert_1.guard)(this.stepCounter >= requestStep, 'Cannot reset request prior to once-per-request stage');
185
- this.input = {
186
- ...this.input,
187
- ...newRequestData
188
- };
189
- this.stepCounter = requestStep;
190
- // clear the results for all steps with an index >= firstStepPerRequest, this is more of a sanity check
191
- for (let i = requestStep; i < this.length; i++) {
192
- this.output[this.pipeline.order[i]] = undefined;
193
- }
194
- }
195
- /**
196
- * Execute all remaining steps and automatically call {@link switchToRequestStage} if necessary.
197
- * @param canSwitchStage - If true, automatically switch to the request stage if necessary
198
- * (i.e., this is what you want if you have never executed {@link nextStep} and you want to execute *all* steps).
199
- * However, passing false allows you to only execute the steps of the 'once-per-file' stage (i.e., the steps that can be cached).
200
- *
201
- * @note There is a small type difference if you pass 'false' and already have manually switched to the 'once-per-request' stage.
202
- * Because now, the results of these steps are no longer part of the result type (although they are still included).
203
- * In such a case, you may be better off with simply passing 'true' as the function will detect that the stage is already switched.
204
- * We could solve this type problem by separating the {@link PipelineExecutor} class into two for each stage,
205
- * but this would break the improved readability and unified handling of the executor that I wanted to achieve with this class.
206
- */
207
- async allRemainingSteps(canSwitchStage = true) {
208
- while (this.hasNextStep()) {
209
- await this.nextStep();
210
- }
211
- if (canSwitchStage && this.stepCounter < this.length && this.currentExecutionStage === 0 /* PipelineStepStage.OncePerFile */) {
212
- this.switchToRequestStage();
213
- while (this.hasNextStep()) {
214
- await this.nextStep();
215
- }
216
- }
217
- return this.stepCounter < this.length ? this.getResults(true) : this.getResults();
218
- }
219
- }
220
- exports.PipelineExecutor = PipelineExecutor;
221
- //# sourceMappingURL=pipeline-executor.js.map
@@ -1,160 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SteppingSlicer = void 0;
4
- const steps_1 = require("./steps");
5
- const pipeline_1 = require("./steps/pipeline");
6
- const _00_parse_1 = require("./steps/all/core/00-parse");
7
- const _10_normalize_1 = require("./steps/all/core/10-normalize");
8
- const _20_dataflow_1 = require("./steps/all/core/20-dataflow");
9
- const _00_slice_1 = require("./steps/all/static-slicing/00-slice");
10
- const _10_reconstruct_1 = require("./steps/all/static-slicing/10-reconstruct");
11
- const pipeline_executor_1 = require("./pipeline-executor");
12
- const legacyPipelines = {
13
- // brrh, but who cares, it is legacy!
14
- 'parse': (0, pipeline_1.createPipeline)(_00_parse_1.PARSE_WITH_R_SHELL_STEP),
15
- 'normalize': (0, pipeline_1.createPipeline)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, _10_normalize_1.NORMALIZE),
16
- 'dataflow': (0, pipeline_1.createPipeline)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, _10_normalize_1.NORMALIZE, _20_dataflow_1.LEGACY_STATIC_DATAFLOW),
17
- 'slice': (0, pipeline_1.createPipeline)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, _10_normalize_1.NORMALIZE, _20_dataflow_1.LEGACY_STATIC_DATAFLOW, _00_slice_1.STATIC_SLICE),
18
- 'reconstruct': (0, pipeline_1.createPipeline)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, _10_normalize_1.NORMALIZE, _20_dataflow_1.LEGACY_STATIC_DATAFLOW, _00_slice_1.STATIC_SLICE, _10_reconstruct_1.NAIVE_RECONSTRUCT)
19
- };
20
- function getLegacyPipeline(interestedIn) {
21
- return legacyPipelines[interestedIn];
22
- }
23
- /**
24
- * This is ultimately the root of flowR's static slicing procedure.
25
- * It clearly defines the steps that are to be executed and splits them into two stages.
26
- * - `once-per-file`: for steps that are executed once per file. These can be performed *without* the knowledge of a slicing criteria,
27
- * and they can be cached and re-used if you want to slice the same file multiple times.
28
- * - `once-per-slice`: for steps that are executed once per slice. These can only be performed *with* a slicing criteria.
29
- *
30
- * Furthermore, this stepper follows an iterable fashion to be *as flexible as possible* (e.g., to be instrumented with measurements).
31
- * So, you can use the stepping slicer like this:
32
- *
33
- * ```ts
34
- * const slicer = new SteppingSlicer({ ... })
35
- * while(slicer.hasNextStep()) {
36
- * await slicer.nextStep()
37
- * }
38
- *
39
- * slicer.switchToSliceStage()
40
- *
41
- * while(slicer.hasNextStep()) {
42
- * await slicer.nextStep()
43
- * }
44
- *
45
- * const result = slicer.getResults()
46
- * ```
47
- *
48
- * Of course, you might think, that this is rather overkill if you simply want to receive the slice of a given input source or in general
49
- * the result of any step. And this is true. Therefore, if you do not want to perform some kind of magic in-between steps, you can use the
50
- * **{@link allRemainingSteps}** function like this:
51
- *
52
- * ```ts
53
- * const slicer = new SteppingSlicer({ ... })
54
- * const result = await slicer.allRemainingSteps()
55
- * ```
56
- *
57
- * As the name suggest, you can combine this name with previous calls to {@link nextStep} to only execute the remaining steps.
58
- *
59
- * Giving the **step of interest** allows you to declare the maximum step to execute.
60
- * So, if you pass `dataflow` as the step of interest, the stepping slicer will stop after the dataflow step.
61
- * If you do not pass a step, the stepping slicer will execute all steps.
62
- *
63
- * By default, the {@link SteppingSlicer} does not offer an automatic way to repeat the per-slice steps for multiple slices (this is mostly to prevent accidental errors).
64
- * However, you can use the **{@link updateCriterion}** function to reset the per-slice steps and re-execute them for a new slice. This allows something like the following:
65
- *
66
- * ```ts
67
- * const slicer = new SteppingSlicer({ ... })
68
- * const result = await slicer.allRemainingSteps()
69
- *
70
- * slicer.updateCriterion(...)
71
- * const result2 = await slicer.allRemainingSteps()
72
- * ```
73
- *
74
- * @note Even though, using the stepping slicer introduces some performance overhead, we consider
75
- * it to be the baseline for performance benchmarking. It may very well be possible to squeeze out some more performance by
76
- * directly constructing the steps in the right order. However, we consider this to be negligible when compared with the time required
77
- * for, for example, the dataflow analysis.
78
- *
79
- * @see retrieveResultOfStep
80
- * @see StepName
81
- */
82
- class SteppingSlicer {
83
- executor;
84
- /**
85
- * Create a new stepping slicer. For more details on the arguments please see {@link SteppingSlicerInput}.
86
- */
87
- constructor(input) {
88
- this.executor = new pipeline_executor_1.PipelineExecutor(getLegacyPipeline(input.stepOfInterest ?? steps_1.LAST_STEP), input);
89
- }
90
- /**
91
- * Retrieve the current stage the stepping slicer is in.
92
- * @see PipelineStepStage
93
- * @see switchToSliceStage
94
- */
95
- getCurrentStage() {
96
- return this.executor.getCurrentStage();
97
- }
98
- /**
99
- * Switch to the next stage of the stepping slicer.
100
- * @see SteppingSlicer
101
- * @see getCurrentStage
102
- */
103
- switchToSliceStage() {
104
- this.executor.switchToRequestStage();
105
- }
106
- /**
107
- * Returns the result of the step of interest, as well as the results of all steps before it.
108
- *
109
- * @param intermediate - normally you can only receive the results *after* the stepper completed the step of interested.
110
- * However, if you pass `true` to this parameter, you can also receive the results *before* the step of interest,
111
- * although the typing system then can not guarantee which of the steps have already happened.
112
- */
113
- getResults(intermediate = false) {
114
- return this.executor.getResults(intermediate);
115
- }
116
- /**
117
- * Returns true only if 1) there are more steps to-do for the current stage and 2) we have not yet reached the step we are interested in
118
- */
119
- hasNextStep() {
120
- return this.executor.hasNextStep();
121
- }
122
- /**
123
- * Execute the next step (guarded with {@link hasNextStep}) and return the name of the step that was executed, so you can guard if the step differs from what you are interested in.
124
- * Furthermore, it returns the step's result.
125
- *
126
- * The `step` parameter is a safeguard if you want to retrieve the result.
127
- * If given, it causes the execution to fail if the next step is not the one you expect.
128
- * *Without step, please refrain from accessing the result.*
129
- */
130
- async nextStep(expectedStepName) {
131
- return this.executor.nextStep(expectedStepName);
132
- }
133
- /**
134
- * This only makes sense if you have already sliced a file (e.g., by running up to the `slice` step) and want to do so again while caching the results.
135
- * Or if for whatever reason you did not pass a criterion with the constructor.
136
- *
137
- * @param newCriterion - the new slicing criterion to use for the next slice
138
- */
139
- updateCriterion(newCriterion) {
140
- // @ts-expect-error -- it is legacy
141
- this.executor.updateRequest({ criterion: newCriterion });
142
- }
143
- /**
144
- * Execute all remaining steps and automatically call {@link switchToSliceStage} if necessary.
145
- * @param canSwitchStage - if true, automatically switch to the slice stage if necessary
146
- * (i.e., this is what you want if you have never executed {@link nextStep} and you want to execute *all* steps).
147
- * However, passing false allows you to only execute the steps of the 'once-per-file' stage (i.e., the steps that can be cached).
148
- *
149
- * @note There is a small type difference if you pass 'false' and already have manually switched to the 'once-per-slice' stage.
150
- * Because now, the results of these steps are no longer part of the result type (although they are still included).
151
- * In such a case, you may be better off with simply passing 'true' as the function will detect that the stage is already switched.
152
- * We could solve this type problem by separating the SteppingSlicer class into two for each stage, but this would break the improved readability and unified handling
153
- * of the slicer that I wanted to achieve with this class.
154
- */
155
- async allRemainingSteps(canSwitchStage = true) {
156
- return this.executor.allRemainingSteps(canSwitchStage);
157
- }
158
- }
159
- exports.SteppingSlicer = SteppingSlicer;
160
- //# sourceMappingURL=stepping-slicer.js.map
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PARSE_WITH_R_SHELL_STEP = void 0;
4
- const print_1 = require("../../print/print");
5
- const parse_printer_1 = require("../../print/parse-printer");
6
- const r_bridge_1 = require("../../../r-bridge");
7
- exports.PARSE_WITH_R_SHELL_STEP = {
8
- name: 'parse',
9
- description: 'Parse the given R code into an AST',
10
- processor: r_bridge_1.retrieveXmlFromRCode,
11
- required: 'once-per-file',
12
- printer: {
13
- [0 /* StepOutputFormat.Internal */]: print_1.internalPrinter,
14
- [2 /* StepOutputFormat.Json */]: text => text,
15
- [5 /* StepOutputFormat.RdfQuads */]: parse_printer_1.parseToQuads
16
- },
17
- dependencies: []
18
- };
19
- //# sourceMappingURL=00-parse.js.map