@eagleoutice/flowr-dev
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
132 lines • 4.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RValue = exports.Bottom = exports.Top = void 0;
exports.typeOfValue = typeOfValue;
exports.isTop = isTop;
exports.isBottom = isBottom;
exports.isValue = isValue;
exports.asValue = asValue;
exports.stringifyValue = stringifyValue;
const assert_1 = require("../../../util/assert");
exports.Top = { type: Symbol('⊤') };
exports.Bottom = { type: Symbol('⊥') };
/**
*
*/
function typeOfValue(value) {
return value.type;
}
/** Checks whether the given value is the top value */
// @ts-expect-error -- this is a save cast
function isTop(value) {
return value === exports.Top;
}
/** Checks whether the given value is the bottom value */
// @ts-expect-error -- this is a save cast
function isBottom(value) {
return value === exports.Bottom;
}
/** Checks whether the given value is a proper value (neither top nor bottom) */
function isValue(value) {
return !isTop(value) && !isBottom(value);
}
/**
* Treat a value as unlifted value, throws if it is top or bottom.
*/
function asValue(value) {
(0, assert_1.guard)(isValue(value), 'Expected a value, but got a top or bottom value');
return value;
}
function tryStringifyBoTop(value, otherwise, onTop = () => '⊤', onBottom = () => '⊥') {
if (isTop(value)) {
return onTop();
}
else if (isBottom(value)) {
return onBottom();
}
else {
return otherwise(value);
}
}
function stringifyRNumberSuffix(value) {
let suffix = '';
if (value.markedAsInt) {
suffix += 'L';
}
if (value.complexNumber) {
suffix += 'i';
}
// do something about iL even though it is impossible?
return suffix;
}
function renderString(value) {
const quote = value.quotes;
const raw = value.flag === 'raw';
if (raw) {
return `r${quote}(${value.str})${quote}`;
}
else {
return `${quote}${JSON.stringify(value.str).slice(1, -1)}${quote}`;
}
}
/**
*
*/
function stringifyValue(value) {
return tryStringifyBoTop(value, v => {
const t = v.type;
switch (t) {
case 'null':
return 'NULL';
case 'interval':
return `${v.startInclusive ? '[' : '('}${stringifyValue(v.start)}, ${stringifyValue(v.end)}${v.endInclusive ? ']' : ')'}`;
case 'vector':
return tryStringifyBoTop(v.elements, e => {
return `<${stringifyValue(v.elementDomain)}> c(${e.map(stringifyValue).join(',')})`;
}, () => `⊤ (vector, ${stringifyValue(v.elementDomain)})`, () => `⊥ (vector, ${stringifyValue(v.elementDomain)})`);
case 'set':
return tryStringifyBoTop(v.elements, e => {
return e.length === 1 ? stringifyValue(e[0]) : `{ ${e.map(stringifyValue).join(',')} }`;
}, () => '⊤ (set)', () => '⊥ (set)');
case 'number':
return tryStringifyBoTop(v.value, n => `${n.num}${stringifyRNumberSuffix(n)}`, () => '⊤ (number)', () => '⊥ (number)');
case 'string':
return tryStringifyBoTop(v.value, renderString, () => '⊤ (string)', () => '⊥ (string)');
case 'logical':
return tryStringifyBoTop(v.value, l => l === 'maybe' ? 'maybe' : l ? 'TRUE' : 'FALSE', () => '⊤ (logical)', () => '⊥ (logical)');
case 'missing':
return '(missing)';
case 'function-definition':
return 'fn-def';
default:
(0, assert_1.assertUnreachable)(t);
}
});
}
/**
* Reads the plain TS value a {@link Value} stands for, `undefined` whenever it stands for more than one, for
* none, or for another kind. Prefer these over reaching into a value's shape by hand.
*
* This is the constant-folding view: it answers "is this one known constant" and nothing else. It runs no
* fixpoint, knows no control flow, and widens nothing. For an abstract state that does, use the dedicated
* abstract interpretation in `src/abstract-interpretation/`.
*/
exports.RValue = {
name: 'RValue',
/** The number the value stands for, collapsing an interval that admits a single one. */
numberOf(value) {
if (value.type === 'number') {
return isValue(value.value) && !value.value.complexNumber ? value.value.num : undefined;
}
else if (value.type === 'interval' && value.startInclusive && value.endInclusive) {
const start = exports.RValue.numberOf(value.start);
return start !== undefined && start === exports.RValue.numberOf(value.end) ? start : undefined;
}
return undefined;
},
/** The string the value stands for. */
stringOf(value) {
return value.type === 'string' && isValue(value.value) ? value.value.str : undefined;
}
};
//# sourceMappingURL=r-value.js.map