Commit 603bab1e authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[class] parse private methods

This patch implements the parsing of private methods
in the stage 3 proposal https://tc39.github.io/proposal-private-methods

- Adds a --harmony-private-methods flag
- Parse the private methods/accessors

The design doc is in
https://docs.google.com/document/d/1T-Ql6HOIH2U_8YjWkwK2rTfywwb7b3Qe8d3jkz72KwA/edit?usp=sharing

This patch only makes sure the syntax parses, doesn't implement
the semantics.

Bug: v8:8330
Change-Id: I9007b3b3dd6a0df35db7bb14f38f1a38d52bc663
Reviewed-on: https://chromium-review.googlesource.com/c/1329706
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57615}
parent 08d8f3a1
...@@ -1070,7 +1070,7 @@ void AstPrinter::PrintClassProperties( ...@@ -1070,7 +1070,7 @@ void AstPrinter::PrintClassProperties(
} }
EmbeddedVector<char, 128> buf; EmbeddedVector<char, 128> buf;
SNPrintF(buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "", SNPrintF(buf, "PROPERTY%s%s - %s", property->is_static() ? " - STATIC" : "",
property->is_private() ? "- PRIVATE" : "- PUBLIC", prop_kind); property->is_private() ? " - PRIVATE" : " - PUBLIC", prop_kind);
IndentedScope prop(this, buf.start()); IndentedScope prop(this, buf.start());
PrintIndentedVisit("KEY", properties->at(i)->key()); PrintIndentedVisit("KEY", properties->at(i)->key());
PrintIndentedVisit("VALUE", properties->at(i)->value()); PrintIndentedVisit("VALUE", properties->at(i)->value());
......
...@@ -4398,6 +4398,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, ...@@ -4398,6 +4398,7 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_namespace_exports) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_namespace_exports)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_public_fields) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_public_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_fields) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_methods)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_static_fields) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_static_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
......
...@@ -189,13 +189,16 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields) ...@@ -189,13 +189,16 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields)
DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields) DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields)
DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields) DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields)
DEFINE_IMPLICATION(harmony_private_methods, harmony_private_fields)
// Update bootstrapper.cc whenever adding a new feature flag. // Update bootstrapper.cc whenever adding a new feature flag.
// Features that are still work in progress (behind individual flags). // Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS_BASE(V) \ #define HARMONY_INPROGRESS_BASE(V) \
V(harmony_class_fields, "harmony fields in class literals") \ V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_await_optimization, "harmony await taking 1 tick") \ V(harmony_await_optimization, "harmony await taking 1 tick") \
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \ 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")
#ifdef V8_INTL_SUPPORT #ifdef V8_INTL_SUPPORT
......
...@@ -352,6 +352,7 @@ namespace internal { ...@@ -352,6 +352,7 @@ namespace internal {
T(ConstructorIsAccessor, "Class constructor may not be an accessor") \ T(ConstructorIsAccessor, "Class constructor may not be an accessor") \
T(ConstructorIsGenerator, "Class constructor may not be a generator") \ T(ConstructorIsGenerator, "Class constructor may not be a generator") \
T(ConstructorIsAsync, "Class constructor may not be an async method") \ T(ConstructorIsAsync, "Class constructor may not be an async method") \
T(ConstructorIsPrivate, "Class constructor may not be a private method") \
T(DerivedConstructorReturnedNonObject, \ T(DerivedConstructorReturnedNonObject, \
"Derived constructors may only return object or undefined") \ "Derived constructors may only return object or undefined") \
T(DuplicateConstructor, "A class may only have one constructor") \ T(DuplicateConstructor, "A class may only have one constructor") \
......
...@@ -248,6 +248,7 @@ class ParserBase { ...@@ -248,6 +248,7 @@ class ParserBase {
allow_harmony_dynamic_import_(false), allow_harmony_dynamic_import_(false),
allow_harmony_import_meta_(false), allow_harmony_import_meta_(false),
allow_harmony_private_fields_(false), allow_harmony_private_fields_(false),
allow_harmony_private_methods_(false),
allow_eval_cache_(true) { allow_eval_cache_(true) {
pointer_buffer_.reserve(128); pointer_buffer_.reserve(128);
} }
...@@ -261,6 +262,7 @@ class ParserBase { ...@@ -261,6 +262,7 @@ class ParserBase {
ALLOW_ACCESSORS(harmony_static_fields); ALLOW_ACCESSORS(harmony_static_fields);
ALLOW_ACCESSORS(harmony_dynamic_import); ALLOW_ACCESSORS(harmony_dynamic_import);
ALLOW_ACCESSORS(harmony_import_meta); ALLOW_ACCESSORS(harmony_import_meta);
ALLOW_ACCESSORS(harmony_private_methods);
ALLOW_ACCESSORS(eval_cache); ALLOW_ACCESSORS(eval_cache);
#undef ALLOW_ACCESSORS #undef ALLOW_ACCESSORS
...@@ -1008,7 +1010,8 @@ class ParserBase { ...@@ -1008,7 +1010,8 @@ class ParserBase {
ExpressionT ParsePropertyName(IdentifierT* name, ParsePropertyKind* kind, ExpressionT ParsePropertyName(IdentifierT* name, ParsePropertyKind* kind,
ParseFunctionFlags* flags, ParseFunctionFlags* flags,
bool* is_computed_name, bool* is_private); bool* is_computed_name, bool* is_private,
bool allow_private);
ExpressionT ParseObjectLiteral(); ExpressionT ParseObjectLiteral();
ClassLiteralPropertyT ParseClassPropertyDefinition( ClassLiteralPropertyT ParseClassPropertyDefinition(
ClassInfo* class_info, IdentifierT* property_name, bool has_extends, ClassInfo* class_info, IdentifierT* property_name, bool has_extends,
...@@ -1407,6 +1410,7 @@ class ParserBase { ...@@ -1407,6 +1410,7 @@ class ParserBase {
bool allow_harmony_dynamic_import_; bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_; bool allow_harmony_import_meta_;
bool allow_harmony_private_fields_; bool allow_harmony_private_fields_;
bool allow_harmony_private_methods_;
bool allow_eval_cache_; bool allow_eval_cache_;
}; };
...@@ -1939,9 +1943,6 @@ inline bool ParsePropertyKindFromToken(Token::Value token, ...@@ -1939,9 +1943,6 @@ inline bool ParsePropertyKindFromToken(Token::Value token,
case Token::SEMICOLON: case Token::SEMICOLON:
*kind = ParsePropertyKind::kClassField; *kind = ParsePropertyKind::kClassField;
return true; return true;
case Token::PRIVATE_NAME:
*kind = ParsePropertyKind::kClassField;
return true;
default: default:
break; break;
} }
...@@ -1951,7 +1952,7 @@ inline bool ParsePropertyKindFromToken(Token::Value token, ...@@ -1951,7 +1952,7 @@ inline bool ParsePropertyKindFromToken(Token::Value token,
template <class Impl> template <class Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
IdentifierT* name, ParsePropertyKind* kind, ParseFunctionFlags* flags, IdentifierT* name, ParsePropertyKind* kind, ParseFunctionFlags* flags,
bool* is_computed_name, bool* is_private) { bool* is_computed_name, bool* is_private, bool allow_private) {
DCHECK_EQ(ParsePropertyKind::kNotSet, *kind); DCHECK_EQ(ParsePropertyKind::kNotSet, *kind);
DCHECK_EQ(*flags, ParseFunctionFlag::kIsNormal); DCHECK_EQ(*flags, ParseFunctionFlag::kIsNormal);
DCHECK(!*is_computed_name); DCHECK(!*is_computed_name);
...@@ -2004,6 +2005,22 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName( ...@@ -2004,6 +2005,22 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePropertyName(
bool is_array_index; bool is_array_index;
uint32_t index; uint32_t index;
switch (peek()) { switch (peek()) {
case Token::PRIVATE_NAME:
*is_private = true;
is_array_index = false;
Consume(Token::PRIVATE_NAME);
if (*kind == ParsePropertyKind::kNotSet) {
ParsePropertyKindFromToken(peek(), kind);
}
*name = impl()->GetSymbol();
if (!allow_private ||
(!allow_harmony_private_methods() &&
(IsAccessor(*kind) || *kind == ParsePropertyKind::kMethod))) {
ReportUnexpectedToken(Next());
return impl()->FailureExpression();
}
break;
case Token::STRING: case Token::STRING:
Consume(Token::STRING); Consume(Token::STRING);
*name = impl()->GetSymbol(); *name = impl()->GetSymbol();
...@@ -2089,6 +2106,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2089,6 +2106,7 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
bool* is_computed_name, ClassLiteralProperty::Kind* property_kind, bool* is_computed_name, ClassLiteralProperty::Kind* property_kind,
bool* is_static, bool* is_private) { bool* is_static, bool* is_private) {
DCHECK_NOT_NULL(class_info); DCHECK_NOT_NULL(class_info);
// TODO(joyee): refactor these out parameters into one struct
ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal; ParseFunctionFlags function_flags = ParseFunctionFlag::kIsNormal;
*is_static = false; *is_static = false;
*property_kind = ClassLiteralProperty::METHOD; *property_kind = ClassLiteralProperty::METHOD;
...@@ -2114,23 +2132,19 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2114,23 +2132,19 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
*name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static' *name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
name_expression = factory()->NewStringLiteral(*name, position()); name_expression = factory()->NewStringLiteral(*name, position());
} else if (peek() == Token::PRIVATE_NAME) { } else if (peek() == Token::PRIVATE_NAME) {
DCHECK(allow_harmony_private_fields());
// TODO(gsathya): Make a better error message for this. // TODO(gsathya): Make a better error message for this.
ReportUnexpectedToken(Next()); ReportUnexpectedToken(Next());
return impl()->NullLiteralProperty(); return impl()->NullLiteralProperty();
} else { } else {
*is_static = true; *is_static = true;
name_expression = ParsePropertyName(name, &kind, &function_flags, name_expression =
is_computed_name, is_private); ParsePropertyName(name, &kind, &function_flags, is_computed_name,
} is_private, !*is_static);
} else if (name_token == Token::PRIVATE_NAME) { }
Consume(Token::PRIVATE_NAME);
*is_private = true;
*name = impl()->GetSymbol();
name_expression = factory()->NewStringLiteral(*name, position());
} else { } else {
name_expression = ParsePropertyName(name, &kind, &function_flags, name_expression =
is_computed_name, is_private); ParsePropertyName(name, &kind, &function_flags, is_computed_name,
is_private, !*is_static);
} }
if (!class_info->has_name_static_property && *is_static && if (!class_info->has_name_static_property && *is_static &&
...@@ -2315,12 +2329,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(bool* has_seen_proto, ...@@ -2315,12 +2329,8 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(bool* has_seen_proto,
bool is_private = false; bool is_private = false;
ExpressionT name_expression = ParsePropertyName( ExpressionT name_expression = ParsePropertyName(
&name, &kind, &function_flags, is_computed_name, &is_private); &name, &kind, &function_flags, is_computed_name, &is_private, false);
if (is_private) {
// TODO(joyee): private names in object literals should be Syntax Errors
// https://tc39.github.io/proposal-private-methods/#prod-PropertyDefinition
}
switch (kind) { switch (kind) {
case ParsePropertyKind::kSpread: case ParsePropertyKind::kSpread:
DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal);
...@@ -5830,6 +5840,10 @@ void ParserBase<Impl>::CheckClassMethodName(IdentifierT name, ...@@ -5830,6 +5840,10 @@ void ParserBase<Impl>::CheckClassMethodName(IdentifierT name,
ReportMessage(MessageTemplate::kStaticPrototype); ReportMessage(MessageTemplate::kStaticPrototype);
return; return;
} }
} else if (impl()->IdentifierEquals(name,
avf->private_constructor_string())) {
ReportMessage(MessageTemplate::kConstructorIsPrivate);
return;
} else if (impl()->IdentifierEquals(name, avf->constructor_string())) { } else if (impl()->IdentifierEquals(name, avf->constructor_string())) {
if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) { if (flags != ParseFunctionFlag::kIsNormal || IsAccessor(type)) {
MessageTemplate msg = (flags & ParseFunctionFlag::kIsGenerator) != 0 MessageTemplate msg = (flags & ParseFunctionFlag::kIsGenerator) != 0
......
...@@ -423,6 +423,7 @@ Parser::Parser(ParseInfo* info) ...@@ -423,6 +423,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_import_meta(FLAG_harmony_import_meta); set_allow_harmony_import_meta(FLAG_harmony_import_meta);
set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator); set_allow_harmony_numeric_separator(FLAG_harmony_numeric_separator);
set_allow_harmony_private_fields(FLAG_harmony_private_fields); set_allow_harmony_private_fields(FLAG_harmony_private_fields);
set_allow_harmony_private_methods(FLAG_harmony_private_methods);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) { ++feature) {
use_counts_[feature] = 0; use_counts_[feature] = 0;
......
...@@ -262,6 +262,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -262,6 +262,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_dynamic_import); SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta); SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_private_fields); SET_ALLOW(harmony_private_fields);
SET_ALLOW(harmony_private_methods);
SET_ALLOW(eval_cache); SET_ALLOW(eval_cache);
#undef SET_ALLOW #undef SET_ALLOW
} }
......
...@@ -48,6 +48,7 @@ class ProgramOptions final { ...@@ -48,6 +48,7 @@ class ProgramOptions final {
async_iteration_(false), async_iteration_(false),
public_fields_(false), public_fields_(false),
private_fields_(false), private_fields_(false),
private_methods_(false),
static_fields_(false), static_fields_(false),
verbose_(false) {} verbose_(false) {}
...@@ -72,6 +73,7 @@ class ProgramOptions final { ...@@ -72,6 +73,7 @@ class ProgramOptions final {
bool async_iteration() const { return async_iteration_; } bool async_iteration() const { return async_iteration_; }
bool public_fields() const { return public_fields_; } bool public_fields() const { return public_fields_; }
bool private_fields() const { return private_fields_; } bool private_fields() const { return private_fields_; }
bool private_methods() const { return private_methods_; }
bool static_fields() const { return static_fields_; } bool static_fields() const { return static_fields_; }
bool verbose() const { return verbose_; } bool verbose() const { return verbose_; }
bool suppress_runtime_errors() const { return rebaseline_ && !verbose_; } bool suppress_runtime_errors() const { return rebaseline_ && !verbose_; }
...@@ -94,6 +96,7 @@ class ProgramOptions final { ...@@ -94,6 +96,7 @@ class ProgramOptions final {
bool async_iteration_; bool async_iteration_;
bool public_fields_; bool public_fields_;
bool private_fields_; bool private_fields_;
bool private_methods_;
bool static_fields_; bool static_fields_;
bool verbose_; bool verbose_;
std::vector<std::string> input_filenames_; std::vector<std::string> input_filenames_;
...@@ -192,6 +195,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { ...@@ -192,6 +195,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
options.public_fields_ = true; options.public_fields_ = true;
} else if (strcmp(argv[i], "--private-fields") == 0) { } else if (strcmp(argv[i], "--private-fields") == 0) {
options.private_fields_ = true; options.private_fields_ = true;
} else if (strcmp(argv[i], "--private-methods") == 0) {
options.private_methods_ = true;
} else if (strcmp(argv[i], "--static-fields") == 0) { } else if (strcmp(argv[i], "--static-fields") == 0) {
options.static_fields_ = true; options.static_fields_ = true;
} else if (strcmp(argv[i], "--verbose") == 0) { } else if (strcmp(argv[i], "--verbose") == 0) {
...@@ -308,6 +313,8 @@ void ProgramOptions::UpdateFromHeader(std::istream& stream) { ...@@ -308,6 +313,8 @@ void ProgramOptions::UpdateFromHeader(std::istream& stream) {
public_fields_ = ParseBoolean(line.c_str() + 15); public_fields_ = ParseBoolean(line.c_str() + 15);
} else if (line.compare(0, 16, "private fields: ") == 0) { } else if (line.compare(0, 16, "private fields: ") == 0) {
private_fields_ = ParseBoolean(line.c_str() + 16); private_fields_ = ParseBoolean(line.c_str() + 16);
} else if (line.compare(0, 16, "private methods: ") == 0) {
private_methods_ = ParseBoolean(line.c_str() + 16);
} else if (line.compare(0, 15, "static fields: ") == 0) { } else if (line.compare(0, 15, "static fields: ") == 0) {
static_fields_ = ParseBoolean(line.c_str() + 15); static_fields_ = ParseBoolean(line.c_str() + 15);
} else if (line == "---") { } else if (line == "---") {
...@@ -337,6 +344,7 @@ void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT ...@@ -337,6 +344,7 @@ void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT
if (async_iteration_) stream << "\nasync iteration: yes"; if (async_iteration_) stream << "\nasync iteration: yes";
if (public_fields_) stream << "\npublic fields: yes"; if (public_fields_) stream << "\npublic fields: yes";
if (private_fields_) stream << "\nprivate fields: yes"; if (private_fields_) stream << "\nprivate fields: yes";
if (private_methods_) stream << "\nprivate methods: yes";
if (static_fields_) stream << "\nstatic fields: yes"; if (static_fields_) stream << "\nstatic fields: yes";
stream << "\n\n"; stream << "\n\n";
...@@ -448,6 +456,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT ...@@ -448,6 +456,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
if (options.public_fields()) i::FLAG_harmony_public_fields = true; if (options.public_fields()) i::FLAG_harmony_public_fields = true;
if (options.private_fields()) i::FLAG_harmony_private_fields = true; if (options.private_fields()) i::FLAG_harmony_private_fields = true;
if (options.private_methods()) i::FLAG_harmony_private_methods = true;
if (options.static_fields()) i::FLAG_harmony_static_fields = true; if (options.static_fields()) i::FLAG_harmony_static_fields = true;
stream << "#\n# Autogenerated by generate-bytecode-expectations.\n#\n\n"; stream << "#\n# Autogenerated by generate-bytecode-expectations.\n#\n\n";
...@@ -458,6 +467,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT ...@@ -458,6 +467,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
i::FLAG_harmony_public_fields = false; i::FLAG_harmony_public_fields = false;
i::FLAG_harmony_private_fields = false; i::FLAG_harmony_private_fields = false;
i::FLAG_harmony_private_methods = false;
i::FLAG_harmony_static_fields = false; i::FLAG_harmony_static_fields = false;
} }
...@@ -509,6 +519,7 @@ void PrintUsage(const char* exec_path) { ...@@ -509,6 +519,7 @@ void PrintUsage(const char* exec_path) {
" --top-level Process top level code, not the top-level function.\n" " --top-level Process top level code, not the top-level function.\n"
" --public-fields Enable harmony_public_fields flag.\n" " --public-fields Enable harmony_public_fields flag.\n"
" --private-fields Enable harmony_private_fields flag.\n" " --private-fields Enable harmony_private_fields flag.\n"
" --private-methods Enable harmony_private_methods flag.\n"
" --static-fields Enable harmony_static_fields flag.\n" " --static-fields Enable harmony_static_fields flag.\n"
" --output=file.name\n" " --output=file.name\n"
" Specify the output file. If not specified, output goes to " " Specify the output file. If not specified, output goes to "
......
...@@ -1495,6 +1495,7 @@ enum ParserFlag { ...@@ -1495,6 +1495,7 @@ enum ParserFlag {
kAllowNatives, kAllowNatives,
kAllowHarmonyPublicFields, kAllowHarmonyPublicFields,
kAllowHarmonyPrivateFields, kAllowHarmonyPrivateFields,
kAllowHarmonyPrivateMethods,
kAllowHarmonyStaticFields, kAllowHarmonyStaticFields,
kAllowHarmonyDynamicImport, kAllowHarmonyDynamicImport,
kAllowHarmonyImportMeta, kAllowHarmonyImportMeta,
...@@ -1511,6 +1512,7 @@ void SetGlobalFlags(i::EnumSet<ParserFlag> flags) { ...@@ -1511,6 +1512,7 @@ void SetGlobalFlags(i::EnumSet<ParserFlag> flags) {
i::FLAG_allow_natives_syntax = flags.Contains(kAllowNatives); i::FLAG_allow_natives_syntax = flags.Contains(kAllowNatives);
i::FLAG_harmony_public_fields = flags.Contains(kAllowHarmonyPublicFields); i::FLAG_harmony_public_fields = flags.Contains(kAllowHarmonyPublicFields);
i::FLAG_harmony_private_fields = flags.Contains(kAllowHarmonyPrivateFields); i::FLAG_harmony_private_fields = flags.Contains(kAllowHarmonyPrivateFields);
i::FLAG_harmony_private_methods = flags.Contains(kAllowHarmonyPrivateMethods);
i::FLAG_harmony_static_fields = flags.Contains(kAllowHarmonyStaticFields); i::FLAG_harmony_static_fields = flags.Contains(kAllowHarmonyStaticFields);
i::FLAG_harmony_dynamic_import = flags.Contains(kAllowHarmonyDynamicImport); i::FLAG_harmony_dynamic_import = flags.Contains(kAllowHarmonyDynamicImport);
i::FLAG_harmony_import_meta = flags.Contains(kAllowHarmonyImportMeta); i::FLAG_harmony_import_meta = flags.Contains(kAllowHarmonyImportMeta);
...@@ -1524,6 +1526,8 @@ void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) { ...@@ -1524,6 +1526,8 @@ void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) {
flags.Contains(kAllowHarmonyPublicFields)); flags.Contains(kAllowHarmonyPublicFields));
parser->set_allow_harmony_private_fields( parser->set_allow_harmony_private_fields(
flags.Contains(kAllowHarmonyPrivateFields)); flags.Contains(kAllowHarmonyPrivateFields));
parser->set_allow_harmony_private_methods(
flags.Contains(kAllowHarmonyPrivateMethods));
parser->set_allow_harmony_static_fields( parser->set_allow_harmony_static_fields(
flags.Contains(kAllowHarmonyStaticFields)); flags.Contains(kAllowHarmonyStaticFields));
parser->set_allow_harmony_dynamic_import( parser->set_allow_harmony_dynamic_import(
...@@ -5157,6 +5161,254 @@ TEST(ClassFieldsNoErrors) { ...@@ -5157,6 +5161,254 @@ TEST(ClassFieldsNoErrors) {
static_flags, arraysize(static_flags)); static_flags, arraysize(static_flags));
} }
TEST(PrivateMethodsNoErrors) {
// clang-format off
// Tests proposed class methods syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
// Basic syntax
"#a() { }",
"get #a() { }",
"set #a(foo) { }",
"*#a() { }",
"async #a() { }",
"async *#a() { }",
"#a() { } #b() {}",
"get #a() { } set #a(foo) {}",
"get #a() { } get #b() {} set #a(foo) {}",
"get #a() { } get #b() {} set #a(foo) {} set #b(foo) {}",
"set #a(foo) { } set #b(foo) {}",
"get #a() { } get #b() {}",
"#a() { } static a() {}",
"#a() { } a() {}",
"#a() { } a() {} static a() {}",
"get #a() { } get a() {} static get a() {}",
"set #a(foo) { } set a(foo) {} static set a(foo) {}",
"#a() { } get #b() {}",
"#a() { } async #b() {}",
"#a() { } async *#b() {}",
// With arguments
"#a(...args) { }",
"#a(a = 1) { }",
"get #a() { }",
"set #a(a = (...args) => {}) { }",
// Misc edge cases
"#get() {}",
"#set() {}",
"#yield() {}",
"#await() {}",
"#async() {}",
"#static() {}",
"#arguments() {}",
"get #yield() {}",
"get #await() {}",
"get #async() {}",
"get #get() {}",
"get #static() {}",
"get #arguments() {}",
"set #yield(test) {}",
"set #async(test) {}",
"set #await(test) {}",
"set #set(test) {}",
"set #static(test) {}",
"set #arguments(test) {}",
"async #yield() {}",
"async #async() {}",
"async #await() {}",
"async #get() {}",
"async #set() {}",
"async #static() {}",
"async #arguments() {}",
"*#async() {}",
"*#await() {}",
"*#yield() {}",
"*#get() {}",
"*#set() {}",
"*#static() {}",
"*#arguments() {}",
"async *#yield() {}",
"async *#async() {}",
"async *#await() {}",
"async *#get() {}",
"async *#set() {}",
"async *#static() {}",
"async *#arguments() {}",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods[] = {kAllowHarmonyPrivateFields,
kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
private_methods, arraysize(private_methods));
}
TEST(PrivateMethodsAndFieldsNoErrors) {
// clang-format off
// Tests proposed class methods syntax in combination with fields
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
// Basic syntax
"#b;#a() { }",
"#b;get #a() { }",
"#b;set #a(foo) { }",
"#b;*#a() { }",
"#b;async #a() { }",
"#b;async *#a() { }",
"#b = 1;#a() { }",
"#b = 1;get #a() { }",
"#b = 1;set #a(foo) { }",
"#b = 1;*#a() { }",
"#b = 1;async #a() { }",
"#b = 1;async *#a() { }",
// With public fields
"a;#a() { }",
"a;get #a() { }",
"a;set #a(foo) { }",
"a;*#a() { }",
"a;async #a() { }",
"a;async *#a() { }",
"a = 1;#a() { }",
"a = 1;get #a() { }",
"a = 1;set #a(foo) { }",
"a = 1;*#a() { }",
"a = 1;async #a() { }",
"a = 1;async *#a() { }",
// ASI
"#a = 0\n #b(){}",
"#a\n *#b(){}",
"#a = 0\n get #b(){}",
"#a\n *#b(){}",
"b = 0\n #b(){}",
"b\n *#b(){}",
"b = 0\n get #b(){}",
"b\n *#b(){}",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods_and_fields[] = {
kAllowHarmonyPrivateFields, kAllowHarmonyPublicFields,
kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
private_methods_and_fields,
arraysize(private_methods_and_fields));
}
TEST(PrivateMethodsErrors) {
// clang-format off
// Tests proposed class methods syntax in combination with fields
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
"#a() : 0",
"#a() =",
"#a() => {}",
"#a => {}",
"*#a() = 0",
"*#a() => 0",
"*#a() => {}",
"get #a()[]",
"yield #a()[]",
"yield #a => {}",
"async #a() = 0",
"async #a => {}",
"#a(arguments) {}",
"set #a(arguments) {}",
"#['a']() { }",
"get #['a']() { }",
"set #['a'](foo) { }",
"*#['a']() { }",
"async #['a']() { }",
"async *#['a]() { }",
// TODO(joyee): check duplicate accessors
"#a\n#",
"#a() c",
"#a() #",
"#a(arg) c",
"#a(arg) #",
"#a(arg) #c",
"#a#",
"#a#b",
"#a#b(){}",
"#[test](){}",
"async *#constructor() {}",
"*#constructor() {}",
"async #constructor() {}",
"set #constructor(test) {}",
"#constructor() {}",
"get #constructor() {}",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods[] = {kAllowHarmonyPrivateFields,
kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
private_methods, arraysize(private_methods));
}
// Test that private members do not parse outside class bodies
TEST(PrivateMembersInNonClassNoErrors) {
// clang-format off
const char* context_data[][2] = {{"", ""},
{"({", "})"},
{"'use strict'; ({", "});"},
{"function() {", "}"},
{"() => {", "}"},
{"class C { test() {", "} }"},
{nullptr, nullptr}};
const char* class_body_data[] = {
"#a = 1",
"#a = () => {}",
"#a",
"#a() { }",
"get #a() { }",
"set #a(foo) { }",
"*#a() { }",
"async #a() { }",
"async *#a() { }",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods[] = {kAllowHarmonyPrivateFields,
kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
private_methods, arraysize(private_methods));
}
TEST(PrivateClassFieldsNoErrors) { TEST(PrivateClassFieldsNoErrors) {
// clang-format off // clang-format off
// Tests proposed class fields syntax. // Tests proposed class fields syntax.
...@@ -5444,16 +5696,18 @@ TEST(PrivateStaticClassFieldsErrors) { ...@@ -5444,16 +5696,18 @@ TEST(PrivateStaticClassFieldsErrors) {
"static #'a';", "static #'a';",
"static # a = 0", "static # a = 0",
"static #get a() { }",
"static #set a() { }",
"static #*a() { }",
"static async #*a() { }",
// TODO(joyee): support static private methods
"static #a() { }", "static #a() { }",
"static get #a() { }", "static get #a() { }",
"static #get a() { }",
"static set #a() { }", "static set #a() { }",
"static #set a() { }",
"static *#a() { }", "static *#a() { }",
"static #*a() { }",
"static async #a() { }", "static async #a() { }",
"static async *#a() { }", "static async *#a() { }",
"static async #*a() { }",
// ASI // ASI
"static #a = 0\n", "static #a = 0\n",
......
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