UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

179 lines 6.1 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 as mapping of AST node IDs of a program 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 mapped AST node ID to Top. * @template Domain - Type of the abstract domain to map the AST node IDs to * @see {@link NodeId} for the node IDs of the AST nodes */ class StateAbstractDomain { _value; constructor(value) { this._value = new Map(value); } get value() { return this._value; } bottom() { return new StateAbstractDomain(new Map()); } top() { const result = new StateAbstractDomain(this.value); for (const [key, value] of result.value) { result._value.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 [nodeId, value] of this.value) { const otherValue = other.value.get(nodeId); if (otherValue === undefined || !value.equals(otherValue)) { return false; } } return true; } leq(other) { if (this.value === other.value) { return true; } for (const [nodeId, value] of this.value) { const otherValue = other.value.get(nodeId); if (otherValue === undefined || !value.leq(otherValue)) { return false; } } return true; } join(...values) { const result = new StateAbstractDomain(this.value); for (const other of values) { for (const [nodeId, value] of other.value) { const currValue = result.value.get(nodeId); if (currValue === undefined) { result.value.set(nodeId, value); } else { result.value.set(nodeId, currValue.join(value)); } } } return result; } meet(...values) { const result = new StateAbstractDomain(this.value); for (const other of values) { for (const [nodeId] of result.value) { if (!other.value.has(nodeId)) { result.value.delete(nodeId); } } for (const [nodeId, value] of other.value) { const currValue = result.value.get(nodeId); if (currValue !== undefined) { result.value.set(nodeId, currValue.meet(value)); } } } return result; } widen(other) { const result = new StateAbstractDomain(this.value); for (const [nodeId, value] of other.value) { const currValue = result.value.get(nodeId); if (currValue === undefined) { result.value.set(nodeId, value); } else { result.value.set(nodeId, currValue.widen(value)); } } return result; } narrow(other) { const result = new StateAbstractDomain(this.value); for (const [nodeId] of this.value) { if (!other.value.has(nodeId)) { result.value.delete(nodeId); } } for (const [nodeId, value] of other.value) { const currValue = result.value.get(nodeId); if (currValue !== undefined) { result.value.set(nodeId, currValue.narrow(value)); } } return result; } concretize(limit = abstract_domain_1.DEFAULT_INFERENCE_LIMIT) { if (this.value.values().some(value => value.isBottom())) { return new Set(); } let states = new Set([new Map()]); for (const [nodeId, value] of this.value) { const concreteValues = value.concretize(limit); if (concreteValues === lattice_1.Top) { return lattice_1.Top; } const newStates = new Set(); for (const state of states) { for (const concrete of concreteValues) { if (newStates.size > limit) { return lattice_1.Top; } const map = new Map(state); map.set(nodeId, concrete); newStates.add(map); } } states = newStates; } return states; } abstract(concrete) { const entry = [...this.value.values()][0]; if (concrete === lattice_1.Top || entry === undefined) { return new StateAbstractDomain(new Map()); } const mappings = new Map(); for (const state of concrete) { for (const [nodeId, value] of state) { const mapping = mappings.get(nodeId); if (mapping === undefined) { mappings.set(nodeId, new Set([value])); } else { mapping.add(value); } } } const result = new Map(); for (const [nodeId, values] of mappings) { result.set(nodeId, entry.abstract(values)); } return new StateAbstractDomain(result); } toString() { return '(' + this.value.entries().toArray().map(([key, value]) => `${key} -> ${value.toString()}`).join(', ') + ')'; } isTop() { return this.value.values().every(value => value.isTop()); } isBottom() { return this.value.size === 0; } isValue() { return true; } } exports.StateAbstractDomain = StateAbstractDomain; //# sourceMappingURL=state-abstract-domain.js.map