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), ...@@ -628,8 +628,10 @@ bool Scanner::ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
return true; return true;
} }
bool Scanner::ScanDecimalDigits() { bool Scanner::ScanDecimalDigits(bool allow_numeric_separator) {
if (allow_harmony_numeric_separator()) { allow_numeric_separator =
allow_harmony_numeric_separator() && allow_numeric_separator;
if (allow_numeric_separator) {
return ScanDigitsWithNumericSeparators(&IsDecimalDigit, false); return ScanDigitsWithNumericSeparators(&IsDecimalDigit, false);
} }
while (IsDecimalDigit(c0_)) { while (IsDecimalDigit(c0_)) {
...@@ -667,8 +669,10 @@ bool Scanner::ScanDecimalAsSmiWithNumericSeparators(uint64_t* value) { ...@@ -667,8 +669,10 @@ bool Scanner::ScanDecimalAsSmiWithNumericSeparators(uint64_t* value) {
return true; return true;
} }
bool Scanner::ScanDecimalAsSmi(uint64_t* value) { bool Scanner::ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator) {
if (allow_harmony_numeric_separator()) { allow_numeric_separator =
allow_harmony_numeric_separator() && allow_numeric_separator;
if (allow_numeric_separator) {
return ScanDecimalAsSmiWithNumericSeparators(value); return ScanDecimalAsSmiWithNumericSeparators(value);
} }
...@@ -753,7 +757,7 @@ bool Scanner::ScanSignedInteger() { ...@@ -753,7 +757,7 @@ bool Scanner::ScanSignedInteger() {
if (c0_ == '+' || c0_ == '-') AddLiteralCharAdvance(); if (c0_ == '+' || c0_ == '-') AddLiteralCharAdvance();
// we must have at least one decimal digit after 'e'/'E' // we must have at least one decimal digit after 'e'/'E'
if (!IsDecimalDigit(c0_)) return false; if (!IsDecimalDigit(c0_)) return false;
return ScanDecimalDigits(); return ScanDecimalDigits(true);
} }
Token::Value Scanner::ScanNumber(bool seen_period) { Token::Value Scanner::ScanNumber(bool seen_period) {
...@@ -771,7 +775,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) { ...@@ -771,7 +775,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
return Token::ILLEGAL; return Token::ILLEGAL;
} }
// we know we have at least one digit // we know we have at least one digit
if (!ScanDecimalDigits()) return Token::ILLEGAL; if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
} else { } else {
// if the first character is '0' we must check for octals and hex // if the first character is '0' we must check for octals and hex
if (c0_ == '0') { if (c0_ == '0') {
...@@ -810,11 +814,14 @@ Token::Value Scanner::ScanNumber(bool seen_period) { ...@@ -810,11 +814,14 @@ Token::Value Scanner::ScanNumber(bool seen_period) {
// Parse decimal digits and allow trailing fractional part. // Parse decimal digits and allow trailing fractional part.
if (IsDecimalNumberKind(kind)) { if (IsDecimalNumberKind(kind)) {
bool allow_numeric_separator = kind != DECIMAL_WITH_LEADING_ZERO;
// This is an optimization for parsing Decimal numbers as Smi's. // This is an optimization for parsing Decimal numbers as Smi's.
if (at_start) { if (at_start) {
uint64_t value = 0; uint64_t value = 0;
// scan subsequent decimal digits // 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 && if (next().literal_chars.one_byte_literal().length() <= 10 &&
value <= Smi::kMaxValue && c0_ != '.' && !IsIdentifierStart(c0_)) { value <= Smi::kMaxValue && c0_ != '.' && !IsIdentifierStart(c0_)) {
...@@ -828,14 +835,16 @@ Token::Value Scanner::ScanNumber(bool seen_period) { ...@@ -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_ == '.') { if (c0_ == '.') {
seen_period = true; seen_period = true;
AddLiteralCharAdvance(); AddLiteralCharAdvance();
if (allow_harmony_numeric_separator() && c0_ == '_') { if (allow_harmony_numeric_separator() && c0_ == '_') {
return Token::ILLEGAL; return Token::ILLEGAL;
} }
if (!ScanDecimalDigits()) return Token::ILLEGAL; if (!ScanDecimalDigits(true)) return Token::ILLEGAL;
} }
} }
} }
......
...@@ -646,9 +646,9 @@ class V8_EXPORT_PRIVATE Scanner { ...@@ -646,9 +646,9 @@ class V8_EXPORT_PRIVATE Scanner {
bool ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch), bool ScanDigitsWithNumericSeparators(bool (*predicate)(uc32 ch),
bool is_check_first_digit); bool is_check_first_digit);
bool ScanDecimalDigits(); bool ScanDecimalDigits(bool allow_numeric_separator);
// Optimized function to scan decimal number as Smi. // 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 ScanDecimalAsSmiWithNumericSeparators(uint64_t* value);
bool ScanHexDigits(); bool ScanHexDigits();
bool ScanBinaryDigits(); bool ScanBinaryDigits();
......
...@@ -1883,6 +1883,21 @@ void RunModuleParserSyncTest( ...@@ -1883,6 +1883,21 @@ void RunModuleParserSyncTest(
always_false_len, true, test_preparser, ignore_error_msg); 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) { TEST(NumericSeparator) {
v8::HandleScope handles(CcTest::isolate()); v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate()); v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
...@@ -1939,6 +1954,36 @@ TEST(NumericSeparatorImplicitOctalsErrors) { ...@@ -1939,6 +1954,36 @@ TEST(NumericSeparatorImplicitOctalsErrors) {
RunParserSyncTest(context_data, statement_data, kError); 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) { TEST(NumericSeparatorUnicodeEscapeSequencesErrors) {
v8::HandleScope handles(CcTest::isolate()); v8::HandleScope handles(CcTest::isolate());
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate()); v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
......
...@@ -40,11 +40,6 @@ ...@@ -40,11 +40,6 @@
const binary = 0b0_1_0_1_0; const binary = 0b0_1_0_1_0;
assertEquals(binary, 0b01010); assertEquals(binary, 0b01010);
} }
{
const leadingZeros = 09_1_3;
assertEquals(leadingZeros, 0913);
}
{ {
const dot1 = 9_1.1_3; const dot1 = 9_1.1_3;
assertEquals(dot1, 91.13); assertEquals(dot1, 91.13);
...@@ -54,6 +49,9 @@ ...@@ -54,6 +49,9 @@
const dot3 = 1_1.21; const dot3 = 1_1.21;
assertEquals(dot3, 11.21); assertEquals(dot3, 11.21);
const dot4 = 09.1_2
assertEquals(dot4, 9.12);
} }
{ {
...@@ -114,3 +112,4 @@ assertThrows('0o7__77', SyntaxError); ...@@ -114,3 +112,4 @@ assertThrows('0o7__77', SyntaxError);
assertThrows('0777_', SyntaxError); assertThrows('0777_', SyntaxError);
assertThrows('07__77', SyntaxError); assertThrows('07__77', SyntaxError);
assertThrows('07_7_7', 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