Commit 2ba55881 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[class] Parse private fields

This patch does not add any functionality, it just parses the private
fields. Adds a new harmony flag as well.


Bug: v8:5368
Change-Id: I71ce11868f458571eb57a4bc922223931ce5baa8
Reviewed-on: https://chromium-review.googlesource.com/862526Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50662}
parent 72be2d21
...@@ -4347,6 +4347,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property) ...@@ -4347,6 +4347,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_private_fields)
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)
......
...@@ -196,8 +196,10 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features") ...@@ -196,8 +196,10 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
DEFINE_IMPLICATION(es_staging, harmony) 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) DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields)
DEFINE_IMPLICATION(harmony_class_fields, harmony_private_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) \
...@@ -207,7 +209,8 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields) ...@@ -207,7 +209,8 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_static_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_static_fields, "harmony static 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") \
V(harmony_private_fields, "harmony private 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(V) \ #define HARMONY_STAGED(V) \
......
...@@ -282,7 +282,8 @@ class ParserBase { ...@@ -282,7 +282,8 @@ class ParserBase {
allow_harmony_static_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_optional_catch_binding_(false) {} allow_harmony_optional_catch_binding_(false),
allow_harmony_private_fields_(false) {}
#define ALLOW_ACCESSORS(name) \ #define ALLOW_ACCESSORS(name) \
bool allow_##name() const { return allow_##name##_; } \ bool allow_##name() const { return allow_##name##_; } \
...@@ -306,6 +307,13 @@ class ParserBase { ...@@ -306,6 +307,13 @@ class ParserBase {
scanner()->set_allow_harmony_bigint(allow); scanner()->set_allow_harmony_bigint(allow);
} }
bool allow_harmony_private_fields() const {
return scanner()->allow_harmony_private_fields();
}
void set_allow_harmony_private_fields(bool allow) {
scanner()->set_allow_harmony_private_fields(allow);
}
uintptr_t stack_limit() const { return stack_limit_; } uintptr_t stack_limit() const { return stack_limit_; }
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
...@@ -1536,6 +1544,7 @@ class ParserBase { ...@@ -1536,6 +1544,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_optional_catch_binding_; bool allow_harmony_optional_catch_binding_;
bool allow_harmony_private_fields_;
friend class DiscardableZoneScope; friend class DiscardableZoneScope;
}; };
...@@ -1587,6 +1596,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage( ...@@ -1587,6 +1596,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage(
case Token::STRING: case Token::STRING:
*message = MessageTemplate::kUnexpectedTokenString; *message = MessageTemplate::kUnexpectedTokenString;
break; break;
case Token::PRIVATE_NAME:
case Token::IDENTIFIER: case Token::IDENTIFIER:
*message = MessageTemplate::kUnexpectedTokenIdentifier; *message = MessageTemplate::kUnexpectedTokenIdentifier;
break; break;
...@@ -2100,6 +2110,9 @@ bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token, ...@@ -2100,6 +2110,9 @@ bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
case Token::SEMICOLON: case Token::SEMICOLON:
*kind = PropertyKind::kClassField; *kind = PropertyKind::kClassField;
return true; return true;
case Token::PRIVATE_NAME:
*kind = PropertyKind::kClassField;
return true;
default: default:
break; break;
} }
...@@ -2261,6 +2274,8 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2261,6 +2274,8 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
PropertyKind kind = PropertyKind::kNotSet; PropertyKind kind = PropertyKind::kNotSet;
Token::Value name_token = peek(); Token::Value name_token = peek();
DCHECK_IMPLIES(name_token == Token::PRIVATE_NAME,
allow_harmony_private_fields());
int name_token_position = scanner()->peek_location().beg_pos; int name_token_position = scanner()->peek_location().beg_pos;
IdentifierT name = impl()->NullIdentifier(); IdentifierT name = impl()->NullIdentifier();
...@@ -2276,12 +2291,22 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2276,12 +2291,22 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
peek() == Token::RBRACE) { peek() == Token::RBRACE) {
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) {
DCHECK(allow_harmony_private_fields());
// TODO(gsathya): Make a better error message for this.
ReportUnexpectedToken(Next());
*ok = false;
return impl()->NullLiteralProperty();
} else { } else {
*is_static = true; *is_static = true;
name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get, name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get,
&is_set, &is_async, is_computed_name, &is_set, &is_async, is_computed_name,
CHECK_OK_CUSTOM(NullLiteralProperty)); CHECK_OK_CUSTOM(NullLiteralProperty));
} }
} else if (name_token == Token::PRIVATE_NAME) {
Consume(Token::PRIVATE_NAME);
name = impl()->GetSymbol();
name_expression = factory()->NewStringLiteral(name, position());
} else { } else {
name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get, name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get,
&is_set, &is_async, is_computed_name, &is_set, &is_async, is_computed_name,
...@@ -2303,14 +2328,14 @@ ParserBase<Impl>::ParseClassPropertyDefinition( ...@@ -2303,14 +2328,14 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
// as an uninitialized field. // as an uninitialized field.
case PropertyKind::kShorthandProperty: case PropertyKind::kShorthandProperty:
case PropertyKind::kValueProperty: case PropertyKind::kValueProperty:
if (allow_harmony_public_fields()) { if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
*property_kind = ClassLiteralProperty::FIELD; *property_kind = ClassLiteralProperty::FIELD;
if (*is_static && !allow_harmony_static_fields()) { if (*is_static && !allow_harmony_static_fields()) {
ReportUnexpectedToken(Next()); ReportUnexpectedToken(Next());
*ok = false; *ok = false;
return impl()->NullLiteralProperty(); return impl()->NullLiteralProperty();
} }
if (!*is_computed_name) { if (!*is_computed_name && name_token != Token::PRIVATE_NAME) {
checker->CheckClassFieldName(*is_static, checker->CheckClassFieldName(*is_static,
CHECK_OK_CUSTOM(NullLiteralProperty)); CHECK_OK_CUSTOM(NullLiteralProperty));
} }
...@@ -3671,7 +3696,13 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression, ...@@ -3671,7 +3696,13 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = peek_position(); int pos = peek_position();
IdentifierT name = ParseIdentifierName(CHECK_OK); IdentifierT name;
if (allow_harmony_private_fields() && peek() == Token::PRIVATE_NAME) {
Consume(Token::PRIVATE_NAME);
name = impl()->GetSymbol();
} else {
name = ParseIdentifierName(CHECK_OK);
}
expression = factory()->NewProperty( expression = factory()->NewProperty(
expression, factory()->NewStringLiteral(name, pos), pos); expression, factory()->NewStringLiteral(name, pos), pos);
impl()->PushLiteralName(name); impl()->PushLiteralName(name);
......
...@@ -548,6 +548,7 @@ Parser::Parser(ParseInfo* info) ...@@ -548,6 +548,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_bigint(FLAG_harmony_bigint); set_allow_harmony_bigint(FLAG_harmony_bigint);
set_allow_harmony_optional_catch_binding(FLAG_harmony_optional_catch_binding); set_allow_harmony_optional_catch_binding(FLAG_harmony_optional_catch_binding);
set_allow_harmony_private_fields(FLAG_harmony_private_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;
...@@ -3326,7 +3327,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name, ...@@ -3326,7 +3327,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
return; return;
} }
DCHECK(allow_harmony_public_fields()); DCHECK(allow_harmony_public_fields() || allow_harmony_private_fields());
if (is_static) { if (is_static) {
DCHECK(allow_harmony_static_fields()); DCHECK(allow_harmony_static_fields());
......
...@@ -306,6 +306,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -306,6 +306,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_import_meta); SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_bigint); SET_ALLOW(harmony_bigint);
SET_ALLOW(harmony_optional_catch_binding); SET_ALLOW(harmony_optional_catch_binding);
SET_ALLOW(harmony_private_fields);
#undef SET_ALLOW #undef SET_ALLOW
} }
return reusable_preparser_; return reusable_preparser_;
......
...@@ -860,6 +860,10 @@ void Scanner::Scan() { ...@@ -860,6 +860,10 @@ void Scanner::Scan() {
token = ScanTemplateStart(); token = ScanTemplateStart();
break; break;
case '#':
token = ScanPrivateName();
break;
default: default:
if (c0_ == kEndOfInput) { if (c0_ == kEndOfInput) {
token = Token::EOS; token = Token::EOS;
...@@ -925,6 +929,7 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { ...@@ -925,6 +929,7 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
case Token::REGEXP_LITERAL: case Token::REGEXP_LITERAL:
case Token::SMI: case Token::SMI:
case Token::STRING: case Token::STRING:
case Token::PRIVATE_NAME:
DCHECK_NOT_NULL(token.literal_chars); DCHECK_NOT_NULL(token.literal_chars);
DCHECK_NULL(token.raw_literal_chars); DCHECK_NULL(token.raw_literal_chars);
DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone); DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
...@@ -1085,6 +1090,26 @@ Token::Value Scanner::ScanString() { ...@@ -1085,6 +1090,26 @@ Token::Value Scanner::ScanString() {
return Token::STRING; return Token::STRING;
} }
Token::Value Scanner::ScanPrivateName() {
if (!allow_harmony_private_fields()) {
ReportScannerError(source_pos(),
MessageTemplate::kInvalidOrUnexpectedToken);
return Token::ILLEGAL;
}
LiteralScope literal(this);
DCHECK_EQ(c0_, '#');
AddLiteralCharAdvance();
if (c0_ == kEndOfInput || !unicode_cache_->IsIdentifierStart(c0_)) {
PushBack(c0_);
ReportScannerError(source_pos(),
MessageTemplate::kInvalidOrUnexpectedToken);
return Token::ILLEGAL;
}
Token::Value token = ScanIdentifierOrKeywordInner(&literal);
return token == Token::ILLEGAL ? Token::ILLEGAL : Token::PRIVATE_NAME;
}
Token::Value Scanner::ScanTemplateSpan() { Token::Value Scanner::ScanTemplateSpan() {
// When scanning a TemplateSpan, we are looking for the following construct: // When scanning a TemplateSpan, we are looking for the following construct:
...@@ -1528,10 +1553,13 @@ static Token::Value KeywordOrIdentifierToken(const uint8_t* input, ...@@ -1528,10 +1553,13 @@ static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
Token::Value Scanner::ScanIdentifierOrKeyword() { Token::Value Scanner::ScanIdentifierOrKeyword() {
DCHECK(unicode_cache_->IsIdentifierStart(c0_));
LiteralScope literal(this); LiteralScope literal(this);
return ScanIdentifierOrKeywordInner(&literal);
}
Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) {
DCHECK(unicode_cache_->IsIdentifierStart(c0_));
if (IsInRange(c0_, 'a', 'z') || c0_ == '_') { if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
do { do {
char first_char = static_cast<char>(c0_); char first_char = static_cast<char>(c0_);
...@@ -1551,7 +1579,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1551,7 +1579,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
AddLiteralChar(first_char); AddLiteralChar(first_char);
} }
if (c0_ <= kMaxAscii && c0_ != '\\') { if (c0_ <= kMaxAscii && c0_ != '\\') {
literal.Complete(); literal->Complete();
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
} else if (c0_ <= kMaxAscii && c0_ != '\\') { } else if (c0_ <= kMaxAscii && c0_ != '\\') {
...@@ -1562,7 +1590,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1562,7 +1590,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
if (token == Token::IDENTIFIER || if (token == Token::IDENTIFIER ||
token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::FUTURE_STRICT_RESERVED_WORD ||
Token::IsContextualKeyword(token)) Token::IsContextualKeyword(token))
literal.Complete(); literal->Complete();
return token; return token;
} }
...@@ -1575,7 +1603,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1575,7 +1603,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
} while (IsAsciiIdentifier(c0_)); } while (IsAsciiIdentifier(c0_));
if (c0_ <= kMaxAscii && c0_ != '\\') { if (c0_ <= kMaxAscii && c0_ != '\\') {
literal.Complete(); literal->Complete();
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
...@@ -1590,7 +1618,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1590,7 +1618,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
return Token::ILLEGAL; return Token::ILLEGAL;
} }
AddLiteralChar(c); AddLiteralChar(c);
return ScanIdentifierSuffix(&literal, true); return ScanIdentifierSuffix(literal, true);
} else { } else {
uc32 first_char = c0_; uc32 first_char = c0_;
Advance(); Advance();
...@@ -1606,7 +1634,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1606,7 +1634,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
continue; continue;
} }
// Fallthrough if no longer able to complete keyword. // Fallthrough if no longer able to complete keyword.
return ScanIdentifierSuffix(&literal, false); return ScanIdentifierSuffix(literal, false);
} }
if (next_.literal_chars->is_one_byte()) { if (next_.literal_chars->is_one_byte()) {
...@@ -1616,10 +1644,10 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { ...@@ -1616,10 +1644,10 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
if (token == Token::IDENTIFIER || if (token == Token::IDENTIFIER ||
token == Token::FUTURE_STRICT_RESERVED_WORD || token == Token::FUTURE_STRICT_RESERVED_WORD ||
Token::IsContextualKeyword(token)) Token::IsContextualKeyword(token))
literal.Complete(); literal->Complete();
return token; return token;
} }
literal.Complete(); literal->Complete();
return Token::IDENTIFIER; return Token::IDENTIFIER;
} }
......
...@@ -360,6 +360,12 @@ class Scanner { ...@@ -360,6 +360,12 @@ class Scanner {
bool allow_harmony_bigint() const { return allow_harmony_bigint_; } bool allow_harmony_bigint() const { return allow_harmony_bigint_; }
void set_allow_harmony_bigint(bool allow) { allow_harmony_bigint_ = allow; } void set_allow_harmony_bigint(bool allow) { allow_harmony_bigint_ = allow; }
bool allow_harmony_private_fields() const {
return allow_harmony_private_fields_;
}
void set_allow_harmony_private_fields(bool allow) {
allow_harmony_private_fields_ = allow;
}
private: private:
// Scoped helper for saving & restoring scanner error state. // Scoped helper for saving & restoring scanner error state.
...@@ -717,9 +723,11 @@ class Scanner { ...@@ -717,9 +723,11 @@ class Scanner {
void ScanDecimalDigits(); void ScanDecimalDigits();
Token::Value ScanNumber(bool seen_period); Token::Value ScanNumber(bool seen_period);
Token::Value ScanIdentifierOrKeyword(); Token::Value ScanIdentifierOrKeyword();
Token::Value ScanIdentifierOrKeywordInner(LiteralScope* literal);
Token::Value ScanIdentifierSuffix(LiteralScope* literal, bool escaped); Token::Value ScanIdentifierSuffix(LiteralScope* literal, bool escaped);
Token::Value ScanString(); Token::Value ScanString();
Token::Value ScanPrivateName();
// Scans an escape-sequence which is part of a string and adds the // Scans an escape-sequence which is part of a string and adds the
// decoded character to the current literal. Returns true if a pattern // decoded character to the current literal. Returns true if a pattern
...@@ -800,8 +808,9 @@ class Scanner { ...@@ -800,8 +808,9 @@ class Scanner {
// Whether this scanner encountered an HTML comment. // Whether this scanner encountered an HTML comment.
bool found_html_comment_; bool found_html_comment_;
// Whether to recognize BIGINT tokens. // Harmony flags to allow ESNext features.
bool allow_harmony_bigint_; bool allow_harmony_bigint_;
bool allow_harmony_private_fields_;
MessageTemplate::Template scanner_error_; MessageTemplate::Template scanner_error_;
Location scanner_error_location_; Location scanner_error_location_;
......
...@@ -151,6 +151,7 @@ namespace internal { ...@@ -151,6 +151,7 @@ namespace internal {
\ \
/* Identifiers (not keywords or future reserved words). */ \ /* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, nullptr, 0) \ T(IDENTIFIER, nullptr, 0) \
T(PRIVATE_NAME, nullptr, 0) \
\ \
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \ /* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \ T(FUTURE_STRICT_RESERVED_WORD, nullptr, 0) \
......
This diff is collapsed.
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