diff options
author | Moonchild <moonchild@palemoon.org> | 2021-02-13 09:41:29 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-02-13 09:41:29 +0000 |
commit | fc65e1f2fa4239c6271d666b3366cdf7cf440580 (patch) | |
tree | 053640b398b85d267fe010fe1249c563010cc562 /js/src/jsnum.cpp | |
parent | 458939c9d94049596ca6148b7b0014d5e7db36f8 (diff) | |
download | uxp-fc65e1f2fa4239c6271d666b3366cdf7cf440580.tar.gz |
Issue #1739 - Implement numeric separators.
Resolves #1739
Diffstat (limited to 'js/src/jsnum.cpp')
-rw-r--r-- | js/src/jsnum.cpp | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index c15b3de0d1..549596e579 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -71,12 +71,16 @@ ComputeAccurateDecimalInteger(ExclusiveContext* cx, const CharT* start, const Ch if (!cstr) return false; + size_t j = 0; for (size_t i = 0; i < length; i++) { char c = char(start[i]); + if (c == '_') { + continue; + } MOZ_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')); - cstr[i] = c; + cstr[j++] = c; } - cstr[length] = 0; + cstr[j] = 0; char* estr; int err = 0; @@ -111,8 +115,14 @@ class BinaryDigitReader if (digitMask == 0) { if (start == end) return -1; - int c = *start++; + if (c == '_') { + // Skip over one _ and one _ only. + if (start == end) + return -1; + c = *start++; + } + MOZ_ASSERT(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')); if ('0' <= c && c <= '9') digit = c - '0'; @@ -209,7 +219,8 @@ js::ParseDecimalNumber(const mozilla::Range<const char16_t> chars); template <typename CharT> bool js::GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, int base, - const CharT** endp, double* dp) + PrefixIntegerSeparatorHandling separatorHandling, const CharT** endp, + double* dp) { MOZ_ASSERT(start <= end); MOZ_ASSERT(2 <= base && base <= 36); @@ -225,6 +236,8 @@ js::GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, digit = c - 'a' + 10; else if ('A' <= c && c <= 'Z') digit = c - 'A' + 10; + else if (c == '_' && separatorHandling == PrefixIntegerSeparatorHandling::SkipUnderscore) + continue; else break; if (digit >= base) @@ -242,7 +255,7 @@ js::GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, /* * Otherwise compute the correct integer from the prefix of valid digits * if we're computing for base ten or a power of two. Don't worry about - * other bases; see 15.1.2.2 step 13. + * other bases; see ES2018, 18.2.5 `parseInt(string, radix)`, step 13. */ if (base == 10) return ComputeAccurateDecimalInteger(cx, start, s, dp); @@ -255,11 +268,13 @@ js::GetPrefixInteger(ExclusiveContext* cx, const CharT* start, const CharT* end, template bool js::GetPrefixInteger(ExclusiveContext* cx, const char16_t* start, const char16_t* end, int base, - const char16_t** endp, double* dp); + PrefixIntegerSeparatorHandling separatorHandling, const char16_t** endp, + double* dp); template bool -js::GetPrefixInteger(ExclusiveContext* cx, const Latin1Char* start, const Latin1Char* end, - int base, const Latin1Char** endp, double* dp); +js::GetPrefixInteger(ExclusiveContext* cx, const Latin1Char* start, const Latin1Char* end, int base, + PrefixIntegerSeparatorHandling separatorHandling, const Latin1Char** endp, + double* dp); bool js::GetDecimalInteger(ExclusiveContext* cx, const char16_t* start, const char16_t* end, double* dp) @@ -270,6 +285,8 @@ js::GetDecimalInteger(ExclusiveContext* cx, const char16_t* start, const char16_ double d = 0.0; for (; s < end; s++) { char16_t c = *s; + if (c == '_') + continue; MOZ_ASSERT('0' <= c && c <= '9'); int digit = c - '0'; d = d * 10 + digit; @@ -285,6 +302,36 @@ js::GetDecimalInteger(ExclusiveContext* cx, const char16_t* start, const char16_ return ComputeAccurateDecimalInteger(cx, start, s, dp); } +bool +js::GetDecimalNonInteger(ExclusiveContext* cx, const char16_t* start, const char16_t* end, double* dp) +{ + MOZ_ASSERT(start <= end); + + size_t length = end - start; + Vector<char, 32> chars(cx); + if (!chars.growByUninitialized(length + 1)) + return false; + + const char16_t* s = start; + size_t i = 0; + for (; s < end; s++) { + char16_t c = *s; + if (c == '_') + continue; + MOZ_ASSERT(('0' <= c && c <= '9') || c == '.' || c == 'e' || c == 'E' || c == '+' || + c == '-'); + chars[i++] = char(c); + } + chars[i] = 0; + + char* ep; + int err; // unused + *dp = js_strtod_harder(cx->dtoaState(), chars.begin(), &ep, &err); + MOZ_ASSERT(ep >= chars.begin()); + + return true; +} + static bool num_parseFloat(JSContext* cx, unsigned argc, Value* vp) { @@ -355,7 +402,7 @@ ParseIntImpl(JSContext* cx, const CharT* chars, size_t length, bool stripPrefix, /* Steps 11-15. */ const CharT* actualEnd; double d; - if (!GetPrefixInteger(cx, s, end, radix, &actualEnd, &d)) + if (!GetPrefixInteger(cx, s, end, radix, PrefixIntegerSeparatorHandling::None, &actualEnd, &d)) return false; if (s == actualEnd) @@ -1322,7 +1369,7 @@ CharsToNumber(ExclusiveContext* cx, const CharT* chars, size_t length, double* r */ const CharT* endptr; double d; - if (!GetPrefixInteger(cx, bp + 2, end, radix, &endptr, &d) || + if (!GetPrefixInteger(cx, bp + 2, end, radix, PrefixIntegerSeparatorHandling::None, &endptr, &d) || endptr == bp + 2 || SkipSpace(endptr, end) != end) { |