@eagleoutice/flowr 2.9.8 → 2.9.10
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 +34 -29
- package/abstract-interpretation/absint-visitor.d.ts +16 -14
- package/abstract-interpretation/absint-visitor.js +91 -46
- package/abstract-interpretation/data-frame/shape-inference.d.ts +2 -5
- package/abstract-interpretation/data-frame/shape-inference.js +4 -5
- package/abstract-interpretation/domains/abstract-domain.d.ts +4 -4
- package/abstract-interpretation/domains/abstract-domain.js +8 -8
- package/abstract-interpretation/domains/mapped-abstract-domain.d.ts +12 -5
- package/abstract-interpretation/domains/mapped-abstract-domain.js +47 -23
- package/abstract-interpretation/domains/state-abstract-domain.d.ts +30 -1
- package/abstract-interpretation/domains/state-abstract-domain.js +130 -4
- package/control-flow/cfg-simplification.d.ts +1 -0
- package/control-flow/cfg-simplification.js +1 -0
- package/control-flow/extract-cfg.js +33 -15
- package/control-flow/semantic-cfg-guided-visitor.js +1 -0
- package/dataflow/environments/built-in.d.ts +4 -0
- package/dataflow/environments/built-in.js +17 -5
- package/dataflow/environments/default-builtin-config.d.ts +4 -8
- package/dataflow/environments/default-builtin-config.js +8 -5
- package/dataflow/environments/reference-to-maybe.d.ts +8 -0
- package/dataflow/environments/reference-to-maybe.js +46 -3
- package/dataflow/eval/resolve/alias-tracking.d.ts +1 -1
- package/dataflow/eval/resolve/alias-tracking.js +4 -5
- package/dataflow/eval/resolve/resolve.js +8 -7
- package/dataflow/graph/graph.d.ts +1 -1
- package/dataflow/graph/graph.js +9 -10
- package/dataflow/graph/unknown-side-effect.js +3 -1
- package/dataflow/info.d.ts +4 -0
- package/dataflow/info.js +2 -2
- package/dataflow/internal/linker.d.ts +2 -2
- package/dataflow/internal/linker.js +52 -27
- package/dataflow/internal/process/functions/call/argument/make-argument.js +2 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +15 -6
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-s-seven-new-generic.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -11
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +22 -19
- package/dataflow/internal/process/functions/call/known-call-handling.js +0 -2
- package/documentation/wiki-absint.js +7 -8
- package/linter/rules/dead-code.js +1 -1
- package/linter/rules/seeded-randomness.js +1 -1
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +7 -7
- package/project/context/flowr-file.d.ts +5 -0
- package/project/context/flowr-file.js +7 -0
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +5 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +9 -0
- package/project/plugins/file-plugins/files/flowr-namespace-file.d.ts +4 -0
- package/project/plugins/file-plugins/files/flowr-namespace-file.js +8 -0
- package/project/plugins/file-plugins/files/flowr-news-file.d.ts +4 -0
- package/project/plugins/file-plugins/files/flowr-news-file.js +8 -0
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-format.js +3 -3
- package/r-bridge/lang-4.x/ast/model/processing/decorate.js +23 -17
- package/r-bridge/lang-4.x/ast/model/processing/role.d.ts +18 -17
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +31 -13
- package/statistics/features/supported/data-access/data-access.js +2 -2
- package/util/mermaid/ast.js +1 -1
- package/util/mermaid/dfg.js +6 -5
- package/util/version.js +1 -1
|
@@ -48,19 +48,19 @@ class AbstractDomain {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Joins an array of abstract values by joining the first abstract value with the other values in the array.
|
|
51
|
-
* The provided array of abstract values
|
|
51
|
+
* The provided array of abstract values must not be empty or a default value must be provided!
|
|
52
52
|
*/
|
|
53
|
-
static joinAll(values) {
|
|
54
|
-
(0, assert_1.guard)(values.length > 0, 'Abstract values to join cannot be empty');
|
|
55
|
-
return values[0]
|
|
53
|
+
static joinAll(values, defaultValue) {
|
|
54
|
+
(0, assert_1.guard)(values.length > 0 || defaultValue !== undefined, 'Abstract values to join cannot be empty');
|
|
55
|
+
return values[0]?.joinAll(values.slice(1)) ?? defaultValue;
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Meets an array of abstract values by meeting the first abstract value with the other values in the array.
|
|
59
|
-
* The provided array of abstract values
|
|
59
|
+
* The provided array of abstract values must not be empty or a default value must be provided!
|
|
60
60
|
*/
|
|
61
|
-
static meetAll(values) {
|
|
62
|
-
(0, assert_1.guard)(values.length > 0, 'Abstract values to meet cannot be empty');
|
|
63
|
-
return values[0]
|
|
61
|
+
static meetAll(values, defaultValue) {
|
|
62
|
+
(0, assert_1.guard)(values.length > 0 || defaultValue !== undefined, 'Abstract values to meet cannot be empty');
|
|
63
|
+
return values[0]?.meetAll(values.slice(1)) ?? defaultValue;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
exports.AbstractDomain = AbstractDomain;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { AbstractDomain, type AnyAbstractDomain, type ConcreteDomain } from './abstract-domain';
|
|
2
2
|
import { Top } from './lattice';
|
|
3
3
|
/** The type of the concrete mapping of the concrete domain of a mapped abstract domain mapping keys to a concrete value in the concrete domain */
|
|
4
|
-
type ConcreteMap<Key, Domain extends AnyAbstractDomain> = ReadonlyMap<Key, ConcreteDomain<Domain>>;
|
|
4
|
+
export type ConcreteMap<Key, Domain extends AnyAbstractDomain> = ReadonlyMap<Key, ConcreteDomain<Domain>>;
|
|
5
5
|
/**
|
|
6
6
|
* A mapped abstract domain as mapping of keys to abstract values of an abstract domain.
|
|
7
7
|
* The Bottom element is defined as empty mapping and the Top element is defined as mapping every existing key to Top.
|
|
8
8
|
* @template Key - Type of the keys of the mapping to abstract values
|
|
9
9
|
* @template Domain - Type of the abstract domain to map the keys to
|
|
10
10
|
*/
|
|
11
|
-
export declare
|
|
11
|
+
export declare class MappedAbstractDomain<Key, Domain extends AnyAbstractDomain> extends AbstractDomain<ConcreteMap<Key, Domain>, ReadonlyMap<Key, Domain>, ReadonlyMap<Key, Domain>, ReadonlyMap<Key, Domain>> {
|
|
12
12
|
constructor(value: ReadonlyMap<Key, Domain>);
|
|
13
|
-
|
|
13
|
+
create(value: ReadonlyMap<Key, Domain>): this;
|
|
14
14
|
get(key: Key): Domain | undefined;
|
|
15
15
|
has(key: Key): boolean;
|
|
16
|
-
set(key: Key, value: Domain): void;
|
|
16
|
+
protected set(key: Key, value: Domain): void;
|
|
17
17
|
protected remove(key: Key): void;
|
|
18
18
|
bottom(): this;
|
|
19
19
|
top(): this;
|
|
@@ -31,4 +31,11 @@ export declare abstract class MappedAbstractDomain<Key, Domain extends AnyAbstra
|
|
|
31
31
|
isBottom(): this is this;
|
|
32
32
|
isValue(): this is this;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* A mutable version of the {@link MappedAbstractDomain} with {@link MutableMappedAbstractDomain#set|`set`} and {@link MutableMappedAbstractDomain#remove|`remove`}.
|
|
36
|
+
*/
|
|
37
|
+
export declare class MutableMappedAbstractDomain<Key, Domain extends AnyAbstractDomain> extends MappedAbstractDomain<Key, Domain> {
|
|
38
|
+
create(value: ReadonlyMap<Key, Domain>): this;
|
|
39
|
+
set(key: Key, value: Domain): void;
|
|
40
|
+
remove(key: Key): void;
|
|
41
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MappedAbstractDomain = void 0;
|
|
3
|
+
exports.MutableMappedAbstractDomain = exports.MappedAbstractDomain = void 0;
|
|
4
4
|
const abstract_domain_1 = require("./abstract-domain");
|
|
5
5
|
const lattice_1 = require("./lattice");
|
|
6
6
|
/**
|
|
@@ -13,6 +13,9 @@ class MappedAbstractDomain extends abstract_domain_1.AbstractDomain {
|
|
|
13
13
|
constructor(value) {
|
|
14
14
|
super(new Map(value));
|
|
15
15
|
}
|
|
16
|
+
create(value) {
|
|
17
|
+
return new MappedAbstractDomain(value);
|
|
18
|
+
}
|
|
16
19
|
get(key) {
|
|
17
20
|
return this._value.get(key);
|
|
18
21
|
}
|
|
@@ -122,50 +125,56 @@ class MappedAbstractDomain extends abstract_domain_1.AbstractDomain {
|
|
|
122
125
|
return result;
|
|
123
126
|
}
|
|
124
127
|
concretize(limit) {
|
|
125
|
-
if (this.value.
|
|
128
|
+
if (this.value.size === 0) {
|
|
126
129
|
return new Set();
|
|
127
130
|
}
|
|
128
|
-
let
|
|
131
|
+
let mappings = new Set([new Map()]);
|
|
129
132
|
for (const [key, value] of this.value) {
|
|
130
133
|
const concreteValues = value.concretize(limit);
|
|
131
134
|
if (concreteValues === lattice_1.Top) {
|
|
132
135
|
return lattice_1.Top;
|
|
133
136
|
}
|
|
134
|
-
const
|
|
135
|
-
for (const state of
|
|
137
|
+
const newMappings = new Set();
|
|
138
|
+
for (const state of mappings) {
|
|
136
139
|
for (const concrete of concreteValues) {
|
|
137
|
-
if (
|
|
140
|
+
if (newMappings.size > limit) {
|
|
138
141
|
return lattice_1.Top;
|
|
139
142
|
}
|
|
140
143
|
const map = new Map(state);
|
|
141
144
|
map.set(key, concrete);
|
|
142
|
-
|
|
145
|
+
newMappings.add(map);
|
|
143
146
|
}
|
|
144
147
|
}
|
|
145
|
-
|
|
148
|
+
mappings = newMappings;
|
|
146
149
|
}
|
|
147
|
-
return
|
|
150
|
+
return mappings;
|
|
148
151
|
}
|
|
149
152
|
abstract(concrete) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
153
|
+
if (concrete === lattice_1.Top) {
|
|
154
|
+
return this.top();
|
|
155
|
+
}
|
|
156
|
+
else if (concrete.size === 0) {
|
|
157
|
+
return this.bottom();
|
|
158
|
+
}
|
|
159
|
+
const domain = this.value.values().toArray()[0];
|
|
160
|
+
if (domain === undefined) {
|
|
161
|
+
return this.top();
|
|
162
|
+
}
|
|
163
|
+
const mapping = new Map();
|
|
164
|
+
for (const concreteMapping of concrete) {
|
|
165
|
+
for (const [key, value] of concreteMapping) {
|
|
166
|
+
const set = mapping.get(key);
|
|
167
|
+
if (set === undefined) {
|
|
168
|
+
mapping.set(key, new Set([value]));
|
|
160
169
|
}
|
|
161
170
|
else {
|
|
162
|
-
|
|
171
|
+
set.add(value);
|
|
163
172
|
}
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
const result = new Map();
|
|
167
|
-
for (const [key, values] of
|
|
168
|
-
result.set(key,
|
|
176
|
+
for (const [key, values] of mapping) {
|
|
177
|
+
result.set(key, domain.abstract(values));
|
|
169
178
|
}
|
|
170
179
|
return this.create(result);
|
|
171
180
|
}
|
|
@@ -176,7 +185,7 @@ class MappedAbstractDomain extends abstract_domain_1.AbstractDomain {
|
|
|
176
185
|
return '(' + this.value.entries().toArray().map(([key, value]) => `${(0, abstract_domain_1.domainElementToString)(key)} -> ${value.toString()}`).join(', ') + ')';
|
|
177
186
|
}
|
|
178
187
|
isTop() {
|
|
179
|
-
return this.value.
|
|
188
|
+
return this.value.values().some(entry => entry.isTop());
|
|
180
189
|
}
|
|
181
190
|
isBottom() {
|
|
182
191
|
return this.value.size === 0;
|
|
@@ -186,4 +195,19 @@ class MappedAbstractDomain extends abstract_domain_1.AbstractDomain {
|
|
|
186
195
|
}
|
|
187
196
|
}
|
|
188
197
|
exports.MappedAbstractDomain = MappedAbstractDomain;
|
|
198
|
+
/**
|
|
199
|
+
* A mutable version of the {@link MappedAbstractDomain} with {@link MutableMappedAbstractDomain#set|`set`} and {@link MutableMappedAbstractDomain#remove|`remove`}.
|
|
200
|
+
*/
|
|
201
|
+
class MutableMappedAbstractDomain extends MappedAbstractDomain {
|
|
202
|
+
create(value) {
|
|
203
|
+
return new MutableMappedAbstractDomain(value);
|
|
204
|
+
}
|
|
205
|
+
set(key, value) {
|
|
206
|
+
super.set(key, value);
|
|
207
|
+
}
|
|
208
|
+
remove(key) {
|
|
209
|
+
super.remove(key);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.MutableMappedAbstractDomain = MutableMappedAbstractDomain;
|
|
189
213
|
//# sourceMappingURL=mapped-abstract-domain.js.map
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
2
2
|
import type { AnyAbstractDomain } from './abstract-domain';
|
|
3
|
+
import { Top } from './lattice';
|
|
4
|
+
import type { ConcreteMap } from './mapped-abstract-domain';
|
|
3
5
|
import { MappedAbstractDomain } from './mapped-abstract-domain';
|
|
4
6
|
/**
|
|
5
7
|
* A state abstract domain as mapping of AST node IDs of a program to abstract values of an abstract domain.
|
|
@@ -8,8 +10,35 @@ import { MappedAbstractDomain } from './mapped-abstract-domain';
|
|
|
8
10
|
* @see {@link NodeId} for the node IDs of the AST nodes
|
|
9
11
|
*/
|
|
10
12
|
export declare class StateAbstractDomain<Domain extends AnyAbstractDomain> extends MappedAbstractDomain<NodeId, Domain> {
|
|
13
|
+
private _isBottom;
|
|
14
|
+
constructor(value: ReadonlyMap<NodeId, Domain>, bottom?: boolean);
|
|
15
|
+
create(value: ReadonlyMap<NodeId, Domain>, bottom?: boolean): this;
|
|
16
|
+
static top<Domain extends AnyAbstractDomain>(): StateAbstractDomain<Domain>;
|
|
17
|
+
get(key: NodeId, ignoreBottom?: boolean): Domain | undefined;
|
|
18
|
+
protected set(key: NodeId, value: Domain): void;
|
|
19
|
+
bottom(): this;
|
|
20
|
+
top(): this;
|
|
21
|
+
equals(other: this): boolean;
|
|
22
|
+
leq(other: this): boolean;
|
|
23
|
+
join(other: this): this;
|
|
24
|
+
meet(other: this): this;
|
|
25
|
+
widen(other: this): this;
|
|
26
|
+
narrow(other: this): this;
|
|
27
|
+
concretize(limit: number): ReadonlySet<ConcreteMap<NodeId, Domain>> | typeof Top;
|
|
28
|
+
abstract(concrete: typeof Top | ReadonlySet<ConcreteMap<NodeId, Domain>>): this;
|
|
29
|
+
toJson(): unknown;
|
|
30
|
+
toString(): string;
|
|
31
|
+
isTop(): this is this;
|
|
32
|
+
isBottom(): this is this;
|
|
33
|
+
isValue(): this is this;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A mutable version of the {@link StateAbstractDomain} with {@link MutableStateAbstractDomain#set|`set`} and {@link MutableStateAbstractDomain#remove|`remove`}.
|
|
37
|
+
*/
|
|
38
|
+
export declare class MutableStateAbstractDomain<Domain extends AnyAbstractDomain> extends StateAbstractDomain<Domain> {
|
|
11
39
|
create(value: ReadonlyMap<NodeId, Domain>): this;
|
|
12
|
-
|
|
40
|
+
set(key: NodeId, value: Domain): void;
|
|
41
|
+
remove(key: NodeId): void;
|
|
13
42
|
}
|
|
14
43
|
/**
|
|
15
44
|
* The type of the value abstract domain of a state abstract domain (i.e. the abstract domain a state abstract domain maps to).
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StateAbstractDomain = void 0;
|
|
3
|
+
exports.MutableStateAbstractDomain = exports.StateAbstractDomain = void 0;
|
|
4
|
+
const lattice_1 = require("./lattice");
|
|
4
5
|
const mapped_abstract_domain_1 = require("./mapped-abstract-domain");
|
|
5
6
|
/**
|
|
6
7
|
* A state abstract domain as mapping of AST node IDs of a program to abstract values of an abstract domain.
|
|
@@ -9,12 +10,137 @@ const mapped_abstract_domain_1 = require("./mapped-abstract-domain");
|
|
|
9
10
|
* @see {@link NodeId} for the node IDs of the AST nodes
|
|
10
11
|
*/
|
|
11
12
|
class StateAbstractDomain extends mapped_abstract_domain_1.MappedAbstractDomain {
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
_isBottom;
|
|
14
|
+
constructor(value, bottom) {
|
|
15
|
+
super(value);
|
|
16
|
+
if (bottom || value.values().some(entry => entry.isBottom())) {
|
|
17
|
+
this._isBottom = true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
create(value, bottom) {
|
|
21
|
+
return new StateAbstractDomain(value, bottom ?? this._isBottom);
|
|
14
22
|
}
|
|
15
|
-
static
|
|
23
|
+
static top() {
|
|
16
24
|
return new StateAbstractDomain(new Map());
|
|
17
25
|
}
|
|
26
|
+
get(key, ignoreBottom) {
|
|
27
|
+
return this._isBottom && !ignoreBottom ? super.get(key)?.bottom() : super.get(key);
|
|
28
|
+
}
|
|
29
|
+
set(key, value) {
|
|
30
|
+
if (value.isBottom()) {
|
|
31
|
+
this._isBottom = true;
|
|
32
|
+
}
|
|
33
|
+
super.set(key, value);
|
|
34
|
+
}
|
|
35
|
+
bottom() {
|
|
36
|
+
return this.create(this.value, true);
|
|
37
|
+
}
|
|
38
|
+
top() {
|
|
39
|
+
return this.create(new Map());
|
|
40
|
+
}
|
|
41
|
+
equals(other) {
|
|
42
|
+
if (this._isBottom !== other._isBottom) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return super.equals(other);
|
|
46
|
+
}
|
|
47
|
+
leq(other) {
|
|
48
|
+
if (this._isBottom) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
else if (other._isBottom) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return super.leq(other);
|
|
55
|
+
}
|
|
56
|
+
join(other) {
|
|
57
|
+
if (this._isBottom) {
|
|
58
|
+
return other.create(other.value);
|
|
59
|
+
}
|
|
60
|
+
else if (other._isBottom) {
|
|
61
|
+
return this.create(this.value);
|
|
62
|
+
}
|
|
63
|
+
return super.join(other);
|
|
64
|
+
}
|
|
65
|
+
meet(other) {
|
|
66
|
+
const result = super.meet(other);
|
|
67
|
+
result._isBottom = this._isBottom || other._isBottom;
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
widen(other) {
|
|
71
|
+
if (this._isBottom) {
|
|
72
|
+
return other.create(other.value);
|
|
73
|
+
}
|
|
74
|
+
else if (other._isBottom) {
|
|
75
|
+
return this.create(this.value);
|
|
76
|
+
}
|
|
77
|
+
return super.widen(other);
|
|
78
|
+
}
|
|
79
|
+
narrow(other) {
|
|
80
|
+
const result = super.narrow(other);
|
|
81
|
+
result._isBottom = this._isBottom || other._isBottom;
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
concretize(limit) {
|
|
85
|
+
if (this._isBottom) {
|
|
86
|
+
return new Set();
|
|
87
|
+
}
|
|
88
|
+
else if (this.value.size === 0) {
|
|
89
|
+
return lattice_1.Top;
|
|
90
|
+
}
|
|
91
|
+
return super.concretize(limit);
|
|
92
|
+
}
|
|
93
|
+
abstract(concrete) {
|
|
94
|
+
if (concrete === lattice_1.Top) {
|
|
95
|
+
return this.top();
|
|
96
|
+
}
|
|
97
|
+
else if (concrete.size === 0) {
|
|
98
|
+
return this.create(new Map(), true);
|
|
99
|
+
}
|
|
100
|
+
return super.abstract(concrete);
|
|
101
|
+
}
|
|
102
|
+
toJson() {
|
|
103
|
+
if (this._isBottom) {
|
|
104
|
+
return lattice_1.BottomSymbol;
|
|
105
|
+
}
|
|
106
|
+
else if (this.value.size === 0) {
|
|
107
|
+
return lattice_1.TopSymbol;
|
|
108
|
+
}
|
|
109
|
+
return super.toJson();
|
|
110
|
+
}
|
|
111
|
+
toString() {
|
|
112
|
+
if (this._isBottom) {
|
|
113
|
+
return lattice_1.BottomSymbol;
|
|
114
|
+
}
|
|
115
|
+
else if (this.value.size === 0) {
|
|
116
|
+
return lattice_1.TopSymbol;
|
|
117
|
+
}
|
|
118
|
+
return super.toString();
|
|
119
|
+
}
|
|
120
|
+
isTop() {
|
|
121
|
+
return this.value.size === 0;
|
|
122
|
+
}
|
|
123
|
+
isBottom() {
|
|
124
|
+
return this._isBottom ?? false;
|
|
125
|
+
}
|
|
126
|
+
isValue() {
|
|
127
|
+
return !this._isBottom;
|
|
128
|
+
}
|
|
18
129
|
}
|
|
19
130
|
exports.StateAbstractDomain = StateAbstractDomain;
|
|
131
|
+
/**
|
|
132
|
+
* A mutable version of the {@link StateAbstractDomain} with {@link MutableStateAbstractDomain#set|`set`} and {@link MutableStateAbstractDomain#remove|`remove`}.
|
|
133
|
+
*/
|
|
134
|
+
class MutableStateAbstractDomain extends StateAbstractDomain {
|
|
135
|
+
create(value) {
|
|
136
|
+
return new MutableStateAbstractDomain(value);
|
|
137
|
+
}
|
|
138
|
+
set(key, value) {
|
|
139
|
+
super.set(key, value);
|
|
140
|
+
}
|
|
141
|
+
remove(key) {
|
|
142
|
+
super.remove(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.MutableStateAbstractDomain = MutableStateAbstractDomain;
|
|
20
146
|
//# sourceMappingURL=state-abstract-domain.js.map
|
|
@@ -34,6 +34,7 @@ declare function uniqueControlFlowSets(cfg: ControlFlowInformation, _info?: CfgP
|
|
|
34
34
|
declare function toBasicBlocks(cfg: ControlFlowInformation, _info?: CfgPassInfo): ControlFlowInformation;
|
|
35
35
|
/**
|
|
36
36
|
* Uses {@link visitCfgInOrder} to find all nodes that are reachable from the control flow graph's {@link ControlFlowInformation.entryPoints} and returns them as a set.
|
|
37
|
+
* Please note that this will not visit the grouping delimiters of expression list!
|
|
37
38
|
* @param cfg - The control flow graph whose reachable nodes to find.
|
|
38
39
|
*/
|
|
39
40
|
export declare function cfgFindAllReachable(cfg: ControlFlowInformation): Set<NodeId>;
|
|
@@ -59,6 +59,7 @@ function toBasicBlocks(cfg, _info) {
|
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Uses {@link visitCfgInOrder} to find all nodes that are reachable from the control flow graph's {@link ControlFlowInformation.entryPoints} and returns them as a set.
|
|
62
|
+
* Please note that this will not visit the grouping delimiters of expression list!
|
|
62
63
|
* @param cfg - The control flow graph whose reachable nodes to find.
|
|
63
64
|
*/
|
|
64
65
|
function cfgFindAllReachable(cfg) {
|
|
@@ -6,7 +6,6 @@ exports.extractCfgQuick = extractCfgQuick;
|
|
|
6
6
|
exports.getCallsInCfg = getCallsInCfg;
|
|
7
7
|
exports.cfg2quads = cfg2quads;
|
|
8
8
|
const quads_1 = require("../util/quads");
|
|
9
|
-
const fold_1 = require("../r-bridge/lang-4.x/ast/model/processing/fold");
|
|
10
9
|
const r_function_call_1 = require("../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
11
10
|
const linker_1 = require("../dataflow/internal/linker");
|
|
12
11
|
const vertex_1 = require("../dataflow/graph/vertex");
|
|
@@ -14,7 +13,18 @@ const control_flow_graph_1 = require("./control-flow-graph");
|
|
|
14
13
|
const cfg_simplification_1 = require("./cfg-simplification");
|
|
15
14
|
const assert_1 = require("../util/assert");
|
|
16
15
|
const built_in_1 = require("../dataflow/environments/built-in");
|
|
16
|
+
const stateful_fold_1 = require("../r-bridge/lang-4.x/ast/model/processing/stateful-fold");
|
|
17
|
+
const type_1 = require("../r-bridge/lang-4.x/ast/model/type");
|
|
17
18
|
const cfgFolds = {
|
|
19
|
+
down: (n, down) => {
|
|
20
|
+
if (n.type === type_1.RType.FunctionDefinition) {
|
|
21
|
+
return [down[0], true];
|
|
22
|
+
}
|
|
23
|
+
else if (n.type === type_1.RType.ForLoop || n.type === type_1.RType.WhileLoop || n.type === type_1.RType.RepeatLoop) {
|
|
24
|
+
return [true, down[1]];
|
|
25
|
+
}
|
|
26
|
+
return down;
|
|
27
|
+
},
|
|
18
28
|
foldNumber: cfgLeaf(control_flow_graph_1.CfgVertexType.Expression),
|
|
19
29
|
foldString: cfgLeaf(control_flow_graph_1.CfgVertexType.Expression),
|
|
20
30
|
foldLogical: cfgLeaf(control_flow_graph_1.CfgVertexType.Expression),
|
|
@@ -99,7 +109,7 @@ function cfgFoldProject(proj, folds) {
|
|
|
99
109
|
return (0, control_flow_graph_1.emptyControlFlowInformation)();
|
|
100
110
|
}
|
|
101
111
|
else if (proj.files.length === 1) {
|
|
102
|
-
return (0,
|
|
112
|
+
return (0, stateful_fold_1.foldAstStateful)(proj.files[0].root, [false, false], folds);
|
|
103
113
|
}
|
|
104
114
|
/* for many files, it is too expensive to keep all asts at once, hence we create and merge them incrementally */
|
|
105
115
|
let exitPoints;
|
|
@@ -109,7 +119,7 @@ function cfgFoldProject(proj, folds) {
|
|
|
109
119
|
let nexts;
|
|
110
120
|
let returns;
|
|
111
121
|
{
|
|
112
|
-
const firstInfo = (0,
|
|
122
|
+
const firstInfo = (0, stateful_fold_1.foldAstStateful)(proj.files[0].root, [false, false], folds);
|
|
113
123
|
exitPoints = firstInfo.exitPoints;
|
|
114
124
|
finalGraph = firstInfo.graph;
|
|
115
125
|
firstEntryPoints = firstInfo.entryPoints;
|
|
@@ -118,7 +128,7 @@ function cfgFoldProject(proj, folds) {
|
|
|
118
128
|
returns = firstInfo.returns;
|
|
119
129
|
}
|
|
120
130
|
for (let i = 1; i < proj.files.length; i++) {
|
|
121
|
-
const nextInfo = (0,
|
|
131
|
+
const nextInfo = (0, stateful_fold_1.foldAstStateful)(proj.files[i].root, [false, false], folds);
|
|
122
132
|
finalGraph.mergeWith(nextInfo.graph);
|
|
123
133
|
for (const exitPoint of exitPoints) {
|
|
124
134
|
for (const entryPoint of nextInfo.entryPoints) {
|
|
@@ -147,17 +157,23 @@ function cfgLeaf(type) {
|
|
|
147
157
|
};
|
|
148
158
|
}
|
|
149
159
|
const cfgLeafStatement = cfgLeaf(control_flow_graph_1.CfgVertexType.Statement);
|
|
150
|
-
function cfgBreak(leaf) {
|
|
160
|
+
function cfgBreak(leaf, down) {
|
|
161
|
+
if (!down[0]) {
|
|
162
|
+
return cfgLeafStatement(leaf);
|
|
163
|
+
}
|
|
151
164
|
return { ...cfgLeafStatement(leaf), breaks: [leaf.info.id], exitPoints: [] };
|
|
152
165
|
}
|
|
153
|
-
function cfgNext(leaf) {
|
|
166
|
+
function cfgNext(leaf, down) {
|
|
167
|
+
if (!down[0]) {
|
|
168
|
+
return cfgLeafStatement(leaf);
|
|
169
|
+
}
|
|
154
170
|
return { ...cfgLeafStatement(leaf), nexts: [leaf.info.id], exitPoints: [] };
|
|
155
171
|
}
|
|
156
172
|
function cfgIgnore(_leaf) {
|
|
157
173
|
return { graph: new control_flow_graph_1.ControlFlowGraph(), breaks: [], nexts: [], returns: [], exitPoints: [], entryPoints: [] };
|
|
158
174
|
}
|
|
159
175
|
function identifyMayStatementType(node) {
|
|
160
|
-
return node.info.role === "
|
|
176
|
+
return node.info.role === "el-c" /* RoleInParent.ExpressionListChild */ ? control_flow_graph_1.CfgVertexType.Statement : control_flow_graph_1.CfgVertexType.Expression;
|
|
161
177
|
}
|
|
162
178
|
function cfgIfThenElse(ifNode, condition, then, otherwise) {
|
|
163
179
|
const ifId = ifNode.info.id;
|
|
@@ -318,7 +334,7 @@ function cfgFunctionDefinition(fn, params, body) {
|
|
|
318
334
|
}
|
|
319
335
|
return { graph: graph, breaks: [], nexts: [], returns: [], exitPoints: [fnId], entryPoints: [fnId] };
|
|
320
336
|
}
|
|
321
|
-
function cfgFunctionCall(call, name, args) {
|
|
337
|
+
function cfgFunctionCall(call, name, args, down) {
|
|
322
338
|
if (call.named && call.functionName.content === 'ifelse') {
|
|
323
339
|
// special built-in handling for ifelse as it is an expression that does not short-circuit
|
|
324
340
|
return cfgIfThenElse(call, args[0] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[0], args[1] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[1], args[2] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[2]);
|
|
@@ -358,30 +374,32 @@ function cfgFunctionCall(call, name, args) {
|
|
|
358
374
|
graph.addEdge(control_flow_graph_1.CfgVertex.toExitId(callId), exit, control_flow_graph_1.CfgEdge.makeFd());
|
|
359
375
|
}
|
|
360
376
|
if (call.named && call.functionName.content === 'return') {
|
|
361
|
-
|
|
362
|
-
|
|
377
|
+
if (down[1]) {
|
|
378
|
+
info.returns.push(control_flow_graph_1.CfgVertex.toExitId(callId));
|
|
379
|
+
info.exitPoints.length = 0;
|
|
380
|
+
}
|
|
363
381
|
}
|
|
364
382
|
// should not contain any breaks, nexts, or returns, (except for the body if something like 'break()')
|
|
365
383
|
return info;
|
|
366
384
|
}
|
|
367
385
|
exports.ResolvedCallSuffix = control_flow_graph_1.CfgVertex.toExitId('-resolved-call');
|
|
368
386
|
const OriginToFoldTypeMap = {
|
|
369
|
-
[built_in_1.BuiltInProcName.IfThenElse]: (folds, call, args) => {
|
|
387
|
+
[built_in_1.BuiltInProcName.IfThenElse]: (folds, call, args, down) => {
|
|
370
388
|
// arguments are in order!
|
|
371
389
|
return folds.foldIfThenElse(call, // we will have to this more sophisticated if we rewrite the dfg based generation
|
|
372
|
-
args[0] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[0], args[1] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[1], args[2] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[2],
|
|
390
|
+
args[0] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[0], args[1] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[1], args[2] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[2], down);
|
|
373
391
|
}
|
|
374
392
|
};
|
|
375
393
|
function cfgFunctionCallWithDataflow(graph, folds) {
|
|
376
|
-
return (call, name, args) => {
|
|
394
|
+
return (call, name, args, down) => {
|
|
377
395
|
const vtx = graph.getVertex(call.info.id);
|
|
378
396
|
if (vtx?.tag === vertex_1.VertexType.FunctionCall && vtx.onlyBuiltin && vtx.origin.length === 1) {
|
|
379
397
|
const mayMap = OriginToFoldTypeMap[vtx.origin[0]];
|
|
380
398
|
if (mayMap) {
|
|
381
|
-
return mayMap(folds, call, args, vtx);
|
|
399
|
+
return mayMap(folds, call, args, down, vtx);
|
|
382
400
|
}
|
|
383
401
|
}
|
|
384
|
-
const baseCfg = cfgFunctionCall(call, name, args);
|
|
402
|
+
const baseCfg = cfgFunctionCall(call, name, args, down);
|
|
385
403
|
/* try to resolve the call and link the target definitions */
|
|
386
404
|
const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
|
|
387
405
|
const exits = [];
|
|
@@ -279,6 +279,7 @@ class SemanticCfgGuidedVisitor extends dfg_cfg_guided_visitor_1.DataflowAwareCfg
|
|
|
279
279
|
case built_in_1.BuiltInProcName.Recall:
|
|
280
280
|
return this.onRecallCall({ call });
|
|
281
281
|
case built_in_1.BuiltInProcName.Default:
|
|
282
|
+
case built_in_1.BuiltInProcName.DefaultReadAllArgs:
|
|
282
283
|
case built_in_1.BuiltInProcName.Function:
|
|
283
284
|
case built_in_1.BuiltInProcName.FunctionDefinition:
|
|
284
285
|
return this.onDefaultFunctionCall({ call });
|
|
@@ -94,6 +94,7 @@ export interface BuiltInEvalHandlerArgs {
|
|
|
94
94
|
}
|
|
95
95
|
export type BuiltInEvalHandler = (args: BuiltInEvalHandlerArgs) => Value;
|
|
96
96
|
declare function defaultBuiltInProcessor<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, { returnsNthArgument, useAsProcessor, forceArgs, readAllArguments, cfg, hasUnknownSideEffects, treatAsFnCall }: DefaultBuiltInProcessorConfiguration): DataflowInformation;
|
|
97
|
+
declare function defaultBuiltInProcessorReadallArgs<OtherInfo>(name: RSymbol<OtherInfo & ParentInformation>, args: readonly RFunctionArgument<OtherInfo & ParentInformation>[], rootId: NodeId, data: DataflowProcessorInformation<OtherInfo & ParentInformation>, { useAsProcessor, forceArgs }: Pick<DefaultBuiltInProcessorConfiguration, 'useAsProcessor' | 'forceArgs'>): DataflowInformation;
|
|
97
98
|
/**
|
|
98
99
|
* This contains all names of built-in function handlers and origins
|
|
99
100
|
*/
|
|
@@ -110,6 +111,8 @@ export declare enum BuiltInProcName {
|
|
|
110
111
|
Break = "builtin:break",
|
|
111
112
|
/** the default built-in processor, see {@link defaultBuiltInProcessor} */
|
|
112
113
|
Default = "builtin:default",
|
|
114
|
+
/** Just a more performant variant of the default processor for built-ins that need to read all their arguments, see {@link defaultBuiltInProcessor}, this will still produce the origin `BuiltIn.Default` */
|
|
115
|
+
DefaultReadAllArgs = "builtin:default-read-all-args",
|
|
113
116
|
/** for `eval` calls, see {@link processEvalCall} */
|
|
114
117
|
Eval = "builtin:eval",
|
|
115
118
|
/** for expression lists, see {@link processExpressionList} */
|
|
@@ -181,6 +184,7 @@ export declare const BuiltInProcessorMapper: {
|
|
|
181
184
|
readonly "builtin:assignment": typeof processAssignment;
|
|
182
185
|
readonly "builtin:assignment-like": typeof processAssignmentLike;
|
|
183
186
|
readonly "builtin:default": typeof defaultBuiltInProcessor;
|
|
187
|
+
readonly "builtin:default-read-all-args": typeof defaultBuiltInProcessorReadallArgs;
|
|
184
188
|
readonly "builtin:eval": typeof processEvalCall;
|
|
185
189
|
readonly "builtin:expression-list": typeof processExpressionList;
|
|
186
190
|
readonly "builtin:for-loop": typeof processForLoop;
|
|
@@ -60,11 +60,10 @@ const builtInPrefixLength = 'built-in:'.length;
|
|
|
60
60
|
function dropBuiltInPrefix(name) {
|
|
61
61
|
return name.slice(builtInPrefixLength);
|
|
62
62
|
}
|
|
63
|
-
function defaultBuiltInProcessor(name, args, rootId, data, { returnsNthArgument, useAsProcessor, forceArgs, readAllArguments, cfg, hasUnknownSideEffects, treatAsFnCall }) {
|
|
64
|
-
const
|
|
65
|
-
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs, origin: activeProcessor });
|
|
63
|
+
function defaultBuiltInProcessor(name, args, rootId, data, { returnsNthArgument, useAsProcessor = BuiltInProcName.Default, forceArgs, readAllArguments, cfg, hasUnknownSideEffects, treatAsFnCall }) {
|
|
64
|
+
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs, origin: useAsProcessor });
|
|
66
65
|
if (returnsNthArgument !== undefined) {
|
|
67
|
-
const arg = returnsNthArgument === 'last' ? processedArguments
|
|
66
|
+
const arg = returnsNthArgument === 'last' ? processedArguments.at(-1) : processedArguments[returnsNthArgument];
|
|
68
67
|
if (arg !== undefined) {
|
|
69
68
|
res.graph.addEdge(rootId, arg.entryPoint, edge_1.EdgeType.Returns);
|
|
70
69
|
}
|
|
@@ -110,7 +109,7 @@ function defaultBuiltInProcessor(name, args, rootId, data, { returnsNthArgument,
|
|
|
110
109
|
environment: data.environment,
|
|
111
110
|
onlyBuiltin: false,
|
|
112
111
|
cds: data.cds,
|
|
113
|
-
origin: [
|
|
112
|
+
origin: [useAsProcessor]
|
|
114
113
|
});
|
|
115
114
|
}
|
|
116
115
|
}
|
|
@@ -120,6 +119,16 @@ function defaultBuiltInProcessor(name, args, rootId, data, { returnsNthArgument,
|
|
|
120
119
|
}
|
|
121
120
|
return res;
|
|
122
121
|
}
|
|
122
|
+
function defaultBuiltInProcessorReadallArgs(name, args, rootId, data, { useAsProcessor = BuiltInProcName.Default, forceArgs }) {
|
|
123
|
+
const { information: res, processedArguments } = (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs, origin: useAsProcessor });
|
|
124
|
+
const g = res.graph;
|
|
125
|
+
for (const arg of processedArguments) {
|
|
126
|
+
if (arg) {
|
|
127
|
+
g.addEdge(rootId, arg.entryPoint, edge_1.EdgeType.Reads);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return res;
|
|
131
|
+
}
|
|
123
132
|
/**
|
|
124
133
|
* This contains all names of built-in function handlers and origins
|
|
125
134
|
*/
|
|
@@ -137,6 +146,8 @@ var BuiltInProcName;
|
|
|
137
146
|
BuiltInProcName["Break"] = "builtin:break";
|
|
138
147
|
/** the default built-in processor, see {@link defaultBuiltInProcessor} */
|
|
139
148
|
BuiltInProcName["Default"] = "builtin:default";
|
|
149
|
+
/** Just a more performant variant of the default processor for built-ins that need to read all their arguments, see {@link defaultBuiltInProcessor}, this will still produce the origin `BuiltIn.Default` */
|
|
150
|
+
BuiltInProcName["DefaultReadAllArgs"] = "builtin:default-read-all-args";
|
|
140
151
|
/** for `eval` calls, see {@link processEvalCall} */
|
|
141
152
|
BuiltInProcName["Eval"] = "builtin:eval";
|
|
142
153
|
/** for expression lists, see {@link processExpressionList} */
|
|
@@ -208,6 +219,7 @@ exports.BuiltInProcessorMapper = {
|
|
|
208
219
|
[BuiltInProcName.Assignment]: built_in_assignment_1.processAssignment,
|
|
209
220
|
[BuiltInProcName.AssignmentLike]: built_in_assignment_1.processAssignmentLike,
|
|
210
221
|
[BuiltInProcName.Default]: defaultBuiltInProcessor,
|
|
222
|
+
[BuiltInProcName.DefaultReadAllArgs]: defaultBuiltInProcessorReadallArgs,
|
|
211
223
|
[BuiltInProcName.Eval]: built_in_eval_1.processEvalCall,
|
|
212
224
|
[BuiltInProcName.ExpressionList]: built_in_expression_list_1.processExpressionList,
|
|
213
225
|
[BuiltInProcName.ForLoop]: built_in_for_loop_1.processForLoop,
|
|
@@ -36,18 +36,14 @@ export declare const DefaultBuiltinConfig: [{
|
|
|
36
36
|
}, {
|
|
37
37
|
readonly type: "function";
|
|
38
38
|
readonly names: ["~", "+", "-", "*", "/", "^", "!", "?", "**", "==", "!=", ">", "<", ">=", "<=", "%%", "%/%", "%*%", "%in%", ":", "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", "is.null", "numeric", "as.character", "as.integer", "as.logical", "as.numeric", "as.matrix", "rbind", "nrow", "ncol", "tryCatch", "expression", "factor", "missing", "as.data.frame", "data.frame", "na.omit", "rownames", "names", "order", "length", "any", "dim", "matrix", "cbind", "nchar", "pdf", "jpeg", "png", "windows", "postscript", "xfig", "bitmap", "pictex", "cairo_pdf", "svg", "bmp", "tiff", "X11", "quartz", "jitter"];
|
|
39
|
-
readonly processor: BuiltInProcName.
|
|
40
|
-
readonly config: {
|
|
41
|
-
readonly readAllArguments: true;
|
|
42
|
-
};
|
|
39
|
+
readonly processor: BuiltInProcName.DefaultReadAllArgs;
|
|
40
|
+
readonly config: {};
|
|
43
41
|
readonly assumePrimitive: true;
|
|
44
42
|
}, {
|
|
45
43
|
readonly type: "function";
|
|
46
44
|
readonly names: ["t", "aperm"];
|
|
47
|
-
readonly processor: BuiltInProcName.
|
|
48
|
-
readonly config: {
|
|
49
|
-
readonly readAllArguments: true;
|
|
50
|
-
};
|
|
45
|
+
readonly processor: BuiltInProcName.DefaultReadAllArgs;
|
|
46
|
+
readonly config: {};
|
|
51
47
|
readonly assumePrimitive: false;
|
|
52
48
|
}, {
|
|
53
49
|
readonly type: "function";
|