@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
164 lines • 6.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetBoundedSetDomain = void 0;
const set_1 = require("../../util/collections/set");
const abstract_domain_1 = require("./abstract-domain");
const lattice_1 = require("./lattice");
/**
* The set bounded set abstract domain as sets capturing possible values of the concrete set bounded by a `limit` for the maximum number of inferred values.
* The Bottom element is defined as the{@link Bottom} and the Top element is defined as {@link Top} symbol.
* @template T - Type of the values in the abstract domain
* @template Value - Type of the constraint in the abstract domain (Top, Bottom, or an actual value)
*/
class SetBoundedSetDomain {
limit;
_value;
constructor(value, limit = abstract_domain_1.DEFAULT_INFERENCE_LIMIT) {
if (value !== lattice_1.Top && value !== lattice_1.Bottom) {
this._value = (value.size > limit ? lattice_1.Top : new Set(value));
}
else {
this._value = value;
}
this.limit = limit;
}
get value() {
return this._value;
}
static top(limit) {
return new SetBoundedSetDomain(lattice_1.Top, limit);
}
static bottom(limit) {
return new SetBoundedSetDomain(lattice_1.Bottom, limit);
}
static abstract(concrete, limit) {
if (concrete === lattice_1.Top) {
return SetBoundedSetDomain.top(limit);
}
else if (concrete.size === 0) {
return SetBoundedSetDomain.bottom(limit);
}
return new SetBoundedSetDomain(concrete.values().reduce((result, set) => result.union(set)), limit);
}
top() {
return SetBoundedSetDomain.top(this.limit);
}
bottom() {
return SetBoundedSetDomain.bottom(this.limit);
}
equals(other) {
return this.value === other.value || (this.isValue() && other.isValue() && (0, set_1.setEquals)(this.value, other.value));
}
leq(other) {
return this.value === lattice_1.Bottom || other.value === lattice_1.Top || (this.isValue() && other.isValue() && this.value.isSubsetOf(other.value));
}
join(...values) {
const result = new SetBoundedSetDomain(this.value, this.limit);
for (const other of values) {
if (result.value === lattice_1.Top || other.value === lattice_1.Top) {
result._value = lattice_1.Top;
}
else if (result.value === lattice_1.Bottom) {
result._value = other.value;
}
else if (other.value === lattice_1.Bottom) {
result._value = result.value;
}
else {
const join = result.value.union(other.value);
result._value = join.size > this.limit ? lattice_1.Top : join;
}
}
return result;
}
meet(...values) {
const result = new SetBoundedSetDomain(this.value, this.limit);
for (const other of values) {
if (result.value === lattice_1.Bottom || other.value === lattice_1.Bottom) {
result._value = lattice_1.Bottom;
}
else if (result.value === lattice_1.Top) {
result._value = other.value;
}
else if (other.value === lattice_1.Top) {
result._value = result.value;
}
else {
result._value = result.value.intersection(other.value);
}
}
return result;
}
/**
* Subtracts another abstract value from the current abstract value by removing all elements of the other abstract value from the current abstract value.
*/
subtract(other) {
if (this.value === lattice_1.Top) {
return this.top();
}
else if (this.value === lattice_1.Bottom) {
return this.bottom();
}
else if (other.value === lattice_1.Top || other.value === lattice_1.Bottom) {
return new SetBoundedSetDomain(this.value, this.limit);
}
else {
return new SetBoundedSetDomain(this.value.difference(other.value), this.limit);
}
}
widen(other) {
if (this.value === lattice_1.Bottom) {
return new SetBoundedSetDomain(other.value, this.limit);
}
else if (other.value === lattice_1.Bottom) {
return new SetBoundedSetDomain(this.value, this.limit);
}
return other.leq(this) ? new SetBoundedSetDomain(this.value, this.limit) : this.top();
}
narrow(other) {
if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) {
return this.bottom();
}
return this.isTop() ? other : this;
}
concretize(limit = abstract_domain_1.DEFAULT_INFERENCE_LIMIT) {
if (this.value === lattice_1.Bottom) {
return new Set();
}
else if (this.value === lattice_1.Top || 2 ** (this.value.size) > limit) {
return lattice_1.Top;
}
const subsets = [new Set()];
for (const element of this.value.values()) {
const newSubsets = subsets.map(subset => new Set([...subset, element]));
for (const subset of newSubsets) {
subsets.push(subset);
}
}
return new Set(subsets);
}
abstract(concrete) {
return SetBoundedSetDomain.abstract(concrete, this.limit);
}
toString() {
if (this.value === lattice_1.Top) {
return '⊤';
}
else if (this.value === lattice_1.Bottom) {
return '⊥';
}
const string = this.value.values().map(abstract_domain_1.domainElementToString).toArray().join(', ');
return `{${string}}`;
}
isTop() {
return this.value === lattice_1.Top;
}
isBottom() {
return this.value == lattice_1.Bottom;
}
isValue() {
return this.value !== lattice_1.Top && this.value !== lattice_1.Bottom;
}
}
exports.SetBoundedSetDomain = SetBoundedSetDomain;
//# sourceMappingURL=set-bounded-set-domain.js.map