Commit 9ffe0670 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Fix StringToBigInt("") to return 0n.

Whitespace-only strings count as empty too.

This behavior is different from BigInt.parseInt(""),
which throws a SyntaxError.

Bug: v8:6791, v8:6957
Change-Id: I6671c803f3ba83e23c3e0cad81d3af29dba61c9f
Reviewed-on: https://chromium-review.googlesource.com/727301Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48797}
parent 5917d5c1
......@@ -261,7 +261,7 @@ void AstValue::Internalize(Isolate* isolate) {
case BIGINT:
// TODO(adamk): Don't check-fail on conversion failure; instead
// check for errors during parsing and throw at that point.
set_value(StringToBigInt(isolate, bigint_buffer_).ToHandleChecked());
set_value(BigIntLiteral(isolate, bigint_buffer_).ToHandleChecked());
break;
case BOOLEAN:
if (bool_) {
......
......@@ -65,7 +65,7 @@ BUILTIN(BigIntParseInt) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewSyntaxError(MessageTemplate::kToRadixFormatRange));
}
RETURN_RESULT_OR_FAILURE(isolate, StringToBigInt(isolate, subject, radix32));
RETURN_RESULT_OR_FAILURE(isolate, BigIntParseInt(isolate, subject, radix32));
}
BUILTIN(BigIntAsUintN) {
......
......@@ -218,7 +218,7 @@ class StringToIntHelper {
}
// Subclasses get access to internal state:
enum State { kRunning, kError, kJunk, kZero, kDone };
enum State { kRunning, kError, kJunk, kEmpty, kZero, kDone };
Isolate* isolate() { return isolate_; }
int radix() { return radix_; }
......@@ -291,7 +291,7 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
UnicodeCache* unicode_cache = isolate_->unicode_cache();
if (!AdvanceToNonspace(unicode_cache, &current, end)) {
return set_state(kJunk);
return set_state(kEmpty);
}
if (*current == '+') {
......@@ -432,6 +432,7 @@ class NumberParseIntHelper : public StringToIntHelper {
ParseInt();
switch (state()) {
case kJunk:
case kEmpty:
return JunkStringValue();
case kZero:
return SignedZero(negative());
......@@ -837,17 +838,32 @@ double StringToInt(Isolate* isolate, Handle<String> string, int radix) {
class BigIntParseIntHelper : public StringToIntHelper {
public:
// Configures what to return for empty or whitespace-only input strings.
enum class EmptyStringResult { kSyntaxError, kZero, kUnreachable };
// Used for BigInt.parseInt API, where the input is a Heap-allocated String.
BigIntParseIntHelper(Isolate* isolate, Handle<String> string, int radix)
: StringToIntHelper(isolate, string, radix) {}
BigIntParseIntHelper(Isolate* isolate, Handle<String> string, int radix,
EmptyStringResult empty_string_result)
: StringToIntHelper(isolate, string, radix),
empty_string_result_(empty_string_result) {}
// Used for parsing BigInt literals, where the input is a buffer of
// one-byte ASCII digits, along with an optional radix prefix.
BigIntParseIntHelper(Isolate* isolate, const uint8_t* string, int length)
: StringToIntHelper(isolate, string, length) {}
: StringToIntHelper(isolate, string, length),
empty_string_result_(EmptyStringResult::kUnreachable) {}
MaybeHandle<BigInt> GetResult() {
ParseInt();
if (state() == kEmpty) {
if (empty_string_result_ == EmptyStringResult::kSyntaxError) {
set_state(kJunk);
} else if (empty_string_result_ == EmptyStringResult::kZero) {
set_state(kZero);
} else {
UNREACHABLE();
}
}
switch (state()) {
case kJunk:
THROW_NEW_ERROR(isolate(),
......@@ -861,6 +877,7 @@ class BigIntParseIntHelper : public StringToIntHelper {
result_->set_sign(negative());
result_->RightTrim();
return result_;
case kEmpty:
case kRunning:
break;
}
......@@ -888,15 +905,24 @@ class BigIntParseIntHelper : public StringToIntHelper {
private:
Handle<BigInt> result_;
EmptyStringResult empty_string_result_;
};
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string,
MaybeHandle<BigInt> BigIntParseInt(Isolate* isolate, Handle<String> string,
int radix) {
BigIntParseIntHelper helper(isolate, string, radix);
BigIntParseIntHelper helper(
isolate, string, radix,
BigIntParseIntHelper::EmptyStringResult::kSyntaxError);
return helper.GetResult();
}
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string) {
BigIntParseIntHelper helper(isolate, string, 10,
BigIntParseIntHelper::EmptyStringResult::kZero);
return helper.GetResult();
}
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, const char* string) {
MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate, const char* string) {
BigIntParseIntHelper helper(isolate, reinterpret_cast<const uint8_t*>(string),
static_cast<int>(strlen(string)));
return helper.GetResult();
......
......@@ -105,17 +105,20 @@ double StringToDouble(UnicodeCache* unicode_cache,
double StringToInt(Isolate* isolate, Handle<String> string, int radix);
V8_EXPORT_PRIVATE MaybeHandle<BigInt> StringToBigInt(Isolate* isolate,
Handle<String> string,
int radix);
// This follows BigInt.parseInt semantics: "" => SyntaxError.
MaybeHandle<BigInt> BigIntParseInt(Isolate* isolate, Handle<String> string,
int radix);
// This follows https://tc39.github.io/proposal-bigint/#sec-string-to-bigint
// semantics: "" => 0n.
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string);
// This version expects a zero-terminated character array. Radix will
// be inferred from string prefix (case-insensitive):
// 0x -> hex
// 0o -> octal
// 0b -> binary
V8_EXPORT_PRIVATE MaybeHandle<BigInt> StringToBigInt(Isolate* isolate,
const char* string);
V8_EXPORT_PRIVATE MaybeHandle<BigInt> BigIntLiteral(Isolate* isolate,
const char* string);
const int kDoubleToCStringMinBufferSize = 100;
......
......@@ -305,7 +305,7 @@ MaybeHandle<BigInt> BigInt::Decrement(Handle<BigInt> x) {
bool BigInt::EqualToString(Handle<BigInt> x, Handle<String> y) {
Isolate* isolate = x->GetIsolate();
// a. Let n be StringToBigInt(y).
MaybeHandle<BigInt> maybe_n = StringToBigInt(isolate, y, 10);
MaybeHandle<BigInt> maybe_n = StringToBigInt(isolate, y);
// b. If n is NaN, return false.
Handle<BigInt> n;
if (!maybe_n.ToHandle(&n)) {
......
......@@ -90,9 +90,8 @@ const six = BigInt(6);
assertFalse(%Equal(one, 1.0000000000001));
assertFalse(%Equal(1.0000000000001, one));
// TODO(neis): Empty string must get converted to 0n.
//assertTrue(%Equal(zero, ""));
//assertTrue(%Equal("", zero));
assertTrue(%Equal(zero, ""));
assertTrue(%Equal("", zero));
assertTrue(%Equal(one, "1"));
assertTrue(%Equal("1", one));
......@@ -141,10 +140,12 @@ const six = BigInt(6);
assertFalse(one == 1.0000000000001);
assertFalse(1.0000000000001 == one);
//assertTrue(zero == "");
//assertTrue("" == zero);
assertTrue(zero == "");
assertTrue("" == zero);
assertTrue(zero == " \t\r\n");
assertTrue(one == "1");
assertTrue("1" == one);
assertFalse(" \t\r\n" == one);
assertTrue(one == {valueOf() { return true }});
assertTrue({valueOf() { return true }} == one);
......@@ -191,8 +192,8 @@ const six = BigInt(6);
assertTrue(%NotEqual(one, 1.0000000000001));
assertTrue(%NotEqual(1.0000000000001, one));
//assertFalse(%NotEqual(zero, ""));
//assertFalse(%NotEqual("", zero));
assertFalse(%NotEqual(zero, ""));
assertFalse(%NotEqual("", zero));
assertFalse(%NotEqual(one, "1"));
assertFalse(%NotEqual("1", one));
......@@ -241,8 +242,8 @@ const six = BigInt(6);
assertTrue(one != 1.0000000000001);
assertTrue(1.0000000000001 != one);
//assertFalse(zero != "");
//assertFalse("" != zero);
assertFalse(zero != "");
assertFalse("" != zero);
assertFalse(one != "1");
assertFalse("1" != one);
......
......@@ -66,25 +66,25 @@ TEST_F(BigIntWithIsolate, CompareToDouble) {
// Same bit length, difference in first digit.
double big_double = 4428155326412785451008.0;
Handle<BigInt> big =
StringToBigInt(isolate(), "0xF10D00000000000000").ToHandleChecked();
BigIntLiteral(isolate(), "0xF10D00000000000000").ToHandleChecked();
Compare(big, big_double, ComparisonResult::kGreaterThan);
big = StringToBigInt(isolate(), "0xE00D00000000000000").ToHandleChecked();
big = BigIntLiteral(isolate(), "0xE00D00000000000000").ToHandleChecked();
Compare(big, big_double, ComparisonResult::kLessThan);
double other_double = -13758438578910658560.0;
Handle<BigInt> other =
StringToBigInt(isolate(), "-0xBEEFC1FE00000000").ToHandleChecked();
BigIntLiteral(isolate(), "-0xBEEFC1FE00000000").ToHandleChecked();
Compare(other, other_double, ComparisonResult::kGreaterThan);
other = StringToBigInt(isolate(), "-0xBEEFCBFE00000000").ToHandleChecked();
other = BigIntLiteral(isolate(), "-0xBEEFCBFE00000000").ToHandleChecked();
Compare(other, other_double, ComparisonResult::kLessThan);
// Same bit length, difference in non-first digit.
big = StringToBigInt(isolate(), "0xF00D00000000000001").ToHandleChecked();
big = BigIntLiteral(isolate(), "0xF00D00000000000001").ToHandleChecked();
Compare(big, big_double, ComparisonResult::kGreaterThan);
big = StringToBigInt(isolate(), "0xF00A00000000000000").ToHandleChecked();
big = BigIntLiteral(isolate(), "0xF00A00000000000000").ToHandleChecked();
Compare(big, big_double, ComparisonResult::kLessThan);
other = StringToBigInt(isolate(), "-0xBEEFCAFE00000001").ToHandleChecked();
other = BigIntLiteral(isolate(), "-0xBEEFCAFE00000001").ToHandleChecked();
Compare(other, other_double, ComparisonResult::kLessThan);
// Same bit length, difference in fractional part.
......@@ -93,17 +93,17 @@ TEST_F(BigIntWithIsolate, CompareToDouble) {
big = factory->NewBigIntFromInt(0xF00D00);
Compare(big, 15731968.125, ComparisonResult::kLessThan);
Compare(big, 15731967.875, ComparisonResult::kGreaterThan);
big = StringToBigInt(isolate(), "0x123456789ab").ToHandleChecked();
big = BigIntLiteral(isolate(), "0x123456789ab").ToHandleChecked();
Compare(big, 1250999896491.125, ComparisonResult::kLessThan);
// Equality!
Compare(one, 1, ComparisonResult::kEqual);
Compare(minus_one, -1, ComparisonResult::kEqual);
big = StringToBigInt(isolate(), "0xF00D00000000000000").ToHandleChecked();
big = BigIntLiteral(isolate(), "0xF00D00000000000000").ToHandleChecked();
Compare(big, big_double, ComparisonResult::kEqual);
Handle<BigInt> two_52 =
StringToBigInt(isolate(), "0x10000000000000").ToHandleChecked();
BigIntLiteral(isolate(), "0x10000000000000").ToHandleChecked();
Compare(two_52, 4503599627370496.0, ComparisonResult::kEqual);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment