[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_regexp_sequence)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_await_optimization)
|
||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_hashbang)
|
||||
|
||||
#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_private_methods, "harmony private methods in class literals") \
|
||||
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
|
||||
#define HARMONY_INPROGRESS(V) \
|
||||
|
@ -495,6 +495,9 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
|
||||
DeserializeScopeChain(isolate, info, info->maybe_outer_scope_info());
|
||||
|
||||
scanner_.Initialize();
|
||||
if (FLAG_harmony_hashbang && !info->is_eval()) {
|
||||
scanner_.SkipHashBang();
|
||||
}
|
||||
FunctionLiteral* result = DoParseProgram(isolate, info);
|
||||
MaybeResetCharacterStream(info, result);
|
||||
MaybeProcessSourceRanges(info, result, stack_limit_);
|
||||
|
@ -78,6 +78,12 @@ PreParser::PreParseResult PreParser::PreParseProgram() {
|
||||
scope->set_is_being_lazily_parsed(true);
|
||||
#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
|
||||
// new Module Environment Record whose outer lexical environment record is
|
||||
// the global scope.
|
||||
|
@ -361,6 +361,13 @@ Token::Value Scanner::SkipMultiLineComment() {
|
||||
return Token::ILLEGAL;
|
||||
}
|
||||
|
||||
void Scanner::SkipHashBang() {
|
||||
if (c0_ == '#' && Peek() == '!' && source_pos() == 0) {
|
||||
SkipSingleLineComment();
|
||||
Scan();
|
||||
}
|
||||
}
|
||||
|
||||
Token::Value Scanner::ScanHtmlComment() {
|
||||
// Check for <!-- comments.
|
||||
DCHECK_EQ(c0_, '!');
|
||||
|
@ -407,6 +407,9 @@ class Scanner {
|
||||
|
||||
const Utf16CharacterStream* stream() const { return source_; }
|
||||
|
||||
// If the next characters in the stream are "#!", the line is skipped.
|
||||
void SkipHashBang();
|
||||
|
||||
private:
|
||||
// Scoped helper for saving & restoring scanner error state.
|
||||
// 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 internal
|
||||
} // 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