Commit 94d53d87 authored by Daniel Ehrenberg's avatar Daniel Ehrenberg Committed by Commit Bot

[class] Split out static fields into a separate flag

This patch implements https://github.com/tc39/proposal-class-fields/pull/65
and https://github.com/tc39/proposal-static-class-features/ by
splitting out instance and static field declarations into separate
flags for the separate proposals. Instance class fields is currently
at Stage 3 whereas static class fields is currently at Stage 2.

Bug: v8:5367
Change-Id: I133c945fd0b22dc5718c7bb61b10f22348087acd
Reviewed-on: https://chromium-review.googlesource.com/839778
Commit-Queue: Daniel Ehrenberg <littledan@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50293}
parent 34235169
...@@ -4312,6 +4312,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property) ...@@ -4312,6 +4312,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_public_fields) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_public_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)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_meta) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_meta)
......
...@@ -197,6 +197,7 @@ DEFINE_IMPLICATION(es_staging, harmony) ...@@ -197,6 +197,7 @@ DEFINE_IMPLICATION(es_staging, harmony)
// Enabling import.meta requires to also enable import() // Enabling import.meta requires to also enable import()
DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import) DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields) DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields)
DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields)
// Features that are still work in progress (behind individual flags). // Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS(V) \ #define HARMONY_INPROGRESS(V) \
...@@ -206,6 +207,7 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields) ...@@ -206,6 +207,7 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_public_fields)
V(harmony_do_expressions, "harmony do-expressions") \ V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony fields in class literals") \ V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_public_fields, "harmony public fields in class literals") \ V(harmony_public_fields, "harmony public fields in class literals") \
V(harmony_static_fields, "harmony static fields in class literals") \
V(harmony_bigint, "harmony arbitrary precision integers") V(harmony_bigint, "harmony arbitrary precision integers")
// Features that are complete (but still behind --harmony/es-staging flag). // Features that are complete (but still behind --harmony/es-staging flag).
......
...@@ -279,6 +279,7 @@ class ParserBase { ...@@ -279,6 +279,7 @@ class ParserBase {
allow_harmony_do_expressions_(false), allow_harmony_do_expressions_(false),
allow_harmony_function_sent_(false), allow_harmony_function_sent_(false),
allow_harmony_public_fields_(false), allow_harmony_public_fields_(false),
allow_harmony_static_fields_(false),
allow_harmony_dynamic_import_(false), allow_harmony_dynamic_import_(false),
allow_harmony_import_meta_(false), allow_harmony_import_meta_(false),
allow_harmony_async_iteration_(false) {} allow_harmony_async_iteration_(false) {}
...@@ -291,6 +292,7 @@ class ParserBase { ...@@ -291,6 +292,7 @@ class ParserBase {
ALLOW_ACCESSORS(harmony_do_expressions); ALLOW_ACCESSORS(harmony_do_expressions);
ALLOW_ACCESSORS(harmony_function_sent); ALLOW_ACCESSORS(harmony_function_sent);
ALLOW_ACCESSORS(harmony_public_fields); ALLOW_ACCESSORS(harmony_public_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_async_iteration); ALLOW_ACCESSORS(harmony_async_iteration);
...@@ -1529,6 +1531,7 @@ class ParserBase { ...@@ -1529,6 +1531,7 @@ class ParserBase {
bool allow_harmony_do_expressions_; bool allow_harmony_do_expressions_;
bool allow_harmony_function_sent_; bool allow_harmony_function_sent_;
bool allow_harmony_public_fields_; bool allow_harmony_public_fields_;
bool allow_harmony_static_fields_;
bool allow_harmony_dynamic_import_; bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_; bool allow_harmony_import_meta_;
bool allow_harmony_async_iteration_; bool allow_harmony_async_iteration_;
...@@ -2295,6 +2298,11 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2295,6 +2298,11 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
case PropertyKind::kValueProperty: case PropertyKind::kValueProperty:
if (allow_harmony_public_fields()) { if (allow_harmony_public_fields()) {
*property_kind = ClassLiteralProperty::FIELD; *property_kind = ClassLiteralProperty::FIELD;
if (*is_static && !allow_harmony_static_fields()) {
ReportUnexpectedToken(Next());
*ok = false;
return impl()->NullLiteralProperty();
}
if (!*is_computed_name) { if (!*is_computed_name) {
checker->CheckClassFieldName(*is_static, checker->CheckClassFieldName(*is_static,
CHECK_OK_CUSTOM(NullLiteralProperty)); CHECK_OK_CUSTOM(NullLiteralProperty));
......
...@@ -543,6 +543,7 @@ Parser::Parser(ParseInfo* info) ...@@ -543,6 +543,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_do_expressions(FLAG_harmony_do_expressions); set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
set_allow_harmony_function_sent(FLAG_harmony_function_sent); set_allow_harmony_function_sent(FLAG_harmony_function_sent);
set_allow_harmony_public_fields(FLAG_harmony_public_fields); set_allow_harmony_public_fields(FLAG_harmony_public_fields);
set_allow_harmony_static_fields(FLAG_harmony_static_fields);
set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import); set_allow_harmony_dynamic_import(FLAG_harmony_dynamic_import);
set_allow_harmony_import_meta(FLAG_harmony_import_meta); set_allow_harmony_import_meta(FLAG_harmony_import_meta);
set_allow_harmony_async_iteration(FLAG_harmony_async_iteration); set_allow_harmony_async_iteration(FLAG_harmony_async_iteration);
...@@ -3318,6 +3319,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, ...@@ -3318,6 +3319,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
DCHECK(allow_harmony_public_fields()); DCHECK(allow_harmony_public_fields());
if (is_static) { if (is_static) {
DCHECK(allow_harmony_static_fields());
class_info->static_fields->Add(property, zone()); class_info->static_fields->Add(property, zone());
} else { } else {
class_info->instance_fields->Add(property, zone()); class_info->instance_fields->Add(property, zone());
......
...@@ -301,6 +301,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -301,6 +301,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_do_expressions); SET_ALLOW(harmony_do_expressions);
SET_ALLOW(harmony_function_sent); SET_ALLOW(harmony_function_sent);
SET_ALLOW(harmony_public_fields); SET_ALLOW(harmony_public_fields);
SET_ALLOW(harmony_static_fields);
SET_ALLOW(harmony_dynamic_import); SET_ALLOW(harmony_dynamic_import);
SET_ALLOW(harmony_import_meta); SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_async_iteration); SET_ALLOW(harmony_async_iteration);
......
...@@ -45,6 +45,7 @@ class ProgramOptions final { ...@@ -45,6 +45,7 @@ class ProgramOptions final {
do_expressions_(false), do_expressions_(false),
async_iteration_(false), async_iteration_(false),
public_fields_(false), public_fields_(false),
static_fields_(false),
verbose_(false) {} verbose_(false) {}
bool Validate() const; bool Validate() const;
...@@ -65,6 +66,7 @@ class ProgramOptions final { ...@@ -65,6 +66,7 @@ class ProgramOptions final {
bool do_expressions() const { return do_expressions_; } bool do_expressions() const { return do_expressions_; }
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 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_; }
std::vector<std::string> input_filenames() const { return input_filenames_; } std::vector<std::string> input_filenames() const { return input_filenames_; }
...@@ -83,6 +85,7 @@ class ProgramOptions final { ...@@ -83,6 +85,7 @@ class ProgramOptions final {
bool do_expressions_; bool do_expressions_;
bool async_iteration_; bool async_iteration_;
bool public_fields_; bool public_fields_;
bool static_fields_;
bool verbose_; bool verbose_;
std::vector<std::string> input_filenames_; std::vector<std::string> input_filenames_;
std::string output_filename_; std::string output_filename_;
...@@ -174,6 +177,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { ...@@ -174,6 +177,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
options.async_iteration_ = true; options.async_iteration_ = true;
} else if (strcmp(argv[i], "--public-fields") == 0) { } else if (strcmp(argv[i], "--public-fields") == 0) {
options.public_fields_ = true; options.public_fields_ = true;
} else if (strcmp(argv[i], "--static-fields") == 0) {
options.static_fields_ = true;
} else if (strcmp(argv[i], "--verbose") == 0) { } else if (strcmp(argv[i], "--verbose") == 0) {
options.verbose_ = true; options.verbose_ = true;
} else if (strncmp(argv[i], "--output=", 9) == 0) { } else if (strncmp(argv[i], "--output=", 9) == 0) {
...@@ -280,6 +285,8 @@ void ProgramOptions::UpdateFromHeader(std::istream& stream) { ...@@ -280,6 +285,8 @@ void ProgramOptions::UpdateFromHeader(std::istream& stream) {
async_iteration_ = ParseBoolean(line.c_str() + 17); async_iteration_ = ParseBoolean(line.c_str() + 17);
} else if (line.compare(0, 15, "public fields: ") == 0) { } else if (line.compare(0, 15, "public fields: ") == 0) {
public_fields_ = ParseBoolean(line.c_str() + 15); public_fields_ = ParseBoolean(line.c_str() + 15);
} else if (line.compare(0, 15, "static fields: ") == 0) {
static_fields_ = ParseBoolean(line.c_str() + 15);
} else if (line == "---") { } else if (line == "---") {
break; break;
} else if (line.empty()) { } else if (line.empty()) {
...@@ -304,6 +311,7 @@ void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT ...@@ -304,6 +311,7 @@ void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT
if (do_expressions_) stream << "\ndo expressions: yes"; if (do_expressions_) stream << "\ndo expressions: yes";
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 (static_fields_) stream << "\nstatic fields: yes";
stream << "\n\n"; stream << "\n\n";
} }
...@@ -409,6 +417,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT ...@@ -409,6 +417,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
if (options.do_expressions()) i::FLAG_harmony_do_expressions = true; if (options.do_expressions()) i::FLAG_harmony_do_expressions = true;
if (options.async_iteration()) i::FLAG_harmony_async_iteration = true; if (options.async_iteration()) i::FLAG_harmony_async_iteration = true;
if (options.public_fields()) i::FLAG_harmony_public_fields = true; if (options.public_fields()) i::FLAG_harmony_public_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";
options.PrintHeader(stream); options.PrintHeader(stream);
...@@ -419,6 +428,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT ...@@ -419,6 +428,7 @@ void GenerateExpectationsFile(std::ostream& stream, // NOLINT
i::FLAG_harmony_do_expressions = false; i::FLAG_harmony_do_expressions = false;
i::FLAG_harmony_async_iteration = false; i::FLAG_harmony_async_iteration = false;
i::FLAG_harmony_public_fields = false; i::FLAG_harmony_public_fields = false;
i::FLAG_harmony_static_fields = false;
} }
bool WriteExpectationsFile(const std::vector<std::string>& snippet_list, bool WriteExpectationsFile(const std::vector<std::string>& snippet_list,
...@@ -467,6 +477,7 @@ void PrintUsage(const char* exec_path) { ...@@ -467,6 +477,7 @@ void PrintUsage(const char* exec_path) {
" --do-expressions Enable harmony_do_expressions flag.\n" " --do-expressions Enable harmony_do_expressions flag.\n"
" --async-iteration Enable harmony_async_iteration flag.\n" " --async-iteration Enable harmony_async_iteration flag.\n"
" --public-fields Enable harmony_public_fields flag.\n" " --public-fields Enable harmony_public_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 "
"stdout.\n" "stdout.\n"
......
...@@ -2239,6 +2239,62 @@ TEST(ClassFields) { ...@@ -2239,6 +2239,62 @@ TEST(ClassFields) {
InitializedIgnitionHandleScope scope; InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate()); BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"{\n"
" class A {\n"
" a;\n"
" ['b'];\n"
" }\n"
"\n"
" class B {\n"
" a = 1;\n"
" ['b'] = this.a;\n"
" }\n"
" new A;\n"
" new B;\n"
"}\n",
"{\n"
" class A extends class {} {\n"
" a;\n"
" ['b'];\n"
" }\n"
"\n"
" class B extends class {} {\n"
" a = 1;\n"
" ['b'] = this.a;\n"
" foo() { return 1; }\n"
" constructor() {\n"
" super();\n"
" }\n"
" }\n"
"\n"
" class C extends B {\n"
" a = 1;\n"
" ['b'] = this.a;\n"
" constructor() {\n"
" (() => super())();\n"
" }\n"
" }\n"
"\n"
" new A;\n"
" new B;\n"
" new C;\n"
"}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("ClassFields.golden")));
i::FLAG_harmony_public_fields = old_flag;
}
TEST(StaticClassFields) {
bool old_flag = i::FLAG_harmony_public_fields;
bool old_static_flag = i::FLAG_harmony_static_fields;
i::FLAG_harmony_public_fields = true;
i::FLAG_harmony_static_fields = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = { const char* snippets[] = {
"{\n" "{\n"
" class A {\n" " class A {\n"
...@@ -2293,8 +2349,9 @@ TEST(ClassFields) { ...@@ -2293,8 +2349,9 @@ TEST(ClassFields) {
"}\n"}; "}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("ClassFields.golden"))); LoadGolden("StaticClassFields.golden")));
i::FLAG_harmony_public_fields = old_flag; i::FLAG_harmony_public_fields = old_flag;
i::FLAG_harmony_static_fields = old_static_flag;
} }
TEST(Generators) { TEST(Generators) {
......
...@@ -660,11 +660,23 @@ TEST(PreParserScopeAnalysis) { ...@@ -660,11 +660,23 @@ TEST(PreParserScopeAnalysis) {
[] { i::FLAG_harmony_public_fields = true; }, [] { i::FLAG_harmony_public_fields = true; },
[] { i::FLAG_harmony_public_fields = false; }}, [] { i::FLAG_harmony_public_fields = false; }},
{"class X { static ['foo'] = 2; }; new X;", {"class X { static ['foo'] = 2; }; new X;",
[] { i::FLAG_harmony_public_fields = true; }, [] {
[] { i::FLAG_harmony_public_fields = false; }}, i::FLAG_harmony_public_fields = true;
i::FLAG_harmony_static_fields = true;
},
[] {
i::FLAG_harmony_public_fields = false;
i::FLAG_harmony_static_fields = false;
}},
{"class X { ['bar'] = 1; static ['foo'] = 2; }; new X;", {"class X { ['bar'] = 1; static ['foo'] = 2; }; new X;",
[] { i::FLAG_harmony_public_fields = true; }, [] {
[] { i::FLAG_harmony_public_fields = false; }}, i::FLAG_harmony_public_fields = true;
i::FLAG_harmony_static_fields = true;
},
[] {
i::FLAG_harmony_public_fields = false;
i::FLAG_harmony_static_fields = false;
}},
}; };
for (unsigned outer_ix = 0; outer_ix < arraysize(outers); ++outer_ix) { for (unsigned outer_ix = 0; outer_ix < arraysize(outers); ++outer_ix) {
......
...@@ -1315,6 +1315,7 @@ enum ParserFlag { ...@@ -1315,6 +1315,7 @@ enum ParserFlag {
kAllowNatives, kAllowNatives,
kAllowHarmonyFunctionSent, kAllowHarmonyFunctionSent,
kAllowHarmonyPublicFields, kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields,
kAllowHarmonyDynamicImport, kAllowHarmonyDynamicImport,
kAllowHarmonyAsyncIteration, kAllowHarmonyAsyncIteration,
kAllowHarmonyImportMeta, kAllowHarmonyImportMeta,
...@@ -1330,6 +1331,7 @@ void SetGlobalFlags(i::EnumSet<ParserFlag> flags) { ...@@ -1330,6 +1331,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_function_sent = flags.Contains(kAllowHarmonyFunctionSent); i::FLAG_harmony_function_sent = flags.Contains(kAllowHarmonyFunctionSent);
i::FLAG_harmony_public_fields = flags.Contains(kAllowHarmonyPublicFields); i::FLAG_harmony_public_fields = flags.Contains(kAllowHarmonyPublicFields);
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);
i::FLAG_harmony_async_iteration = flags.Contains(kAllowHarmonyAsyncIteration); i::FLAG_harmony_async_iteration = flags.Contains(kAllowHarmonyAsyncIteration);
...@@ -1341,6 +1343,8 @@ void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) { ...@@ -1341,6 +1343,8 @@ void SetParserFlags(i::PreParser* parser, i::EnumSet<ParserFlag> flags) {
flags.Contains(kAllowHarmonyFunctionSent)); flags.Contains(kAllowHarmonyFunctionSent));
parser->set_allow_harmony_public_fields( parser->set_allow_harmony_public_fields(
flags.Contains(kAllowHarmonyPublicFields)); flags.Contains(kAllowHarmonyPublicFields));
parser->set_allow_harmony_static_fields(
flags.Contains(kAllowHarmonyStaticFields));
parser->set_allow_harmony_dynamic_import( parser->set_allow_harmony_dynamic_import(
flags.Contains(kAllowHarmonyDynamicImport)); flags.Contains(kAllowHarmonyDynamicImport));
parser->set_allow_harmony_import_meta( parser->set_allow_harmony_import_meta(
...@@ -4693,6 +4697,93 @@ TEST(ClassPropertyNameNoErrors) { ...@@ -4693,6 +4697,93 @@ TEST(ClassPropertyNameNoErrors) {
RunParserSyncTest(context_data, name_data, kSuccess); RunParserSyncTest(context_data, name_data, kSuccess);
} }
TEST(StaticClassFieldsNoErrors) {
// clang-format off
// Tests proposed class fields 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
"static a = 0;",
"static a = 0; b",
"static a = 0; b(){}",
"static a = 0; *b(){}",
"static a = 0; ['b'](){}",
"static a;",
"static a; b;",
"static a; b(){}",
"static a; *b(){}",
"static a; ['b'](){}",
"static ['a'] = 0;",
"static ['a'] = 0; b",
"static ['a'] = 0; b(){}",
"static ['a'] = 0; *b(){}",
"static ['a'] = 0; ['b'](){}",
"static ['a'];",
"static ['a']; b;",
"static ['a']; b(){}",
"static ['a']; *b(){}",
"static ['a']; ['b'](){}",
"static 0 = 0;",
"static 0;",
"static 'a' = 0;",
"static 'a';",
// ASI
"static a = 0\n",
"static a = 0\n b",
"static a = 0\n b(){}",
"static a\n",
"static a\n b\n",
"static a\n b(){}",
"static a\n *b(){}",
"static a\n ['b'](){}",
"static ['a'] = 0\n",
"static ['a'] = 0\n b",
"static ['a'] = 0\n b(){}",
"static ['a']\n",
"static ['a']\n b\n",
"static ['a']\n b(){}",
"static ['a']\n *b(){}",
"static ['a']\n ['b'](){}",
// ASI edge cases
"static a\n get",
"static get\n *a(){}",
"static a\n static",
// Misc edge cases
"static yield",
"static yield = 0",
"static yield\n a",
"static async;",
"static async = 0;",
"static async",
"static async = 0",
"static async\n a(){}", // a field named async, and a method named a.
"static async\n a",
"static await;",
"static await = 0;",
"static await\n a",
nullptr
};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
always_flags, arraysize(always_flags));
// Without the static flag, all of these are errors
static const ParserFlag no_static_flags[] = {kAllowHarmonyPublicFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
no_static_flags, arraysize(no_static_flags));
}
TEST(ClassFieldsNoErrors) { TEST(ClassFieldsNoErrors) {
// clang-format off // clang-format off
// Tests proposed class fields syntax. // Tests proposed class fields syntax.
...@@ -4729,15 +4820,6 @@ TEST(ClassFieldsNoErrors) { ...@@ -4729,15 +4820,6 @@ TEST(ClassFieldsNoErrors) {
"'a' = 0;", "'a' = 0;",
"'a';", "'a';",
"static a = 0;",
"static a;",
"static ['a'] = 0",
"static ['a']",
"static 0 = 0;",
"static 0;",
"static 'a' = 0;",
"static 'a';",
// ASI // ASI
"a = 0\n", "a = 0\n",
"a = 0\n b", "a = 0\n b",
...@@ -4767,10 +4849,8 @@ TEST(ClassFieldsNoErrors) { ...@@ -4767,10 +4849,8 @@ TEST(ClassFieldsNoErrors) {
"yield\n a", "yield\n a",
"async;", "async;",
"async = 0;", "async = 0;",
"static async;"
"async", "async",
"async = 0", "async = 0",
"static async",
"async\n a(){}", // a field named async, and a method named a. "async\n a(){}", // a field named async, and a method named a.
"async\n a", "async\n a",
"await;", "await;",
...@@ -4783,6 +4863,53 @@ TEST(ClassFieldsNoErrors) { ...@@ -4783,6 +4863,53 @@ TEST(ClassFieldsNoErrors) {
static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields}; static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0, RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
always_flags, arraysize(always_flags)); always_flags, arraysize(always_flags));
static const ParserFlag static_flags[] = {kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
static_flags, arraysize(static_flags));
}
TEST(StaticClassFieldsErrors) {
// clang-format off
// Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
"static a : 0",
"static a =",
"static constructor",
"static prototype",
"static *a = 0",
"static *a",
"static get a",
"static get\n a",
"static yield a",
"static async a = 0",
"static async a",
// ASI requires a linebreak
"static a b",
"static a = 0 b",
// ASI requires that the next token is not part of any legal production
"static a = 0\n *b(){}",
"static a = 0\n ['b'](){}",
nullptr
};
// clang-format on
static const ParserFlag no_static_flags[] = {kAllowHarmonyPublicFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
no_static_flags, arraysize(no_static_flags));
static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
always_flags, arraysize(always_flags));
} }
TEST(ClassFieldsErrors) { TEST(ClassFieldsErrors) {
...@@ -4796,19 +4923,11 @@ TEST(ClassFieldsErrors) { ...@@ -4796,19 +4923,11 @@ TEST(ClassFieldsErrors) {
const char* class_body_data[] = { const char* class_body_data[] = {
"a : 0", "a : 0",
"a =", "a =",
"static constructor",
"static prototype",
"constructor", "constructor",
"*a = 0", "*a = 0",
"*a", "*a",
"get a", "get a",
"yield a", "yield a",
"a : 0;",
"a =;",
"*a = 0;",
"*a;",
"get a;",
"yield a;",
"async a = 0", "async a = 0",
"async a", "async a",
...@@ -4827,6 +4946,11 @@ TEST(ClassFieldsErrors) { ...@@ -4827,6 +4946,11 @@ TEST(ClassFieldsErrors) {
static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields}; static const ParserFlag always_flags[] = {kAllowHarmonyPublicFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0, RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
always_flags, arraysize(always_flags)); always_flags, arraysize(always_flags));
static const ParserFlag static_flags[] = {kAllowHarmonyPublicFields,
kAllowHarmonyStaticFields};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
static_flags, arraysize(static_flags));
} }
TEST(ClassExpressionErrors) { TEST(ClassExpressionErrors) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Flags: --harmony-public-fields // Flags: --harmony-public-fields --harmony-static-fields
class X { class X {
static constructor = function() {}; static constructor = function() {};
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// Flags: --harmony-public-fields // Flags: --harmony-public-fields --harmony-static-fields
class X { class X {
static prototype = function() {}; static prototype = function() {};
......
...@@ -52,16 +52,8 @@ ...@@ -52,16 +52,8 @@
b = x; b = x;
c = 1; c = 1;
hasOwnProperty() { return 1;} hasOwnProperty() { return 1;}
static [x] = 2;
static b = 3;
static d;
} }
assertEquals(2, C.a);
assertEquals(3, C.b);
assertEquals(undefined, C.d);
assertEquals(undefined, C.c);
let c = new C; let c = new C;
assertEquals(undefined, c.a); assertEquals(undefined, c.a);
assertEquals('a', c.b); assertEquals('a', c.b);
...@@ -281,10 +273,10 @@ ...@@ -281,10 +273,10 @@
} }
class C { class C {
[run(1)] = run(7); [run(1)] = run(6);
[run(2)] = run(8); [run(2)] = run(7);
[run(3)]() { run(9);} [run(3)]() { run(9);}
static [run(4)] = run(6); [run(4)] = run(8);
[run(5)]() { throw new Error('should not execute');}; [run(5)]() { throw new Error('should not execute');};
} }
...@@ -303,10 +295,10 @@ function x() { ...@@ -303,10 +295,10 @@ function x() {
} }
class C { class C {
[run(1)] = run(7); [run(1)] = run(6);
[run(2)] = run(8); [run(2)] = run(7);
[run(3)]() { run(9);} [run(3)]() { run(9);}
static [run(4)] = run(6); [run(4)] = run(8);
[run(5)]() { throw new Error('should not execute');}; [run(5)]() { throw new Error('should not execute');};
} }
...@@ -636,20 +628,6 @@ x()(); ...@@ -636,20 +628,6 @@ x()();
assertEquals(1, obj.x); assertEquals(1, obj.x);
} }
{
function t() {
return class {
['x'] = 1;
static ['x'] = 2;
}
}
let klass = t();
let obj = new klass;
assertEquals(1, obj.x);
assertEquals(2, klass.x);
}
{ {
new class { new class {
t = 1; t = 1;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-public-fields // Flags: --harmony-public-fields --harmony-static-fields
"use strict"; "use strict";
...@@ -312,6 +312,50 @@ function x() { ...@@ -312,6 +312,50 @@ function x() {
} }
x()(); x()();
{
let log = [];
function run(i) {
log.push(i);
return i;
}
class C {
[run(1)] = run(7);
[run(2)] = run(8);
[run(3)]() { run(9);}
static [run(4)] = run(6);
[run(5)]() { throw new Error('should not execute');};
}
let c = new C;
c[3]();
assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log);
}
function y() {
// This tests lazy parsing.
return function() {
let log = [];
function run(i) {
log.push(i);
return i;
}
class C {
[run(1)] = run(7);
[run(2)] = run(8);
[run(3)]() { run(9);}
static [run(4)] = run(6);
[run(5)]() { throw new Error('should not execute');};
}
let c = new C;
c[3]();
assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], log);
}
}
y()();
{ {
class C {} class C {}
class D { class D {
...@@ -333,3 +377,42 @@ x()(); ...@@ -333,3 +377,42 @@ x()();
let obj = new klass; let obj = new klass;
assertEquals(2, klass.x); assertEquals(2, klass.x);
} }
{
let x = 'a';
class C {
a;
b = x;
c = 1;
hasOwnProperty() { return 1;}
static [x] = 2;
static b = 3;
static d;
}
assertEquals(2, C.a);
assertEquals(3, C.b);
assertEquals(undefined, C.d);
assertEquals(undefined, C.c);
let c = new C;
assertEquals(undefined, c.a);
assertEquals('a', c.b);
assertEquals(1, c.c);
assertEquals(undefined, c.d);
assertEquals(1, c.hasOwnProperty());
}
{
function t() {
return class {
['x'] = 1;
static ['x'] = 2;
}
}
let klass = t();
let obj = new klass;
assertEquals(1, obj.x);
assertEquals(2, klass.x);
}
...@@ -47,7 +47,7 @@ FEATURE_FLAGS = { ...@@ -47,7 +47,7 @@ FEATURE_FLAGS = {
'regexp-named-groups': '--harmony-regexp-named-captures', 'regexp-named-groups': '--harmony-regexp-named-captures',
'regexp-unicode-property-escapes': '--harmony-regexp-property', 'regexp-unicode-property-escapes': '--harmony-regexp-property',
'Promise.prototype.finally': '--harmony-promise-finally', 'Promise.prototype.finally': '--harmony-promise-finally',
'class-fields-public': '--harmony-public-fields', 'class-fields-public': '--harmony-class-fields',
} }
SKIPPED_FEATURES = set(['class-fields-private', 'optional-catch-binding']) SKIPPED_FEATURES = set(['class-fields-private', 'optional-catch-binding'])
......
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