UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

213 lines 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MutableMappedAbstractDomain = exports.MappedAbstractDomain = void 0; const abstract_domain_1 = require("./abstract-domain"); const lattice_1 = require("./lattice"); /** * A mapped abstract domain as mapping of keys to abstract values of an abstract domain. * The Bottom element is defined as empty mapping and the Top element is defined as mapping every existing key to Top. * @template Key - Type of the keys of the mapping to abstract values * @template Domain - Type of the abstract domain to map the keys to */ class MappedAbstractDomain extends abstract_domain_1.AbstractDomain { constructor(value) { super(new Map(value)); } create(value) { return new MappedAbstractDomain(value); } get(key) { return this._value.get(key); } has(key) { return this._value.has(key); } set(key, value) { this._value.set(key, value); } remove(key) { this._value.delete(key); } bottom() { return this.create(new Map()); } top() { const result = this.create(this.value); for (const [key, value] of result.value) { result.set(key, value.top()); } return result; } equals(other) { if (this.value === other.value) { return true; } else if (this.value.size !== other.value.size) { return false; } for (const [key, value] of this.value) { const otherValue = other.get(key); if (otherValue === undefined || !value.equals(otherValue)) { return false; } } return true; } leq(other) { if (this.value === other.value) { return true; } else if (this.value.size > other.value.size) { return false; } for (const [key, value] of this.value) { const otherValue = other.get(key); if (otherValue === undefined || !value.leq(otherValue)) { return false; } } return true; } join(other) { const result = this.create(this.value); for (const [key, value] of other.value) { const currValue = result.get(key); if (currValue === undefined) { result.set(key, value); } else { result.set(key, currValue.join(value)); } } return result; } meet(other) { const result = this.create(this.value); for (const [key] of result.value) { if (!other.has(key)) { result.remove(key); } } for (const [key, value] of other.value) { const currValue = result.get(key); if (currValue !== undefined) { result.set(key, currValue.meet(value)); } } return result; } widen(other) { const result = this.create(this.value); for (const [key, value] of other.value) { const currValue = result.get(key); if (currValue === undefined) { result.set(key, value); } else { result.set(key, currValue.widen(value)); } } return result; } narrow(other) { const result = this.create(this.value); for (const [key] of this.value) { if (!other.has(key)) { result.remove(key); } } for (const [key, value] of other.value) { const currValue = result.get(key); if (currValue !== undefined) { result.set(key, currValue.narrow(value)); } } return result; } concretize(limit) { if (this.value.size === 0) { return new Set(); } let mappings = new Set([new Map()]); for (const [key, value] of this.value) { const concreteValues = value.concretize(limit); if (concreteValues === lattice_1.Top) { return lattice_1.Top; } const newMappings = new Set(); for (const state of mappings) { for (const concrete of concreteValues) { if (newMappings.size > limit) { return lattice_1.Top; } const map = new Map(state); map.set(key, concrete); newMappings.add(map); } } mappings = newMappings; } return mappings; } abstract(concrete) { if (concrete === lattice_1.Top) { return this.top(); } else if (concrete.size === 0) { return this.bottom(); } const domain = this.value.values().toArray()[0]; if (domain === undefined) { return this.top(); } const mapping = new Map(); for (const concreteMapping of concrete) { for (const [key, value] of concreteMapping) { const set = mapping.get(key); if (set === undefined) { mapping.set(key, new Set([value])); } else { set.add(value); } } } const result = new Map(); for (const [key, values] of mapping) { result.set(key, domain.abstract(values)); } return this.create(result); } toJson() { return Object.fromEntries(this.value.entries().map(([key, value]) => [key, value.toJson()])); } toString() { return '(' + this.value.entries().toArray().map(([key, value]) => `${(0, abstract_domain_1.domainElementToString)(key)} -> ${value.toString()}`).join(', ') + ')'; } isTop() { return this.value.values().some(entry => entry.isTop()); } isBottom() { return this.value.size === 0; } isValue() { return true; } } exports.MappedAbstractDomain = MappedAbstractDomain; /** * A mutable version of the {@link MappedAbstractDomain} with {@link MutableMappedAbstractDomain#set|`set`} and {@link MutableMappedAbstractDomain#remove|`remove`}. */ class MutableMappedAbstractDomain extends MappedAbstractDomain { create(value) { return new MutableMappedAbstractDomain(value); } set(key, value) { super.set(key, value); } remove(key) { super.remove(key); } } exports.MutableMappedAbstractDomain = MutableMappedAbstractDomain; //# sourceMappingURL=mapped-abstract-domain.js.map