UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

132 lines 4.94 kB
"use strict"; 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