import { TrimString } from '../runtime-semantics/all.mts'; import { Q, X, type ValueEvaluator } from '../completion.mts'; import { Value, type Arguments } from '../value.mts'; import { Assert, CreateBuiltinFunction, ToInt32, ToString, F, R as MathematicalValue, Realm, } from '#self'; function digitToNumber(_digit: string) { let digit = _digit.charCodeAt(0); if (digit < 0x30 /* 0 */) { return NaN; } if (digit <= 0x39 /* 9 */) { return digit - 0x30; } // Convert to lower case. digit &= ~0x20; // eslint-disable-line no-bitwise if (digit < 0x41 /* A */) { return NaN; } if (digit <= 0x5a /* Z */) { return digit - 0x41 /* A */ + 10; } return NaN; } function stringToRadixNumber(str: string, R: number) { let num = 0; for (let i = 0; i < str.length; i += 1) { const power = str.length - i - 1; const multiplier = R ** power; const dig = digitToNumber(str[i]); Assert(!Number.isNaN(dig) && dig < R); num += dig * multiplier; } return num; } function searchNotRadixDigit(str: string, R: number) { for (let i = 0; i < str.length; i += 1) { const num = digitToNumber(str[i]); if (Number.isNaN(num) || num >= R) { return i; } } return str.length; } /** https://tc39.es/ecma262/#sec-parseint-string-radix */ function* ParseInt([string = Value.undefined, radix = Value.undefined]: Arguments): ValueEvaluator { const inputString = Q(yield* ToString(string)); let S = X(TrimString(inputString, 'start')).stringValue(); let sign = 1; if (S !== '' && S[0] === '\x2D') { sign = -1; } if (S !== '' && (S[0] === '\x2B' || S[0] === '\x2D')) { S = S.slice(1); } let R = MathematicalValue(Q(yield* ToInt32(radix))); let stripPrefix = true; if (R !== 0) { if (R < 2 || R > 36) { return F(NaN); } if (R !== 16) { stripPrefix = false; } } else { R = 10; } if (stripPrefix === true) { if (S.length >= 2 && (S.startsWith('0x') || S.startsWith('0X'))) { S = S.slice(2); R = 16; } } const Z = S.slice(0, searchNotRadixDigit(S, R)); if (Z === '') { return F(NaN); } const mathInt = stringToRadixNumber(Z, R); if (mathInt === 0) { if (sign === -1) { return F(-0); } return F(+0); } const number = mathInt; return F(sign * number); } export function bootstrapParseInt(realmRec: Realm) { realmRec.Intrinsics['%parseInt%'] = CreateBuiltinFunction(ParseInt, 2, Value('parseInt'), [], realmRec); }