diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index fa430cfd9b..8f598ce035 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -4281,6 +4281,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_meta) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrict_constructor_return) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_optional_catch_binding) +EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_subsume_json) void InstallPublicSymbol(Factory* factory, Handle native_context, const char* name, Handle value) { diff --git a/src/flag-definitions.h b/src/flag-definitions.h index f3d012caf0..413f1aea43 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -203,8 +203,11 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields) DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields) DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields) +// Update bootstrapper.cc whenever adding a new feature flag. + // Features that are still work in progress (behind individual flags). #define HARMONY_INPROGRESS(V) \ + V(harmony_subsume_json, "harmony subsume JSON") \ V(harmony_array_prototype_values, "harmony Array.prototype.values") \ V(harmony_function_sent, "harmony function.sent") \ V(harmony_do_expressions, "harmony do-expressions") \ diff --git a/src/parsing/scanner.cc b/src/parsing/scanner.cc index c28775d6f3..4430cae528 100644 --- a/src/parsing/scanner.cc +++ b/src/parsing/scanner.cc @@ -1071,8 +1071,11 @@ Token::Value Scanner::ScanString() { AddLiteralChar(c); } - while (c0_ != quote && c0_ != kEndOfInput && - !unibrow::IsLineTerminator(c0_)) { + bool (*line_terminator_func)(unsigned int) = + FLAG_harmony_subsume_json ? unibrow::IsStringLiteralLineTerminator + : unibrow::IsLineTerminator; + + while (c0_ != quote && c0_ != kEndOfInput && !line_terminator_func(c0_)) { uc32 c = c0_; Advance(); if (c == '\\') { diff --git a/src/unicode.h b/src/unicode.h index c6ce9a8eb2..75f53e22d1 100644 --- a/src/unicode.h +++ b/src/unicode.h @@ -204,6 +204,10 @@ V8_INLINE bool IsLineTerminator(uchar c) { return c == 0x000A || c == 0x000D || c == 0x2028 || c == 0x2029; } +V8_INLINE bool IsStringLiteralLineTerminator(uchar c) { + return c == 0x000A || c == 0x000D; +} + #ifndef V8_INTL_SUPPORT struct ToLowercase { static const int kMaxWidth = 3; diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 5ade26b4b6..5962c1c9a9 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -273,7 +273,7 @@ TEST(UsingCachedData) { CcTest::i_isolate()->stack_guard()->SetStackLimit( i::GetCurrentStackPosition() - 128 * 1024); - // Source containing functions that might be lazily compiled and all types + // Source containing functions that might be lazily compiled and all types // of symbols (string, propertyName, regexp). const char* source = "var x = 42;" @@ -1478,7 +1478,10 @@ void TestParserSync(const char* source, const ParserFlag* varying_flags, bool is_module = false, bool test_preparser = true, bool ignore_error_msg = false) { i::Handle str = - CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source); + CcTest::i_isolate() + ->factory() + ->NewStringFromUtf8(Vector(source, strlen(source))) + .ToHandleChecked(); for (int bits = 0; bits < (1 << varying_flags_length); bits++) { i::EnumSet flags; for (size_t flag_index = 0; flag_index < varying_flags_length; @@ -3899,15 +3902,42 @@ TEST(BothModesUseCount) { TEST(LineOrParagraphSeparatorAsLineTerminator) { // Tests that both preparsing and parsing accept U+2028 LINE SEPARATOR and - // U+2029 PARAGRAPH SEPARATOR as LineTerminator symbols. + // U+2029 PARAGRAPH SEPARATOR as LineTerminator symbols outside of string + // literals. const char* context_data[][2] = {{"", ""}, {nullptr, nullptr}}; - const char* statement_data[] = {"\x31\xE2\x80\xA8\x32", // "12" - "\x31\xE2\x80\xA9\x32", // "12" + const char* statement_data[] = {"\x31\xE2\x80\xA8\x32", // 12 + "\x31\xE2\x80\xA9\x32", // 12 + nullptr}; + + RunParserSyncTest(context_data, statement_data, kSuccess); +} + +TEST(LineOrParagraphSeparatorInStringLiteral) { + // Tests that both preparsing and parsing treat U+2028 LINE SEPARATOR and + // U+2029 PARAGRAPH SEPARATOR as line terminators within string literals. + const char* context_data[][2] = { + {"\"", "\""}, {"'", "'"}, {nullptr, nullptr}}; + const char* statement_data[] = {"\x31\xE2\x80\xA8\x32", // 12 + "\x31\xE2\x80\xA9\x32", // 12 nullptr}; RunParserSyncTest(context_data, statement_data, kError); } +TEST(LineOrParagraphSeparatorInStringLiteralHarmony) { + // Tests that both preparsing and parsing don't treat U+2028 LINE SEPARATOR + // and U+2029 PARAGRAPH SEPARATOR as line terminators within string literals + // with the "subsume JSON" flag enabled. + v8::internal::FLAG_harmony_subsume_json = true; + const char* context_data[][2] = { + {"\"", "\""}, {"'", "'"}, {nullptr, nullptr}}; + const char* statement_data[] = {"\x31\xE2\x80\xA8\x32", // 12 + "\x31\xE2\x80\xA9\x32", // 12 + nullptr}; + + RunParserSyncTest(context_data, statement_data, kSuccess); +} + TEST(ErrorsArrowFormalParameters) { const char* context_data[][2] = { { "()", "=>{}" },