@eagleoutice/flowr 2.2.16 → 2.3.0
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 +35 -19
- package/abstract-interpretation/data-frame/absint-info.d.ts +109 -0
- package/abstract-interpretation/data-frame/absint-info.js +31 -0
- package/abstract-interpretation/data-frame/absint-visitor.d.ts +59 -0
- package/abstract-interpretation/data-frame/absint-visitor.js +173 -0
- package/abstract-interpretation/data-frame/domain.d.ts +107 -0
- package/abstract-interpretation/data-frame/domain.js +315 -0
- package/abstract-interpretation/data-frame/mappers/access-mapper.d.ts +17 -0
- package/abstract-interpretation/data-frame/mappers/access-mapper.js +166 -0
- package/abstract-interpretation/data-frame/mappers/arguments.d.ts +117 -0
- package/abstract-interpretation/data-frame/mappers/arguments.js +188 -0
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.d.ts +20 -0
- package/abstract-interpretation/data-frame/mappers/assignment-mapper.js +34 -0
- package/abstract-interpretation/data-frame/mappers/function-mapper.d.ts +261 -0
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +1219 -0
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.d.ts +12 -0
- package/abstract-interpretation/data-frame/mappers/replacement-mapper.js +206 -0
- package/abstract-interpretation/data-frame/resolve-args.d.ts +42 -0
- package/abstract-interpretation/data-frame/resolve-args.js +118 -0
- package/abstract-interpretation/data-frame/semantics.d.ts +213 -0
- package/abstract-interpretation/data-frame/semantics.js +366 -0
- package/abstract-interpretation/data-frame/shape-inference.d.ts +38 -0
- package/abstract-interpretation/data-frame/shape-inference.js +117 -0
- package/benchmark/slicer.d.ts +15 -1
- package/benchmark/slicer.js +135 -0
- package/benchmark/stats/print.js +123 -45
- package/benchmark/stats/size-of.d.ts +7 -0
- package/benchmark/stats/size-of.js +1 -0
- package/benchmark/stats/stats.d.ts +30 -1
- package/benchmark/stats/stats.js +4 -2
- package/benchmark/summarizer/data.d.ts +33 -2
- package/benchmark/summarizer/first-phase/input.js +5 -1
- package/benchmark/summarizer/first-phase/process.js +47 -1
- package/benchmark/summarizer/second-phase/process.js +101 -3
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +1 -0
- package/cli/benchmark-helper-app.js +8 -2
- package/cli/common/options.js +2 -0
- package/config.d.ts +31 -0
- package/config.js +21 -1
- package/control-flow/control-flow-graph.d.ts +1 -0
- package/control-flow/control-flow-graph.js +4 -0
- package/control-flow/dfg-cfg-guided-visitor.js +1 -1
- package/control-flow/semantic-cfg-guided-visitor.d.ts +1 -1
- package/control-flow/semantic-cfg-guided-visitor.js +1 -1
- package/dataflow/environments/built-in.d.ts +5 -3
- package/dataflow/environments/built-in.js +3 -1
- package/dataflow/eval/resolve/alias-tracking.js +2 -2
- package/dataflow/eval/resolve/resolve.d.ts +53 -9
- package/dataflow/eval/resolve/resolve.js +132 -38
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +4 -0
- package/documentation/doc-util/doc-query.js +10 -0
- package/documentation/print-interface-wiki.js +11 -0
- package/documentation/print-linter-wiki.js +4 -0
- package/documentation/print-query-wiki.js +17 -0
- package/linter/linter-rules.d.ts +25 -2
- package/linter/linter-rules.js +3 -1
- package/linter/rules/absolute-path.d.ts +1 -1
- package/linter/rules/dataframe-access-validation.d.ts +53 -0
- package/linter/rules/dataframe-access-validation.js +116 -0
- package/linter/rules/naming-convention.d.ts +1 -1
- package/linter/rules/naming-convention.js +5 -1
- package/package.json +2 -2
- package/queries/catalog/df-shape-query/df-shape-query-executor.d.ts +3 -0
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +46 -0
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +72 -0
- package/queries/catalog/df-shape-query/df-shape-query-format.js +31 -0
- package/queries/query.d.ts +61 -1
- package/queries/query.js +2 -0
- package/util/files.d.ts +8 -2
- package/util/files.js +22 -4
- package/util/r-value.d.ts +23 -0
- package/util/r-value.js +113 -0
- package/util/version.js +1 -1
- package/util/cfg/cfg.d.ts +0 -0
- package/util/cfg/cfg.js +0 -2
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataFrameTop = exports.DataFrameBottom = exports.ColNamesTop = exports.ColNamesBottom = exports.IntervalTop = exports.IntervalBottom = void 0;
|
|
4
|
+
exports.equalColNames = equalColNames;
|
|
5
|
+
exports.leqColNames = leqColNames;
|
|
6
|
+
exports.joinColNames = joinColNames;
|
|
7
|
+
exports.meetColNames = meetColNames;
|
|
8
|
+
exports.subtractColNames = subtractColNames;
|
|
9
|
+
exports.wideningColNames = wideningColNames;
|
|
10
|
+
exports.satisfiesColsNames = satisfiesColsNames;
|
|
11
|
+
exports.equalInterval = equalInterval;
|
|
12
|
+
exports.leqInterval = leqInterval;
|
|
13
|
+
exports.joinInterval = joinInterval;
|
|
14
|
+
exports.meetInterval = meetInterval;
|
|
15
|
+
exports.addInterval = addInterval;
|
|
16
|
+
exports.subtractInterval = subtractInterval;
|
|
17
|
+
exports.minInterval = minInterval;
|
|
18
|
+
exports.maxInterval = maxInterval;
|
|
19
|
+
exports.extendIntervalToZero = extendIntervalToZero;
|
|
20
|
+
exports.extendIntervalToInfinity = extendIntervalToInfinity;
|
|
21
|
+
exports.wideningInterval = wideningInterval;
|
|
22
|
+
exports.satisfiesInterval = satisfiesInterval;
|
|
23
|
+
exports.satisfiesLeqInterval = satisfiesLeqInterval;
|
|
24
|
+
exports.equalDataFrameDomain = equalDataFrameDomain;
|
|
25
|
+
exports.joinDataFrames = joinDataFrames;
|
|
26
|
+
exports.meetDataFrames = meetDataFrames;
|
|
27
|
+
exports.wideningDataFrames = wideningDataFrames;
|
|
28
|
+
exports.equalDataFrameState = equalDataFrameState;
|
|
29
|
+
exports.joinDataFrameStates = joinDataFrameStates;
|
|
30
|
+
exports.meetDataFrameStates = meetDataFrameStates;
|
|
31
|
+
exports.wideningDataFrameStates = wideningDataFrameStates;
|
|
32
|
+
const config_1 = require("../../config");
|
|
33
|
+
const set_1 = require("../../util/collections/set");
|
|
34
|
+
const MaxColNames = config_1.defaultConfigOptions.abstractInterpretation.dataFrame.maxColNames;
|
|
35
|
+
/** The bottom element (least element) of the positive interval domain representing no possible values, explicitly given as "bottom". */
|
|
36
|
+
exports.IntervalBottom = 'bottom';
|
|
37
|
+
/** The top element (greatest element) of the positive interval domain representing all possible values, defined as the interval from 0 to infinity. */
|
|
38
|
+
exports.IntervalTop = [0, Infinity];
|
|
39
|
+
/** The bottom element (least element) of the column names domain representing no possible column name, defined as the empty list []. */
|
|
40
|
+
exports.ColNamesBottom = [];
|
|
41
|
+
/** The top element (greatest element) of the column names domain representing all possible values, explicitly given as "top". */
|
|
42
|
+
exports.ColNamesTop = 'top';
|
|
43
|
+
/**
|
|
44
|
+
* The bottom element (least element) of the data frame shape domain representing no possible value, mapping the columns names to {@link ColNamesBottom}
|
|
45
|
+
* and the number of columns and rows to {@link IntervalBottom}.
|
|
46
|
+
*/
|
|
47
|
+
exports.DataFrameBottom = {
|
|
48
|
+
colnames: exports.ColNamesBottom,
|
|
49
|
+
cols: exports.IntervalBottom,
|
|
50
|
+
rows: exports.IntervalBottom
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The top element (greatest element) of the data frame shape domain representing all possible value, mapping the columns names to {@link ColNamesTop}
|
|
54
|
+
* and the number of columns and rows to {@link IntervalTop}.
|
|
55
|
+
*/
|
|
56
|
+
exports.DataFrameTop = {
|
|
57
|
+
colnames: exports.ColNamesTop,
|
|
58
|
+
cols: exports.IntervalTop,
|
|
59
|
+
rows: exports.IntervalTop
|
|
60
|
+
};
|
|
61
|
+
/** Checks if two abstract values of the column names domain are equal. */
|
|
62
|
+
function equalColNames(set1, set2) {
|
|
63
|
+
return set1 === set2 || (set1 !== exports.ColNamesTop && set2 !== exports.ColNamesTop && (0, set_1.setEquals)(new Set(set1), new Set(set2)));
|
|
64
|
+
}
|
|
65
|
+
/** Checks if two abstract values of the column names domain are ordered according to the partial ordering of the column names lattice. */
|
|
66
|
+
function leqColNames(set1, set2) {
|
|
67
|
+
return set2 === exports.ColNamesTop || (set1 !== exports.ColNamesTop && new Set(set1).isSubsetOf(new Set(set2)));
|
|
68
|
+
}
|
|
69
|
+
/** Joins two abstract values of the columns names domain according to the column names lattice by creating the least upper bound (LUB). */
|
|
70
|
+
function joinColNames(set1, set2, maxColNames = MaxColNames) {
|
|
71
|
+
if (set1 === exports.ColNamesTop || set2 === exports.ColNamesTop) {
|
|
72
|
+
return exports.ColNamesTop;
|
|
73
|
+
}
|
|
74
|
+
const join = Array.from(new Set(set1).union(new Set(set2)));
|
|
75
|
+
return join.length > maxColNames ? exports.ColNamesTop : join;
|
|
76
|
+
}
|
|
77
|
+
/** Meets two abstract values of the columns names domain according to the column names lattice by creating the greatest lower bound (GLB). */
|
|
78
|
+
function meetColNames(set1, set2) {
|
|
79
|
+
if (set1 === exports.ColNamesTop) {
|
|
80
|
+
return set2;
|
|
81
|
+
}
|
|
82
|
+
else if (set2 === exports.ColNamesTop) {
|
|
83
|
+
return set1;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return Array.from(new Set(set1).intersection(new Set(set2)));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Subtracts an abstract value from another abstract value of the column names domain by performing a set minus. */
|
|
90
|
+
function subtractColNames(set1, set2) {
|
|
91
|
+
if (set1 === exports.ColNamesTop) {
|
|
92
|
+
return exports.ColNamesTop;
|
|
93
|
+
}
|
|
94
|
+
else if (set2 === exports.ColNamesTop) {
|
|
95
|
+
return set1;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return Array.from(new Set(set1).difference(new Set(set2)));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Widens two abstract values of the column names domain via naive widening to soundly over-approximate the join in (possibly infinite) fixpoint iterations.
|
|
103
|
+
*
|
|
104
|
+
* This is technically not necessary, as the join is limited by the maximum number of inferred column names.
|
|
105
|
+
* However, this speeds up the iteration in larger loops significantly, as we are over-approximating the column names much earlier.
|
|
106
|
+
*/
|
|
107
|
+
function wideningColNames(set1, set2) {
|
|
108
|
+
return leqColNames(set1, set2) ? set2 : exports.ColNamesTop;
|
|
109
|
+
}
|
|
110
|
+
/** Checks whether an abstract value of the column names domain satisfies a column name */
|
|
111
|
+
function satisfiesColsNames(set, value) {
|
|
112
|
+
return set === exports.ColNamesTop || set.includes(value);
|
|
113
|
+
}
|
|
114
|
+
/** Checks if two abstract values of the positive interval domain are equal. */
|
|
115
|
+
function equalInterval(interval1, interval2) {
|
|
116
|
+
return interval1 === interval2 || (interval1 !== exports.IntervalBottom && interval2 !== exports.IntervalBottom && interval1[0] === interval2[0] && interval1[1] === interval2[1]);
|
|
117
|
+
}
|
|
118
|
+
/** Checks if two abstract values of the positive interval domain are ordered according to the partial ordering of the positive interval lattice. */
|
|
119
|
+
function leqInterval(interval1, interval2) {
|
|
120
|
+
return interval1 === exports.IntervalBottom || (interval2 !== exports.IntervalBottom && interval2[0] <= interval1[0] && interval1[1] <= interval2[1]);
|
|
121
|
+
}
|
|
122
|
+
/** Joins two abstract values of the positive interval domain according to the positive interval lattice by creating the least upper bound (LUB). */
|
|
123
|
+
function joinInterval(interval1, interval2) {
|
|
124
|
+
if (interval1 === exports.IntervalBottom) {
|
|
125
|
+
return interval2;
|
|
126
|
+
}
|
|
127
|
+
else if (interval2 === exports.IntervalBottom) {
|
|
128
|
+
return interval1;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
return [Math.min(interval1[0], interval2[0]), Math.max(interval1[1], interval2[1])];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** Meets two abstract values of the positive interval domain according to the positive interval lattice by creating the greatest lower bound (GLB). */
|
|
135
|
+
function meetInterval(interval1, interval2) {
|
|
136
|
+
if (interval1 === exports.IntervalBottom || interval2 === exports.IntervalBottom) {
|
|
137
|
+
return exports.IntervalBottom;
|
|
138
|
+
}
|
|
139
|
+
else if (Math.max(interval1[0], interval2[0]) > Math.min(interval1[1], interval2[1])) {
|
|
140
|
+
return exports.IntervalBottom;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return [Math.max(interval1[0], interval2[0]), Math.min(interval1[1], interval2[1])];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Adds two abstract values of the positive interval domain, by adding the lower bounds and upper bounds. */
|
|
147
|
+
function addInterval(interval1, interval2) {
|
|
148
|
+
if (interval1 === exports.IntervalBottom || interval2 === exports.IntervalBottom) {
|
|
149
|
+
return exports.IntervalBottom;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
return [interval1[0] + interval2[0], interval1[1] + interval2[1]];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** Subtracts an abstract value from another abstract values of the positive interval domain, by subtracting the lower bounds and upper bounds. */
|
|
156
|
+
function subtractInterval(interval1, interval2) {
|
|
157
|
+
if (interval1 === exports.IntervalBottom || interval2 === exports.IntervalBottom) {
|
|
158
|
+
return exports.IntervalBottom;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
return [Math.max(interval1[0] - interval2[0], 0), Math.max(interval1[1] - interval2[1], 0)];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** Creates the minium of two abstract values of the positive interval domain, by creating the minimum of the lower bounds and upper bounds. */
|
|
165
|
+
function minInterval(interval1, interval2) {
|
|
166
|
+
if (interval1 === exports.IntervalBottom || interval2 === exports.IntervalBottom) {
|
|
167
|
+
return exports.IntervalBottom;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
return [Math.min(interval1[0], interval2[0]), Math.min(interval1[1], interval2[1])];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Creates the maximum of two abstract values of the positive interval domain, by creating the maximum of the lower bounds and upper bounds. */
|
|
174
|
+
function maxInterval(interval1, interval2) {
|
|
175
|
+
if (interval1 === exports.IntervalBottom || interval2 === exports.IntervalBottom) {
|
|
176
|
+
return exports.IntervalBottom;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
return [Math.max(interval1[0], interval2[0]), Math.max(interval1[1], interval2[1])];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Extrends the lower bound of an abstract value of the positive interval domain to 0. */
|
|
183
|
+
function extendIntervalToZero(interval) {
|
|
184
|
+
if (interval === exports.IntervalBottom) {
|
|
185
|
+
return exports.IntervalBottom;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
return [0, interval[1]];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/** Extrends the upper bound of an abstract value of the positive interval domain to infinity. */
|
|
192
|
+
function extendIntervalToInfinity(interval) {
|
|
193
|
+
if (interval === exports.IntervalBottom) {
|
|
194
|
+
return exports.IntervalBottom;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
return [interval[0], Infinity];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/** Widens two abstract values of the positive interval domain via naive widening to soundly over-approximate the join in (possibly infinite) fixpoint iterations. */
|
|
201
|
+
function wideningInterval(interval1, interval2) {
|
|
202
|
+
if (interval1 === exports.IntervalBottom) {
|
|
203
|
+
return interval2;
|
|
204
|
+
}
|
|
205
|
+
else if (interval2 === exports.IntervalBottom) {
|
|
206
|
+
return interval1;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
return [interval1[0] <= interval2[0] ? interval1[0] : 0, interval1[1] >= interval2[1] ? interval1[1] : Infinity];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Checks whether an abstract value of the positive interval domain satisfies a numeric value. */
|
|
213
|
+
function satisfiesInterval(interval, value) {
|
|
214
|
+
return interval !== exports.IntervalBottom && interval[0] <= value && value <= interval[1];
|
|
215
|
+
}
|
|
216
|
+
/** Checks whether a numeric value satisfies the less-than relation with an abstract value of the positive interval domain. */
|
|
217
|
+
function satisfiesLeqInterval(interval, value) {
|
|
218
|
+
return interval !== exports.IntervalBottom && value <= interval[1];
|
|
219
|
+
}
|
|
220
|
+
/** Checks if two abstract values of the data frame shape domain are equal. */
|
|
221
|
+
function equalDataFrameDomain(value1, value2) {
|
|
222
|
+
return value1 === value2 || (equalColNames(value1.colnames, value2.colnames) && equalInterval(value1.cols, value2.cols) && equalInterval(value1.rows, value2.rows));
|
|
223
|
+
}
|
|
224
|
+
/** Joins multiple abstract values of the data frame shape domain by creating the least upper bound (LUB). */
|
|
225
|
+
function joinDataFrames(...values) {
|
|
226
|
+
let result = values[0] ?? exports.DataFrameTop;
|
|
227
|
+
for (let i = 1; i < values.length; i++) {
|
|
228
|
+
result = {
|
|
229
|
+
colnames: joinColNames(result.colnames, values[i].colnames),
|
|
230
|
+
cols: joinInterval(result.cols, values[i].cols),
|
|
231
|
+
rows: joinInterval(result.rows, values[i].rows)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
/** Meets multiple abstract values of the data frame shape domain by creating the greatest lower bound (GLB). */
|
|
237
|
+
function meetDataFrames(...values) {
|
|
238
|
+
let result = values[0] ?? exports.DataFrameTop;
|
|
239
|
+
for (let i = 1; i < values.length; i++) {
|
|
240
|
+
result = {
|
|
241
|
+
colnames: meetColNames(result.colnames, values[i].colnames),
|
|
242
|
+
cols: meetInterval(result.cols, values[i].cols),
|
|
243
|
+
rows: meetInterval(result.rows, values[i].rows)
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
/** Widens two abstract values of the data frame shape domain by widening the column names and number of columns and rows. */
|
|
249
|
+
function wideningDataFrames(value1, value2) {
|
|
250
|
+
return {
|
|
251
|
+
colnames: wideningColNames(value1.colnames, value2.colnames),
|
|
252
|
+
cols: wideningInterval(value1.cols, value2.cols),
|
|
253
|
+
rows: wideningInterval(value1.rows, value2.rows)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/** Checks if two abstract states of the data frame shape state domain are equal. */
|
|
257
|
+
function equalDataFrameState(state1, state2) {
|
|
258
|
+
if (state1 === state2) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
else if (state1.size !== state2.size) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
for (const [nodeId, value] of state1) {
|
|
265
|
+
const other = state2.get(nodeId);
|
|
266
|
+
if (other === undefined || !equalDataFrameDomain(value, other)) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
/** Joins multiple abstract states of the data frame shape state domain by joining each data frame shape of the states. */
|
|
273
|
+
function joinDataFrameStates(...states) {
|
|
274
|
+
const result = new Map(states[0]);
|
|
275
|
+
for (let i = 1; i < states.length; i++) {
|
|
276
|
+
for (const [nodeId, value] of states[i]) {
|
|
277
|
+
if (result.has(nodeId)) {
|
|
278
|
+
result.set(nodeId, joinDataFrames(result.get(nodeId) ?? exports.DataFrameTop, value));
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
result.set(nodeId, value);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
/** Meets multiple abstract states of the data frame shape state domain by meeting each data frame shape of the states. */
|
|
288
|
+
function meetDataFrameStates(...states) {
|
|
289
|
+
const result = new Map(states[0]);
|
|
290
|
+
for (let i = 1; i < states.length; i++) {
|
|
291
|
+
for (const [nodeId, value] of states[i]) {
|
|
292
|
+
if (result.has(nodeId)) {
|
|
293
|
+
result.set(nodeId, meetDataFrames(result.get(nodeId) ?? exports.DataFrameTop, value));
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
result.set(nodeId, value);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
/** Widens two abstract states of the data frame shape state domain by widening each data frame shape of the states. */
|
|
303
|
+
function wideningDataFrameStates(state1, state2) {
|
|
304
|
+
const result = new Map(state1);
|
|
305
|
+
for (const [nodeId, value] of state2) {
|
|
306
|
+
if (result.has(nodeId)) {
|
|
307
|
+
result.set(nodeId, wideningDataFrames(result.get(nodeId) ?? exports.DataFrameTop, value));
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
result.set(nodeId, value);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DataflowGraph } from '../../../dataflow/graph/graph';
|
|
2
|
+
import type { RNode } from '../../../r-bridge/lang-4.x/ast/model/model';
|
|
3
|
+
import type { RAccess, RNamedAccess } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-access';
|
|
4
|
+
import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
|
+
import type { DataFrameExpressionInfo } from '../absint-info';
|
|
6
|
+
/**
|
|
7
|
+
* Maps a concrete data frame access to abstract data frame operations.
|
|
8
|
+
*
|
|
9
|
+
* @param node - The R node of the access
|
|
10
|
+
* @param dfg - The data flow graph for resolving the arguments
|
|
11
|
+
* @returns Data frame expression info containing the mapped abstract data frame operations, or `undefined` if the node does not represent a data frame access
|
|
12
|
+
*/
|
|
13
|
+
export declare function mapDataFrameAccess(node: RNode<ParentInformation>, dfg: DataflowGraph): DataFrameExpressionInfo | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Checks whether an access node represents a string-based access (`$` or `@`), and no index-based access (`[` or `[[`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function isStringBasedAccess(access: RAccess<ParentInformation>): access is RNamedAccess<ParentInformation>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapDataFrameAccess = mapDataFrameAccess;
|
|
4
|
+
exports.isStringBasedAccess = isStringBasedAccess;
|
|
5
|
+
const config_1 = require("../../../config");
|
|
6
|
+
const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
7
|
+
const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
|
|
8
|
+
const resolve_args_1 = require("../resolve-args");
|
|
9
|
+
const arguments_1 = require("./arguments");
|
|
10
|
+
/**
|
|
11
|
+
* Special named arguments of index-based access operators
|
|
12
|
+
*/
|
|
13
|
+
const SpecialAccessArgumentsMapper = {
|
|
14
|
+
'[': ['drop'],
|
|
15
|
+
'[[': ['exact']
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Maps a concrete data frame access to abstract data frame operations.
|
|
19
|
+
*
|
|
20
|
+
* @param node - The R node of the access
|
|
21
|
+
* @param dfg - The data flow graph for resolving the arguments
|
|
22
|
+
* @returns Data frame expression info containing the mapped abstract data frame operations, or `undefined` if the node does not represent a data frame access
|
|
23
|
+
*/
|
|
24
|
+
function mapDataFrameAccess(node, dfg) {
|
|
25
|
+
if (node.type !== type_1.RType.Access) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const resolveInfo = { graph: dfg, idMap: dfg.idMap, full: true, resolve: config_1.VariableResolve.Alias };
|
|
29
|
+
let operations;
|
|
30
|
+
if (isStringBasedAccess(node)) {
|
|
31
|
+
operations = mapDataFrameNamedColumnAccess(node, resolveInfo);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
operations = mapDataFrameIndexColRowAccess(node, resolveInfo);
|
|
35
|
+
}
|
|
36
|
+
if (operations !== undefined) {
|
|
37
|
+
return { type: 'expression', operations: operations };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function mapDataFrameNamedColumnAccess(access, info) {
|
|
41
|
+
const dataFrame = access.accessed;
|
|
42
|
+
if (!(0, arguments_1.isDataFrameArgument)(dataFrame, info)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const colname = (0, resolve_args_1.resolveIdToArgValueSymbolName)(access.access[0], info);
|
|
46
|
+
return [{
|
|
47
|
+
operation: 'accessCols',
|
|
48
|
+
operand: dataFrame.info.id,
|
|
49
|
+
columns: colname ? [colname] : undefined
|
|
50
|
+
}];
|
|
51
|
+
}
|
|
52
|
+
function mapDataFrameIndexColRowAccess(access, info) {
|
|
53
|
+
const dataFrame = access.accessed;
|
|
54
|
+
const drop = (0, arguments_1.getArgumentValue)(access.access, 'drop', info);
|
|
55
|
+
const exact = (0, arguments_1.getArgumentValue)(access.access, 'exact', info);
|
|
56
|
+
const args = getAccessArgs(access.operator, access.access);
|
|
57
|
+
if (!(0, arguments_1.isDataFrameArgument)(dataFrame, info)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
else if (args.every(arg => arg === r_function_call_1.EmptyArgument)) {
|
|
61
|
+
return [{ operation: 'identity', operand: dataFrame.info.id }];
|
|
62
|
+
}
|
|
63
|
+
const result = [];
|
|
64
|
+
const rowArg = args.length < 2 ? undefined : args[0];
|
|
65
|
+
const colArg = args.length < 2 ? args[0] : args[1];
|
|
66
|
+
let rows = undefined;
|
|
67
|
+
let columns = undefined;
|
|
68
|
+
if (rowArg !== undefined && rowArg !== r_function_call_1.EmptyArgument) {
|
|
69
|
+
const rowValue = (0, resolve_args_1.resolveIdToArgValue)(rowArg, info);
|
|
70
|
+
if (typeof rowValue === 'number') {
|
|
71
|
+
rows = [rowValue];
|
|
72
|
+
}
|
|
73
|
+
else if (Array.isArray(rowValue) && rowValue.every(row => typeof row === 'number')) {
|
|
74
|
+
rows = rowValue;
|
|
75
|
+
}
|
|
76
|
+
result.push({
|
|
77
|
+
operation: 'accessRows',
|
|
78
|
+
operand: dataFrame.info.id,
|
|
79
|
+
rows: rows?.map(Math.abs)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (colArg !== undefined && colArg !== r_function_call_1.EmptyArgument) {
|
|
83
|
+
const colValue = (0, resolve_args_1.resolveIdToArgValue)(colArg, info);
|
|
84
|
+
if (typeof colValue === 'number') {
|
|
85
|
+
columns = [colValue];
|
|
86
|
+
}
|
|
87
|
+
else if (typeof colValue === 'string' && exact !== false) {
|
|
88
|
+
columns = [colValue];
|
|
89
|
+
}
|
|
90
|
+
else if (Array.isArray(colValue) && colValue.every(col => typeof col === 'number')) {
|
|
91
|
+
columns = colValue;
|
|
92
|
+
}
|
|
93
|
+
else if (Array.isArray(colValue) && colValue.every(col => typeof col === 'string') && exact !== false) {
|
|
94
|
+
columns = colValue;
|
|
95
|
+
}
|
|
96
|
+
result.push({
|
|
97
|
+
operation: 'accessCols',
|
|
98
|
+
operand: dataFrame.info.id,
|
|
99
|
+
columns: columns?.every(col => typeof col === 'number') ? columns.map(Math.abs) : columns
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// The data frame extent is dropped if the operator `[[` is used, the argument `drop` is true, or only one column is accessed
|
|
103
|
+
const dropExtent = access.operator === '[[' ? true :
|
|
104
|
+
args.length === 2 && typeof drop === 'boolean' ? drop :
|
|
105
|
+
rowArg !== undefined && columns?.length === 1 && (typeof columns[0] === 'string' || columns[0] > 0);
|
|
106
|
+
if (!dropExtent) {
|
|
107
|
+
const rowSubset = rows === undefined || rows.every(row => row >= 0);
|
|
108
|
+
const colSubset = columns === undefined || columns.every(col => typeof col === 'string' || col >= 0);
|
|
109
|
+
const rowZero = rows?.length === 1 && rows[0] === 0;
|
|
110
|
+
const colZero = columns?.length === 1 && columns[0] === 0;
|
|
111
|
+
const duplicateRows = rows?.some((row, index, list) => list.indexOf(row) !== index);
|
|
112
|
+
const duplicateCols = columns?.some((col, index, list) => list.indexOf(col) !== index);
|
|
113
|
+
let operand = dataFrame;
|
|
114
|
+
if (rowArg !== undefined && rowArg !== r_function_call_1.EmptyArgument) {
|
|
115
|
+
if (rowSubset) {
|
|
116
|
+
result.push({
|
|
117
|
+
operation: 'subsetRows',
|
|
118
|
+
operand: operand?.info.id,
|
|
119
|
+
rows: rowZero ? 0 : rows?.filter(index => index !== 0).length,
|
|
120
|
+
...(duplicateRows ? { options: { duplicateRows: true } } : {})
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
result.push({
|
|
125
|
+
operation: 'removeRows',
|
|
126
|
+
operand: operand?.info.id,
|
|
127
|
+
rows: rowZero ? 0 : rows?.filter(index => index !== 0).length
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
operand = undefined;
|
|
131
|
+
}
|
|
132
|
+
if (colArg !== undefined && colArg !== r_function_call_1.EmptyArgument) {
|
|
133
|
+
if (colSubset) {
|
|
134
|
+
result.push({
|
|
135
|
+
operation: 'subsetCols',
|
|
136
|
+
operand: operand?.info.id,
|
|
137
|
+
colnames: colZero ? [] : columns?.map(col => typeof col === 'string' ? col : undefined),
|
|
138
|
+
...(duplicateCols ? { options: { duplicateCols: true } } : {})
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
result.push({
|
|
143
|
+
operation: 'removeCols',
|
|
144
|
+
operand: operand?.info.id,
|
|
145
|
+
colnames: columns?.map(col => typeof col === 'string' ? col : undefined)
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
operand = undefined;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Removes all special named arguments from the arguments of an access operator (i.e. arguments like "drop" and "exact").
|
|
155
|
+
*/
|
|
156
|
+
function getAccessArgs(operator, args) {
|
|
157
|
+
const specialArgs = SpecialAccessArgumentsMapper[operator];
|
|
158
|
+
return args.filter(arg => arg === r_function_call_1.EmptyArgument || arg.name === undefined || !specialArgs.includes((0, resolve_args_1.unquoteArgument)(arg.name.content)));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Checks whether an access node represents a string-based access (`$` or `@`), and no index-based access (`[` or `[[`).
|
|
162
|
+
*/
|
|
163
|
+
function isStringBasedAccess(access) {
|
|
164
|
+
return access.operator === '$' || access.operator === '@';
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=access-mapper.js.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { ResolveInfo } from '../../../dataflow/eval/resolve/alias-tracking';
|
|
2
|
+
import type { DataflowGraph } from '../../../dataflow/graph/graph';
|
|
3
|
+
import type { RNode } from '../../../r-bridge/lang-4.x/ast/model/model';
|
|
4
|
+
import type { RArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-argument';
|
|
5
|
+
import type { RFunctionArgument, RFunctionCall } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
6
|
+
import { EmptyArgument } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
|
|
7
|
+
import type { RSymbol } from '../../../r-bridge/lang-4.x/ast/model/nodes/r-symbol';
|
|
8
|
+
import type { ParentInformation } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
9
|
+
import { RNull } from '../../../r-bridge/lang-4.x/convert-values';
|
|
10
|
+
import type { AbstractInterpretationInfo } from '../absint-info';
|
|
11
|
+
/**
|
|
12
|
+
* The location of a function parameter for mapping function call arguments to function parameters.
|
|
13
|
+
* - `pos` contains the position of the function parameter (use `-1` for non-existent or non-positional arguments)
|
|
14
|
+
* - `name` optionally contains the name of the function parameter
|
|
15
|
+
* - `default` optionally contains the default value of the function parameter
|
|
16
|
+
*/
|
|
17
|
+
export interface FunctionParameterLocation<T = never> {
|
|
18
|
+
pos: number;
|
|
19
|
+
name?: string;
|
|
20
|
+
default?: T;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Escapes a regular expression given as string by escaping all special regular expression characters.
|
|
24
|
+
*
|
|
25
|
+
* @param text - The text to escape
|
|
26
|
+
* @param allowTokens - Whether to allow and keep unescaped tokens like `\s`, `\t`, or `\n`
|
|
27
|
+
* @returns The escaped text
|
|
28
|
+
*/
|
|
29
|
+
export declare function escapeRegExp(text: string, allowTokens?: boolean): string;
|
|
30
|
+
/**
|
|
31
|
+
* Maps all invalid, duplicate, or empty column names to top depending on the provided arguments.
|
|
32
|
+
*
|
|
33
|
+
* @param colnames - The columns names to filter
|
|
34
|
+
* @param checkNames - Whether to map all invalid column names to top (`undefined`)
|
|
35
|
+
* @param noDupNames - Whether to map all duplicate column names to top (`undefined`)
|
|
36
|
+
* @param noEmptyNames - Whether to map all empty column names to top (`undefined`)
|
|
37
|
+
* @returns The filtered column names
|
|
38
|
+
*/
|
|
39
|
+
export declare function filterValidNames(colnames: (string | undefined)[] | undefined, checkNames?: boolean, noDupNames?: boolean, noEmptyNames?: boolean): (string | undefined)[] | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Gets the value of an argument that specified as {@link FunctionParameterLocation}.
|
|
42
|
+
*
|
|
43
|
+
* @param args - The arguments to get the requested argument from
|
|
44
|
+
* @param argument - The specification of the argument to get the value for
|
|
45
|
+
* @param info - Argument resolve information
|
|
46
|
+
* @returns The resolved value of the argument or `undefined`
|
|
47
|
+
*/
|
|
48
|
+
export declare function getArgumentValue<T>(args: readonly RFunctionArgument<ParentInformation>[], argument: FunctionParameterLocation<T> | string, info: ResolveInfo): string | number | boolean | (string | number | boolean)[] | T | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Gets all effective argument from a list of arguments by removing all arguments whose names should be excluded.
|
|
51
|
+
*
|
|
52
|
+
* @param args - The list of arguments to filter
|
|
53
|
+
* @param excluded - The names of the arguments to exclude
|
|
54
|
+
* @returns The filtered list of arguments
|
|
55
|
+
*/
|
|
56
|
+
export declare function getEffectiveArgs(args: readonly RFunctionArgument<ParentInformation>[], excluded: string[]): readonly RFunctionArgument<ParentInformation>[];
|
|
57
|
+
/**
|
|
58
|
+
* Gets an argument specified as {@link FunctionParameterLocation} from a list of arguments.
|
|
59
|
+
*
|
|
60
|
+
* @param args - The arguments to get the requested argument from
|
|
61
|
+
* @param argument - The specification of the argument to get
|
|
62
|
+
* @param info - Argument resolve information
|
|
63
|
+
* @returns An argument matching the specified `argument` or `undefined`
|
|
64
|
+
*/
|
|
65
|
+
export declare function getFunctionArgument(args: readonly RFunctionArgument<ParentInformation>[], argument: FunctionParameterLocation<unknown> | string, info: ResolveInfo): RFunctionArgument<ParentInformation> | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Get all function arguments of a function call node in the data flow graph.
|
|
68
|
+
*
|
|
69
|
+
* @param node - The function call node to get the arguments for
|
|
70
|
+
* @param dfg - The data flow graph for retrieving the arguments
|
|
71
|
+
* @returns The arguments of the function call in the data flow graph
|
|
72
|
+
*/
|
|
73
|
+
export declare function getFunctionArguments(node: RFunctionCall<ParentInformation>, dfg: DataflowGraph): readonly RFunctionArgument<ParentInformation>[];
|
|
74
|
+
/**
|
|
75
|
+
* Gets all nested symbols in an expression that have no outgoing edges in the data flow graph.
|
|
76
|
+
* @param expression - The expression to get the symbols from
|
|
77
|
+
* @param dfg - The data flow graph for checking the outgoing edges
|
|
78
|
+
* @returns The name of all unresolved symbols in the expression
|
|
79
|
+
*/
|
|
80
|
+
export declare function getUnresolvedSymbolsInExpression(expression: RNode<ParentInformation> | typeof EmptyArgument | undefined, dfg?: DataflowGraph): string[];
|
|
81
|
+
/**
|
|
82
|
+
* Checks whether a list of arguments contains any critical argument.
|
|
83
|
+
*
|
|
84
|
+
* @param args - The list of arguments to check
|
|
85
|
+
* @param critical - The critical arguments to search for (as string or {@link FunctionParameterLocation}s)
|
|
86
|
+
* @param info - Argument resolve information
|
|
87
|
+
* @returns Whether the arguments contain any critical argument
|
|
88
|
+
*/
|
|
89
|
+
export declare function hasCriticalArgument(args: readonly RFunctionArgument<ParentInformation>[], critical: (FunctionParameterLocation<unknown> | string)[] | undefined, info: ResolveInfo): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Checks if a given argument has any data frame shape information and therefore may represent a data frame.
|
|
92
|
+
*
|
|
93
|
+
* @param arg - The argument to check
|
|
94
|
+
* @param info - Argument resolve information
|
|
95
|
+
* @returns Whether the argument has any data frame shape information and may represent a data frame
|
|
96
|
+
*/
|
|
97
|
+
export declare function isDataFrameArgument(arg: RNode<ParentInformation> | undefined, info: ResolveInfo): arg is RNode<ParentInformation & Required<AbstractInterpretationInfo>>;
|
|
98
|
+
export declare function isDataFrameArgument(arg: RFunctionArgument<ParentInformation> | undefined, info: ResolveInfo): arg is RArgument<ParentInformation & Required<AbstractInterpretationInfo>> & {
|
|
99
|
+
value: RNode<ParentInformation & Required<AbstractInterpretationInfo>>;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Checks whether a function argument is a names argument.
|
|
103
|
+
*/
|
|
104
|
+
export declare function isNamedArgument(arg: RFunctionArgument<ParentInformation> | undefined): arg is RArgument<ParentInformation> & {
|
|
105
|
+
name: RSymbol<ParentInformation>;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Checks whether a node is `NULL` in R (represents a `NULL` symbol).
|
|
109
|
+
*/
|
|
110
|
+
export declare function isRNull(node: RNode<ParentInformation> | undefined): node is RSymbol<ParentInformation, typeof RNull>;
|
|
111
|
+
export declare function isRNull(node: RFunctionArgument<ParentInformation> | undefined): node is RArgument<ParentInformation> & {
|
|
112
|
+
value: RSymbol<ParentInformation, typeof RNull>;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Checks whether a string is a valid columns name according to the flag `check.names` in R.
|
|
116
|
+
*/
|
|
117
|
+
export declare function isValidColName(colname: string | undefined): boolean;
|