Class fields, part 1 (parsing and infrastructure)
This is one part of a WIP implementation of the stage-2 proposal to add fields to classes: https://github.com/tc39/proposal-class-public-fields See design doc: https://docs.google.com/document/d/1WRtNm3ZLNJT1WVr8aq4RJuByYgfuAFAhj20LwTW6JVE/ This adds support for parsing fields in classes, including infrastructure. In particular, it adds: * Two booleans on function literal AST nodes * Two compiler hints on SharedFunctionInfos representing said bools * A new type of ClassLiteralProperty, FIELD * Parser support for the syntax * Syntax tests * A flag to enable it. Currently the fields are parsed and then droppped. Subsequent patches will add semantics, mostly by desugaring in the parser and the remainder in the non-crankshaft backends. BUG=v8:5367 Review-Url: https://codereview.chromium.org/2315733003 Cr-Commit-Position: refs/heads/master@{#39459}
This commit is contained in:
parent
9df94139d8
commit
fe6b76d491
@ -2626,6 +2626,21 @@ class FunctionLiteral final : public Expression {
|
|||||||
int yield_count() { return yield_count_; }
|
int yield_count() { return yield_count_; }
|
||||||
void set_yield_count(int yield_count) { yield_count_ = yield_count; }
|
void set_yield_count(int yield_count) { yield_count_ = yield_count; }
|
||||||
|
|
||||||
|
bool requires_class_field_init() {
|
||||||
|
return RequiresClassFieldInit::decode(bitfield_);
|
||||||
|
}
|
||||||
|
void set_requires_class_field_init(bool requires_class_field_init) {
|
||||||
|
bitfield_ =
|
||||||
|
RequiresClassFieldInit::update(bitfield_, requires_class_field_init);
|
||||||
|
}
|
||||||
|
bool is_class_field_initializer() {
|
||||||
|
return IsClassFieldInitializer::decode(bitfield_);
|
||||||
|
}
|
||||||
|
void set_is_class_field_initializer(bool is_class_field_initializer) {
|
||||||
|
bitfield_ =
|
||||||
|
IsClassFieldInitializer::update(bitfield_, is_class_field_initializer);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class AstNodeFactory;
|
friend class AstNodeFactory;
|
||||||
|
|
||||||
@ -2655,21 +2670,23 @@ class FunctionLiteral final : public Expression {
|
|||||||
kHasDuplicateParameters) |
|
kHasDuplicateParameters) |
|
||||||
IsFunction::encode(is_function) |
|
IsFunction::encode(is_function) |
|
||||||
ShouldEagerCompile::encode(eager_compile_hint == kShouldEagerCompile) |
|
ShouldEagerCompile::encode(eager_compile_hint == kShouldEagerCompile) |
|
||||||
|
RequiresClassFieldInit::encode(false) |
|
||||||
|
IsClassFieldInitializer::encode(false) |
|
||||||
FunctionKindBits::encode(kind) | ShouldBeUsedOnceHint::encode(false);
|
FunctionKindBits::encode(kind) | ShouldBeUsedOnceHint::encode(false);
|
||||||
DCHECK(IsValidFunctionKind(kind));
|
DCHECK(IsValidFunctionKind(kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
class FunctionTypeBits : public BitField16<FunctionType, 0, 2> {};
|
class FunctionTypeBits : public BitField<FunctionType, 0, 2> {};
|
||||||
class Pretenure : public BitField16<bool, 2, 1> {};
|
class Pretenure : public BitField<bool, 2, 1> {};
|
||||||
class HasDuplicateParameters : public BitField16<bool, 3, 1> {};
|
class HasDuplicateParameters : public BitField<bool, 3, 1> {};
|
||||||
class IsFunction : public BitField16<bool, 4, 1> {};
|
class IsFunction : public BitField<bool, 4, 1> {};
|
||||||
class ShouldEagerCompile : public BitField16<bool, 5, 1> {};
|
class ShouldEagerCompile : public BitField<bool, 5, 1> {};
|
||||||
class ShouldBeUsedOnceHint : public BitField16<bool, 6, 1> {};
|
class ShouldBeUsedOnceHint : public BitField<bool, 6, 1> {};
|
||||||
class FunctionKindBits : public BitField16<FunctionKind, 7, 9> {};
|
class RequiresClassFieldInit : public BitField<bool, 7, 1> {};
|
||||||
|
class IsClassFieldInitializer : public BitField<bool, 8, 1> {};
|
||||||
|
class FunctionKindBits : public BitField<FunctionKind, 9, 9> {};
|
||||||
|
|
||||||
// Start with 16-bit field, which should get packed together
|
uint32_t bitfield_;
|
||||||
// with Expression's trailing 16-bit field.
|
|
||||||
uint16_t bitfield_;
|
|
||||||
|
|
||||||
BailoutReason dont_optimize_reason_;
|
BailoutReason dont_optimize_reason_;
|
||||||
|
|
||||||
@ -2691,7 +2708,7 @@ class FunctionLiteral final : public Expression {
|
|||||||
// about a class literal's properties from the parser to the code generator.
|
// about a class literal's properties from the parser to the code generator.
|
||||||
class ClassLiteralProperty final : public LiteralProperty {
|
class ClassLiteralProperty final : public LiteralProperty {
|
||||||
public:
|
public:
|
||||||
enum Kind : uint8_t { METHOD, GETTER, SETTER };
|
enum Kind : uint8_t { METHOD, GETTER, SETTER, FIELD };
|
||||||
|
|
||||||
Kind kind() const { return kind_; }
|
Kind kind() const { return kind_; }
|
||||||
|
|
||||||
@ -2720,6 +2737,13 @@ class ClassLiteral final : public Expression {
|
|||||||
int start_position() const { return position(); }
|
int start_position() const { return position(); }
|
||||||
int end_position() const { return end_position_; }
|
int end_position() const { return end_position_; }
|
||||||
|
|
||||||
|
VariableProxy* static_initializer_proxy() const {
|
||||||
|
return static_initializer_proxy_;
|
||||||
|
}
|
||||||
|
void set_static_initializer_proxy(VariableProxy* proxy) {
|
||||||
|
static_initializer_proxy_ = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
|
BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
|
||||||
BailoutId PrototypeId() { return BailoutId(local_id(1)); }
|
BailoutId PrototypeId() { return BailoutId(local_id(1)); }
|
||||||
|
|
||||||
@ -2754,7 +2778,8 @@ class ClassLiteral final : public Expression {
|
|||||||
class_variable_proxy_(class_variable_proxy),
|
class_variable_proxy_(class_variable_proxy),
|
||||||
extends_(extends),
|
extends_(extends),
|
||||||
constructor_(constructor),
|
constructor_(constructor),
|
||||||
properties_(properties) {}
|
properties_(properties),
|
||||||
|
static_initializer_proxy_(nullptr) {}
|
||||||
|
|
||||||
static int parent_num_ids() { return Expression::num_ids(); }
|
static int parent_num_ids() { return Expression::num_ids(); }
|
||||||
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
|
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
|
||||||
@ -2766,6 +2791,7 @@ class ClassLiteral final : public Expression {
|
|||||||
Expression* extends_;
|
Expression* extends_;
|
||||||
FunctionLiteral* constructor_;
|
FunctionLiteral* constructor_;
|
||||||
ZoneList<Property*>* properties_;
|
ZoneList<Property*>* properties_;
|
||||||
|
VariableProxy* static_initializer_proxy_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -919,6 +919,9 @@ void AstPrinter::PrintClassProperties(
|
|||||||
case ClassLiteral::Property::SETTER:
|
case ClassLiteral::Property::SETTER:
|
||||||
prop_kind = "SETTER";
|
prop_kind = "SETTER";
|
||||||
break;
|
break;
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
|
prop_kind = "FIELD";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
EmbeddedVector<char, 128> buf;
|
EmbeddedVector<char, 128> buf;
|
||||||
SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "",
|
SNPrintF(buf, "PROPERTY%s - %s", property->is_static() ? " - STATIC" : "",
|
||||||
|
@ -685,7 +685,14 @@ class DeclarationScope : public Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the default function arity excluding default or rest parameters.
|
// Returns the default function arity excluding default or rest parameters.
|
||||||
int default_function_length() const { return arity_; }
|
// This will be used to set the length of the function, by default.
|
||||||
|
// Class field initializers use this property to indicate the number of
|
||||||
|
// fields being initialized.
|
||||||
|
int arity() const { return arity_; }
|
||||||
|
|
||||||
|
// Normal code should not need to call this. Class field initializers use this
|
||||||
|
// property to indicate the number of fields being initialized.
|
||||||
|
void set_arity(int arity) { arity_ = arity; }
|
||||||
|
|
||||||
// Returns the number of formal parameters, excluding a possible rest
|
// Returns the number of formal parameters, excluding a possible rest
|
||||||
// parameter. Examples:
|
// parameter. Examples:
|
||||||
|
@ -2816,6 +2816,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(icu_case_mapping)
|
|||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_async_await)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_generators)
|
||||||
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_trailing_commas)
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_trailing_commas)
|
||||||
|
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_fields)
|
||||||
|
|
||||||
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
|
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
|
||||||
const char* name, Handle<Symbol> value) {
|
const char* name, Handle<Symbol> value) {
|
||||||
@ -3416,6 +3417,7 @@ bool Genesis::InstallExperimentalNatives() {
|
|||||||
"native harmony-async-await.js", nullptr};
|
"native harmony-async-await.js", nullptr};
|
||||||
static const char* harmony_restrictive_generators_natives[] = {nullptr};
|
static const char* harmony_restrictive_generators_natives[] = {nullptr};
|
||||||
static const char* harmony_trailing_commas_natives[] = {nullptr};
|
static const char* harmony_trailing_commas_natives[] = {nullptr};
|
||||||
|
static const char* harmony_class_fields_natives[] = {nullptr};
|
||||||
|
|
||||||
for (int i = ExperimentalNatives::GetDebuggerCount();
|
for (int i = ExperimentalNatives::GetDebuggerCount();
|
||||||
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
i < ExperimentalNatives::GetBuiltinsCount(); i++) {
|
||||||
|
@ -1652,6 +1652,10 @@ void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
|
|||||||
NewNode(op, receiver, key, value, attr);
|
NewNode(op, receiver, key, value, attr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ClassLiteral::Property::FIELD: {
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,8 @@ DEFINE_IMPLICATION(es_staging, move_object_start)
|
|||||||
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
V(harmony_regexp_property, "harmony unicode regexp property classes") \
|
||||||
V(harmony_for_in, "harmony for-in syntax") \
|
V(harmony_for_in, "harmony for-in syntax") \
|
||||||
V(harmony_trailing_commas, \
|
V(harmony_trailing_commas, \
|
||||||
"harmony trailing commas in function parameter lists")
|
"harmony trailing commas in function parameter lists") \
|
||||||
|
V(harmony_class_fields, "harmony public fields in class literals")
|
||||||
|
|
||||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||||
#define HARMONY_STAGED_BASE(V) \
|
#define HARMONY_STAGED_BASE(V) \
|
||||||
|
@ -2018,6 +2018,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1919,6 +1919,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1923,6 +1923,10 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
PushOperand(Smi::FromInt(DONT_ENUM));
|
PushOperand(Smi::FromInt(DONT_ENUM));
|
||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2021,6 +2021,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -2021,6 +2021,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -2025,6 +2025,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1982,6 +1982,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1916,6 +1916,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1904,6 +1904,10 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
|
|||||||
PushOperand(Smi::FromInt(DONT_ENUM));
|
PushOperand(Smi::FromInt(DONT_ENUM));
|
||||||
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ClassLiteral::Property::FIELD:
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1593,6 +1593,10 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
|
|||||||
receiver, 4);
|
receiver, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ClassLiteral::Property::FIELD: {
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6107,6 +6107,10 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
|||||||
kIsDefaultConstructor)
|
kIsDefaultConstructor)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
|
||||||
kIsAsmWasmBroken)
|
kIsAsmWasmBroken)
|
||||||
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, requires_class_field_init,
|
||||||
|
kRequiresClassFieldInit)
|
||||||
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_class_field_initializer,
|
||||||
|
kIsClassFieldInitializer)
|
||||||
|
|
||||||
inline bool SharedFunctionInfo::is_resumable() const {
|
inline bool SharedFunctionInfo::is_resumable() const {
|
||||||
return is_generator() || is_async();
|
return is_generator() || is_async();
|
||||||
|
@ -13630,7 +13630,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
|
|||||||
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
|
Handle<SharedFunctionInfo> shared_info, FunctionLiteral* lit) {
|
||||||
// When adding fields here, make sure DeclarationScope::AnalyzePartially is
|
// When adding fields here, make sure DeclarationScope::AnalyzePartially is
|
||||||
// updated accordingly.
|
// updated accordingly.
|
||||||
shared_info->set_length(lit->scope()->default_function_length());
|
shared_info->set_length(lit->scope()->arity());
|
||||||
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
|
shared_info->set_internal_formal_parameter_count(lit->parameter_count());
|
||||||
shared_info->set_function_token_position(lit->function_token_position());
|
shared_info->set_function_token_position(lit->function_token_position());
|
||||||
shared_info->set_start_position(lit->start_position());
|
shared_info->set_start_position(lit->start_position());
|
||||||
@ -13654,6 +13654,9 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
|
|||||||
}
|
}
|
||||||
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
|
shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
|
||||||
shared_info->set_asm_function(lit->scope()->asm_function());
|
shared_info->set_asm_function(lit->scope()->asm_function());
|
||||||
|
shared_info->set_requires_class_field_init(lit->requires_class_field_init());
|
||||||
|
shared_info->set_is_class_field_initializer(
|
||||||
|
lit->is_class_field_initializer());
|
||||||
SetExpectedNofPropertiesFromEstimate(shared_info, lit);
|
SetExpectedNofPropertiesFromEstimate(shared_info, lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7384,6 +7384,12 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
// Indicates that this function is a default constructor.
|
// Indicates that this function is a default constructor.
|
||||||
DECL_BOOLEAN_ACCESSORS(is_default_constructor)
|
DECL_BOOLEAN_ACCESSORS(is_default_constructor)
|
||||||
|
|
||||||
|
// Indicates that this is a constructor for a base class with instance fields.
|
||||||
|
DECL_BOOLEAN_ACCESSORS(requires_class_field_init)
|
||||||
|
// Indicates that this is a synthesized function to set up class instance
|
||||||
|
// fields.
|
||||||
|
DECL_BOOLEAN_ACCESSORS(is_class_field_initializer)
|
||||||
|
|
||||||
// Indicates that this function is an asm function.
|
// Indicates that this function is an asm function.
|
||||||
DECL_BOOLEAN_ACCESSORS(asm_function)
|
DECL_BOOLEAN_ACCESSORS(asm_function)
|
||||||
|
|
||||||
@ -7672,6 +7678,8 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
kDeserialized,
|
kDeserialized,
|
||||||
kIsDeclaration,
|
kIsDeclaration,
|
||||||
kIsAsmWasmBroken,
|
kIsAsmWasmBroken,
|
||||||
|
kRequiresClassFieldInit,
|
||||||
|
kIsClassFieldInitializer,
|
||||||
kCompilerHintsCount, // Pseudo entry
|
kCompilerHintsCount, // Pseudo entry
|
||||||
};
|
};
|
||||||
// kFunctionKind has to be byte-aligned
|
// kFunctionKind has to be byte-aligned
|
||||||
|
@ -101,6 +101,15 @@ bool ParseInfo::is_default_constructor() const {
|
|||||||
0;
|
0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParseInfo::requires_class_field_init() const {
|
||||||
|
return (compiler_hints_ &
|
||||||
|
(1 << SharedFunctionInfo::kRequiresClassFieldInit)) != 0;
|
||||||
|
}
|
||||||
|
bool ParseInfo::is_class_field_initializer() const {
|
||||||
|
return (compiler_hints_ &
|
||||||
|
(1 << SharedFunctionInfo::kIsClassFieldInitializer)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
FunctionKind ParseInfo::function_kind() const {
|
FunctionKind ParseInfo::function_kind() const {
|
||||||
return SharedFunctionInfo::FunctionKindBits::decode(compiler_hints_);
|
return SharedFunctionInfo::FunctionKindBits::decode(compiler_hints_);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,8 @@ class ParseInfo {
|
|||||||
bool is_arrow() const;
|
bool is_arrow() const;
|
||||||
bool is_async() const;
|
bool is_async() const;
|
||||||
bool is_default_constructor() const;
|
bool is_default_constructor() const;
|
||||||
|
bool requires_class_field_init() const;
|
||||||
|
bool is_class_field_initializer() const;
|
||||||
FunctionKind function_kind() const;
|
FunctionKind function_kind() const;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -199,7 +199,8 @@ class ParserBase {
|
|||||||
allow_harmony_function_sent_(false),
|
allow_harmony_function_sent_(false),
|
||||||
allow_harmony_async_await_(false),
|
allow_harmony_async_await_(false),
|
||||||
allow_harmony_restrictive_generators_(false),
|
allow_harmony_restrictive_generators_(false),
|
||||||
allow_harmony_trailing_commas_(false) {}
|
allow_harmony_trailing_commas_(false),
|
||||||
|
allow_harmony_class_fields_(false) {}
|
||||||
|
|
||||||
#define ALLOW_ACCESSORS(name) \
|
#define ALLOW_ACCESSORS(name) \
|
||||||
bool allow_##name() const { return allow_##name##_; } \
|
bool allow_##name() const { return allow_##name##_; } \
|
||||||
@ -215,6 +216,7 @@ class ParserBase {
|
|||||||
ALLOW_ACCESSORS(harmony_async_await);
|
ALLOW_ACCESSORS(harmony_async_await);
|
||||||
ALLOW_ACCESSORS(harmony_restrictive_generators);
|
ALLOW_ACCESSORS(harmony_restrictive_generators);
|
||||||
ALLOW_ACCESSORS(harmony_trailing_commas);
|
ALLOW_ACCESSORS(harmony_trailing_commas);
|
||||||
|
ALLOW_ACCESSORS(harmony_class_fields);
|
||||||
|
|
||||||
#undef ALLOW_ACCESSORS
|
#undef ALLOW_ACCESSORS
|
||||||
|
|
||||||
@ -1100,6 +1102,7 @@ class ParserBase {
|
|||||||
kValueProperty,
|
kValueProperty,
|
||||||
kShorthandProperty,
|
kShorthandProperty,
|
||||||
kMethodProperty,
|
kMethodProperty,
|
||||||
|
kClassField,
|
||||||
kNotSet
|
kNotSet
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1112,6 +1115,8 @@ class ParserBase {
|
|||||||
ClassLiteralPropertyT ParseClassPropertyDefinition(
|
ClassLiteralPropertyT ParseClassPropertyDefinition(
|
||||||
ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
|
ClassLiteralChecker* checker, bool has_extends, bool* is_computed_name,
|
||||||
bool* has_seen_constructor, bool* ok);
|
bool* has_seen_constructor, bool* ok);
|
||||||
|
FunctionLiteralT ParseClassFieldForInitializer(bool has_initializer,
|
||||||
|
bool* ok);
|
||||||
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
|
ObjectLiteralPropertyT ParseObjectPropertyDefinition(
|
||||||
ObjectLiteralChecker* checker, bool* is_computed_name, bool* ok);
|
ObjectLiteralChecker* checker, bool* is_computed_name, bool* ok);
|
||||||
ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
|
ExpressionListT ParseArguments(Scanner::Location* first_spread_pos,
|
||||||
@ -1387,6 +1392,7 @@ class ParserBase {
|
|||||||
bool allow_harmony_async_await_;
|
bool allow_harmony_async_await_;
|
||||||
bool allow_harmony_restrictive_generators_;
|
bool allow_harmony_restrictive_generators_;
|
||||||
bool allow_harmony_trailing_commas_;
|
bool allow_harmony_trailing_commas_;
|
||||||
|
bool allow_harmony_class_fields_;
|
||||||
|
|
||||||
friend class DiscardableZoneScope;
|
friend class DiscardableZoneScope;
|
||||||
};
|
};
|
||||||
@ -1942,6 +1948,10 @@ bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
|
|||||||
case Token::LPAREN:
|
case Token::LPAREN:
|
||||||
*kind = PropertyKind::kMethodProperty;
|
*kind = PropertyKind::kMethodProperty;
|
||||||
return true;
|
return true;
|
||||||
|
case Token::MUL:
|
||||||
|
case Token::SEMICOLON:
|
||||||
|
*kind = PropertyKind::kClassField;
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2079,6 +2089,10 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
|
|||||||
kind = PropertyKind::kMethodProperty;
|
kind = PropertyKind::kMethodProperty;
|
||||||
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::ASSIGN || peek() == Token::SEMICOLON ||
|
||||||
|
peek() == Token::RBRACE) {
|
||||||
|
name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
|
||||||
|
name_expression = factory()->NewStringLiteral(name, position());
|
||||||
} else {
|
} else {
|
||||||
is_static = true;
|
is_static = true;
|
||||||
name_expression = ParsePropertyName(
|
name_expression = ParsePropertyName(
|
||||||
@ -2092,11 +2106,29 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
case PropertyKind::kClassField:
|
||||||
|
case PropertyKind::kNotSet: // This case is a name followed by a name or
|
||||||
|
// other property. Here we have to assume
|
||||||
|
// that's an uninitialized field followed by a
|
||||||
|
// linebreak followed by a property, with ASI
|
||||||
|
// adding the semicolon. If not, there will be
|
||||||
|
// a syntax error after parsing the first name
|
||||||
|
// as an uninitialized field.
|
||||||
case PropertyKind::kShorthandProperty:
|
case PropertyKind::kShorthandProperty:
|
||||||
case PropertyKind::kValueProperty:
|
case PropertyKind::kValueProperty:
|
||||||
ReportUnexpectedToken(Next());
|
if (allow_harmony_class_fields()) {
|
||||||
*ok = false;
|
bool has_initializer = Check(Token::ASSIGN);
|
||||||
return impl()->EmptyClassLiteralProperty();
|
ExpressionT function_literal = ParseClassFieldForInitializer(
|
||||||
|
has_initializer, CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
|
||||||
|
ExpectSemicolon(CHECK_OK_CUSTOM(EmptyClassLiteralProperty));
|
||||||
|
return factory()->NewClassLiteralProperty(
|
||||||
|
name_expression, function_literal, ClassLiteralProperty::FIELD,
|
||||||
|
is_static, *is_computed_name);
|
||||||
|
} else {
|
||||||
|
ReportUnexpectedToken(Next());
|
||||||
|
*ok = false;
|
||||||
|
return impl()->EmptyClassLiteralProperty();
|
||||||
|
}
|
||||||
|
|
||||||
case PropertyKind::kMethodProperty: {
|
case PropertyKind::kMethodProperty: {
|
||||||
DCHECK(!is_get && !is_set);
|
DCHECK(!is_get && !is_set);
|
||||||
@ -2163,16 +2195,48 @@ ParserBase<Impl>::ParseClassPropertyDefinition(ClassLiteralChecker* checker,
|
|||||||
is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER,
|
is_get ? ClassLiteralProperty::GETTER : ClassLiteralProperty::SETTER,
|
||||||
is_static, *is_computed_name);
|
is_static, *is_computed_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
case PropertyKind::kNotSet:
|
|
||||||
ReportUnexpectedToken(Next());
|
|
||||||
*ok = false;
|
|
||||||
return impl()->EmptyClassLiteralProperty();
|
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return impl()->EmptyClassLiteralProperty();
|
return impl()->EmptyClassLiteralProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Impl>
|
||||||
|
typename ParserBase<Impl>::FunctionLiteralT
|
||||||
|
ParserBase<Impl>::ParseClassFieldForInitializer(bool has_initializer,
|
||||||
|
bool* ok) {
|
||||||
|
// Makes a concise method which evaluates and returns the initialized value
|
||||||
|
// (or undefined if absent).
|
||||||
|
FunctionKind kind = FunctionKind::kConciseMethod;
|
||||||
|
DeclarationScope* initializer_scope = NewFunctionScope(kind);
|
||||||
|
initializer_scope->set_start_position(scanner()->location().end_pos);
|
||||||
|
FunctionState initializer_state(&function_state_, &scope_state_,
|
||||||
|
initializer_scope, kind);
|
||||||
|
DCHECK(scope() == initializer_scope);
|
||||||
|
scope()->SetLanguageMode(STRICT);
|
||||||
|
ExpressionClassifier expression_classifier(this);
|
||||||
|
ExpressionT value;
|
||||||
|
if (has_initializer) {
|
||||||
|
value = this->ParseAssignmentExpression(
|
||||||
|
true, CHECK_OK_CUSTOM(EmptyFunctionLiteral));
|
||||||
|
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(EmptyFunctionLiteral));
|
||||||
|
} else {
|
||||||
|
value = factory()->NewUndefinedLiteral(kNoSourcePosition);
|
||||||
|
}
|
||||||
|
initializer_scope->set_end_position(scanner()->location().end_pos);
|
||||||
|
typename Types::StatementList body = impl()->NewStatementList(1);
|
||||||
|
body->Add(factory()->NewReturnStatement(value, kNoSourcePosition), zone());
|
||||||
|
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
|
||||||
|
impl()->EmptyIdentifierString(), initializer_scope, body,
|
||||||
|
initializer_state.materialized_literal_count(),
|
||||||
|
initializer_state.expected_property_count(), 0,
|
||||||
|
FunctionLiteral::kNoDuplicateParameters,
|
||||||
|
FunctionLiteral::kAnonymousExpression,
|
||||||
|
FunctionLiteral::kShouldLazyCompile, kind,
|
||||||
|
initializer_scope->start_position());
|
||||||
|
function_literal->set_is_class_field_initializer(true);
|
||||||
|
return function_literal;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Impl>
|
template <typename Impl>
|
||||||
typename ParserBase<Impl>::ObjectLiteralPropertyT
|
typename ParserBase<Impl>::ObjectLiteralPropertyT
|
||||||
ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
|
ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
|
||||||
@ -2343,6 +2407,7 @@ ParserBase<Impl>::ParseObjectPropertyDefinition(ObjectLiteralChecker* checker,
|
|||||||
*is_computed_name);
|
*is_computed_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PropertyKind::kClassField:
|
||||||
case PropertyKind::kNotSet:
|
case PropertyKind::kNotSet:
|
||||||
ReportUnexpectedToken(Next());
|
ReportUnexpectedToken(Next());
|
||||||
*ok = false;
|
*ok = false;
|
||||||
|
@ -151,8 +151,9 @@ void Parser::SetCachedData(ParseInfo* info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
|
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
|
||||||
bool call_super, int pos,
|
bool call_super,
|
||||||
int end_pos,
|
bool requires_class_field_init,
|
||||||
|
int pos, int end_pos,
|
||||||
LanguageMode language_mode) {
|
LanguageMode language_mode) {
|
||||||
int materialized_literal_count = -1;
|
int materialized_literal_count = -1;
|
||||||
int expected_property_count = -1;
|
int expected_property_count = -1;
|
||||||
@ -221,6 +222,8 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
|
|||||||
FunctionLiteral::kAnonymousExpression,
|
FunctionLiteral::kAnonymousExpression,
|
||||||
FunctionLiteral::kShouldLazyCompile, kind, pos);
|
FunctionLiteral::kShouldLazyCompile, kind, pos);
|
||||||
|
|
||||||
|
function_literal->set_requires_class_field_init(requires_class_field_init);
|
||||||
|
|
||||||
return function_literal;
|
return function_literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,6 +593,7 @@ Parser::Parser(ParseInfo* info)
|
|||||||
set_allow_harmony_async_await(FLAG_harmony_async_await);
|
set_allow_harmony_async_await(FLAG_harmony_async_await);
|
||||||
set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators);
|
set_allow_harmony_restrictive_generators(FLAG_harmony_restrictive_generators);
|
||||||
set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas);
|
set_allow_harmony_trailing_commas(FLAG_harmony_trailing_commas);
|
||||||
|
set_allow_harmony_class_fields(FLAG_harmony_class_fields);
|
||||||
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;
|
||||||
@ -962,7 +966,8 @@ FunctionLiteral* Parser::DoParseLazy(ParseInfo* info,
|
|||||||
DCHECK_EQ(scope(), outer);
|
DCHECK_EQ(scope(), outer);
|
||||||
result = DefaultConstructor(
|
result = DefaultConstructor(
|
||||||
raw_name, IsSubclassConstructor(info->function_kind()),
|
raw_name, IsSubclassConstructor(info->function_kind()),
|
||||||
info->start_position(), info->end_position(), info->language_mode());
|
info->requires_class_field_init(), info->start_position(),
|
||||||
|
info->end_position(), info->language_mode());
|
||||||
} else {
|
} else {
|
||||||
result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
|
result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
|
||||||
kSkipFunctionNameCheck,
|
kSkipFunctionNameCheck,
|
||||||
@ -3722,6 +3727,7 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
|
|||||||
SET_ALLOW(harmony_restrictive_declarations);
|
SET_ALLOW(harmony_restrictive_declarations);
|
||||||
SET_ALLOW(harmony_async_await);
|
SET_ALLOW(harmony_async_await);
|
||||||
SET_ALLOW(harmony_trailing_commas);
|
SET_ALLOW(harmony_trailing_commas);
|
||||||
|
SET_ALLOW(harmony_class_fields);
|
||||||
#undef SET_ALLOW
|
#undef SET_ALLOW
|
||||||
}
|
}
|
||||||
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
|
||||||
@ -3782,8 +3788,15 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
|
|||||||
|
|
||||||
ClassLiteralChecker checker(this);
|
ClassLiteralChecker checker(this);
|
||||||
ZoneList<ClassLiteral::Property*>* properties = NewClassPropertyList(4);
|
ZoneList<ClassLiteral::Property*>* properties = NewClassPropertyList(4);
|
||||||
|
ZoneList<Expression*>* instance_field_initializers =
|
||||||
|
new (zone()) ZoneList<Expression*>(0, zone());
|
||||||
FunctionLiteral* constructor = nullptr;
|
FunctionLiteral* constructor = nullptr;
|
||||||
bool has_seen_constructor = false;
|
bool has_seen_constructor = false;
|
||||||
|
Variable* static_initializer_var = nullptr;
|
||||||
|
|
||||||
|
Block* do_block = factory()->NewBlock(nullptr, 1, false, pos);
|
||||||
|
Variable* result_var = NewTemporary(ast_value_factory()->empty_string());
|
||||||
|
DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos);
|
||||||
|
|
||||||
Expect(Token::LBRACE, CHECK_OK);
|
Expect(Token::LBRACE, CHECK_OK);
|
||||||
|
|
||||||
@ -3806,6 +3819,10 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
|
|||||||
constructor->set_raw_name(
|
constructor->set_raw_name(
|
||||||
name != nullptr ? name : ast_value_factory()->empty_string());
|
name != nullptr ? name : ast_value_factory()->empty_string());
|
||||||
} else {
|
} else {
|
||||||
|
if (property->kind() == ClassLiteralProperty::FIELD) {
|
||||||
|
DCHECK(allow_harmony_class_fields());
|
||||||
|
continue; // TODO(bakkot) implementation
|
||||||
|
}
|
||||||
properties->Add(property, zone());
|
properties->Add(property, zone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3816,13 +3833,18 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
|
|||||||
Expect(Token::RBRACE, CHECK_OK);
|
Expect(Token::RBRACE, CHECK_OK);
|
||||||
int end_pos = scanner()->location().end_pos;
|
int end_pos = scanner()->location().end_pos;
|
||||||
|
|
||||||
if (constructor == nullptr) {
|
bool has_instance_fields = instance_field_initializers->length() > 0;
|
||||||
constructor = DefaultConstructor(name, has_extends, pos, end_pos,
|
DCHECK(!has_instance_fields || allow_harmony_class_fields());
|
||||||
block_state.language_mode());
|
bool has_default_constructor = constructor == nullptr;
|
||||||
|
if (has_default_constructor) {
|
||||||
|
constructor = DefaultConstructor(name, has_extends, has_instance_fields,
|
||||||
|
pos, end_pos, block_state.language_mode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we do not finalize this block scope because it is
|
if (has_instance_fields && extends == nullptr) {
|
||||||
// used as a sentinel value indicating an anonymous class.
|
constructor->set_requires_class_field_init(true);
|
||||||
|
} // The derived case is handled by rewriting super calls.
|
||||||
|
|
||||||
block_state.set_end_position(end_pos);
|
block_state.set_end_position(end_pos);
|
||||||
|
|
||||||
if (name != nullptr) {
|
if (name != nullptr) {
|
||||||
@ -3830,18 +3852,23 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
|
|||||||
proxy->var()->set_initializer_position(end_pos);
|
proxy->var()->set_initializer_position(end_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* do_block = factory()->NewBlock(nullptr, 1, false, pos);
|
|
||||||
Variable* result_var = NewTemporary(ast_value_factory()->empty_string());
|
|
||||||
do_block->set_scope(block_state.FinalizedBlockScope());
|
|
||||||
DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos);
|
|
||||||
|
|
||||||
ClassLiteral* class_literal = factory()->NewClassLiteral(
|
ClassLiteral* class_literal = factory()->NewClassLiteral(
|
||||||
proxy, extends, constructor, properties, pos, end_pos);
|
proxy, extends, constructor, properties, pos, end_pos);
|
||||||
|
|
||||||
|
if (static_initializer_var != nullptr) {
|
||||||
|
class_literal->set_static_initializer_proxy(
|
||||||
|
factory()->NewVariableProxy(static_initializer_var));
|
||||||
|
}
|
||||||
|
|
||||||
do_block->statements()->Add(
|
do_block->statements()->Add(
|
||||||
factory()->NewExpressionStatement(class_literal, pos), zone());
|
factory()->NewExpressionStatement(
|
||||||
|
factory()->NewAssignment(Token::ASSIGN,
|
||||||
|
factory()->NewVariableProxy(result_var),
|
||||||
|
class_literal, kNoSourcePosition),
|
||||||
|
pos),
|
||||||
|
zone());
|
||||||
|
do_block->set_scope(block_state.FinalizedBlockScope());
|
||||||
do_expr->set_represented_function(constructor);
|
do_expr->set_represented_function(constructor);
|
||||||
Rewriter::Rewrite(this, GetClosureScope(), do_expr, ast_value_factory());
|
|
||||||
|
|
||||||
return do_expr;
|
return do_expr;
|
||||||
}
|
}
|
||||||
|
@ -464,8 +464,8 @@ class Parser : public ParserBase<Parser> {
|
|||||||
|
|
||||||
// Factory methods.
|
// Factory methods.
|
||||||
FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
|
FunctionLiteral* DefaultConstructor(const AstRawString* name, bool call_super,
|
||||||
int pos, int end_pos,
|
bool requires_class_field_init, int pos,
|
||||||
LanguageMode language_mode);
|
int end_pos, LanguageMode language_mode);
|
||||||
|
|
||||||
// Skip over a lazy function, either using cached data if we have it, or
|
// Skip over a lazy function, either using cached data if we have it, or
|
||||||
// by parsing the function with PreParser. Consumes the ending }.
|
// by parsing the function with PreParser. Consumes the ending }.
|
||||||
@ -542,6 +542,8 @@ class Parser : public ParserBase<Parser> {
|
|||||||
int pos);
|
int pos);
|
||||||
Expression* SpreadCallNew(Expression* function, ZoneList<Expression*>* args,
|
Expression* SpreadCallNew(Expression* function, ZoneList<Expression*>* args,
|
||||||
int pos);
|
int pos);
|
||||||
|
Expression* CallClassFieldInitializer(Scope* scope, Expression* this_expr);
|
||||||
|
Expression* RewriteSuperCall(Expression* call_expression);
|
||||||
|
|
||||||
void SetLanguageMode(Scope* scope, LanguageMode mode);
|
void SetLanguageMode(Scope* scope, LanguageMode mode);
|
||||||
void SetAsmModule();
|
void SetAsmModule();
|
||||||
|
@ -316,6 +316,8 @@ class PreParserExpression {
|
|||||||
int position() const { return kNoSourcePosition; }
|
int position() const { return kNoSourcePosition; }
|
||||||
void set_function_token_position(int position) {}
|
void set_function_token_position(int position) {}
|
||||||
|
|
||||||
|
void set_is_class_field_initializer(bool is_class_field_initializer) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {
|
enum Type {
|
||||||
kEmpty,
|
kEmpty,
|
||||||
@ -477,6 +479,9 @@ class PreParserFactory {
|
|||||||
int pos) {
|
int pos) {
|
||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
}
|
}
|
||||||
|
PreParserExpression NewUndefinedLiteral(int pos) {
|
||||||
|
return PreParserExpression::Default();
|
||||||
|
}
|
||||||
PreParserExpression NewRegExpLiteral(PreParserIdentifier js_pattern,
|
PreParserExpression NewRegExpLiteral(PreParserIdentifier js_pattern,
|
||||||
int js_flags, int literal_index,
|
int js_flags, int literal_index,
|
||||||
int pos) {
|
int pos) {
|
||||||
|
@ -1490,6 +1490,7 @@ enum ParserFlag {
|
|||||||
kAllowHarmonyAsyncAwait,
|
kAllowHarmonyAsyncAwait,
|
||||||
kAllowHarmonyRestrictiveGenerators,
|
kAllowHarmonyRestrictiveGenerators,
|
||||||
kAllowHarmonyTrailingCommas,
|
kAllowHarmonyTrailingCommas,
|
||||||
|
kAllowHarmonyClassFields,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ParserSyncTestResult {
|
enum ParserSyncTestResult {
|
||||||
@ -1514,6 +1515,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
|
|||||||
flags.Contains(kAllowHarmonyRestrictiveGenerators));
|
flags.Contains(kAllowHarmonyRestrictiveGenerators));
|
||||||
parser->set_allow_harmony_trailing_commas(
|
parser->set_allow_harmony_trailing_commas(
|
||||||
flags.Contains(kAllowHarmonyTrailingCommas));
|
flags.Contains(kAllowHarmonyTrailingCommas));
|
||||||
|
parser->set_allow_harmony_class_fields(
|
||||||
|
flags.Contains(kAllowHarmonyClassFields));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4569,6 +4572,160 @@ TEST(ClassPropertyNameNoErrors) {
|
|||||||
RunParserSyncTest(context_data, name_data, kSuccess);
|
RunParserSyncTest(context_data, name_data, kSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClassFieldsNoErrors) {
|
||||||
|
// clang-format off
|
||||||
|
// Tests proposed class fields syntax.
|
||||||
|
const char* context_data[][2] = {{"(class {", "});"},
|
||||||
|
{"(class extends Base {", "});"},
|
||||||
|
{"class C {", "}"},
|
||||||
|
{"class C extends Base {", "}"},
|
||||||
|
{NULL, NULL}};
|
||||||
|
const char* class_body_data[] = {
|
||||||
|
// Basic syntax
|
||||||
|
"a = 0;",
|
||||||
|
"a = 0; b",
|
||||||
|
"a = 0; b(){}",
|
||||||
|
"a = 0; *b(){}",
|
||||||
|
"a = 0; ['b'](){}",
|
||||||
|
"a;",
|
||||||
|
"a; b;",
|
||||||
|
"a; b(){}",
|
||||||
|
"a; *b(){}",
|
||||||
|
"a; ['b'](){}",
|
||||||
|
"['a'] = 0;",
|
||||||
|
"['a'] = 0; b",
|
||||||
|
"['a'] = 0; b(){}",
|
||||||
|
"['a'] = 0; *b(){}",
|
||||||
|
"['a'] = 0; ['b'](){}",
|
||||||
|
"['a'];",
|
||||||
|
"['a']; b;",
|
||||||
|
"['a']; b(){}",
|
||||||
|
"['a']; *b(){}",
|
||||||
|
"['a']; ['b'](){}",
|
||||||
|
|
||||||
|
"0 = 0;",
|
||||||
|
"0;",
|
||||||
|
"'a' = 0;",
|
||||||
|
"'a';",
|
||||||
|
|
||||||
|
"static a = 0;",
|
||||||
|
"static a;",
|
||||||
|
"static ['a'] = 0",
|
||||||
|
"static ['a']",
|
||||||
|
"static 0 = 0;",
|
||||||
|
"static 0;",
|
||||||
|
"static 'a' = 0;",
|
||||||
|
"static 'a';",
|
||||||
|
|
||||||
|
// ASI
|
||||||
|
"a = 0\n",
|
||||||
|
"a = 0\n b",
|
||||||
|
"a = 0\n b(){}",
|
||||||
|
"a\n",
|
||||||
|
"a\n b\n",
|
||||||
|
"a\n b(){}",
|
||||||
|
"a\n *b(){}",
|
||||||
|
"a\n ['b'](){}",
|
||||||
|
"['a'] = 0\n",
|
||||||
|
"['a'] = 0\n b",
|
||||||
|
"['a'] = 0\n b(){}",
|
||||||
|
"['a']\n",
|
||||||
|
"['a']\n b\n",
|
||||||
|
"['a']\n b(){}",
|
||||||
|
"['a']\n *b(){}",
|
||||||
|
"['a']\n ['b'](){}",
|
||||||
|
|
||||||
|
// ASI edge cases
|
||||||
|
"a\n get",
|
||||||
|
"get\n *a(){}",
|
||||||
|
"a\n static",
|
||||||
|
|
||||||
|
// Misc edge cases
|
||||||
|
"yield",
|
||||||
|
"yield = 0",
|
||||||
|
"yield\n a",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag without_async[] = {kAllowHarmonyClassFields};
|
||||||
|
RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
|
||||||
|
without_async, arraysize(without_async));
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const char* async_data[] = {
|
||||||
|
"async;",
|
||||||
|
"async = 0;",
|
||||||
|
"static async;"
|
||||||
|
"async",
|
||||||
|
"async = 0",
|
||||||
|
"static async",
|
||||||
|
"async\n a(){}", // a field named async, and a method named a.
|
||||||
|
"async\n a",
|
||||||
|
"await;",
|
||||||
|
"await = 0;",
|
||||||
|
"await\n a",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag with_async[] = {kAllowHarmonyClassFields,
|
||||||
|
kAllowHarmonyAsyncAwait};
|
||||||
|
RunParserSyncTest(context_data, async_data, kSuccess, NULL, 0, with_async,
|
||||||
|
arraysize(with_async));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ClassFieldsErrors) {
|
||||||
|
// clang-format off
|
||||||
|
// Tests proposed class fields syntax.
|
||||||
|
const char* context_data[][2] = {{"(class {", "});"},
|
||||||
|
{"(class extends Base {", "});"},
|
||||||
|
{"class C {", "}"},
|
||||||
|
{"class C extends Base {", "}"},
|
||||||
|
{NULL, NULL}};
|
||||||
|
const char* class_body_data[] = {
|
||||||
|
"a : 0",
|
||||||
|
"a =",
|
||||||
|
"*a = 0",
|
||||||
|
"*a",
|
||||||
|
"get a",
|
||||||
|
"yield a",
|
||||||
|
"a : 0;",
|
||||||
|
"a =;",
|
||||||
|
"*a = 0;",
|
||||||
|
"*a;",
|
||||||
|
"get a;",
|
||||||
|
"yield a;",
|
||||||
|
|
||||||
|
// ASI requires a linebreak
|
||||||
|
"a b",
|
||||||
|
"a = 0 b",
|
||||||
|
|
||||||
|
// ASI requires that the next token is not part of any legal production
|
||||||
|
"a = 0\n *b(){}",
|
||||||
|
"a = 0\n ['b'](){}",
|
||||||
|
"get\n a",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag without_async[] = {kAllowHarmonyClassFields};
|
||||||
|
RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
|
||||||
|
without_async, arraysize(without_async));
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
const char* async_data[] = {
|
||||||
|
"async a = 0",
|
||||||
|
"async a",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
static const ParserFlag with_async[] = {kAllowHarmonyClassFields,
|
||||||
|
kAllowHarmonyAsyncAwait};
|
||||||
|
RunParserSyncTest(context_data, async_data, kError, NULL, 0, with_async,
|
||||||
|
arraysize(with_async));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ClassExpressionErrors) {
|
TEST(ClassExpressionErrors) {
|
||||||
const char* context_data[][2] = {{"(", ");"},
|
const char* context_data[][2] = {{"(", ");"},
|
||||||
|
Loading…
Reference in New Issue
Block a user