@eagleoutice/flowr 2.0.15 → 2.0.17
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 +15 -5
- 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 +34 -0
- 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/dataflow/environments/built-in.js +18 -8
- 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 +18 -19
- package/dataflow/graph/graph.js +41 -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 +3 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +5 -4
- 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 +1 -0
- 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 +3 -2
- package/dataflow/internal/process/functions/call/known-call-handling.js +2 -2
- 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 +5 -0
- package/r-bridge/data/data.js +6 -0
- package/reconstruct/reconstruct.js +3 -3
- package/slicing/criterion/parse.d.ts +3 -4
- package/slicing/criterion/parse.js +3 -3
- package/slicing/static/slice-call.js +35 -13
- 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
|
@@ -268,8 +268,8 @@ function reconstructArgument(argument, name, value) {
|
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
function reconstructParameter(parameter, name, defaultValue, configuration) {
|
|
271
|
-
if (
|
|
272
|
-
return
|
|
271
|
+
if (isSelected(configuration, parameter)) {
|
|
272
|
+
return plain(getLexeme(parameter));
|
|
273
273
|
}
|
|
274
274
|
if (parameter.defaultValue !== undefined && name.length > 0) {
|
|
275
275
|
return plain(`${getLexeme(parameter.name)}=${getLexeme(parameter.defaultValue)}`);
|
|
@@ -282,7 +282,7 @@ function reconstructParameter(parameter, name, defaultValue, configuration) {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
function reconstructFunctionDefinition(definition, functionParameters, body, config) {
|
|
285
|
-
// if a definition is not selected, we only use the body - slicing will always select the definition
|
|
285
|
+
// if a definition is not selected, we only use the body - slicing will always select the definition if it is required
|
|
286
286
|
if (functionParameters.every(p => p.length === 0)) {
|
|
287
287
|
const empty = body === undefined || body.length === 0;
|
|
288
288
|
const selected = isSelected(config, definition);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { NoInfo } from '../../r-bridge/lang-4.x/ast/model/model';
|
|
2
1
|
import { type NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
|
-
import type {
|
|
2
|
+
import type { AstIdMap } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
3
|
/** Either `line:column`, `line@variable-name`, or `$id` */
|
|
5
4
|
export type SingleSlicingCriterion = `${number}:${number}` | `${number}@${string}` | `$${number}`;
|
|
6
5
|
export type SlicingCriteria = SingleSlicingCriterion[];
|
|
@@ -13,10 +12,10 @@ export declare class CriteriaParseError extends Error {
|
|
|
13
12
|
/**
|
|
14
13
|
* Takes a criterion in the form of `line:column` or `line@variable-name` and returns the corresponding node id
|
|
15
14
|
*/
|
|
16
|
-
export declare function slicingCriterionToId
|
|
15
|
+
export declare function slicingCriterionToId(criterion: SingleSlicingCriterion, idMap: AstIdMap): NodeId;
|
|
17
16
|
export interface DecodedCriterion {
|
|
18
17
|
criterion: SingleSlicingCriterion;
|
|
19
18
|
id: NodeId;
|
|
20
19
|
}
|
|
21
20
|
export type DecodedCriteria = ReadonlyArray<DecodedCriterion>;
|
|
22
|
-
export declare function convertAllSlicingCriteriaToIds(criteria: SlicingCriteria, decorated:
|
|
21
|
+
export declare function convertAllSlicingCriteriaToIds(criteria: SlicingCriteria, decorated: AstIdMap): DecodedCriteria;
|
|
@@ -17,18 +17,18 @@ exports.CriteriaParseError = CriteriaParseError;
|
|
|
17
17
|
/**
|
|
18
18
|
* Takes a criterion in the form of `line:column` or `line@variable-name` and returns the corresponding node id
|
|
19
19
|
*/
|
|
20
|
-
function slicingCriterionToId(criterion,
|
|
20
|
+
function slicingCriterionToId(criterion, idMap) {
|
|
21
21
|
let resolved;
|
|
22
22
|
if (criterion.startsWith('$')) {
|
|
23
23
|
resolved = (0, node_id_1.normalizeIdToNumberIfPossible)(criterion.substring(1));
|
|
24
24
|
}
|
|
25
25
|
else if (criterion.includes(':')) {
|
|
26
26
|
const [line, column] = criterion.split(':').map(c => parseInt(c));
|
|
27
|
-
resolved = locationToId([line, column],
|
|
27
|
+
resolved = locationToId([line, column], idMap);
|
|
28
28
|
}
|
|
29
29
|
else if (criterion.includes('@')) {
|
|
30
30
|
const [line, name] = criterion.split(/@(.*)/s); // only split at first occurrence
|
|
31
|
-
resolved = conventionalCriteriaToId(parseInt(line), name,
|
|
31
|
+
resolved = conventionalCriteriaToId(parseInt(line), name, idMap);
|
|
32
32
|
}
|
|
33
33
|
if (resolved === undefined) {
|
|
34
34
|
throw new CriteriaParseError(`invalid slicing criterion ${criterion}`);
|
|
@@ -7,6 +7,7 @@ const linker_1 = require("../../dataflow/internal/linker");
|
|
|
7
7
|
const environment_1 = require("../../dataflow/environments/environment");
|
|
8
8
|
const scoping_1 = require("../../dataflow/environments/scoping");
|
|
9
9
|
const overwrite_1 = require("../../dataflow/environments/overwrite");
|
|
10
|
+
const graph_1 = require("../../dataflow/graph/graph");
|
|
10
11
|
const built_in_1 = require("../../dataflow/environments/built-in");
|
|
11
12
|
const resolve_by_name_1 = require("../../dataflow/environments/resolve-by-name");
|
|
12
13
|
const edge_1 = require("../../dataflow/graph/edge");
|
|
@@ -23,6 +24,31 @@ function retrieveActiveEnvironment(callerInfo, baseEnvironment) {
|
|
|
23
24
|
}
|
|
24
25
|
return (0, overwrite_1.overwriteEnvironment)(baseEnvironment, callerEnvironment);
|
|
25
26
|
}
|
|
27
|
+
function includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowGraph) {
|
|
28
|
+
const valueRoot = (0, graph_1.getReferenceOfArgument)(arg);
|
|
29
|
+
if (!valueRoot) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const callTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set([valueRoot]), dataflowGraph);
|
|
33
|
+
linkCallTargets(false, callTargets, baseEnvironment, (0, fingerprint_1.envFingerprint)(baseEnvironment), activeEnvironment, (0, fingerprint_1.envFingerprint)(activeEnvironment), queue);
|
|
34
|
+
}
|
|
35
|
+
function linkCallTargets(onlyForSideEffects, functionCallTargets, baseEnvironment, baseEnvPrint, activeEnvironment, activeEnvironmentFingerprint, queue) {
|
|
36
|
+
for (const functionCallTarget of functionCallTargets) {
|
|
37
|
+
// all those linked within the scopes of other functions are already linked when exiting a function definition
|
|
38
|
+
for (const openIn of functionCallTarget.subflow.in) {
|
|
39
|
+
const defs = openIn.name ? (0, resolve_by_name_1.resolveByName)(openIn.name, activeEnvironment) : undefined;
|
|
40
|
+
if (defs === undefined) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
for (const def of defs.filter(d => d.nodeId !== built_in_1.BuiltIn)) {
|
|
44
|
+
queue.add(def.nodeId, baseEnvironment, baseEnvPrint, onlyForSideEffects);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const exitPoint of functionCallTarget.exitPoints) {
|
|
48
|
+
queue.add(exitPoint, activeEnvironment, activeEnvironmentFingerprint, onlyForSideEffects);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
26
52
|
/** returns the new threshold hit count */
|
|
27
53
|
function sliceForCall(current, callerInfo, dataflowGraph, queue) {
|
|
28
54
|
// bind with call-local environments during slicing
|
|
@@ -42,21 +68,17 @@ function sliceForCall(current, callerInfo, dataflowGraph, queue) {
|
|
|
42
68
|
}
|
|
43
69
|
}
|
|
44
70
|
const functionCallTargets = (0, linker_1.getAllLinkedFunctionDefinitions)(new Set(functionCallDefs), dataflowGraph);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
for (const def of defs.filter(d => d.nodeId !== built_in_1.BuiltIn)) {
|
|
53
|
-
queue.add(def.nodeId, baseEnvironment, baseEnvPrint, current.onlyForSideEffects);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
for (const exitPoint of functionCallTarget.exitPoints) {
|
|
57
|
-
queue.add(exitPoint, activeEnvironment, activeEnvironmentFingerprint, current.onlyForSideEffects);
|
|
71
|
+
if (functionCallTargets.size === 0) {
|
|
72
|
+
/*
|
|
73
|
+
* if we do not have any call to resolve this function, we have to assume that every function passed is actually called!
|
|
74
|
+
* hence, we add a new flag and add all argument values to the queue causing directly
|
|
75
|
+
*/
|
|
76
|
+
for (const arg of callerInfo.args) {
|
|
77
|
+
includeArgumentFunctionCallClosure(arg, baseEnvironment, activeEnvironment, queue, dataflowGraph);
|
|
58
78
|
}
|
|
79
|
+
return;
|
|
59
80
|
}
|
|
81
|
+
linkCallTargets(current.onlyForSideEffects, functionCallTargets, baseEnvironment, baseEnvPrint, activeEnvironment, activeEnvironmentFingerprint, queue);
|
|
60
82
|
}
|
|
61
83
|
exports.sliceForCall = sliceForCall;
|
|
62
84
|
/** Returns true if we found at least one return edge */
|
|
@@ -13,4 +13,4 @@ export declare const slicerLogger: import("tslog").Logger<import("tslog").ILogOb
|
|
|
13
13
|
* @param criteria - The criteras to slice on.
|
|
14
14
|
* @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
|
|
15
15
|
*/
|
|
16
|
-
export declare function staticSlicing(graph: DataflowGraph,
|
|
16
|
+
export declare function staticSlicing(graph: DataflowGraph, { idMap }: NormalizedAst, criteria: SlicingCriteria, threshold?: number): Readonly<SliceResult>;
|
|
@@ -20,9 +20,9 @@ exports.slicerLogger = log_1.log.getSubLogger({ name: 'slicer' });
|
|
|
20
20
|
* @param criteria - The criteras to slice on.
|
|
21
21
|
* @param threshold - The maximum number of nodes to visit in the graph. If the threshold is reached, the slice will side with inclusion and drop its minimal guarantee. The limit ensures that the algorithm halts.
|
|
22
22
|
*/
|
|
23
|
-
function staticSlicing(graph,
|
|
23
|
+
function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
|
|
24
24
|
(0, assert_1.guard)(criteria.length > 0, 'must have at least one seed id to calculate slice');
|
|
25
|
-
const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria,
|
|
25
|
+
const decodedCriteria = (0, parse_1.convertAllSlicingCriteriaToIds)(criteria, idMap);
|
|
26
26
|
(0, log_1.expensiveTrace)(exports.slicerLogger, () => `calculating slice for ${decodedCriteria.length} seed criteria: ${decodedCriteria.map(s => JSON.stringify(s)).join(', ')}`);
|
|
27
27
|
const queue = new visiting_queue_1.VisitingQueue(threshold);
|
|
28
28
|
let minDepth = Number.MAX_SAFE_INTEGER;
|
|
@@ -34,9 +34,15 @@ function staticSlicing(graph, ast, criteria, threshold = 75) {
|
|
|
34
34
|
for (const { id: startId } of decodedCriteria) {
|
|
35
35
|
queue.add(startId, emptyEnv, basePrint, false);
|
|
36
36
|
// retrieve the minimum depth of all nodes to only add control dependencies if they are "part" of the current execution
|
|
37
|
-
minDepth = Math.min(minDepth,
|
|
37
|
+
minDepth = Math.min(minDepth, idMap.get(startId)?.info.depth ?? minDepth);
|
|
38
38
|
sliceSeedIds.add(startId);
|
|
39
39
|
}
|
|
40
|
+
/* additionally,
|
|
41
|
+
* include all the implicit side effects that we have to consider as we are unable to narrow them down
|
|
42
|
+
*/
|
|
43
|
+
for (const id of graph.unknownSideEffects) {
|
|
44
|
+
queue.add(id, emptyEnv, basePrint, true);
|
|
45
|
+
}
|
|
40
46
|
}
|
|
41
47
|
while (queue.nonEmpty()) {
|
|
42
48
|
const current = queue.next();
|
|
@@ -52,7 +58,7 @@ function staticSlicing(graph, ast, criteria, threshold = 75) {
|
|
|
52
58
|
if (currentVertex.controlDependencies && currentVertex.controlDependencies.length > 0) {
|
|
53
59
|
const topLevel = graph.isRoot(id) || sliceSeedIds.has(id);
|
|
54
60
|
for (const cd of currentVertex.controlDependencies.filter(({ id }) => !queue.hasId(id))) {
|
|
55
|
-
if (!topLevel || (
|
|
61
|
+
if (!topLevel || (idMap.get(cd.id)?.info.depth ?? 0) <= minDepth) {
|
|
56
62
|
queue.add(cd.id, baseEnvironment, baseEnvFingerprint, false);
|
|
57
63
|
}
|
|
58
64
|
}
|
package/statistics/statistics.js
CHANGED
|
@@ -64,7 +64,7 @@ function initializeFeatureStatistics() {
|
|
|
64
64
|
const result = {};
|
|
65
65
|
for (const key of feature_1.allFeatureNames) {
|
|
66
66
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
67
|
-
result[key] = JSON.parse(JSON.stringify(feature_1.ALL_FEATURES[key].initialValue, json_1.jsonReplacer), json_1.
|
|
67
|
+
result[key] = JSON.parse(JSON.stringify(feature_1.ALL_FEATURES[key].initialValue, json_1.jsonReplacer), json_1.jsonBigIntRetriever);
|
|
68
68
|
}
|
|
69
69
|
return result;
|
|
70
70
|
}
|
package/util/json.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function jsonReplacer(key: any, value: any): any;
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function jsonBigIntRetriever(key: string, value: unknown): unknown;
|
package/util/json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.jsonBigIntRetriever = exports.jsonReplacer = void 0;
|
|
4
4
|
// to get the types within JSON.stringify
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
6
|
function jsonReplacer(key, value) {
|
|
@@ -16,7 +16,7 @@ function jsonReplacer(key, value) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
exports.jsonReplacer = jsonReplacer;
|
|
19
|
-
function
|
|
19
|
+
function jsonBigIntRetriever(key, value) {
|
|
20
20
|
if (typeof value === 'string' && value.endsWith('n')) {
|
|
21
21
|
return BigInt(value.slice(0, -1));
|
|
22
22
|
}
|
|
@@ -24,5 +24,5 @@ function jsonRetriever(key, value) {
|
|
|
24
24
|
return value;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
exports.
|
|
27
|
+
exports.jsonBigIntRetriever = jsonBigIntRetriever;
|
|
28
28
|
//# sourceMappingURL=json.js.map
|
package/util/logic.d.ts
CHANGED
package/util/version.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flowrVersion = void 0;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
// this is automatically replaced with the current version by release-it
|
|
6
|
-
const version = '2.0.
|
|
6
|
+
const version = '2.0.17';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
interface IntervalBound {
|
|
2
|
-
readonly value: number;
|
|
3
|
-
readonly inclusive: boolean;
|
|
4
|
-
}
|
|
5
|
-
export declare class Interval {
|
|
6
|
-
readonly min: IntervalBound;
|
|
7
|
-
readonly max: IntervalBound;
|
|
8
|
-
/**
|
|
9
|
-
* Build a new interval from the given bounds.
|
|
10
|
-
* If the interval represents a scalar, the min and max bounds should be equal, as well as their inclusivity.
|
|
11
|
-
* @param min - The minimum bound of the interval.
|
|
12
|
-
* @param max - The maximum bound of the interval.
|
|
13
|
-
*/
|
|
14
|
-
constructor(min: IntervalBound, max: IntervalBound);
|
|
15
|
-
toString(): string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* A domain represents a set of intervals describing a range of possible values a variable may hold.
|
|
19
|
-
* In the future we may want to extend this to support more complex types.
|
|
20
|
-
*/
|
|
21
|
-
export declare class Domain {
|
|
22
|
-
/** set of intervals to hold */
|
|
23
|
-
private readonly _intervals;
|
|
24
|
-
private constructor();
|
|
25
|
-
static bottom(): Domain;
|
|
26
|
-
static fromIntervals(intervals: readonly Interval[] | ReadonlySet<Interval>): Domain;
|
|
27
|
-
static fromScalar(n: number): Domain;
|
|
28
|
-
get intervals(): Set<Interval>;
|
|
29
|
-
private set intervals(value);
|
|
30
|
-
addInterval(interval: Interval): void;
|
|
31
|
-
toString(): string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Returns true if the given intervals overlap, checking for inclusivity.
|
|
35
|
-
*/
|
|
36
|
-
export declare function doIntervalsOverlap(interval1: Interval, interval2: Interval): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Unifies the given domains by creating a new domain that contains all values from all given domains.
|
|
39
|
-
*/
|
|
40
|
-
export declare function unifyDomains(domains: readonly Domain[]): Domain;
|
|
41
|
-
/**
|
|
42
|
-
* Unify all intervals which overlap with each other to one.
|
|
43
|
-
*/
|
|
44
|
-
export declare function unifyOverlappingIntervals(intervals: readonly Interval[]): Interval[];
|
|
45
|
-
/**
|
|
46
|
-
* Returns domain1 + domain2, mapping the inclusivity.
|
|
47
|
-
*
|
|
48
|
-
* @see subtractDomains
|
|
49
|
-
*/
|
|
50
|
-
export declare function addDomains(domain1: Domain, domain2: Domain): Domain;
|
|
51
|
-
/**
|
|
52
|
-
* Returns domain1 - domain2, mapping the inclusivity.
|
|
53
|
-
*
|
|
54
|
-
* @see addDomains
|
|
55
|
-
*/
|
|
56
|
-
export declare function subtractDomains(domain1: Domain, domain2: Domain): Domain;
|
|
57
|
-
export {};
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.subtractDomains = exports.addDomains = exports.unifyOverlappingIntervals = exports.unifyDomains = exports.doIntervalsOverlap = exports.Domain = exports.Interval = void 0;
|
|
4
|
-
const assert_1 = require("../util/assert");
|
|
5
|
-
class Interval {
|
|
6
|
-
min;
|
|
7
|
-
max;
|
|
8
|
-
/**
|
|
9
|
-
* Build a new interval from the given bounds.
|
|
10
|
-
* If the interval represents a scalar, the min and max bounds should be equal, as well as their inclusivity.
|
|
11
|
-
* @param min - The minimum bound of the interval.
|
|
12
|
-
* @param max - The maximum bound of the interval.
|
|
13
|
-
*/
|
|
14
|
-
constructor(min, max) {
|
|
15
|
-
this.min = min;
|
|
16
|
-
this.max = max;
|
|
17
|
-
(0, assert_1.guard)(min.value <= max.value, () => `The interval ${this.toString()} has a minimum that is greater than its maximum`);
|
|
18
|
-
(0, assert_1.guard)(min.value !== max.value || (min.inclusive === max.inclusive), `The bound ${min.value} cannot be in- and exclusive at the same time`);
|
|
19
|
-
}
|
|
20
|
-
toString() {
|
|
21
|
-
return `${this.min.inclusive ? '[' : '('}${this.min.value}, ${this.max.value}${this.max.inclusive ? ']' : ')'}`;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.Interval = Interval;
|
|
25
|
-
/**
|
|
26
|
-
* A domain represents a set of intervals describing a range of possible values a variable may hold.
|
|
27
|
-
* In the future we may want to extend this to support more complex types.
|
|
28
|
-
*/
|
|
29
|
-
class Domain {
|
|
30
|
-
/** set of intervals to hold */
|
|
31
|
-
_intervals;
|
|
32
|
-
constructor(intervals = []) {
|
|
33
|
-
this._intervals = new Set(unifyOverlappingIntervals(intervals));
|
|
34
|
-
}
|
|
35
|
-
static bottom() {
|
|
36
|
-
return new Domain();
|
|
37
|
-
}
|
|
38
|
-
static fromIntervals(intervals) {
|
|
39
|
-
return new Domain(Array.from(intervals));
|
|
40
|
-
}
|
|
41
|
-
static fromScalar(n) {
|
|
42
|
-
return new Domain([new Interval({ value: n, inclusive: true }, { value: n, inclusive: true })]);
|
|
43
|
-
}
|
|
44
|
-
get intervals() {
|
|
45
|
-
return this._intervals;
|
|
46
|
-
}
|
|
47
|
-
set intervals(intervals) {
|
|
48
|
-
this._intervals.clear();
|
|
49
|
-
for (const interval of intervals) {
|
|
50
|
-
this._intervals.add(interval);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
addInterval(interval) {
|
|
54
|
-
this.intervals = unifyOverlappingIntervals([...this.intervals, interval]);
|
|
55
|
-
}
|
|
56
|
-
toString() {
|
|
57
|
-
return `{${Array.from(this.intervals).join(', ')}}`;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
exports.Domain = Domain;
|
|
61
|
-
function compareIntervals(compareType, interval1, interval2) {
|
|
62
|
-
const diff = interval1.value - interval2.value;
|
|
63
|
-
if (diff !== 0 || compareType === 2 /* CompareType.IgnoreInclusivity */) {
|
|
64
|
-
return diff;
|
|
65
|
-
}
|
|
66
|
-
switch (compareType) {
|
|
67
|
-
case 0 /* CompareType.Min */:
|
|
68
|
-
return Number(!interval1.inclusive) - Number(!interval2.inclusive);
|
|
69
|
-
case 1 /* CompareType.Max */:
|
|
70
|
-
return Number(interval1.inclusive) - Number(interval2.inclusive);
|
|
71
|
-
default:
|
|
72
|
-
(0, assert_1.assertUnreachable)(compareType);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function compareIntervalsByTheirMinimum(interval1, interval2) {
|
|
76
|
-
return compareIntervals(0 /* CompareType.Min */, interval1.min, interval2.min);
|
|
77
|
-
}
|
|
78
|
-
function compareIntervalsByTheirMaximum(interval1, interval2) {
|
|
79
|
-
return compareIntervals(1 /* CompareType.Max */, interval1.max, interval2.max);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Returns true if the given intervals overlap, checking for inclusivity.
|
|
83
|
-
*/
|
|
84
|
-
function doIntervalsOverlap(interval1, interval2) {
|
|
85
|
-
const diff1 = compareIntervals(2 /* CompareType.IgnoreInclusivity */, interval1.max, interval2.min);
|
|
86
|
-
const diff2 = compareIntervals(2 /* CompareType.IgnoreInclusivity */, interval2.max, interval1.min);
|
|
87
|
-
// If one interval ends before the other starts, they don't overlap
|
|
88
|
-
if (diff1 < 0 || diff2 < 0) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
// If their end and start are equal, they only overlap if both are inclusive
|
|
92
|
-
if (diff1 === 0) {
|
|
93
|
-
return interval1.max.inclusive && interval2.min.inclusive;
|
|
94
|
-
}
|
|
95
|
-
if (diff2 === 0) {
|
|
96
|
-
return interval2.max.inclusive && interval1.min.inclusive;
|
|
97
|
-
}
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
exports.doIntervalsOverlap = doIntervalsOverlap;
|
|
101
|
-
/**
|
|
102
|
-
* Unifies the given domains by creating a new domain that contains all values from all given domains.
|
|
103
|
-
*/
|
|
104
|
-
function unifyDomains(domains) {
|
|
105
|
-
const unifiedIntervals = unifyOverlappingIntervals(domains.flatMap(domain => Array.from(domain.intervals)));
|
|
106
|
-
return Domain.fromIntervals(unifiedIntervals);
|
|
107
|
-
}
|
|
108
|
-
exports.unifyDomains = unifyDomains;
|
|
109
|
-
/**
|
|
110
|
-
* Unify all intervals which overlap with each other to one.
|
|
111
|
-
*/
|
|
112
|
-
function unifyOverlappingIntervals(intervals) {
|
|
113
|
-
if (intervals.length === 0) {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
const sortedIntervals = [...intervals].sort(compareIntervalsByTheirMinimum);
|
|
117
|
-
const unifiedIntervals = [];
|
|
118
|
-
let currentInterval = sortedIntervals[0];
|
|
119
|
-
for (const nextInterval of sortedIntervals) {
|
|
120
|
-
if (doIntervalsOverlap(currentInterval, nextInterval)) {
|
|
121
|
-
const intervalWithEarlierStart = compareIntervalsByTheirMinimum(currentInterval, nextInterval) < 0 ? currentInterval : nextInterval;
|
|
122
|
-
const intervalWithLaterEnd = compareIntervalsByTheirMaximum(currentInterval, nextInterval) > 0 ? currentInterval : nextInterval;
|
|
123
|
-
currentInterval = new Interval(intervalWithEarlierStart.min, intervalWithLaterEnd.max);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
unifiedIntervals.push(currentInterval);
|
|
127
|
-
currentInterval = nextInterval;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
unifiedIntervals.push(currentInterval);
|
|
131
|
-
return unifiedIntervals;
|
|
132
|
-
}
|
|
133
|
-
exports.unifyOverlappingIntervals = unifyOverlappingIntervals;
|
|
134
|
-
/**
|
|
135
|
-
* Returns domain1 + domain2, mapping the inclusivity.
|
|
136
|
-
*
|
|
137
|
-
* @see subtractDomains
|
|
138
|
-
*/
|
|
139
|
-
function addDomains(domain1, domain2) {
|
|
140
|
-
const intervals = new Set();
|
|
141
|
-
for (const interval1 of domain1.intervals) {
|
|
142
|
-
for (const interval2 of domain2.intervals) {
|
|
143
|
-
intervals.add(new Interval({
|
|
144
|
-
value: interval1.min.value + interval2.min.value,
|
|
145
|
-
inclusive: interval1.min.inclusive && interval2.min.inclusive
|
|
146
|
-
}, {
|
|
147
|
-
value: interval1.max.value + interval2.max.value,
|
|
148
|
-
inclusive: interval1.max.inclusive && interval2.max.inclusive
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return Domain.fromIntervals(intervals);
|
|
153
|
-
}
|
|
154
|
-
exports.addDomains = addDomains;
|
|
155
|
-
/**
|
|
156
|
-
* Returns domain1 - domain2, mapping the inclusivity.
|
|
157
|
-
*
|
|
158
|
-
* @see addDomains
|
|
159
|
-
*/
|
|
160
|
-
function subtractDomains(domain1, domain2) {
|
|
161
|
-
const intervals = new Set();
|
|
162
|
-
for (const interval1 of domain1.intervals) {
|
|
163
|
-
for (const interval2 of domain2.intervals) {
|
|
164
|
-
intervals.add(new Interval({
|
|
165
|
-
value: interval1.min.value - interval2.max.value,
|
|
166
|
-
inclusive: interval1.min.inclusive && interval2.max.inclusive
|
|
167
|
-
}, {
|
|
168
|
-
value: interval1.max.value - interval2.min.value,
|
|
169
|
-
inclusive: interval1.max.inclusive && interval2.min.inclusive
|
|
170
|
-
}));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return Domain.fromIntervals(intervals);
|
|
174
|
-
}
|
|
175
|
-
exports.subtractDomains = subtractDomains;
|
|
176
|
-
//# sourceMappingURL=domain.js.map
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Handler } from '../handler';
|
|
2
|
-
import type { AINode } from '../../processor';
|
|
3
|
-
import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
4
|
-
import type { RBinaryOp } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-binary-op';
|
|
5
|
-
export type BinaryOpProcessor = (lhs: AINode, rhs: AINode, node: RBinaryOp<ParentInformation>) => AINode;
|
|
6
|
-
export declare class BinOp implements Handler<AINode> {
|
|
7
|
-
readonly node: RBinaryOp<ParentInformation>;
|
|
8
|
-
lhs: AINode | undefined;
|
|
9
|
-
rhs: AINode | undefined;
|
|
10
|
-
constructor(node: RBinaryOp<ParentInformation>);
|
|
11
|
-
getName(): string;
|
|
12
|
-
enter(): void;
|
|
13
|
-
exit(): AINode;
|
|
14
|
-
next(node: AINode): void;
|
|
15
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BinOp = void 0;
|
|
4
|
-
const processor_1 = require("../../processor");
|
|
5
|
-
const assert_1 = require("../../../util/assert");
|
|
6
|
-
const operators_1 = require("./operators");
|
|
7
|
-
class BinOp {
|
|
8
|
-
node;
|
|
9
|
-
lhs;
|
|
10
|
-
rhs;
|
|
11
|
-
constructor(node) {
|
|
12
|
-
this.node = node;
|
|
13
|
-
}
|
|
14
|
-
getName() {
|
|
15
|
-
return `Bin Op (${this.node.operator})`;
|
|
16
|
-
}
|
|
17
|
-
enter() {
|
|
18
|
-
processor_1.aiLogger.trace(`Entered ${this.getName()}`);
|
|
19
|
-
}
|
|
20
|
-
exit() {
|
|
21
|
-
processor_1.aiLogger.trace(`Exited ${this.getName()}`);
|
|
22
|
-
(0, assert_1.guard)(this.lhs !== undefined, `No LHS found for assignment ${this.node.info.id}`);
|
|
23
|
-
(0, assert_1.guard)(this.rhs !== undefined, `No RHS found for assignment ${this.node.info.id}`);
|
|
24
|
-
const processor = operators_1.operators[this.node.operator];
|
|
25
|
-
(0, assert_1.guard)(processor !== undefined, `No processor found for binary operator ${this.node.operator}`);
|
|
26
|
-
return processor(this.lhs, this.rhs, this.node);
|
|
27
|
-
}
|
|
28
|
-
next(node) {
|
|
29
|
-
processor_1.aiLogger.trace(`${this.getName()} received`);
|
|
30
|
-
if (this.lhs === undefined) {
|
|
31
|
-
this.lhs = node;
|
|
32
|
-
}
|
|
33
|
-
else if (this.rhs === undefined) {
|
|
34
|
-
this.rhs = node;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
(0, assert_1.guard)(false, `BinOp ${this.node.info.id} already has both LHS and RHS`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exports.BinOp = BinOp;
|
|
42
|
-
//# sourceMappingURL=binop.js.map
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.operators = void 0;
|
|
4
|
-
const domain_1 = require("../../domain");
|
|
5
|
-
exports.operators = {
|
|
6
|
-
'<-': (lhs, rhs, node) => {
|
|
7
|
-
return {
|
|
8
|
-
id: lhs.id,
|
|
9
|
-
domain: rhs.domain,
|
|
10
|
-
astNode: node.lhs,
|
|
11
|
-
};
|
|
12
|
-
},
|
|
13
|
-
'+': (lhs, rhs, node) => {
|
|
14
|
-
return {
|
|
15
|
-
id: lhs.id,
|
|
16
|
-
domain: (0, domain_1.addDomains)(lhs.domain, rhs.domain),
|
|
17
|
-
astNode: node,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
'-': (lhs, rhs, node) => {
|
|
21
|
-
return {
|
|
22
|
-
id: lhs.id,
|
|
23
|
-
domain: (0, domain_1.subtractDomains)(lhs.domain, rhs.domain),
|
|
24
|
-
astNode: node,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
//# sourceMappingURL=operators.js.map
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { DataflowInformation } from '../dataflow/info';
|
|
2
|
-
import { Domain } from './domain';
|
|
3
|
-
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
|
-
import type { NormalizedAst, ParentInformation, RNodeWithParent } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
|
-
export declare const aiLogger: import("tslog").Logger<import("tslog").ILogObj>;
|
|
6
|
-
export interface AINode {
|
|
7
|
-
readonly id: NodeId;
|
|
8
|
-
readonly domain: Domain;
|
|
9
|
-
readonly astNode: RNodeWithParent<ParentInformation>;
|
|
10
|
-
}
|
|
11
|
-
export declare function runAbstractInterpretation(ast: NormalizedAst, dfg: DataflowInformation): DataflowInformation;
|