@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
163 lines • 5.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PartialProductDomain = void 0;
const abstract_domain_1 = require("./abstract-domain");
const lattice_1 = require("./lattice");
const record_1 = require("../../util/record");
/**
* A partial product abstract domain as named Cartesian product of (optional) sub abstract domains.
* The sub abstract domains are represented by a (partial) record mapping property names to abstract domains.
* The Bottom element is defined as mapping every sub abstract domain to Bottom and the Top element is defined as having no sub abstract domain value.
* @template Product - Type of the abstract product of the product domain mapping (optional) property names to abstract domains
*/
class PartialProductDomain extends abstract_domain_1.AbstractDomain {
domain;
constructor(value, domain) {
super(record_1.Record.mapProperties(value, entry => entry?.create(entry.value)));
this._value = this.reduce(this.value);
this.domain = domain;
}
bottom() {
const result = this.create(this.domain);
for (const key in result.value) {
result.value[key] = this.domain[key]?.bottom();
}
return result;
}
top() {
return this.create({});
}
equals(other) {
if (this.value === other.value) {
return true;
}
for (const key in this.value) {
if (this.value[key] == other.value[key]) {
continue;
}
else if (this.value[key] === undefined || other.value[key] === undefined || !this.value[key].equals(other.value[key])) {
return false;
}
}
return true;
}
leq(other) {
if (this.value === other.value) {
return true;
}
for (const key in this.value) {
if (this.value[key] === other.value[key] || other.value[key] === undefined) {
continue;
}
else if (this.value[key] === undefined || !this.value[key].leq(other.value[key])) {
return false;
}
}
return true;
}
join(other) {
const result = {};
for (const key in this.domain) {
if (this.value[key] !== undefined && other.value[key] !== undefined) {
result[key] = this.value[key].join(other.value[key]);
}
}
return this.create(result);
}
meet(other) {
const result = {};
for (const key in this.domain) {
if (this.value[key] === undefined) {
result[key] = other.value[key];
}
else if (other.value[key] === undefined) {
result[key] = this.value[key];
}
else {
result[key] = this.value[key].meet(other.value[key]);
}
}
return this.create(result);
}
widen(other) {
const result = {};
for (const key in this.domain) {
if (this.value[key] !== undefined && other.value[key] !== undefined) {
result[key] = this.value[key].widen(other.value[key]);
}
}
return this.create(result);
}
narrow(other) {
const result = {};
for (const key in this.domain) {
if (this.value[key] === undefined) {
result[key] = other.value[key];
}
else if (other.value[key] === undefined) {
result[key] = this.value[key];
}
else {
result[key] = this.value[key].narrow(other.value[key]);
}
}
return this.create(result);
}
concretize(limit) {
let result = new Set([{}]);
for (const key in this.value) {
if (this.value[key] === undefined) {
continue;
}
const concrete = this.value[key].concretize(limit);
if (concrete === lattice_1.Top) {
return lattice_1.Top;
}
const newResult = new Set();
for (const value of concrete) {
for (const entry of result) {
if (newResult.size >= limit) {
return lattice_1.Top;
}
newResult.add({ ...entry, [key]: value });
}
}
result = newResult;
}
return result;
}
abstract(concrete) {
if (concrete === lattice_1.Top) {
return this.top();
}
const result = {};
for (const key in this.domain) {
const concreteValues = new Set(concrete.values().map(value => value[key]));
result[key] = this.domain[key]?.abstract(concreteValues);
}
return this.create(result);
}
toJson() {
return record_1.Record.mapProperties(this.value, entry => entry?.toJson());
}
toString() {
return '(' + record_1.Record.entries(this.value).map(([key, value]) => `${key}: ${value.toString()}`).join(', ') + ')';
}
isTop() {
return record_1.Record.values(this.value).length === 0;
}
isBottom() {
return record_1.Record.values(this.value).every(value => value.isBottom());
}
isValue() {
return true;
}
/**
* Optional reduction function for a reduced product domain.
*/
reduce(value) {
return value;
}
}
exports.PartialProductDomain = PartialProductDomain;
//# sourceMappingURL=partial-product-domain.js.map