[bigint] Support parsing of BigInt literals
Reuses the existing logic for BigInt.parseInt, adapted slightly to allow octal and binary radix prefixes (and to support parsing of a raw character buffer, rather than a v8::internal::String). Bug: v8:6791 Change-Id: I41904b2204721eac452e0765fa9ff0ab26ee343b Reviewed-on: https://chromium-review.googlesource.com/711334 Commit-Queue: Adam Klein <adamk@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Marja Hölttä <marja@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#48560}
This commit is contained in:
parent
c076667b7f
commit
3872ed6543
@ -213,6 +213,17 @@ bool AstValue::BooleanValue() const {
|
|||||||
return DoubleToBoolean(number_);
|
return DoubleToBoolean(number_);
|
||||||
case SMI:
|
case SMI:
|
||||||
return smi_ != 0;
|
return smi_ != 0;
|
||||||
|
case BIGINT: {
|
||||||
|
size_t length = strlen(bigint_buffer_);
|
||||||
|
DCHECK_GT(length, 0);
|
||||||
|
if (length == 1 && bigint_buffer_[0] == '0') return false;
|
||||||
|
// Skip over any radix prefix; BigInts with length > 1 only
|
||||||
|
// begin with zero if they include a radix.
|
||||||
|
for (size_t i = (bigint_buffer_[0] == '0') ? 2 : 0; i < length; ++i) {
|
||||||
|
if (bigint_buffer_[i] != '0') return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
return bool_;
|
return bool_;
|
||||||
case NULL_TYPE:
|
case NULL_TYPE:
|
||||||
@ -247,6 +258,11 @@ void AstValue::Internalize(Isolate* isolate) {
|
|||||||
case SMI:
|
case SMI:
|
||||||
set_value(handle(Smi::FromInt(smi_), isolate));
|
set_value(handle(Smi::FromInt(smi_), isolate));
|
||||||
break;
|
break;
|
||||||
|
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());
|
||||||
|
break;
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
if (bool_) {
|
if (bool_) {
|
||||||
set_value(isolate->factory()->true_value());
|
set_value(isolate->factory()->true_value());
|
||||||
@ -396,6 +412,11 @@ const AstValue* AstValueFactory::NewSmi(uint32_t number) {
|
|||||||
return AddValue(value);
|
return AddValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AstValue* AstValueFactory::NewBigInt(const char* number) {
|
||||||
|
AstValue* value = new (zone_) AstValue(number);
|
||||||
|
return AddValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
#define GENERATE_VALUE_GETTER(value, initializer) \
|
#define GENERATE_VALUE_GETTER(value, initializer) \
|
||||||
if (!value) { \
|
if (!value) { \
|
||||||
value = AddValue(new (zone_) AstValue(initializer)); \
|
value = AddValue(new (zone_) AstValue(initializer)); \
|
||||||
|
@ -217,10 +217,11 @@ class AstValue : public ZoneObject {
|
|||||||
|
|
||||||
bool IsPropertyName() const;
|
bool IsPropertyName() const;
|
||||||
|
|
||||||
bool BooleanValue() const;
|
V8_EXPORT_PRIVATE bool BooleanValue() const;
|
||||||
|
|
||||||
bool IsSmi() const { return type_ == SMI; }
|
bool IsSmi() const { return type_ == SMI; }
|
||||||
bool IsHeapNumber() const { return type_ == NUMBER; }
|
bool IsHeapNumber() const { return type_ == NUMBER; }
|
||||||
|
bool IsBigInt() const { return type_ == BIGINT; }
|
||||||
bool IsFalse() const { return type_ == BOOLEAN && !bool_; }
|
bool IsFalse() const { return type_ == BOOLEAN && !bool_; }
|
||||||
bool IsTrue() const { return type_ == BOOLEAN && bool_; }
|
bool IsTrue() const { return type_ == BOOLEAN && bool_; }
|
||||||
bool IsUndefined() const { return type_ == UNDEFINED; }
|
bool IsUndefined() const { return type_ == UNDEFINED; }
|
||||||
@ -249,6 +250,7 @@ class AstValue : public ZoneObject {
|
|||||||
SYMBOL,
|
SYMBOL,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
SMI,
|
SMI,
|
||||||
|
BIGINT,
|
||||||
BOOLEAN,
|
BOOLEAN,
|
||||||
NULL_TYPE,
|
NULL_TYPE,
|
||||||
UNDEFINED,
|
UNDEFINED,
|
||||||
@ -270,6 +272,10 @@ class AstValue : public ZoneObject {
|
|||||||
smi_ = i;
|
smi_ = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit AstValue(const char* n) : type_(BIGINT), next_(nullptr) {
|
||||||
|
bigint_buffer_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
explicit AstValue(bool b) : type_(BOOLEAN), next_(nullptr) { bool_ = b; }
|
explicit AstValue(bool b) : type_(BOOLEAN), next_(nullptr) { bool_ = b; }
|
||||||
|
|
||||||
explicit AstValue(Type t) : type_(t), next_(nullptr) {
|
explicit AstValue(Type t) : type_(t), next_(nullptr) {
|
||||||
@ -292,6 +298,7 @@ class AstValue : public ZoneObject {
|
|||||||
int smi_;
|
int smi_;
|
||||||
bool bool_;
|
bool bool_;
|
||||||
AstSymbol symbol_;
|
AstSymbol symbol_;
|
||||||
|
const char* bigint_buffer_;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -430,6 +437,7 @@ class AstValueFactory {
|
|||||||
const AstValue* NewSymbol(AstSymbol symbol);
|
const AstValue* NewSymbol(AstSymbol symbol);
|
||||||
V8_EXPORT_PRIVATE const AstValue* NewNumber(double number);
|
V8_EXPORT_PRIVATE const AstValue* NewNumber(double number);
|
||||||
const AstValue* NewSmi(uint32_t number);
|
const AstValue* NewSmi(uint32_t number);
|
||||||
|
V8_EXPORT_PRIVATE const AstValue* NewBigInt(const char* number);
|
||||||
const AstValue* NewBoolean(bool b);
|
const AstValue* NewBoolean(bool b);
|
||||||
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
|
const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
|
||||||
const AstValue* NewNull();
|
const AstValue* NewNull();
|
||||||
|
@ -3134,6 +3134,10 @@ class AstNodeFactory final BASE_EMBEDDED {
|
|||||||
return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos);
|
return new (zone_) Literal(ast_value_factory_->NewSmi(number), pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Literal* NewBigIntLiteral(const char* buffer, int pos) {
|
||||||
|
return new (zone_) Literal(ast_value_factory_->NewBigInt(buffer), pos);
|
||||||
|
}
|
||||||
|
|
||||||
Literal* NewBooleanLiteral(bool b, int pos) {
|
Literal* NewBooleanLiteral(bool b, int pos) {
|
||||||
return new (zone_) Literal(ast_value_factory_->NewBoolean(b), pos);
|
return new (zone_) Literal(ast_value_factory_->NewBoolean(b), pos);
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,11 @@ class StringToIntHelper {
|
|||||||
: isolate_(isolate), subject_(subject), radix_(radix) {
|
: isolate_(isolate), subject_(subject), radix_(radix) {
|
||||||
DCHECK(subject->IsFlat());
|
DCHECK(subject->IsFlat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for parsing BigInt literals, where the input is a Zone-allocated
|
||||||
|
// buffer of one-byte digits, along with an optional radix prefix.
|
||||||
|
StringToIntHelper(Isolate* isolate, const uint8_t* subject, int length)
|
||||||
|
: isolate_(isolate), raw_one_byte_subject_(subject), length_(length) {}
|
||||||
virtual ~StringToIntHelper() {}
|
virtual ~StringToIntHelper() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -197,11 +202,26 @@ class StringToIntHelper {
|
|||||||
// Subclasses may override this.
|
// Subclasses may override this.
|
||||||
virtual void HandleSpecialCases() {}
|
virtual void HandleSpecialCases() {}
|
||||||
|
|
||||||
|
bool IsOneByte() const {
|
||||||
|
return raw_one_byte_subject_ != nullptr ||
|
||||||
|
subject_->IsOneByteRepresentationUnderneath();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<const uint8_t> GetOneByteVector() {
|
||||||
|
if (raw_one_byte_subject_ != nullptr) {
|
||||||
|
return Vector<const uint8_t>(raw_one_byte_subject_, length_);
|
||||||
|
}
|
||||||
|
return subject_->GetFlatContent().ToOneByteVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<const uc16> GetTwoByteVector() {
|
||||||
|
return subject_->GetFlatContent().ToUC16Vector();
|
||||||
|
}
|
||||||
|
|
||||||
// Subclasses get access to internal state:
|
// Subclasses get access to internal state:
|
||||||
enum State { kRunning, kError, kJunk, kZero, kDone };
|
enum State { kRunning, kError, kJunk, kZero, kDone };
|
||||||
|
|
||||||
Isolate* isolate() { return isolate_; }
|
Isolate* isolate() { return isolate_; }
|
||||||
Handle<String> subject() { return subject_; }
|
|
||||||
int radix() { return radix_; }
|
int radix() { return radix_; }
|
||||||
int cursor() { return cursor_; }
|
int cursor() { return cursor_; }
|
||||||
int length() { return length_; }
|
int length() { return length_; }
|
||||||
@ -209,6 +229,14 @@ class StringToIntHelper {
|
|||||||
State state() { return state_; }
|
State state() { return state_; }
|
||||||
void set_state(State state) { state_ = state; }
|
void set_state(State state) { state_ = state; }
|
||||||
|
|
||||||
|
bool AllowOctalRadixPrefix() const {
|
||||||
|
return raw_one_byte_subject_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AllowBinaryRadixPrefix() const {
|
||||||
|
return raw_one_byte_subject_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class Char>
|
template <class Char>
|
||||||
void DetectRadixInternal(Char current, int length);
|
void DetectRadixInternal(Char current, int length);
|
||||||
@ -217,7 +245,8 @@ class StringToIntHelper {
|
|||||||
|
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
Handle<String> subject_;
|
Handle<String> subject_;
|
||||||
int radix_;
|
const uint8_t* raw_one_byte_subject_ = nullptr;
|
||||||
|
int radix_ = 0;
|
||||||
int cursor_ = 0;
|
int cursor_ = 0;
|
||||||
int length_ = 0;
|
int length_ = 0;
|
||||||
bool negative_ = false;
|
bool negative_ = false;
|
||||||
@ -228,12 +257,11 @@ class StringToIntHelper {
|
|||||||
void StringToIntHelper::ParseInt() {
|
void StringToIntHelper::ParseInt() {
|
||||||
{
|
{
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
String::FlatContent flat = subject_->GetFlatContent();
|
if (IsOneByte()) {
|
||||||
if (flat.IsOneByte()) {
|
Vector<const uint8_t> vector = GetOneByteVector();
|
||||||
Vector<const uint8_t> vector = flat.ToOneByteVector();
|
|
||||||
DetectRadixInternal(vector.start(), vector.length());
|
DetectRadixInternal(vector.start(), vector.length());
|
||||||
} else {
|
} else {
|
||||||
Vector<const uc16> vector = flat.ToUC16Vector();
|
Vector<const uc16> vector = GetTwoByteVector();
|
||||||
DetectRadixInternal(vector.start(), vector.length());
|
DetectRadixInternal(vector.start(), vector.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,13 +271,12 @@ void StringToIntHelper::ParseInt() {
|
|||||||
if (state_ != kRunning) return;
|
if (state_ != kRunning) return;
|
||||||
{
|
{
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
String::FlatContent flat = subject_->GetFlatContent();
|
if (IsOneByte()) {
|
||||||
if (flat.IsOneByte()) {
|
Vector<const uint8_t> vector = GetOneByteVector();
|
||||||
Vector<const uint8_t> vector = flat.ToOneByteVector();
|
|
||||||
DCHECK_EQ(length_, vector.length());
|
DCHECK_EQ(length_, vector.length());
|
||||||
ParseInternal(vector.start());
|
ParseInternal(vector.start());
|
||||||
} else {
|
} else {
|
||||||
Vector<const uc16> vector = flat.ToUC16Vector();
|
Vector<const uc16> vector = GetTwoByteVector();
|
||||||
DCHECK_EQ(length_, vector.length());
|
DCHECK_EQ(length_, vector.length());
|
||||||
ParseInternal(vector.start());
|
ParseInternal(vector.start());
|
||||||
}
|
}
|
||||||
@ -292,6 +319,16 @@ void StringToIntHelper::DetectRadixInternal(Char current, int length) {
|
|||||||
radix_ = 16;
|
radix_ = 16;
|
||||||
++current;
|
++current;
|
||||||
if (current == end) return set_state(kJunk);
|
if (current == end) return set_state(kJunk);
|
||||||
|
} else if (AllowOctalRadixPrefix() &&
|
||||||
|
(*current == 'o' || *current == 'O')) {
|
||||||
|
radix_ = 8;
|
||||||
|
++current;
|
||||||
|
DCHECK(current != end);
|
||||||
|
} else if (AllowBinaryRadixPrefix() &&
|
||||||
|
(*current == 'b' || *current == 'B')) {
|
||||||
|
radix_ = 2;
|
||||||
|
++current;
|
||||||
|
DCHECK(current != end);
|
||||||
} else {
|
} else {
|
||||||
leading_zero_ = true;
|
leading_zero_ = true;
|
||||||
}
|
}
|
||||||
@ -419,14 +456,13 @@ class NumberParseIntHelper : public StringToIntHelper {
|
|||||||
bool is_power_of_two = base::bits::IsPowerOfTwo(radix());
|
bool is_power_of_two = base::bits::IsPowerOfTwo(radix());
|
||||||
if (!is_power_of_two && radix() != 10) return;
|
if (!is_power_of_two && radix() != 10) return;
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
String::FlatContent flat = subject()->GetFlatContent();
|
if (IsOneByte()) {
|
||||||
if (flat.IsOneByte()) {
|
Vector<const uint8_t> vector = GetOneByteVector();
|
||||||
Vector<const uint8_t> vector = flat.ToOneByteVector();
|
|
||||||
DCHECK_EQ(length(), vector.length());
|
DCHECK_EQ(length(), vector.length());
|
||||||
result_ = is_power_of_two ? HandlePowerOfTwoCase(vector.start())
|
result_ = is_power_of_two ? HandlePowerOfTwoCase(vector.start())
|
||||||
: HandleBaseTenCase(vector.start());
|
: HandleBaseTenCase(vector.start());
|
||||||
} else {
|
} else {
|
||||||
Vector<const uc16> vector = flat.ToUC16Vector();
|
Vector<const uc16> vector = GetTwoByteVector();
|
||||||
DCHECK_EQ(length(), vector.length());
|
DCHECK_EQ(length(), vector.length());
|
||||||
result_ = is_power_of_two ? HandlePowerOfTwoCase(vector.start())
|
result_ = is_power_of_two ? HandlePowerOfTwoCase(vector.start())
|
||||||
: HandleBaseTenCase(vector.start());
|
: HandleBaseTenCase(vector.start());
|
||||||
@ -802,9 +838,15 @@ double StringToInt(Isolate* isolate, Handle<String> string, int radix) {
|
|||||||
|
|
||||||
class BigIntParseIntHelper : public StringToIntHelper {
|
class BigIntParseIntHelper : public StringToIntHelper {
|
||||||
public:
|
public:
|
||||||
|
// Used for BigInt.parseInt API, where the input is a Heap-allocated String.
|
||||||
BigIntParseIntHelper(Isolate* isolate, Handle<String> string, int radix)
|
BigIntParseIntHelper(Isolate* isolate, Handle<String> string, int radix)
|
||||||
: StringToIntHelper(isolate, string, radix) {}
|
: StringToIntHelper(isolate, string, radix) {}
|
||||||
|
|
||||||
|
// 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) {}
|
||||||
|
|
||||||
MaybeHandle<BigInt> GetResult() {
|
MaybeHandle<BigInt> GetResult() {
|
||||||
ParseInt();
|
ParseInt();
|
||||||
switch (state()) {
|
switch (state()) {
|
||||||
@ -855,6 +897,12 @@ MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string,
|
|||||||
return helper.GetResult();
|
return helper.GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, const char* string) {
|
||||||
|
BigIntParseIntHelper helper(isolate, reinterpret_cast<const uint8_t*>(string),
|
||||||
|
static_cast<int>(strlen(string)));
|
||||||
|
return helper.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
const char* DoubleToCString(double v, Vector<char> buffer) {
|
const char* DoubleToCString(double v, Vector<char> buffer) {
|
||||||
switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
|
switch (FPCLASSIFY_NAMESPACE::fpclassify(v)) {
|
||||||
case FP_NAN: return "NaN";
|
case FP_NAN: return "NaN";
|
||||||
|
@ -108,6 +108,13 @@ double StringToInt(Isolate* isolate, Handle<String> string, int radix);
|
|||||||
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string,
|
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, Handle<String> string,
|
||||||
int radix);
|
int radix);
|
||||||
|
|
||||||
|
// This version expects a zero-terminated character array. Radix will
|
||||||
|
// be inferred from string prefix (case-insensitive):
|
||||||
|
// 0x -> hex
|
||||||
|
// 0o -> octal
|
||||||
|
// 0b -> binary
|
||||||
|
MaybeHandle<BigInt> StringToBigInt(Isolate* isolate, const char* string);
|
||||||
|
|
||||||
const int kDoubleToCStringMinBufferSize = 100;
|
const int kDoubleToCStringMinBufferSize = 100;
|
||||||
|
|
||||||
// Converts a double to a string value according to ECMA-262 9.8.1.
|
// Converts a double to a string value according to ECMA-262 9.8.1.
|
||||||
|
@ -600,7 +600,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
|
|||||||
return LoadTheHole();
|
return LoadTheHole();
|
||||||
} else if (ast_value->IsString()) {
|
} else if (ast_value->IsString()) {
|
||||||
return LoadLiteral(ast_value->AsString());
|
return LoadLiteral(ast_value->AsString());
|
||||||
} else if (ast_value->IsHeapNumber()) {
|
} else if (ast_value->IsHeapNumber() || ast_value->IsBigInt()) {
|
||||||
size_t entry = GetConstantPoolEntry(ast_value);
|
size_t entry = GetConstantPoolEntry(ast_value);
|
||||||
OutputLdaConstant(entry);
|
OutputLdaConstant(entry);
|
||||||
return *this;
|
return *this;
|
||||||
@ -1448,7 +1448,7 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const AstValue* heap_number) {
|
size_t BytecodeArrayBuilder::GetConstantPoolEntry(const AstValue* heap_number) {
|
||||||
DCHECK(heap_number->IsHeapNumber());
|
DCHECK(heap_number->IsHeapNumber() || heap_number->IsBigInt());
|
||||||
return constant_array_builder()->Insert(heap_number);
|
return constant_array_builder()->Insert(heap_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,12 +191,12 @@ size_t ConstantArrayBuilder::Insert(const AstRawString* raw_string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t ConstantArrayBuilder::Insert(const AstValue* heap_number) {
|
size_t ConstantArrayBuilder::Insert(const AstValue* heap_number) {
|
||||||
// This method only accepts heap numbers. Other types of ast value should
|
// This method only accepts heap numbers and BigInts. Other types of
|
||||||
// either be passed through as raw values (in the case of strings), use the
|
// AstValue should either be passed through as raw values (in the
|
||||||
// singleton Insert methods (in the case of symbols), or skip the constant
|
// case of strings), use the singleton Insert methods (in the case
|
||||||
// pool entirely and use bytecodes with immediate values (Smis, booleans,
|
// of symbols), or skip the constant pool entirely and use bytecodes
|
||||||
// undefined, etc.).
|
// with immediate values (Smis, booleans, undefined, etc.).
|
||||||
DCHECK(heap_number->IsHeapNumber());
|
DCHECK(heap_number->IsHeapNumber() || heap_number->IsBigInt());
|
||||||
return constants_map_
|
return constants_map_
|
||||||
.LookupOrInsert(reinterpret_cast<intptr_t>(heap_number),
|
.LookupOrInsert(reinterpret_cast<intptr_t>(heap_number),
|
||||||
static_cast<uint32_t>(base::hash_value(heap_number)),
|
static_cast<uint32_t>(base::hash_value(heap_number)),
|
||||||
@ -340,7 +340,7 @@ Handle<Object> ConstantArrayBuilder::Entry::ToHandle(Isolate* isolate) const {
|
|||||||
case Tag::kRawString:
|
case Tag::kRawString:
|
||||||
return raw_string_->string();
|
return raw_string_->string();
|
||||||
case Tag::kHeapNumber:
|
case Tag::kHeapNumber:
|
||||||
DCHECK(heap_number_->IsHeapNumber());
|
DCHECK(heap_number_->IsHeapNumber() || heap_number_->IsBigInt());
|
||||||
return heap_number_->value();
|
return heap_number_->value();
|
||||||
case Tag::kScope:
|
case Tag::kScope:
|
||||||
return scope_->scope_info();
|
return scope_->scope_info();
|
||||||
|
@ -298,6 +298,13 @@ class ParserBase {
|
|||||||
|
|
||||||
#undef ALLOW_ACCESSORS
|
#undef ALLOW_ACCESSORS
|
||||||
|
|
||||||
|
bool allow_harmony_bigint() const {
|
||||||
|
return scanner()->allow_harmony_bigint();
|
||||||
|
}
|
||||||
|
void set_allow_harmony_bigint(bool allow) {
|
||||||
|
scanner()->set_allow_harmony_bigint(allow);
|
||||||
|
}
|
||||||
|
|
||||||
uintptr_t stack_limit() const { return stack_limit_; }
|
uintptr_t stack_limit() const { return stack_limit_; }
|
||||||
|
|
||||||
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
|
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
|
||||||
@ -1549,6 +1556,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage(
|
|||||||
break;
|
break;
|
||||||
case Token::SMI:
|
case Token::SMI:
|
||||||
case Token::NUMBER:
|
case Token::NUMBER:
|
||||||
|
case Token::BIGINT:
|
||||||
*message = MessageTemplate::kUnexpectedTokenNumber;
|
*message = MessageTemplate::kUnexpectedTokenNumber;
|
||||||
break;
|
break;
|
||||||
case Token::STRING:
|
case Token::STRING:
|
||||||
@ -1780,6 +1788,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
|
|||||||
case Token::FALSE_LITERAL:
|
case Token::FALSE_LITERAL:
|
||||||
case Token::SMI:
|
case Token::SMI:
|
||||||
case Token::NUMBER:
|
case Token::NUMBER:
|
||||||
|
case Token::BIGINT:
|
||||||
BindingPatternUnexpectedToken();
|
BindingPatternUnexpectedToken();
|
||||||
return impl()->ExpressionFromLiteral(Next(), beg_pos);
|
return impl()->ExpressionFromLiteral(Next(), beg_pos);
|
||||||
|
|
||||||
@ -4233,9 +4242,10 @@ template <typename Impl>
|
|||||||
bool ParserBase<Impl>::IsTrivialExpression() {
|
bool ParserBase<Impl>::IsTrivialExpression() {
|
||||||
Token::Value peek_token = peek();
|
Token::Value peek_token = peek();
|
||||||
if (peek_token == Token::SMI || peek_token == Token::NUMBER ||
|
if (peek_token == Token::SMI || peek_token == Token::NUMBER ||
|
||||||
peek_token == Token::NULL_LITERAL || peek_token == Token::TRUE_LITERAL ||
|
peek_token == Token::BIGINT || peek_token == Token::NULL_LITERAL ||
|
||||||
peek_token == Token::FALSE_LITERAL || peek_token == Token::STRING ||
|
peek_token == Token::TRUE_LITERAL || peek_token == Token::FALSE_LITERAL ||
|
||||||
peek_token == Token::IDENTIFIER || peek_token == Token::THIS) {
|
peek_token == Token::STRING || peek_token == Token::IDENTIFIER ||
|
||||||
|
peek_token == Token::THIS) {
|
||||||
// PeekAhead() is expensive & may not always be called, so we only call it
|
// PeekAhead() is expensive & may not always be called, so we only call it
|
||||||
// after checking peek().
|
// after checking peek().
|
||||||
Token::Value peek_ahead = PeekAhead();
|
Token::Value peek_ahead = PeekAhead();
|
||||||
|
@ -405,6 +405,9 @@ Literal* Parser::ExpressionFromLiteral(Token::Value token, int pos) {
|
|||||||
double value = scanner()->DoubleValue();
|
double value = scanner()->DoubleValue();
|
||||||
return factory()->NewNumberLiteral(value, pos);
|
return factory()->NewNumberLiteral(value, pos);
|
||||||
}
|
}
|
||||||
|
case Token::BIGINT:
|
||||||
|
return factory()->NewBigIntLiteral(
|
||||||
|
scanner()->CurrentLiteralAsCString(zone()), pos);
|
||||||
default:
|
default:
|
||||||
DCHECK(false);
|
DCHECK(false);
|
||||||
}
|
}
|
||||||
@ -513,6 +516,7 @@ Parser::Parser(ParseInfo* info)
|
|||||||
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
|
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
|
||||||
set_allow_harmony_async_iteration(FLAG_harmony_async_iteration);
|
set_allow_harmony_async_iteration(FLAG_harmony_async_iteration);
|
||||||
set_allow_harmony_template_escapes(FLAG_harmony_template_escapes);
|
set_allow_harmony_template_escapes(FLAG_harmony_template_escapes);
|
||||||
|
set_allow_harmony_bigint(FLAG_harmony_bigint);
|
||||||
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
|
||||||
++feature) {
|
++feature) {
|
||||||
use_counts_[feature] = 0;
|
use_counts_[feature] = 0;
|
||||||
|
@ -299,6 +299,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
SET_ALLOW(harmony_async_iteration);
|
SET_ALLOW(harmony_async_iteration);
|
||||||
SET_ALLOW(harmony_template_escapes);
|
SET_ALLOW(harmony_template_escapes);
|
||||||
SET_ALLOW(harmony_restrictive_generators);
|
SET_ALLOW(harmony_restrictive_generators);
|
||||||
|
SET_ALLOW(harmony_bigint);
|
||||||
#undef SET_ALLOW
|
#undef SET_ALLOW
|
||||||
}
|
}
|
||||||
return reusable_preparser_;
|
return reusable_preparser_;
|
||||||
|
@ -196,6 +196,7 @@ Scanner::Scanner(UnicodeCache* unicode_cache, int* use_counts)
|
|||||||
octal_pos_(Location::invalid()),
|
octal_pos_(Location::invalid()),
|
||||||
octal_message_(MessageTemplate::kNone),
|
octal_message_(MessageTemplate::kNone),
|
||||||
found_html_comment_(false),
|
found_html_comment_(false),
|
||||||
|
allow_harmony_bigint_(false),
|
||||||
use_counts_(use_counts) {}
|
use_counts_(use_counts) {}
|
||||||
|
|
||||||
void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) {
|
void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) {
|
||||||
@ -934,6 +935,7 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
|
|||||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||||
case Token::IDENTIFIER:
|
case Token::IDENTIFIER:
|
||||||
case Token::NUMBER:
|
case Token::NUMBER:
|
||||||
|
case Token::BIGINT:
|
||||||
case Token::REGEXP_LITERAL:
|
case Token::REGEXP_LITERAL:
|
||||||
case Token::SMI:
|
case Token::SMI:
|
||||||
case Token::STRING:
|
case Token::STRING:
|
||||||
@ -1321,14 +1323,20 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
|
|||||||
|
|
||||||
ScanDecimalDigits(); // optional
|
ScanDecimalDigits(); // optional
|
||||||
if (c0_ == '.') {
|
if (c0_ == '.') {
|
||||||
|
seen_period = true;
|
||||||
AddLiteralCharAdvance();
|
AddLiteralCharAdvance();
|
||||||
ScanDecimalDigits(); // optional
|
ScanDecimalDigits(); // optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan exponent, if any
|
bool is_bigint = false;
|
||||||
if (c0_ == 'e' || c0_ == 'E') {
|
if (allow_harmony_bigint() && c0_ == 'n' && !seen_period &&
|
||||||
|
(kind == DECIMAL || kind == HEX || kind == OCTAL || kind == BINARY)) {
|
||||||
|
is_bigint = true;
|
||||||
|
Advance();
|
||||||
|
} else if (c0_ == 'e' || c0_ == 'E') {
|
||||||
|
// scan exponent, if any
|
||||||
DCHECK(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
|
DCHECK(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
|
||||||
if (!(kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO))
|
if (!(kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO))
|
||||||
return Token::ILLEGAL;
|
return Token::ILLEGAL;
|
||||||
@ -1357,7 +1365,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
|
|||||||
octal_pos_ = Location(start_pos, source_pos());
|
octal_pos_ = Location(start_pos, source_pos());
|
||||||
octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero;
|
octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero;
|
||||||
}
|
}
|
||||||
return Token::NUMBER;
|
return is_bigint ? Token::BIGINT : Token::NUMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1787,6 +1795,16 @@ double Scanner::DoubleValue() {
|
|||||||
ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* Scanner::CurrentLiteralAsCString(Zone* zone) const {
|
||||||
|
DCHECK(is_literal_one_byte());
|
||||||
|
Vector<const uint8_t> vector = literal_one_byte_string();
|
||||||
|
int length = vector.length();
|
||||||
|
char* buffer = zone->NewArray<char>(length + 1);
|
||||||
|
memcpy(buffer, vector.start(), length);
|
||||||
|
buffer[length] = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
bool Scanner::IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
|
bool Scanner::IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
|
||||||
AstValueFactory* ast_value_factory) const {
|
AstValueFactory* ast_value_factory) const {
|
||||||
DCHECK_NOT_NULL(duplicate_finder);
|
DCHECK_NOT_NULL(duplicate_finder);
|
||||||
|
@ -260,6 +260,8 @@ class Scanner {
|
|||||||
|
|
||||||
double DoubleValue();
|
double DoubleValue();
|
||||||
|
|
||||||
|
const char* CurrentLiteralAsCString(Zone* zone) const;
|
||||||
|
|
||||||
inline bool CurrentMatches(Token::Value token) const {
|
inline bool CurrentMatches(Token::Value token) const {
|
||||||
DCHECK(Token::IsKeyword(token));
|
DCHECK(Token::IsKeyword(token));
|
||||||
return current_.token == token;
|
return current_.token == token;
|
||||||
@ -356,6 +358,9 @@ class Scanner {
|
|||||||
|
|
||||||
bool FoundHtmlComment() const { return found_html_comment_; }
|
bool FoundHtmlComment() const { return found_html_comment_; }
|
||||||
|
|
||||||
|
bool allow_harmony_bigint() const { return allow_harmony_bigint_; }
|
||||||
|
void set_allow_harmony_bigint(bool allow) { allow_harmony_bigint_ = allow; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Scoped helper for saving & restoring scanner error state.
|
// Scoped helper for saving & restoring scanner error state.
|
||||||
// This is used for tagged template literals, in which normally forbidden
|
// This is used for tagged template literals, in which normally forbidden
|
||||||
@ -801,6 +806,9 @@ class Scanner {
|
|||||||
// Whether this scanner encountered an HTML comment.
|
// Whether this scanner encountered an HTML comment.
|
||||||
bool found_html_comment_;
|
bool found_html_comment_;
|
||||||
|
|
||||||
|
// Whether to recognize BIGINT tokens.
|
||||||
|
bool allow_harmony_bigint_;
|
||||||
|
|
||||||
int* use_counts_;
|
int* use_counts_;
|
||||||
|
|
||||||
MessageTemplate::Template scanner_error_;
|
MessageTemplate::Template scanner_error_;
|
||||||
|
@ -147,6 +147,7 @@ namespace internal {
|
|||||||
T(NUMBER, nullptr, 0) \
|
T(NUMBER, nullptr, 0) \
|
||||||
T(SMI, nullptr, 0) \
|
T(SMI, nullptr, 0) \
|
||||||
T(STRING, nullptr, 0) \
|
T(STRING, nullptr, 0) \
|
||||||
|
T(BIGINT, NULL, 0) \
|
||||||
\
|
\
|
||||||
/* Identifiers (not keywords or future reserved words). */ \
|
/* Identifiers (not keywords or future reserved words). */ \
|
||||||
T(IDENTIFIER, nullptr, 0) \
|
T(IDENTIFIER, nullptr, 0) \
|
||||||
|
@ -399,6 +399,26 @@ const six = BigInt(6);
|
|||||||
assertThrows(() => +One, TypeError);
|
assertThrows(() => +One, TypeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Literals
|
||||||
|
{
|
||||||
|
// Invalid literals.
|
||||||
|
assertThrows("00n", SyntaxError);
|
||||||
|
assertThrows("01n", SyntaxError);
|
||||||
|
assertThrows("0bn", SyntaxError);
|
||||||
|
assertThrows("0on", SyntaxError);
|
||||||
|
assertThrows("0xn", SyntaxError);
|
||||||
|
assertThrows("1.n", SyntaxError);
|
||||||
|
assertThrows("1.0n", SyntaxError);
|
||||||
|
assertThrows("1e25n", SyntaxError);
|
||||||
|
|
||||||
|
// Various radixes.
|
||||||
|
assertTrue(12345n === BigInt(12345));
|
||||||
|
assertTrue(0xabcden === BigInt(0xabcde));
|
||||||
|
assertTrue(0xAbCdEn === BigInt(0xabcde));
|
||||||
|
assertTrue(0o54321n === BigInt(0o54321));
|
||||||
|
assertTrue(0b1010101n === BigInt(0b1010101));
|
||||||
|
}
|
||||||
|
|
||||||
// Binary ops.
|
// Binary ops.
|
||||||
{
|
{
|
||||||
assertTrue(one + two === three);
|
assertTrue(one + two === three);
|
||||||
|
@ -165,6 +165,7 @@ v8_source_set("unittests_sources") {
|
|||||||
"libplatform/worker-thread-unittest.cc",
|
"libplatform/worker-thread-unittest.cc",
|
||||||
"locked-queue-unittest.cc",
|
"locked-queue-unittest.cc",
|
||||||
"object-unittest.cc",
|
"object-unittest.cc",
|
||||||
|
"parser/ast-value-unittest.cc",
|
||||||
"parser/preparser-unittest.cc",
|
"parser/preparser-unittest.cc",
|
||||||
"register-configuration-unittest.cc",
|
"register-configuration-unittest.cc",
|
||||||
"run-all-unittests.cc",
|
"run-all-unittests.cc",
|
||||||
|
43
test/unittests/parser/ast-value-unittest.cc
Normal file
43
test/unittests/parser/ast-value-unittest.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "src/ast/ast-value-factory.h"
|
||||||
|
#include "src/heap/heap-inl.h"
|
||||||
|
#include "src/isolate-inl.h"
|
||||||
|
#include "src/zone/zone.h"
|
||||||
|
#include "test/unittests/test-utils.h"
|
||||||
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class AstValueTest : public TestWithIsolateAndZone {
|
||||||
|
protected:
|
||||||
|
AstValueTest()
|
||||||
|
: ast_value_factory_(zone(), i_isolate()->ast_string_constants(),
|
||||||
|
i_isolate()->heap()->HashSeed()) {}
|
||||||
|
|
||||||
|
AstValueFactory ast_value_factory_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AstValueTest, BigIntBooleanValue) {
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b0")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o0")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x0")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0b000")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0o00000")->BooleanValue());
|
||||||
|
EXPECT_FALSE(ast_value_factory_.NewBigInt("0x000000000")->BooleanValue());
|
||||||
|
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("3")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b1")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o6")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0xa")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0b0000001")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0o00005000")->BooleanValue());
|
||||||
|
EXPECT_TRUE(ast_value_factory_.NewBigInt("0x0000d00c0")->BooleanValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace v8
|
@ -138,6 +138,7 @@
|
|||||||
'libplatform/worker-thread-unittest.cc',
|
'libplatform/worker-thread-unittest.cc',
|
||||||
'locked-queue-unittest.cc',
|
'locked-queue-unittest.cc',
|
||||||
'object-unittest.cc',
|
'object-unittest.cc',
|
||||||
|
'parser/ast-value-unittest.cc',
|
||||||
'parser/preparser-unittest.cc',
|
'parser/preparser-unittest.cc',
|
||||||
'register-configuration-unittest.cc',
|
'register-configuration-unittest.cc',
|
||||||
'run-all-unittests.cc',
|
'run-all-unittests.cc',
|
||||||
|
Loading…
Reference in New Issue
Block a user