[esnext] add support for hashbang syntax
Implements https://tc39.github.io/proposal-hashbang/, which simply ignores the first line of a source file if it begins with '#!' (U+0023 U+0021). The test cases are influenced by https://github.com/tc39/test262/pull/1983, which have not been pulled into test262 local-tests due to issues with parseTestRecord. BUG=v8:8523 R=gsathya@chromium.org, adamk@chromium.org, littledan@chromium.org Change-Id: I4ae40222298de768a170c7a1d45fec118ed5713c Reviewed-on: https://chromium-review.googlesource.com/c/1409527 Commit-Queue: Caitlin Potter <caitp@igalia.com> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Daniel Ehrenberg <littledan@chromium.org> Cr-Commit-Position: refs/heads/master@{#58838}
This commit is contained in:
parent
93283bf04a
commit
10a408a6a7
@ -4209,6 +4209,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_numeric_separator)
|
|||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_json_stringify)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_json_stringify)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_sequence)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_sequence)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_await_optimization)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_await_optimization)
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_hashbang)
|
||||||
|
|
||||||
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
|
#undef EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE
|
||||||
|
|
||||||
|
@ -201,7 +201,8 @@ DEFINE_IMPLICATION(harmony_private_methods, harmony_private_fields)
|
|||||||
V(harmony_class_fields, "harmony fields in class literals") \
|
V(harmony_class_fields, "harmony fields in class literals") \
|
||||||
V(harmony_private_methods, "harmony private methods in class literals") \
|
V(harmony_private_methods, "harmony private methods in class literals") \
|
||||||
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
|
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
|
||||||
V(harmony_weak_refs, "harmony weak references")
|
V(harmony_weak_refs, "harmony weak references") \
|
||||||
|
V(harmony_hashbang, "harmony hashbang syntax")
|
||||||
|
|
||||||
#ifdef V8_INTL_SUPPORT
|
#ifdef V8_INTL_SUPPORT
|
||||||
#define HARMONY_INPROGRESS(V) \
|
#define HARMONY_INPROGRESS(V) \
|
||||||
|
@ -495,6 +495,9 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
|
|||||||
DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
|
DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
|
||||||
|
|
||||||
scanner_.Initialize();
|
scanner_.Initialize();
|
||||||
|
if (FLAG_harmony_hashbang && !info->is_eval()) {
|
||||||
|
scanner_.SkipHashBang();
|
||||||
|
}
|
||||||
FunctionLiteral* result = DoParseProgram(isolate, info);
|
FunctionLiteral* result = DoParseProgram(isolate, info);
|
||||||
MaybeResetCharacterStream(info, result);
|
MaybeResetCharacterStream(info, result);
|
||||||
MaybeProcessSourceRanges(info, result, stack_limit_);
|
MaybeProcessSourceRanges(info, result, stack_limit_);
|
||||||
|
@ -78,6 +78,12 @@ PreParser::PreParseResult PreParser::PreParseProgram() {
|
|||||||
scope->set_is_being_lazily_parsed(true);
|
scope->set_is_being_lazily_parsed(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (FLAG_harmony_hashbang) {
|
||||||
|
// Note: We should only skip the hashbang in non-Eval scripts
|
||||||
|
// (currently, Eval is not handled by the PreParser).
|
||||||
|
scanner()->SkipHashBang();
|
||||||
|
}
|
||||||
|
|
||||||
// ModuleDeclarationInstantiation for Source Text Module Records creates a
|
// ModuleDeclarationInstantiation for Source Text Module Records creates a
|
||||||
// new Module Environment Record whose outer lexical environment record is
|
// new Module Environment Record whose outer lexical environment record is
|
||||||
// the global scope.
|
// the global scope.
|
||||||
|
@ -361,6 +361,13 @@ Token::Value Scanner::SkipMultiLineComment() {
|
|||||||
return Token::ILLEGAL;
|
return Token::ILLEGAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scanner::SkipHashBang() {
|
||||||
|
if (c0_ == '#' && Peek() == '!' && source_pos() == 0) {
|
||||||
|
SkipSingleLineComment();
|
||||||
|
Scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Token::Value Scanner::ScanHtmlComment() {
|
Token::Value Scanner::ScanHtmlComment() {
|
||||||
// Check for <!-- comments.
|
// Check for <!-- comments.
|
||||||
DCHECK_EQ(c0_, '!');
|
DCHECK_EQ(c0_, '!');
|
||||||
|
@ -407,6 +407,9 @@ class Scanner {
|
|||||||
|
|
||||||
const Utf16CharacterStream* stream() const { return source_; }
|
const Utf16CharacterStream* stream() const { return source_; }
|
||||||
|
|
||||||
|
// If the next characters in the stream are "#!", the line is skipped.
|
||||||
|
void SkipHashBang();
|
||||||
|
|
||||||
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
|
||||||
|
@ -11416,6 +11416,72 @@ TEST(PrivateNamesSyntaxError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(HashbangSyntax) {
|
||||||
|
const char* context_data[][2] = {
|
||||||
|
{"#!\n", ""}, {"#!---IGNORED---\n", ""}, {nullptr, nullptr}};
|
||||||
|
|
||||||
|
const char* data[] = {"function\nFN\n(\n)\n {\n}\nFN();", nullptr};
|
||||||
|
|
||||||
|
i::FLAG_harmony_hashbang = true;
|
||||||
|
RunParserSyncTest(context_data, data, kSuccess);
|
||||||
|
RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, nullptr, 0,
|
||||||
|
nullptr, 0, true);
|
||||||
|
|
||||||
|
i::FLAG_harmony_hashbang = false;
|
||||||
|
RunParserSyncTest(context_data, data, kError);
|
||||||
|
RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0, nullptr,
|
||||||
|
0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HashbangSyntaxErrors) {
|
||||||
|
const char* file_context_data[][2] = {{"", ""}, {nullptr, nullptr}};
|
||||||
|
const char* other_context_data[][2] = {{"/**/", ""},
|
||||||
|
{"//---\n", ""},
|
||||||
|
{";", ""},
|
||||||
|
{"function fn() {", "}"},
|
||||||
|
{"function* fn() {", "}"},
|
||||||
|
{"async function fn() {", "}"},
|
||||||
|
{"async function* fn() {", "}"},
|
||||||
|
{"() => {", "}"},
|
||||||
|
{"() => ", ""},
|
||||||
|
{"function fn(a = ", ") {}"},
|
||||||
|
{"function* fn(a = ", ") {}"},
|
||||||
|
{"async function fn(a = ", ") {}"},
|
||||||
|
{"async function* fn(a = ", ") {}"},
|
||||||
|
{"(a = ", ") => {}"},
|
||||||
|
{"(a = ", ") => a"},
|
||||||
|
{"class k {", "}"},
|
||||||
|
{"[", "]"},
|
||||||
|
{"{", "}"},
|
||||||
|
{"({", "})"},
|
||||||
|
{nullptr, nullptr}};
|
||||||
|
|
||||||
|
const char* invalid_hashbang_data[] = {// Encoded characters are not allowed
|
||||||
|
"#\\u0021\n"
|
||||||
|
"\\u0023!\n",
|
||||||
|
"\\u0023\\u0021\n",
|
||||||
|
|
||||||
|
"\n#!---IGNORED---\n",
|
||||||
|
" #!---IGNORED---\n", nullptr};
|
||||||
|
const char* hashbang_data[] = {"#!\n", "#!---IGNORED---\n", nullptr};
|
||||||
|
|
||||||
|
auto SyntaxErrorTest = [](const char* context_data[][2], const char* data[]) {
|
||||||
|
i::FLAG_harmony_hashbang = true;
|
||||||
|
RunParserSyncTest(context_data, data, kError);
|
||||||
|
RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0,
|
||||||
|
nullptr, 0, true);
|
||||||
|
|
||||||
|
i::FLAG_harmony_hashbang = false;
|
||||||
|
RunParserSyncTest(context_data, data, kError);
|
||||||
|
RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0,
|
||||||
|
nullptr, 0, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
SyntaxErrorTest(file_context_data, invalid_hashbang_data);
|
||||||
|
SyntaxErrorTest(other_context_data, invalid_hashbang_data);
|
||||||
|
SyntaxErrorTest(other_context_data, hashbang_data);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test_parsing
|
} // namespace test_parsing
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
11
test/mjsunit/harmony/hashbang-eval.js
Normal file
11
test/mjsunit/harmony/hashbang-eval.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
// Flags: --harmony-hashbang
|
||||||
|
|
||||||
|
// Hashbang syntax is not allowed in eval.
|
||||||
|
assertThrows("#!", SyntaxError);
|
||||||
|
assertThrows("#!\n", SyntaxError);
|
||||||
|
assertThrows("#!---IGNORED---", SyntaxError);
|
||||||
|
assertThrows("#!---IGNORED---\n", SyntaxError);
|
Loading…
Reference in New Issue
Block a user