Commit af4a7dc3 authored by Joshua Litt's avatar Joshua Litt Committed by Commit Bot

[scanner] fix edge case for parsing numeric separators

Numeric separators are not allowed in NonOctalDecimalIntegerLiterals.

Bug: v8:9437
Change-Id: Ic62b35b361de36fc622e207c140c365665021029
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1722194
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62994}
parent 19810c48
......@@ -628,8 +628,10 @@ bool Scanner::ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
return true;
}
bool Scanner::ScanDecimalDigits() {
if (allow_harmony_numeric_separator()) {
bool Scanner::ScanDecimalDigits(bool allow_numeric_separator) {
allow_numeric_separator =
allow_harmony_numeric_separator() && allow_numeric_separator;
if (allow_numeric_separator) {
return ScanDigitsWithNumericSeparators(&IsDecimalDigit, false);
}
while (IsDecimalDigit(c0_)) {
......@@ -667,8 +669,10 @@ bool Scanner::ScanDecimalAsSmiWithNumericSeparators(uint64_t* value) {
return true;
}
bool Scanner::ScanDecimalAsSmi(uint64_t* value) {
if (allow_harmony_numeric_separator()) {
bool Scanner::ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator) {
allow_numeric_separator =
allow_harmony_numeric_separator() && allow_numeric_separator;
if (allow_numeric_separator) {
return ScanDecimalAsSmiWithNumericSeparators(value);
}
......@@ -753,7 +757,7 @@ bool Scanner::ScanSignedInteger() {
if (c0_ == '+' || c0_ == '-') AddLiteralCharAdvance();
// we must have at least one decimal digit after 'e'/'E'
if (!IsDecimalDigit(c0_)) return false;
return ScanDecimalDigits();
return ScanDecimalDigits(true);
}
Token::Value Scanner::ScanNumber(bool seen_period) {
......@@ -771,7 +775,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
return Token::ILLEGAL;
}
// we know we have at least one digit
if (!ScanDecimalDigits()) return Token::ILLEGAL;
if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
} else {
// if the first character is '0' we must check for octals and hex
if (c0_ == '0') {
......@@ -810,11 +814,14 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// Parse decimal digits and allow trailing fractional part.
if (IsDecimalNumberKind(kind)) {
bool allow_numeric_separator = kind != DECIMAL_WITH_LEADING_ZERO;
// This is an optimization for parsing Decimal numbers as Smi's.
if (at_start) {
uint64_t value = 0;
// scan subsequent decimal digits
if (!ScanDecimalAsSmi(&value)) return Token::ILLEGAL;
if (!ScanDecimalAsSmi(&value, allow_numeric_separator)) {
return Token::ILLEGAL;
}
if (next().literal_chars.one_byte_literal().length() <= 10 &&
value <= Smi::kMaxValue && c0_ != '.' && !IsIdentifierStart(c0_)) {
......@@ -828,14 +835,16 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
}
}
if (!ScanDecimalDigits()) return Token::ILLEGAL;
if (!ScanDecimalDigits(allow_numeric_separator)) {
return Token::ILLEGAL;
}
if (c0_ == '.') {
seen_period = true;
AddLiteralCharAdvance();
if (allow_harmony_numeric_separator() && c0_ == '_') {
return Token::ILLEGAL;
}
if (!ScanDecimalDigits()) return Token::ILLEGAL;
if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
}
}
}
......
......@@ -646,9 +646,9 @@ class V8_EXPORT_PRIVATE Scanner {
bool ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
bool is_check_first_digit);
bool ScanDecimalDigits();
bool ScanDecimalDigits(bool allow_numeric_separator);
// Optimized function to scan decimal number as Smi.
bool ScanDecimalAsSmi(uint64_t* value);
bool ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator);
bool ScanDecimalAsSmiWithNumericSeparators(uint64_t* value);
bool ScanHexDigits();
bool ScanBinaryDigits();
......
......@@ -1883,6 +1883,21 @@ void RunModuleParserSyncTest(
always_false_len, true, test_preparser, ignore_error_msg);
}
TEST(NonOctalDecimalIntegerStrictError) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
const char* context_data[][2] = {{"\"use strict\";", ""}, {nullptr, nullptr}};
const char* statement_data[] = {"09", "09.1_2", nullptr};
static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1,
nullptr, 0, false, true, true);
RunParserSyncTest(context_data, statement_data, kError);
}
TEST(NumericSeparator) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
......@@ -1939,6 +1954,36 @@ TEST(NumericSeparatorImplicitOctalsErrors) {
RunParserSyncTest(context_data, statement_data, kError);
}
TEST(NumericSeparatorNonOctalDecimalInteger) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
const char* context_data[][2] = {{"", ""}, {nullptr, nullptr}};
const char* statement_data[] = {"09.1_2", nullptr};
static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
RunParserSyncTest(context_data, statement_data, kSuccess, nullptr, 0, flags,
1, nullptr, 0, false, true, true);
RunParserSyncTest(context_data, statement_data, kError);
}
TEST(NumericSeparatorNonOctalDecimalIntegerErrors) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope context_scope(context);
const char* context_data[][2] = {{"", ""}, {nullptr, nullptr}};
const char* statement_data[] = {"09_12", nullptr};
static const ParserFlag flags[] = {kAllowHarmonyNumericSeparator};
RunParserSyncTest(context_data, statement_data, kError, nullptr, 0, flags, 1,
nullptr, 0, false, true, true);
RunParserSyncTest(context_data, statement_data, kError);
}
TEST(NumericSeparatorUnicodeEscapeSequencesErrors) {
v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
......
......@@ -40,11 +40,6 @@
const binary = 0b0_1_0_1_0;
assertEquals(binary, 0b01010);
}
{
const leadingZeros = 09_1_3;
assertEquals(leadingZeros, 0913);
}
{
const dot1 = 9_1.1_3;
assertEquals(dot1, 91.13);
......@@ -54,6 +49,9 @@
const dot3 = 1_1.21;
assertEquals(dot3, 11.21);
const dot4 = 09.1_2
assertEquals(dot4, 9.12);
}
{
......@@ -114,3 +112,4 @@ assertThrows('0o7__77', SyntaxError);
assertThrows('0777_', SyntaxError);
assertThrows('07__77', SyntaxError);
assertThrows('07_7_7', SyntaxError);
assertThrows('09_1_3', SyntaxError);
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