@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
134 lines • 4.89 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PartialProductDomain = void 0;
const assert_1 = require("../../util/assert");
const record_1 = require("../../util/record");
const abstract_domain_1 = require("./abstract-domain");
/**
* 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;
reductions;
constructor(value, domain, reductions = [], reduce = true) {
super(record_1.Record.mapProperties(value, entry => entry?.create(entry.value)));
this.reductions = reductions;
this.domain = domain;
if (reduce) {
this._value = this.reduce(this.value);
}
}
bottom() {
const result = {};
for (const key in this.domain) {
result[key] = this.domain[key]?.bottom();
}
return this.create(result);
}
top() {
return this.create({});
}
equalsValue(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;
}
leqValue(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;
}
joinValue(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);
}
meetValue(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);
}
widenValue(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);
}
narrowValue(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);
}
jsonify() {
return record_1.Record.mapProperties(this.value, entry => entry?.toJSON());
}
stringify() {
return '(' + record_1.Record.entries(this.value).map(([key, value]) => `${key}: ${value.toString()}`).join(', ') + ')';
}
isTop() {
return record_1.Record.values(this.value).filter(assert_1.isNotUndefined).length === 0;
}
isBottom() {
return record_1.Record.values(this.value).some(value => value.isBottom());
}
isValue() {
return true;
}
/**
* Applies the {@link reductions} of the (reduced) product domain to refine the abstract value based on its components.
* Subclasses may override this to implement a fixed reduction instead of (or in addition to) the configurable reductions.
*/
reduce(value) {
return this.reductions.reduce((current, reduction) => reduction(current), value);
}
}
exports.PartialProductDomain = PartialProductDomain;
//# sourceMappingURL=partial-product-domain.js.map