@eagleoutice/flowr 2.0.16 → 2.0.18
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.
- package/README.md +1 -1
- package/cli/repl/commands/commands.js +3 -1
- package/cli/repl/commands/lineage.d.ts +15 -0
- package/cli/repl/commands/lineage.js +66 -0
- package/cli/repl/server/connection.d.ts +1 -0
- package/cli/repl/server/connection.js +36 -2
- package/cli/repl/server/messages/lineage.d.ts +16 -0
- package/cli/repl/server/messages/lineage.js +17 -0
- package/cli/repl/server/messages/messages.d.ts +2 -1
- package/cli/slicer-app.js +2 -2
- package/dataflow/environments/built-in.js +29 -9
- package/dataflow/environments/environment.js +4 -3
- package/dataflow/environments/resolve-by-name.d.ts +1 -1
- package/dataflow/environments/resolve-by-name.js +4 -4
- package/dataflow/graph/diff.js +1 -0
- package/dataflow/graph/graph.d.ts +24 -20
- package/dataflow/graph/graph.js +51 -24
- package/dataflow/graph/vertex.d.ts +6 -1
- package/dataflow/graph/vertex.js +21 -0
- package/dataflow/info.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +29 -7
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.d.ts +14 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +65 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +19 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +40 -24
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +10 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-library.js +7 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.d.ts +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-quote.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +3 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +18 -7
- package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.d.ts → built-in-special-bin-op.d.ts} +2 -1
- package/dataflow/internal/process/functions/call/built-in/{built-in-logical-bin-op.js → built-in-special-bin-op.js} +3 -3
- package/dataflow/internal/process/functions/call/common.d.ts +6 -2
- package/dataflow/internal/process/functions/call/common.js +36 -1
- package/dataflow/internal/process/functions/call/known-call-handling.d.ts +8 -3
- package/dataflow/internal/process/functions/call/known-call-handling.js +10 -7
- package/dataflow/internal/process/functions/call/named-call-handling.js +3 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +1 -0
- package/dataflow/internal/process/functions/process-argument.js +0 -28
- package/package.json +3 -2
- package/r-bridge/data/data.d.ts +10 -0
- package/r-bridge/data/data.js +12 -0
- package/r-bridge/lang-4.x/ast/model/operators.js +1 -1
- package/reconstruct/auto-select/auto-select-defaults.d.ts +1 -6
- package/reconstruct/auto-select/auto-select-defaults.js +1 -13
- package/reconstruct/reconstruct.js +1 -1
- package/slicing/criterion/parse.d.ts +3 -4
- package/slicing/criterion/parse.js +3 -3
- package/slicing/static/static-slicer.d.ts +1 -1
- package/slicing/static/static-slicer.js +10 -4
- package/statistics/statistics.js +1 -1
- package/util/json.d.ts +1 -1
- package/util/json.js +3 -3
- package/util/logic.d.ts +5 -1
- package/util/version.js +1 -1
- package/abstract-interpretation/domain.d.ts +0 -57
- package/abstract-interpretation/domain.js +0 -176
- package/abstract-interpretation/handler/binop/binop.d.ts +0 -15
- package/abstract-interpretation/handler/binop/binop.js +0 -42
- package/abstract-interpretation/handler/binop/operators.d.ts +0 -2
- package/abstract-interpretation/handler/binop/operators.js +0 -28
- package/abstract-interpretation/handler/handler.d.ts +0 -6
- package/abstract-interpretation/handler/handler.js +0 -3
- package/abstract-interpretation/processor.d.ts +0 -11
- package/abstract-interpretation/processor.js +0 -84
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ const ansi_1 = require("../../../util/ansi");
|
|
|
14
14
|
const args_1 = require("../../../util/args");
|
|
15
15
|
const assert_1 = require("../../../util/assert");
|
|
16
16
|
const scripts_info_1 = require("../../common/scripts-info");
|
|
17
|
+
const lineage_1 = require("./lineage");
|
|
17
18
|
function printHelpForScript(script, f) {
|
|
18
19
|
const base = ` ${(0, ansi_1.bold)(padCmd(':' + script[0]), f)}${script[1].description}`;
|
|
19
20
|
if (script[1].aliases.length === 0) {
|
|
@@ -58,7 +59,8 @@ const _commands = {
|
|
|
58
59
|
'dataflow': dataflow_1.dataflowCommand,
|
|
59
60
|
'dataflow*': dataflow_1.dataflowStarCommand,
|
|
60
61
|
'controlflow': cfg_1.controlflowCommand,
|
|
61
|
-
'controlflow*': cfg_1.controlflowStarCommand
|
|
62
|
+
'controlflow*': cfg_1.controlflowStarCommand,
|
|
63
|
+
'lineage': lineage_1.getLineageCommand
|
|
62
64
|
};
|
|
63
65
|
let commandsInitialized = false;
|
|
64
66
|
function hasModule(path) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReplCommand } from './main';
|
|
2
|
+
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
3
|
+
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
|
+
import type { DataflowInformation } from '../../../dataflow/info';
|
|
5
|
+
import type { NormalizedAst } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
|
+
/**
|
|
7
|
+
* Get the lineage of a node in the dataflow graph
|
|
8
|
+
*
|
|
9
|
+
* @param criterion - The criterion to get the lineage of
|
|
10
|
+
* @param ast - The normalized AST
|
|
11
|
+
* @param dfg - The dataflow graph
|
|
12
|
+
* @returns The lineage of the node represented as a set of node ids
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLineage(criterion: SingleSlicingCriterion, { idMap }: NormalizedAst, dfg: DataflowInformation): Set<NodeId>;
|
|
15
|
+
export declare const getLineageCommand: ReplCommand;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLineageCommand = exports.getLineage = void 0;
|
|
4
|
+
const pipeline_executor_1 = require("../../../core/pipeline-executor");
|
|
5
|
+
const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipelines");
|
|
6
|
+
const retriever_1 = require("../../../r-bridge/retriever");
|
|
7
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
8
|
+
const edge_1 = require("../../../dataflow/graph/edge");
|
|
9
|
+
const assert_1 = require("../../../util/assert");
|
|
10
|
+
function splitAt(str, idx) {
|
|
11
|
+
return [str.slice(0, idx), str.slice(idx)];
|
|
12
|
+
}
|
|
13
|
+
async function getDfg(shell, remainingLine) {
|
|
14
|
+
return await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
|
|
15
|
+
shell,
|
|
16
|
+
request: (0, retriever_1.requestFromInput)(remainingLine.trim())
|
|
17
|
+
}).allRemainingSteps();
|
|
18
|
+
}
|
|
19
|
+
function filterRelevantEdges(edge) {
|
|
20
|
+
return (0, edge_1.edgeIncludesType)(2 /* EdgeType.DefinedBy */ | 32 /* EdgeType.DefinedByOnCall */ | 8 /* EdgeType.Returns */ | 1 /* EdgeType.Reads */, edge.types);
|
|
21
|
+
}
|
|
22
|
+
function pushRelevantEdges(queue, outgoingEdges) {
|
|
23
|
+
queue.push(...[...outgoingEdges].filter(([_, edge]) => filterRelevantEdges(edge)));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get the lineage of a node in the dataflow graph
|
|
27
|
+
*
|
|
28
|
+
* @param criterion - The criterion to get the lineage of
|
|
29
|
+
* @param ast - The normalized AST
|
|
30
|
+
* @param dfg - The dataflow graph
|
|
31
|
+
* @returns The lineage of the node represented as a set of node ids
|
|
32
|
+
*/
|
|
33
|
+
function getLineage(criterion, { idMap }, dfg) {
|
|
34
|
+
const src = dfg.graph.get((0, parse_1.slicingCriterionToId)(criterion, idMap));
|
|
35
|
+
(0, assert_1.guard)(src !== undefined, 'The ID pointed to by the criterion does not exist in the dataflow graph');
|
|
36
|
+
const [vertex, outgoingEdges] = src;
|
|
37
|
+
const result = new Set([vertex.id]);
|
|
38
|
+
const edgeQueue = [];
|
|
39
|
+
pushRelevantEdges(edgeQueue, outgoingEdges);
|
|
40
|
+
while (edgeQueue.length > 0) {
|
|
41
|
+
const [target] = edgeQueue.shift();
|
|
42
|
+
if (result.has(target)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
result.add(target);
|
|
46
|
+
const outgoingEdges = dfg.graph.outgoingEdges(target);
|
|
47
|
+
if (outgoingEdges !== undefined) {
|
|
48
|
+
pushRelevantEdges(edgeQueue, outgoingEdges);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
exports.getLineage = getLineage;
|
|
54
|
+
exports.getLineageCommand = {
|
|
55
|
+
description: 'Get the lineage of an R object',
|
|
56
|
+
usageExample: ':lineage',
|
|
57
|
+
aliases: ['lin'],
|
|
58
|
+
script: false,
|
|
59
|
+
fn: async (output, shell, remainingLine) => {
|
|
60
|
+
const [criterion, rest] = splitAt(remainingLine, remainingLine.indexOf(' '));
|
|
61
|
+
const { dataflow: dfg, normalize: ast } = await getDfg(shell, rest);
|
|
62
|
+
const lineageIds = getLineage(criterion, ast, dfg);
|
|
63
|
+
output.stdout([...lineageIds].join('\n'));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=lineage.js.map
|
|
@@ -22,5 +22,6 @@ export declare class FlowRServerConnection {
|
|
|
22
22
|
private createPipelineExecutorForRequest;
|
|
23
23
|
private handleSliceRequest;
|
|
24
24
|
private handleRepl;
|
|
25
|
+
private handleLineageRequest;
|
|
25
26
|
}
|
|
26
27
|
export declare function sanitizeAnalysisResults(results: Partial<PipelineOutput<typeof DEFAULT_SLICING_PIPELINE>>): DeepPartial<PipelineOutput<typeof DEFAULT_SLICING_PIPELINE>>;
|
|
@@ -46,8 +46,11 @@ const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipeli
|
|
|
46
46
|
const graph_1 = require("../../../dataflow/graph/graph");
|
|
47
47
|
const tmp = __importStar(require("tmp"));
|
|
48
48
|
const fs_1 = __importDefault(require("fs"));
|
|
49
|
-
const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
|
|
50
49
|
const magic_comments_1 = require("../../../reconstruct/auto-select/magic-comments");
|
|
50
|
+
const lineage_1 = require("./messages/lineage");
|
|
51
|
+
const lineage_2 = require("../commands/lineage");
|
|
52
|
+
const assert_1 = require("../../../util/assert");
|
|
53
|
+
const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
|
|
51
54
|
/**
|
|
52
55
|
* Each connection handles a single client, answering to its requests.
|
|
53
56
|
* There is no need to construct this class manually, {@link FlowRServer} will do it for you.
|
|
@@ -97,6 +100,9 @@ class FlowRServerConnection {
|
|
|
97
100
|
case 'request-repl-execution':
|
|
98
101
|
this.handleRepl(request.message);
|
|
99
102
|
break;
|
|
103
|
+
case 'request-lineage':
|
|
104
|
+
this.handleLineageRequest(request.message);
|
|
105
|
+
break;
|
|
100
106
|
default:
|
|
101
107
|
(0, send_1.sendMessage)(this.socket, {
|
|
102
108
|
id: request.message.id,
|
|
@@ -215,7 +221,7 @@ class FlowRServerConnection {
|
|
|
215
221
|
}
|
|
216
222
|
fileInformation.pipeline.updateRequest({
|
|
217
223
|
criterion: request.criterion,
|
|
218
|
-
autoSelectIf: request.noMagicComments ? auto_select_defaults_1.
|
|
224
|
+
autoSelectIf: request.noMagicComments ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect)
|
|
219
225
|
});
|
|
220
226
|
void fileInformation.pipeline.allRemainingSteps(true).then(results => {
|
|
221
227
|
(0, send_1.sendMessage)(this.socket, {
|
|
@@ -260,6 +266,34 @@ class FlowRServerConnection {
|
|
|
260
266
|
});
|
|
261
267
|
});
|
|
262
268
|
}
|
|
269
|
+
handleLineageRequest(base) {
|
|
270
|
+
const requestResult = (0, validate_1.validateMessage)(base, lineage_1.requestLineageMessage);
|
|
271
|
+
if (requestResult.type === 'error') {
|
|
272
|
+
(0, validate_1.answerForValidationError)(this.socket, requestResult, base.id);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const request = requestResult.message;
|
|
276
|
+
this.logger.info(`[${this.name}] Received lineage request for criterion ${request.criterion}`);
|
|
277
|
+
const fileInformation = this.fileMap.get(request.filetoken);
|
|
278
|
+
if (!fileInformation) {
|
|
279
|
+
(0, send_1.sendMessage)(this.socket, {
|
|
280
|
+
id: request.id,
|
|
281
|
+
type: 'error',
|
|
282
|
+
fatal: false,
|
|
283
|
+
reason: `The file token ${request.filetoken} has never been analyzed.`
|
|
284
|
+
});
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const { dataflow: dfg, normalize: ast } = fileInformation.pipeline.getResults(true);
|
|
288
|
+
(0, assert_1.guard)(dfg !== undefined, `Dataflow graph must be present (request: ${request.filetoken})`);
|
|
289
|
+
(0, assert_1.guard)(ast !== undefined, `AST must be present (request: ${request.filetoken})`);
|
|
290
|
+
const lineageIds = (0, lineage_2.getLineage)(request.criterion, ast, dfg);
|
|
291
|
+
(0, send_1.sendMessage)(this.socket, {
|
|
292
|
+
type: 'response-lineage',
|
|
293
|
+
id: request.id,
|
|
294
|
+
lineage: [...lineageIds]
|
|
295
|
+
});
|
|
296
|
+
}
|
|
263
297
|
}
|
|
264
298
|
exports.FlowRServerConnection = FlowRServerConnection;
|
|
265
299
|
function sanitizeAnalysisResults(results) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SingleSlicingCriterion } from '../../../../slicing/criterion/parse';
|
|
2
|
+
import type { IdMessageBase, MessageDefinition } from './messages';
|
|
3
|
+
import type { NodeId } from '../../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
|
+
export interface LineageRequestMessage extends IdMessageBase {
|
|
5
|
+
type: 'request-lineage';
|
|
6
|
+
/** The {@link FileAnalysisRequestMessage#filetoken} of the file/data */
|
|
7
|
+
filetoken: string;
|
|
8
|
+
/** The criterion to start the lineage from */
|
|
9
|
+
criterion: SingleSlicingCriterion;
|
|
10
|
+
}
|
|
11
|
+
export declare const requestLineageMessage: MessageDefinition<LineageRequestMessage>;
|
|
12
|
+
export interface LineageResponseMessage extends IdMessageBase {
|
|
13
|
+
type: 'response-lineage';
|
|
14
|
+
/** The lineage of the given criterion. With this being the representation of a set, there is no guarantee about order. */
|
|
15
|
+
lineage: NodeId[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.requestLineageMessage = void 0;
|
|
7
|
+
const joi_1 = __importDefault(require("joi"));
|
|
8
|
+
exports.requestLineageMessage = {
|
|
9
|
+
type: 'request-lineage',
|
|
10
|
+
schema: joi_1.default.object({
|
|
11
|
+
type: joi_1.default.string().valid('request-lineage').required(),
|
|
12
|
+
id: joi_1.default.string().optional(),
|
|
13
|
+
filetoken: joi_1.default.string().required(),
|
|
14
|
+
criterion: joi_1.default.string().required()
|
|
15
|
+
})
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=lineage.js.map
|
|
@@ -9,6 +9,7 @@ import type { FileAnalysisRequestMessage, FileAnalysisResponseMessageJson } from
|
|
|
9
9
|
import type { ExecuteEndMessage, ExecuteIntermediateResponseMessage, ExecuteRequestMessage } from './repl';
|
|
10
10
|
import type { SliceRequestMessage, SliceResponseMessage } from './slice';
|
|
11
11
|
import type { FlowrErrorMessage } from './error';
|
|
12
|
+
import type { LineageRequestMessage, LineageResponseMessage } from './lineage';
|
|
12
13
|
/**
|
|
13
14
|
* If you send a message it must *not* contain a newline but the message must be terminated by a newline.
|
|
14
15
|
*/
|
|
@@ -32,4 +33,4 @@ export declare const baseMessage: MessageDefinition<IdMessageBase>;
|
|
|
32
33
|
/**
|
|
33
34
|
* This is the main message type that should be used to represent a message in *flowR*
|
|
34
35
|
*/
|
|
35
|
-
export type FlowrMessage = FlowrHelloResponseMessage | FileAnalysisRequestMessage | FileAnalysisResponseMessageJson | ExecuteRequestMessage | ExecuteIntermediateResponseMessage | ExecuteEndMessage | SliceRequestMessage | SliceResponseMessage | FlowrErrorMessage;
|
|
36
|
+
export type FlowrMessage = FlowrHelloResponseMessage | FileAnalysisRequestMessage | FileAnalysisResponseMessageJson | ExecuteRequestMessage | ExecuteIntermediateResponseMessage | ExecuteEndMessage | SliceRequestMessage | SliceResponseMessage | LineageRequestMessage | LineageResponseMessage | FlowrErrorMessage;
|
package/cli/slicer-app.js
CHANGED
|
@@ -12,8 +12,8 @@ const json_1 = require("../util/json");
|
|
|
12
12
|
const script_1 = require("./common/script");
|
|
13
13
|
const slicer_1 = require("../benchmark/slicer");
|
|
14
14
|
const print_1 = require("../benchmark/stats/print");
|
|
15
|
-
const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
|
|
16
15
|
const magic_comments_1 = require("../reconstruct/auto-select/magic-comments");
|
|
16
|
+
const auto_select_defaults_1 = require("../reconstruct/auto-select/auto-select-defaults");
|
|
17
17
|
const options = (0, script_1.processCommandLineArgs)('slicer', ['input', 'criterion'], {
|
|
18
18
|
subtitle: 'Slice R code based on a given slicing criterion',
|
|
19
19
|
examples: [
|
|
@@ -30,7 +30,7 @@ async function getSlice() {
|
|
|
30
30
|
(0, assert_1.guard)(options.criterion !== undefined, 'a slicing criterion must be given');
|
|
31
31
|
await slicer.init(options['input-is-text']
|
|
32
32
|
? { request: 'text', content: options.input }
|
|
33
|
-
: { request: 'file', content: options.input }, options['no-magic-comments'] ? auto_select_defaults_1.
|
|
33
|
+
: { request: 'file', content: options.input }, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
|
|
34
34
|
let mappedSlices = [];
|
|
35
35
|
let reconstruct = undefined;
|
|
36
36
|
const doSlicing = options.criterion.trim() !== '';
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EmptyBuiltInMemory = exports.BuiltInMemory = exports.registerReplacementFunctions = exports.registerBuiltInFunctions = exports.BuiltIn = void 0;
|
|
4
4
|
const known_call_handling_1 = require("../internal/process/functions/call/known-call-handling");
|
|
5
|
-
const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
|
|
6
5
|
const built_in_access_1 = require("../internal/process/functions/call/built-in/built-in-access");
|
|
7
6
|
const built_in_if_then_else_1 = require("../internal/process/functions/call/built-in/built-in-if-then-else");
|
|
8
7
|
const built_in_assignment_1 = require("../internal/process/functions/call/built-in/built-in-assignment");
|
|
9
|
-
const
|
|
8
|
+
const built_in_special_bin_op_1 = require("../internal/process/functions/call/built-in/built-in-special-bin-op");
|
|
10
9
|
const built_in_pipe_1 = require("../internal/process/functions/call/built-in/built-in-pipe");
|
|
11
10
|
const built_in_for_loop_1 = require("../internal/process/functions/call/built-in/built-in-for-loop");
|
|
12
11
|
const built_in_repeat_loop_1 = require("../internal/process/functions/call/built-in/built-in-repeat-loop");
|
|
@@ -18,9 +17,11 @@ const built_in_function_definition_1 = require("../internal/process/functions/ca
|
|
|
18
17
|
const built_in_expression_list_1 = require("../internal/process/functions/call/built-in/built-in-expression-list");
|
|
19
18
|
const built_in_get_1 = require("../internal/process/functions/call/built-in/built-in-get");
|
|
20
19
|
const built_in_library_1 = require("../internal/process/functions/call/built-in/built-in-library");
|
|
20
|
+
const built_in_source_1 = require("../internal/process/functions/call/built-in/built-in-source");
|
|
21
|
+
const built_in_apply_1 = require("../internal/process/functions/call/built-in/built-in-apply");
|
|
21
22
|
exports.BuiltIn = 'built-in';
|
|
22
23
|
function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
23
|
-
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data });
|
|
24
|
+
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs });
|
|
24
25
|
if (config.returnsNthArgument !== undefined) {
|
|
25
26
|
const arg = config.returnsNthArgument === 'last' ? processedArguments[args.length - 1] : processedArguments[config.returnsNthArgument];
|
|
26
27
|
if (arg !== undefined) {
|
|
@@ -34,6 +35,9 @@ function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
if (config.hasUnknownSideEffects) {
|
|
39
|
+
res.graph.markIdForUnknownSideEffects(rootId);
|
|
40
|
+
}
|
|
37
41
|
if (config.cfg !== undefined) {
|
|
38
42
|
res.exitPoints = [...res.exitPoints, { type: config.cfg, nodeId: rootId, controlDependencies: data.controlDependencies }];
|
|
39
43
|
}
|
|
@@ -41,6 +45,7 @@ function defaultBuiltInProcessor(name, args, rootId, data, config) {
|
|
|
41
45
|
}
|
|
42
46
|
function registerBuiltInFunctions(both, names, processor, config) {
|
|
43
47
|
for (const name of names) {
|
|
48
|
+
(0, assert_1.guard)(processor !== undefined, `Processor for ${name} is undefined, maybe you have an import loop? You may run 'npm run detect-circular-deps' - although by far not all are bad`);
|
|
44
49
|
(0, assert_1.guard)(!exports.BuiltInMemory.has(name), `Built-in ${name} already defined`);
|
|
45
50
|
const d = [{
|
|
46
51
|
kind: 'built-in-function',
|
|
@@ -101,9 +106,16 @@ registerBuiltInConstant(true, 'TRUE', true);
|
|
|
101
106
|
registerBuiltInConstant(true, 'T', true);
|
|
102
107
|
registerBuiltInConstant(true, 'FALSE', false);
|
|
103
108
|
registerBuiltInConstant(true, 'F', false);
|
|
104
|
-
registerSimpleFunctions('~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':', 'list', 'c', 'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max', 'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean', 'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'plot', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix', '
|
|
105
|
-
registerBuiltInFunctions(true, ['
|
|
106
|
-
|
|
109
|
+
registerSimpleFunctions('~', '+', '-', '*', '/', '^', '!', '?', '**', '==', '!=', '>', '<', '>=', '<=', '%%', '%/%', '%*%', '%in%', ':', 'list', 'c', 'rep', 'seq', 'seq_len', 'seq_along', 'seq.int', 'gsub', 'which', 'class', 'dimnames', 'min', 'max', 'intersect', 'subset', 'match', 'sqrt', 'abs', 'round', 'floor', 'ceiling', 'signif', 'trunc', 'log', 'log10', 'log2', 'sum', 'mean', 'unique', 'paste', 'paste0', 'read.csv', 'stop', 'is.null', 'plot', 'numeric', 'as.character', 'as.integer', 'as.logical', 'as.numeric', 'as.matrix', 'do.call', 'rbind', 'nrow', 'ncol', 'tryCatch', 'expression', 'factor', 'missing', 'as.data.frame', 'data.frame', 'na.omit', 'rownames', 'names', 'order', 'length', 'any', 'dim', 'matrix', 'cbind', 'nchar', 't');
|
|
110
|
+
registerBuiltInFunctions(true, ['lapply', 'sapply', 'vapply', 'mapply'], built_in_apply_1.processApply, { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' });
|
|
111
|
+
/* functool wrappers */
|
|
112
|
+
registerBuiltInFunctions(true, ['Lapply', 'Sapply', 'Vapply', 'Mapply'], built_in_apply_1.processApply, { indexOfFunction: 1, nameOfFunctionArgument: 'FUN' });
|
|
113
|
+
registerBuiltInFunctions(true, ['apply', 'tapply', 'Tapply'], built_in_apply_1.processApply, { indexOfFunction: 2, nameOfFunctionArgument: 'FUN' });
|
|
114
|
+
registerBuiltInFunctions(true, ['print'], defaultBuiltInProcessor, { returnsNthArgument: 0, forceArgs: 'all' });
|
|
115
|
+
registerBuiltInFunctions(true, ['('], defaultBuiltInProcessor, { returnsNthArgument: 0 });
|
|
116
|
+
registerBuiltInFunctions(true, ['load', 'load_all', 'setwd', 'set.seed'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: [true] });
|
|
117
|
+
registerBuiltInFunctions(false, ['cat'], defaultBuiltInProcessor, { forceArgs: 'all' }); /* returns null */
|
|
118
|
+
registerBuiltInFunctions(false, ['switch'], defaultBuiltInProcessor, {}); /* returns null */
|
|
107
119
|
registerBuiltInFunctions(true, ['return'], defaultBuiltInProcessor, { returnsNthArgument: 0, cfg: 1 /* ExitPointType.Return */ });
|
|
108
120
|
registerBuiltInFunctions(true, ['break'], defaultBuiltInProcessor, { cfg: 2 /* ExitPointType.Break */ });
|
|
109
121
|
registerBuiltInFunctions(true, ['next'], defaultBuiltInProcessor, { cfg: 3 /* ExitPointType.Next */ });
|
|
@@ -113,21 +125,29 @@ registerBuiltInFunctions(true, ['[', '[['], built_in_access_1.processAccess, { t
|
|
|
113
125
|
registerBuiltInFunctions(true, ['$', '@'], built_in_access_1.processAccess, { treatIndicesAsString: true });
|
|
114
126
|
registerBuiltInFunctions(true, ['if', 'ifelse'], built_in_if_then_else_1.processIfThenElse, {});
|
|
115
127
|
registerBuiltInFunctions(true, ['get'], built_in_get_1.processGet, {});
|
|
116
|
-
registerBuiltInFunctions(false, ['library'], built_in_library_1.processLibrary, {});
|
|
128
|
+
registerBuiltInFunctions(false, ['library', 'require'], built_in_library_1.processLibrary, {});
|
|
117
129
|
registerBuiltInFunctions(true, ['<-', '='], built_in_assignment_1.processAssignment, { canBeReplacement: true });
|
|
118
130
|
registerBuiltInFunctions(true, [':=', 'assign'], built_in_assignment_1.processAssignment, {});
|
|
119
131
|
registerBuiltInFunctions(true, ['delayedAssign'], built_in_assignment_1.processAssignment, { quoteSource: true });
|
|
120
132
|
registerBuiltInFunctions(true, ['<<-'], built_in_assignment_1.processAssignment, { superAssignment: true, canBeReplacement: true });
|
|
121
133
|
registerBuiltInFunctions(true, ['->'], built_in_assignment_1.processAssignment, { swapSourceAndTarget: true, canBeReplacement: true });
|
|
122
134
|
registerBuiltInFunctions(true, ['->>'], built_in_assignment_1.processAssignment, { superAssignment: true, swapSourceAndTarget: true, canBeReplacement: true });
|
|
123
|
-
registerBuiltInFunctions(true, ['&&', '&'],
|
|
124
|
-
registerBuiltInFunctions(true, ['||', '|'],
|
|
135
|
+
registerBuiltInFunctions(true, ['&&', '&'], built_in_special_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: true });
|
|
136
|
+
registerBuiltInFunctions(true, ['||', '|'], built_in_special_bin_op_1.processSpecialBinOp, { lazy: true, evalRhsWhen: false });
|
|
125
137
|
registerBuiltInFunctions(true, ['|>', '%>%'], built_in_pipe_1.processPipe, {});
|
|
126
138
|
registerBuiltInFunctions(true, ['function', '\\'], built_in_function_definition_1.processFunctionDefinition, {});
|
|
127
139
|
registerBuiltInFunctions(true, ['quote', 'substitute', 'bquote'], built_in_quote_1.processQuote, { quoteArgumentsWithIndex: 0 });
|
|
128
140
|
registerBuiltInFunctions(true, ['for'], built_in_for_loop_1.processForLoop, {});
|
|
129
141
|
registerBuiltInFunctions(true, ['repeat'], built_in_repeat_loop_1.processRepeatLoop, {});
|
|
130
142
|
registerBuiltInFunctions(true, ['while'], built_in_while_loop_1.processWhileLoop, {});
|
|
143
|
+
registerBuiltInFunctions(true, ['options'], defaultBuiltInProcessor, { hasUnknownSideEffects: true, forceArgs: 'all' });
|
|
144
|
+
registerBuiltInFunctions(true, ['on.exit', 'sys.on.exit'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
|
|
145
|
+
/* library and require is handled above */
|
|
146
|
+
registerBuiltInFunctions(true, ['requireNamespace', 'loadNamespace', 'attachNamespace', 'asNamespace'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
|
|
147
|
+
/* downloader and installer functions (R, devtools, BiocManager) */
|
|
148
|
+
registerBuiltInFunctions(true, ['library.dynam', 'install.packages', 'install', 'install_github', 'install_gitlab', 'install_bitbucket', 'install_url', 'install_git', 'install_svn', 'install_local', 'install_version', 'update_packages'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
|
|
149
|
+
/* weird env attachments */
|
|
150
|
+
registerBuiltInFunctions(true, ['attach'], defaultBuiltInProcessor, { hasUnknownSideEffects: true });
|
|
131
151
|
/* they are all mapped to `<-` but we separate super assignments */
|
|
132
152
|
registerReplacementFunctions({ makeMaybe: true }, ['<-', '<<-'], '[', '[[', '$', '@', 'names', 'dimnames', 'attributes', 'attr', 'class', 'levels', 'rownames', 'colnames');
|
|
133
153
|
//# sourceMappingURL=built-in.js.map
|
|
@@ -20,11 +20,12 @@ function makeReferenceMaybe(ref, graph, environments, includeDefs, defaultCd = u
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
if (node) {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const [fst] = node;
|
|
24
|
+
if (fst.controlDependencies && defaultCd && !fst.controlDependencies.includes(defaultCd)) {
|
|
25
|
+
fst.controlDependencies.push(defaultCd);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
|
-
|
|
28
|
+
fst.controlDependencies = defaultCd ? [defaultCd] : [];
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
return { ...ref, controlDependencies: [...ref.controlDependencies ?? [], ...(defaultCd ? [defaultCd] : [])] };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { REnvironmentInformation } from './environment';
|
|
2
|
-
import
|
|
2
|
+
import { Ternary } from '../../util/logic';
|
|
3
3
|
import type { Identifier, IdentifierDefinition } from './identifier';
|
|
4
4
|
/**
|
|
5
5
|
* Resolves a given identifier name to a list of its possible definition location using R scoping and resolving rules.
|
|
@@ -24,11 +24,11 @@ function resolveByName(name, environment) {
|
|
|
24
24
|
exports.resolveByName = resolveByName;
|
|
25
25
|
function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
26
26
|
if (name === undefined) {
|
|
27
|
-
return
|
|
27
|
+
return 2 /* Ternary.Never */;
|
|
28
28
|
}
|
|
29
29
|
const definition = resolveByName(name, environment);
|
|
30
30
|
if (definition === undefined) {
|
|
31
|
-
return
|
|
31
|
+
return 2 /* Ternary.Never */;
|
|
32
32
|
}
|
|
33
33
|
let all = true;
|
|
34
34
|
let some = false;
|
|
@@ -41,10 +41,10 @@ function resolvesToBuiltInConstant(name, environment, wantedValue) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
if (all) {
|
|
44
|
-
return
|
|
44
|
+
return 0 /* Ternary.Always */;
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
|
-
return some ?
|
|
47
|
+
return some ? 1 /* Ternary.Maybe */ : 2 /* Ternary.Never */;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
exports.resolvesToBuiltInConstant = resolvesToBuiltInConstant;
|
package/dataflow/graph/diff.js
CHANGED
|
@@ -94,6 +94,7 @@ function diffOutgoingEdges(ctx) {
|
|
|
94
94
|
}
|
|
95
95
|
function diffRootVertices(ctx) {
|
|
96
96
|
(0, diff_1.setDifference)(ctx.left.rootIds(), ctx.right.rootIds(), { ...ctx, position: `${ctx.position}Root vertices differ in graphs. ` });
|
|
97
|
+
(0, diff_1.setDifference)(ctx.left.unknownSideEffects, ctx.right.unknownSideEffects, { ...ctx, position: `${ctx.position}Unknown side effects differ in graphs. ` });
|
|
97
98
|
}
|
|
98
99
|
function diffOfDataflowGraphs(left, right, config) {
|
|
99
100
|
if (left.graph === right.graph) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { DataflowGraphEdge } from './edge';
|
|
2
2
|
import { EdgeType } from './edge';
|
|
3
3
|
import type { DataflowInformation } from '../info';
|
|
4
|
-
import type {
|
|
5
|
-
import type { DataflowGraphVertexArgument, DataflowGraphVertexInfo } from './vertex';
|
|
4
|
+
import type { DataflowGraphVertexArgument, DataflowGraphVertexFunctionCall, DataflowGraphVertexInfo } from './vertex';
|
|
6
5
|
import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
6
|
import type { IdentifierDefinition, IdentifierReference } from '../environments/identifier';
|
|
8
7
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
@@ -47,10 +46,10 @@ type EdgeData<Edge extends DataflowGraphEdge> = Omit<Edge, 'from' | 'to' | 'type
|
|
|
47
46
|
export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = DataflowGraphVertexInfo, Edge extends DataflowGraphEdge = DataflowGraphEdge> {
|
|
48
47
|
private static DEFAULT_ENVIRONMENT;
|
|
49
48
|
private _idMap;
|
|
50
|
-
|
|
49
|
+
private _unknownSideEffects;
|
|
51
50
|
constructor(idMap: AstIdMap | undefined);
|
|
52
51
|
/** Contains the vertices of the root level graph (i.e., included those vertices from the complete graph, that are nested within function definitions) */
|
|
53
|
-
|
|
52
|
+
protected rootVertices: Set<NodeId>;
|
|
54
53
|
/** All vertices in the complete graph (including those nested in function definition) */
|
|
55
54
|
private vertexInformation;
|
|
56
55
|
/** All edges in the complete graph (including those nested in function definition) */
|
|
@@ -79,14 +78,18 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
79
78
|
ingoingEdges(id: NodeId): IngoingEdges | undefined;
|
|
80
79
|
/** Retrieves the id-map to the normalized AST attached to the dataflow graph */
|
|
81
80
|
get idMap(): AstIdMap | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Retrieves the set of vertices which have side effects that we do not know anything about.
|
|
83
|
+
*/
|
|
84
|
+
get unknownSideEffects(): ReadonlySet<NodeId>;
|
|
82
85
|
/** Allows setting the id-map explicitly (which should only be used when, e.g., you plan to compare two dataflow graphs on the same AST-basis) */
|
|
83
86
|
setIdMap(idMap: AstIdMap): void;
|
|
84
87
|
/**
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
* @param includeDefinedFunctions - If true this will iterate over function definitions as well and not just the toplevel
|
|
89
|
+
* @returns the ids of all toplevel vertices in the graph together with their vertex information
|
|
87
90
|
*
|
|
88
91
|
* @see #edges
|
|
89
|
-
|
|
92
|
+
*/
|
|
90
93
|
vertices(includeDefinedFunctions: boolean): IterableIterator<[NodeId, Vertex]>;
|
|
91
94
|
/**
|
|
92
95
|
* @returns the ids of all edges in the graph together with their edge information
|
|
@@ -107,15 +110,15 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
107
110
|
isRoot(id: NodeId): boolean;
|
|
108
111
|
rootIds(): ReadonlySet<NodeId>;
|
|
109
112
|
/**
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
* Adds a new vertex to the graph, for ease of use, some arguments are optional and filled automatically.
|
|
114
|
+
*
|
|
112
115
|
* @param vertex - The vertex to add
|
|
113
116
|
* @param asRoot - If false, this will only add the vertex but do not add it to the {@link rootIds|root vertices} of the graph.
|
|
114
117
|
* This is probably only of use, when you construct dataflow graphs for tests.
|
|
115
118
|
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
* @see DataflowGraphVertexInfo
|
|
120
|
+
* @see DataflowGraphVertexArgument
|
|
121
|
+
*/
|
|
119
122
|
addVertex(vertex: DataflowGraphVertexArgument & Omit<Vertex, keyof DataflowGraphVertexArgument>, asRoot?: boolean): this;
|
|
120
123
|
/** {@inheritDoc} */
|
|
121
124
|
addEdge(from: NodeId, to: NodeId, edgeInfo: EdgeData<Edge>): this;
|
|
@@ -133,18 +136,19 @@ export declare class DataflowGraph<Vertex extends DataflowGraphVertexInfo = Data
|
|
|
133
136
|
*/
|
|
134
137
|
mergeWith(otherGraph: DataflowGraph<Vertex, Edge> | undefined, mergeRootVertices?: boolean): this;
|
|
135
138
|
private mergeEdges;
|
|
136
|
-
equals(other: DataflowGraph<Vertex, Edge>, diff: true, names?: {
|
|
137
|
-
left: string;
|
|
138
|
-
right: string;
|
|
139
|
-
}): DataflowDifferenceReport;
|
|
140
|
-
equals(other: DataflowGraph<Vertex, Edge>, diff?: false, names?: {
|
|
141
|
-
left: string;
|
|
142
|
-
right: string;
|
|
143
|
-
}): boolean;
|
|
144
139
|
/**
|
|
145
140
|
* Marks a vertex in the graph to be a definition
|
|
146
141
|
* @param reference - The reference to the vertex to mark as definition
|
|
147
142
|
*/
|
|
148
143
|
setDefinitionOfVertex(reference: IdentifierReference): void;
|
|
144
|
+
/**
|
|
145
|
+
* Marks a vertex in the graph to be a function call with the new information
|
|
146
|
+
* @param info - The information about the new function call node
|
|
147
|
+
*/
|
|
148
|
+
updateToFunctionCall(info: DataflowGraphVertexFunctionCall): void;
|
|
149
|
+
/** If you do not pass the `to` node, this will just mark the node as maybe */
|
|
150
|
+
addControlDependency(from: NodeId, to?: NodeId, when?: boolean): this;
|
|
151
|
+
/** Marks the given node as having unknown side effects */
|
|
152
|
+
markIdForUnknownSideEffects(id: NodeId): this;
|
|
149
153
|
}
|
|
150
154
|
export {};
|