@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
157 lines • 5.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RNull = exports.RNa = exports.RInf = exports.RIntegerMarker = exports.RImaginaryMarker = exports.RNumHexFloatRegex = exports.RFalse = exports.RTrue = void 0;
exports.ts2r = ts2r;
exports.isBoolean = isBoolean;
exports.boolean2ts = boolean2ts;
exports.number2ts = number2ts;
exports.string2ts = string2ts;
exports.isNA = isNA;
class ValueConversionError extends Error {
constructor(message) {
super(message);
this.name = 'ValueConversionError';
}
}
/**
* transforms a value to something R can understand (e.g., booleans to TRUE/FALSE)
*/
function ts2r(value) {
if (typeof value === 'string') {
return JSON.stringify(value);
}
else if (typeof value === 'number') {
if (isNaN(value)) {
return exports.RNa;
}
else if (!isFinite(value)) {
return exports.RInf;
}
return value.toString();
}
else if (typeof value === 'boolean') {
return value ? 'TRUE' : 'FALSE';
}
else if (value === null) {
return 'NULL';
}
else if (typeof value === 'undefined') {
return 'NA';
}
else if (Array.isArray(value)) {
return `c(${value.map(ts2r).join(', ')})`;
}
else if (typeof value === 'object') {
const obj = Object.entries(value)
.map(([key, value]) => `${key} = ${ts2r(value)}`)
.join(', ');
return `list(${obj})`;
}
throw new ValueConversionError(`cannot convert value of type ${typeof value} to R code`);
}
/** The R literal for the logical true */
exports.RTrue = 'TRUE';
/** The R literal for the logical false */
exports.RFalse = 'FALSE';
function isBoolean(value) {
return value === exports.RTrue || value === exports.RFalse;
}
function boolean2ts(value) {
if (value === exports.RTrue) {
return true;
}
else if (value === exports.RFalse) {
return false;
}
throw new ValueConversionError(`value ${value} is not a legal R boolean`);
}
exports.RNumHexFloatRegex = /^\s*0x(?<intPart>[0-9a-f]+)?(\.(?<floatPart>[0-9a-f]*))?p(?<exp>[-+]?\d+)\s*$/;
function getDecimalPlacesWithRadix(floatPart, radix) {
return [...floatPart].reduce((acc, c, idx) => acc + parseInt(c, radix) / (radix ** (idx + 1)), 0);
}
exports.RImaginaryMarker = 'i';
exports.RIntegerMarker = 'L';
exports.RInf = 'Inf';
function number2ts(value) {
// check for hexadecimal number with floating point addon which is supported by R but not by JS :/
let lcValue = value.toLowerCase();
/* both checks are case-sensitive! */
const last = value[value.length - 1];
const markedAsInt = last === exports.RIntegerMarker;
const complexNumber = last === exports.RImaginaryMarker;
if (markedAsInt || complexNumber) {
lcValue = lcValue.slice(0, -1);
}
if (value === exports.RInf) {
return {
num: Infinity,
complexNumber,
markedAsInt
};
}
if (value === exports.RNa) {
return {
num: NaN,
complexNumber,
markedAsInt
};
}
const floatHex = lcValue.match(exports.RNumHexFloatRegex);
if (floatHex == null) {
return {
num: Number(lcValue),
complexNumber,
markedAsInt
};
}
else {
const { intPart, floatPart, exp } = floatHex.groups;
const base = intPart === undefined ? 0 : parseInt(`${intPart}`, 16);
const floatSuffix = floatPart === undefined ? 0 : getDecimalPlacesWithRadix(floatPart, 16);
const exponent = parseInt(exp, 10);
return {
num: (base + floatSuffix) * Math.pow(2, exponent),
complexNumber,
markedAsInt
};
}
}
/**
* Convert a valid R string into a {@link RStringValue}.
*
* @throws {@link ValueConversionError} if the string has an unknown starting quote
*/
function string2ts(value) {
if (value.length < 2) {
throw new ValueConversionError(`cannot parse string '${value}' as it is too short`);
}
const init = value[0];
if (init === '"' || init === '\'') {
return {
str: value.slice(1, -1),
quotes: init
};
}
else if (init === 'r' || init === 'R' && value.length >= 3) {
const flags = value[1];
if (flags === '"' || flags === '\'') {
return {
str: value.slice(2, -1),
quotes: flags,
flag: 'raw'
};
}
else {
throw new ValueConversionError(`expected string to start with a known quote (' or "), or raw, yet received ${value}`);
}
}
else {
throw new ValueConversionError(`expected string to start with a known quote (' or "), or raw, yet received ${value}`);
}
}
exports.RNa = 'NA';
exports.RNull = 'NULL';
function isNA(value) {
return value === exports.RNa;
}
//# sourceMappingURL=convert-values.js.map