import { Q, X, type ValueEvaluator } from '../completion.mts'; import { Value, type Arguments } from '../value.mts'; import { TrimString, } from '../runtime-semantics/all.mts'; import { CreateBuiltinFunction, ToString, F, Realm, } from '#self'; /** https://tc39.es/ecma262/#sec-parsefloat-string */ function* ParseFloat([string = Value.undefined]: Arguments): ValueEvaluator { // 1. Let inputString be ? ToString(string). const inputString = Q(yield* ToString(string)); // 2. Let trimmedString be ! TrimString(inputString, start). const trimmedString = X(TrimString(inputString, 'start')).stringValue(); // 3. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral (see 7.1.4.1), return NaN. // 4. Let numberString be the longest prefix of trimmedString, which might be trimmedString itself, that satisfies the syntax of a StrDecimalLiteral. // 5. Let mathFloat be MV of numberString. // 6. If mathFloat = 0ℝ, then // a. If the first code unit of trimmedString is the code unit 0x002D (HYPHEN-MINUS), return -0. // b. Return +0. // 7. Return the Number value for mathFloat. let numberString = trimmedString; if (/^[+-]/.test(numberString)) { numberString = numberString.slice(1); } const multiplier = trimmedString.startsWith('-') ? -1 : 1; if (numberString.startsWith('Infinity')) { return F(Infinity * multiplier); } let index = 0; done: { // eslint-disable-line no-labels // Eat leading zeros while (numberString[index] === '0') { index += 1; if (index === numberString.length) { return F(+0 * multiplier); } } // Eat integer part if (numberString[index] !== '.') { while (/[0-9]/.test(numberString[index])) { index += 1; } } // Eat fractional part if (numberString[index] === '.') { if (!/[0-9eE]/.test(numberString[index + 1])) { break done; // eslint-disable-line no-labels } index += 1; while (/[0-9]/.test(numberString[index])) { index += 1; } } // Eat exponent part if (numberString[index] === 'e' || numberString[index] === 'E') { if (!/[-+0-9]/.test(numberString[index + 1])) { break done; // eslint-disable-line no-labels } index += 1; if (numberString[index] === '-' || numberString[index] === '+') { index += 1; } while (/[0-9]/.test(numberString[index])) { index += 1; } } } return F(parseFloat(numberString.slice(0, index)) * multiplier); } export function bootstrapParseFloat(realmRec: Realm) { realmRec.Intrinsics['%parseFloat%'] = CreateBuiltinFunction(ParseFloat, 1, Value('parseFloat'), [], realmRec); }