UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

231 lines 7.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StateAbstractDomain = void 0; const abstract_domain_1 = require("./abstract-domain"); const lattice_1 = require("./lattice"); /** * A state abstract domain that maps AST node IDs of a program to abstract values of an abstract domain. * The Bottom element is defined as {@link Bottom} symbol and the Top element as empty mapping. * @template Domain - Type of the value abstract domain to map the AST node IDs to * @see {@link NodeId} for the node IDs of the AST nodes */ class StateAbstractDomain extends abstract_domain_1.AbstractDomain { domain; constructor(value, domain) { if (value === lattice_1.Bottom || value.values().some(entry => entry.isBottom())) { super(lattice_1.Bottom); } else { super(new Map(value)); } this.domain = domain; } create(value) { return new StateAbstractDomain(value, this.domain); } static top(domain) { return new this(new Map(), domain); } static bottom(domain) { return new this(lattice_1.Bottom, domain); } get(node) { return this.value === lattice_1.Bottom ? this.domain.bottom() : this.value.get(node); } has(node) { return this.value !== lattice_1.Bottom && this.value.has(node); } set(node, value) { if (this.value !== lattice_1.Bottom) { this._value.set(node, value); } } remove(node) { if (this.value !== lattice_1.Bottom) { this._value.delete(node); } } top() { return this.create(new Map()); } bottom() { return this.create(lattice_1.Bottom); } equals(other) { if (this.value === other.value) { return true; } else if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom || this.value.size !== other.value.size) { return false; } for (const [key, value] of this.value.entries()) { const otherValue = other.get(key); if (otherValue === undefined || !value.equals(otherValue)) { return false; } } return true; } leq(other) { if (this.value === other.value || this.value === lattice_1.Bottom) { return true; } else if (other.value === lattice_1.Bottom || this.value.size > other.value.size) { return false; } for (const [key, value] of this.value.entries()) { const otherValue = other.get(key); if (otherValue === undefined || !value.leq(otherValue)) { return false; } } return true; } join(other) { if (this.value === lattice_1.Bottom) { return this.create(other.value); } else if (other.value === lattice_1.Bottom) { return this.create(this.value); } const result = this.create(this.value); for (const [key, value] of other.value.entries()) { const currValue = result.get(key); if (currValue === undefined) { result.set(key, value); } else { result.set(key, currValue.join(value)); } } return result; } meet(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } const result = this.create(this.value); for (const key of result.value.keys()) { if (!other.has(key)) { result.remove(key); } } for (const [key, value] of other.value.entries()) { const currValue = result.get(key); if (currValue !== undefined) { result.set(key, currValue.meet(value)); } } return result; } 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); } const result = this.create(this.value); for (const [key, value] of other.value.entries()) { const currValue = result.get(key); if (currValue === undefined) { result.set(key, value); } else { result.set(key, currValue.widen(value)); } } return result; } narrow(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } const result = this.create(this.value); for (const key of result.value.keys()) { if (!other.has(key)) { result.remove(key); } } for (const [key, value] of other.value.entries()) { const currValue = result.get(key); if (currValue !== undefined) { result.set(key, currValue.narrow(value)); } } return result; } concretize(limit) { if (this.value === lattice_1.Bottom) { return new Set(); } let mappings = new Set([new Map()]); for (const [key, value] of this.value.entries()) { 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 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, this.domain.abstract(values)); } return this.create(result); } toJson() { if (this.value === lattice_1.Bottom) { return this.value.description; } return Object.fromEntries(this.value.entries().map(([key, value]) => [key, value.toJson()])); } toString() { if (this.value === lattice_1.Bottom) { return lattice_1.BottomSymbol; } return '(' + this.value.entries().toArray().map(([key, value]) => `${abstract_domain_1.AbstractDomain.toString(key)} -> ${value.toString()}`).join(', ') + ')'; } isTop() { return this.value !== lattice_1.Bottom && this.value.size === 0; } isBottom() { return this.value === lattice_1.Bottom; } isValue() { return this.value !== lattice_1.Bottom; } } exports.StateAbstractDomain = StateAbstractDomain; //# sourceMappingURL=state-abstract-domain.js.map