@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
213 lines • 6.76 kB
JavaScript
"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