summaryrefslogtreecommitdiff
path: root/js/src/jsnum.cpp
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2021-02-13 09:41:29 +0000
committerMoonchild <moonchild@palemoon.org>2021-02-13 09:41:29 +0000
commitfc65e1f2fa4239c6271d666b3366cdf7cf440580 (patch)
tree053640b398b85d267fe010fe1249c563010cc562 /js/src/jsnum.cpp
parent458939c9d94049596ca6148b7b0014d5e7db36f8 (diff)
downloaduxp-fc65e1f2fa4239c6271d666b3366cdf7cf440580.tar.gz
Issue #1739 - Implement numeric separators.
Resolves #1739
Diffstat (limited to 'js/src/jsnum.cpp')
-rw-r--r--js/src/jsnum.cpp67
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)
{