@@ -405,17 +405,29 @@ using namespace Js;
405
405
}
406
406
407
407
template <typename EncodedChar>
408
- double NumberUtilities::DblFromHex (const EncodedChar *psz, const EncodedChar **ppchLim)
408
+ double NumberUtilities::DblFromHex (const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled )
409
409
{
410
410
double dbl;
411
411
uint uT;
412
412
byte bExtra;
413
413
int cbit;
414
+ const EncodedChar* pszSave = psz;
414
415
415
416
// Skip leading zeros.
417
+ LSkipZeroes:
416
418
while (*psz == ' 0' )
417
419
psz++;
418
420
421
+ // If we stopped fast-scanning zeroes above because we ran into a numeric separator, skip that separator character if
422
+ // the previous character was a '0' (meaning the separator was not the first character in the literal) and the following
423
+ // character is a hex digit.
424
+ int unused;
425
+ if (*psz == ' _' && isNumericSeparatorEnabled && pszSave < psz && psz[-1 ] == ' 0' && FHexDigit (psz[1 ], &unused))
426
+ {
427
+ psz++;
428
+ goto LSkipZeroes;
429
+ }
430
+
419
431
dbl = 0 ;
420
432
Assert (Js::NumberUtilities::LuHiDbl (dbl) == 0 );
421
433
Assert (Js::NumberUtilities::LuLoDbl (dbl) == 0 );
@@ -460,9 +472,17 @@ using namespace Js;
460
472
if ((uT = (*psz - ' 0' )) > 9 )
461
473
{
462
474
if ((uT -= ' A' - ' 0' ) <= 5 || (uT -= ' a' - ' A' ) <= 5 )
475
+ {
463
476
uT += 10 ;
477
+ }
478
+ else if (*psz == ' _' && isNumericSeparatorEnabled && pszSave < psz && psz[-1 ] != ' _' && FHexDigit (psz[1 ], &unused))
479
+ {
480
+ continue ;
481
+ }
464
482
else
483
+ {
465
484
break ;
485
+ }
466
486
}
467
487
468
488
if (cbit <= 17 )
@@ -511,24 +531,40 @@ using namespace Js;
511
531
}
512
532
513
533
template <typename EncodedChar>
514
- double NumberUtilities::DblFromBinary (const EncodedChar *psz, const EncodedChar **ppchLim)
534
+ double NumberUtilities::DblFromBinary (const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled )
515
535
{
516
536
double dbl = 0 ;
517
537
Assert (Js::NumberUtilities::LuHiDbl (dbl) == 0 );
518
538
Assert (Js::NumberUtilities::LuLoDbl (dbl) == 0 );
519
539
uint uT;
520
540
byte bExtra = 0 ;
521
541
int cbit = 0 ;
542
+ const EncodedChar* pszSave = psz;
543
+
522
544
// Skip leading zeros.
545
+ LSkipZeroes:
523
546
while (*psz == ' 0' )
524
547
psz++;
548
+
525
549
// Get the first digit.
526
550
uT = *psz - ' 0' ;
527
551
if (uT > 1 )
528
552
{
553
+ // We can skip over this numeric separator character if:
554
+ // - numeric separators are enabled
555
+ // - we've walked past at least one zero character (ie: this isn't the first character in psz)
556
+ // - the previous character was a zero
557
+ // - the following character is a valid binary digit
558
+ if (*psz == ' _' && isNumericSeparatorEnabled && pszSave < psz && psz[-1 ] == ' 0' && static_cast <uint>(psz[1 ] - ' 0' ) <= 1 )
559
+ {
560
+ psz++;
561
+ goto LSkipZeroes;
562
+ }
563
+
529
564
*ppchLim = psz;
530
565
return dbl;
531
566
}
567
+
532
568
// Now that leading zeros are skipped first bit should be one so lets
533
569
// go ahead and count it and increment psz
534
570
cbit = 1 ;
@@ -544,12 +580,14 @@ using namespace Js;
544
580
// Why 52? 52 is the last explicit bit and 1 bit away from 53 (max bits of precision
545
581
// for double precision floating point)
546
582
const uint leftShiftValue = 52 ;
547
- for (; (uT = (*psz - ' 0' )) <= 1 ; psz++)
583
+
584
+ LGetBinaryDigit:
585
+ uT = *psz - ' 0' ;
586
+ if (uT <= 1 )
548
587
{
549
588
if (cbit <= rightShiftValue)
550
589
{
551
590
Js::NumberUtilities::LuHiDbl (dbl) |= (uint32)uT << (rightShiftValue - cbit);
552
-
553
591
}
554
592
else if (cbit <= leftShiftValue)
555
593
{
@@ -565,6 +603,16 @@ using namespace Js;
565
603
bExtra |= 1 ;
566
604
}
567
605
cbit++;
606
+ psz++;
607
+ goto LGetBinaryDigit;
608
+ }
609
+ else if (*psz == ' _' )
610
+ {
611
+ if (isNumericSeparatorEnabled && cbit > 0 && psz[-1 ] != ' _' && static_cast <uint>(psz[1 ] - ' 0' ) <= 1 )
612
+ {
613
+ psz++;
614
+ goto LGetBinaryDigit;
615
+ }
568
616
}
569
617
// Set the lim.
570
618
*ppchLim = psz;
@@ -593,17 +641,25 @@ using namespace Js;
593
641
}
594
642
595
643
template <typename EncodedChar>
596
- double NumberUtilities::DblFromOctal (const EncodedChar *psz, const EncodedChar **ppchLim)
644
+ double NumberUtilities::DblFromOctal (const EncodedChar *psz, const EncodedChar **ppchLim, bool isNumericSeparatorEnabled )
597
645
{
598
646
double dbl;
599
647
uint uT;
600
648
byte bExtra;
601
649
int cbit;
650
+ const EncodedChar* pszSave = psz;
602
651
603
652
// Skip leading zeros.
653
+ LSkipZeroes:
604
654
while (*psz == ' 0' )
605
655
psz++;
606
656
657
+ if (*psz == ' _' && isNumericSeparatorEnabled && psz > pszSave && psz[-1 ] == ' 0' && static_cast <uint>(psz[1 ] - ' 0' ) <= 7 )
658
+ {
659
+ psz++;
660
+ goto LSkipZeroes;
661
+ }
662
+
607
663
dbl = 0 ;
608
664
Assert (Js::NumberUtilities::LuHiDbl (dbl) == 0 );
609
665
Assert (Js::NumberUtilities::LuLoDbl (dbl) == 0 );
@@ -634,7 +690,9 @@ using namespace Js;
634
690
}
635
691
bExtra = 0 ;
636
692
637
- for (; (uT = (*psz - ' 0' )) <= 7 ; psz++)
693
+ LGetOctalDigit:
694
+ uT = *psz - ' 0' ;
695
+ if (uT <= 7 )
638
696
{
639
697
if (cbit <= 18 )
640
698
Js::NumberUtilities::LuHiDbl (dbl) |= (uint32)uT << (18 - cbit);
@@ -653,6 +711,16 @@ using namespace Js;
653
711
else if (0 != uT)
654
712
bExtra |= 1 ;
655
713
cbit += 3 ;
714
+ psz++;
715
+ goto LGetOctalDigit;
716
+ }
717
+ else if (*psz == ' _' )
718
+ {
719
+ if (isNumericSeparatorEnabled && cbit > 0 && psz[-1 ] != ' _' && static_cast <uint>(psz[1 ] - ' 0' ) <= 7 )
720
+ {
721
+ psz++;
722
+ goto LGetOctalDigit;
723
+ }
656
724
}
657
725
658
726
// Set the lim.
@@ -692,9 +760,9 @@ using namespace Js;
692
760
693
761
template double NumberUtilities::StrToDbl<char16>(const char16 * psz, const char16 **ppchLim, Js::ScriptContext *const scriptContext);
694
762
template double NumberUtilities::StrToDbl<utf8char_t >(const utf8char_t * psz, const utf8char_t **ppchLim, Js::ScriptContext *const scriptContext);
695
- template double NumberUtilities::DblFromHex<char16>(const char16 *psz, const char16 **ppchLim);
696
- template double NumberUtilities::DblFromHex<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim);
697
- template double NumberUtilities::DblFromBinary<char16>(const char16 *psz, const char16 **ppchLim);
698
- template double NumberUtilities::DblFromBinary<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim);
699
- template double NumberUtilities::DblFromOctal<char16>(const char16 *psz, const char16 **ppchLim);
700
- template double NumberUtilities::DblFromOctal<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim);
763
+ template double NumberUtilities::DblFromHex<char16>(const char16 *psz, const char16 **ppchLim, bool isNumericSeparatorEnabled );
764
+ template double NumberUtilities::DblFromHex<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim, bool isNumericSeparatorEnabled );
765
+ template double NumberUtilities::DblFromBinary<char16>(const char16 *psz, const char16 **ppchLim, bool isNumericSeparatorEnabled );
766
+ template double NumberUtilities::DblFromBinary<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim, bool isNumericSeparatorEnabled );
767
+ template double NumberUtilities::DblFromOctal<char16>(const char16 *psz, const char16 **ppchLim, bool isNumericSeparatorEnabled );
768
+ template double NumberUtilities::DblFromOctal<utf8char_t >(const utf8char_t *psz, const utf8char_t **ppchLim, bool isNumericSeparatorEnabled );
0 commit comments