UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

173 lines 5.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RNull = exports.RNa = exports.RStringValue = exports.RNumberValue = exports.RInf = exports.RIntegerMarker = exports.RImaginaryMarker = exports.RNumHexFloatRegex = exports.RFalse = exports.RTrue = void 0; exports.ts2r = ts2r; exports.isBoolean = isBoolean; exports.boolean2ts = boolean2ts; exports.isNA = isNA; const strings_1 = require("../../util/text/strings"); 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'; /** * Checks whether the given string is an R boolean (logical) literal. */ function isBoolean(value) { return value === exports.RTrue || value === exports.RFalse; } /** * Converts an R boolean (logical) literal to a TypeScript boolean. */ 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'; exports.RNumberValue = { name: 'RNumberValue', fromRLexeme(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.at(-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 }; } } }; /** * Checks whether the given string is an R string literal (including raw strings). */ exports.RStringValue = { name: 'RStringValue', /** * Convert a valid R string into a {@link RStringValue}. * @throws {@link ValueConversionError} if the string has an unknown starting quote */ fromRLexeme(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: (0, strings_1.dropRawStringSurround)(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'; /** * Checks whether the given string is the R NA literal (untyped). */ function isNA(value) { return value === exports.RNa; } //# sourceMappingURL=convert-values.js.map