UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

197 lines 7.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SetUpperBoundDomain = void 0; const assert_1 = require("../../util/assert"); const set_1 = require("../../util/collections/set"); const logic_1 = require("../../util/logic"); const abstract_domain_1 = require("./abstract-domain"); const lattice_1 = require("./lattice"); const satisfiable_domain_1 = require("./satisfiable-domain"); /** * The set upper bound 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 SetUpperBoundDomain extends abstract_domain_1.AbstractDomain { limit; setType; /** * @param limit - A limit for the maximum number of elements to store in the set * @param newSet - An optional set constructor for the domain elements if the type `T` is not storable in a HashSet */ constructor(value, limit = abstract_domain_1.DEFAULT_INFERENCE_LIMIT, setType = Set) { if (value !== lattice_1.Top && value !== lattice_1.Bottom) { if (Array.isArray(value)) { super((value.length > limit ? lattice_1.Top : new setType(value))); } else { super((value.size > limit ? lattice_1.Top : new setType(value))); } } else { super(value); } this.limit = limit; this.setType = setType; } create(value) { return new SetUpperBoundDomain(value, this.limit, this.setType); } static top(limit, setType) { return new SetUpperBoundDomain(lattice_1.Top, limit, setType); } static bottom(limit, setType) { return new SetUpperBoundDomain(lattice_1.Bottom, limit, setType); } static abstract(concrete, limit, setType) { if (concrete === lattice_1.Top) { return SetUpperBoundDomain.top(limit, setType); } else if (concrete.size === 0) { return SetUpperBoundDomain.bottom(limit, setType); } return new SetUpperBoundDomain(concrete.values().reduce((result, set) => result.union(set)), limit, setType); } top() { return SetUpperBoundDomain.top(this.limit, this.setType); } bottom() { return SetUpperBoundDomain.bottom(this.limit, this.setType); } 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(other) { const otherValue = other instanceof SetUpperBoundDomain ? other.value : Array.isArray(other) ? new this.setType(other) : other; if (this.value === lattice_1.Top || otherValue === lattice_1.Top) { return this.top(); } else if (this.value === lattice_1.Bottom) { return this.create(otherValue); } else if (otherValue === lattice_1.Bottom) { return this.create(this.value); } else { return this.create(this.value.union(otherValue)); } } meet(other) { const otherValue = other instanceof SetUpperBoundDomain ? other.value : Array.isArray(other) ? new this.setType(other) : other; if (this.value === lattice_1.Bottom || otherValue === lattice_1.Bottom) { return this.bottom(); } else if (this.value === lattice_1.Top) { return this.create(otherValue); } else if (otherValue === lattice_1.Top) { return this.create(this.value); } else { return this.create(this.value.intersection(otherValue)); } } /** * 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) { const otherValue = other instanceof SetUpperBoundDomain ? other.value : Array.isArray(other) ? new this.setType(other) : other; if (this.value === lattice_1.Top) { return this.top(); } else if (this.value === lattice_1.Bottom) { return this.bottom(); } else if (otherValue === lattice_1.Top || otherValue === lattice_1.Bottom) { return this.create(this.value); } else { return this.create(this.value.difference(otherValue)); } } widen(other) { if (this.value === lattice_1.Bottom) { return this.create(other.value); } else if (other.value === lattice_1.Bottom) { return this.create(this.value); } return other.leq(this) ? this.create(this.value) : this.top(); } narrow(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } return this.isTop() ? this.create(other.value) : this.create(this.value); } concretize(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 this.setType()]; for (const element of this.value.values()) { const newSubsets = subsets.map(subset => new this.setType([...subset, element])); for (const subset of newSubsets) { subsets.push(subset); } } return new Set(subsets); } abstract(concrete) { return SetUpperBoundDomain.abstract(concrete, this.limit, this.setType); } satisfies(set, comparator = satisfiable_domain_1.SetComparator.Equal) { switch (comparator) { case satisfiable_domain_1.SetComparator.Equal: case satisfiable_domain_1.SetComparator.SubsetOrEqual: { if (this.isTop() || (this.isValue() && [...set].length <= this.value.size && [...set].every(value => this.value.has(value)))) { return logic_1.Ternary.Maybe; } return logic_1.Ternary.Never; } case satisfiable_domain_1.SetComparator.Subset: { if (this.isTop() || (this.isValue() && [...set].length < this.value.size && [...set].every(value => this.value.has(value)))) { return logic_1.Ternary.Maybe; } return logic_1.Ternary.Never; } default: { (0, assert_1.assertUnreachable)(comparator); } } } toJson() { if (this.value === lattice_1.Top || this.value === lattice_1.Bottom) { return this.value.description; } return this.value.values().toArray(); } toString() { if (this.value === lattice_1.Top) { return lattice_1.TopSymbol; } else if (this.value === lattice_1.Bottom) { return lattice_1.BottomSymbol; } 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.SetUpperBoundDomain = SetUpperBoundDomain; //# sourceMappingURL=set-upper-bound-domain.js.map