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)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_tostring)
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_class_fields)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_dynamic_import)
......
......@@ -196,8 +196,10 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
DEFINE_IMPLICATION(es_staging, harmony)
// Enabling import.meta requires to also enable import()
DEFINE_IMPLICATION(harmony_import_meta, harmony_dynamic_import)
DEFINE_IMPLICATION(harmony_class_fields, harmony_public_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).
#define HARMONY_INPROGRESS(V) \
......@@ -207,7 +209,8 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_static_fields)
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony 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).
#define HARMONY_STAGED(V) \
......
......@@ -282,7 +282,8 @@ class ParserBase {
allow_harmony_static_fields_(false),
allow_harmony_dynamic_import_(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) \
bool allow_##name() const { return allow_##name##_; } \
......@@ -306,6 +307,13 @@ class ParserBase {
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_; }
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
......@@ -1536,6 +1544,7 @@ class ParserBase {
bool allow_harmony_dynamic_import_;
bool allow_harmony_import_meta_;
bool allow_harmony_optional_catch_binding_;
bool allow_harmony_private_fields_;
friend class DiscardableZoneScope;
};
......@@ -1587,6 +1596,7 @@ void ParserBase<Impl>::GetUnexpectedTokenMessage(
case Token::STRING:
*message = MessageTemplate::kUnexpectedTokenString;
break;
case Token::PRIVATE_NAME:
case Token::IDENTIFIER:
*message = MessageTemplate::kUnexpectedTokenIdentifier;
break;
......@@ -2100,6 +2110,9 @@ bool ParserBase<Impl>::SetPropertyKindFromToken(Token::Value token,
case Token::SEMICOLON:
*kind = PropertyKind::kClassField;
return true;
case Token::PRIVATE_NAME:
*kind = PropertyKind::kClassField;
return true;
default:
break;
}
......@@ -2261,6 +2274,8 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
PropertyKind kind = PropertyKind::kNotSet;
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;
IdentifierT name = impl()->NullIdentifier();
......@@ -2276,12 +2291,22 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
peek() == Token::RBRACE) {
name = impl()->GetSymbol(); // TODO(bakkot) specialize on 'static'
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 {
*is_static = true;
name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get,
&is_set, &is_async, is_computed_name,
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 {
name_expression = ParsePropertyName(&name, &kind, &is_generator, &is_get,
&is_set, &is_async, is_computed_name,
......@@ -2303,14 +2328,14 @@ ParserBase<Impl>::ParseClassPropertyDefinition(
// as an uninitialized field.
case PropertyKind::kShorthandProperty:
case PropertyKind::kValueProperty:
if (allow_harmony_public_fields()) {
if (allow_harmony_public_fields() || allow_harmony_private_fields()) {
*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 && name_token != Token::PRIVATE_NAME) {
checker->CheckClassFieldName(*is_static,
CHECK_OK_CUSTOM(NullLiteralProperty));
}
......@@ -3671,7 +3696,13 @@ ParserBase<Impl>::ParseMemberExpressionContinuation(ExpressionT expression,
Consume(Token::PERIOD);
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()->NewStringLiteral(name, pos), pos);
impl()->PushLiteralName(name);
......
......@@ -548,6 +548,7 @@ Parser::Parser(ParseInfo* info)
set_allow_harmony_import_meta(FLAG_harmony_import_meta);
set_allow_harmony_bigint(FLAG_harmony_bigint);
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;
++feature) {
use_counts_[feature] = 0;
......@@ -3326,7 +3327,7 @@ void Parser::DeclareClassProperty(const AstRawString* class_name,
return;
}
DCHECK(allow_harmony_public_fields());
DCHECK(allow_harmony_public_fields() || allow_harmony_private_fields());
if (is_static) {
DCHECK(allow_harmony_static_fields());
......
......@@ -306,6 +306,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
SET_ALLOW(harmony_import_meta);
SET_ALLOW(harmony_bigint);
SET_ALLOW(harmony_optional_catch_binding);
SET_ALLOW(harmony_private_fields);
#undef SET_ALLOW
}
return reusable_preparser_;
......
......@@ -860,6 +860,10 @@ void Scanner::Scan() {
token = ScanTemplateStart();
break;
case '#':
token = ScanPrivateName();
break;
default:
if (c0_ == kEndOfInput) {
token = Token::EOS;
......@@ -925,6 +929,7 @@ void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
case Token::REGEXP_LITERAL:
case Token::SMI:
case Token::STRING:
case Token::PRIVATE_NAME:
DCHECK_NOT_NULL(token.literal_chars);
DCHECK_NULL(token.raw_literal_chars);
DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
......@@ -1085,6 +1090,26 @@ Token::Value Scanner::ScanString() {
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() {
// When scanning a TemplateSpan, we are looking for the following construct:
......@@ -1528,10 +1553,13 @@ static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
return Token::IDENTIFIER;
}
Token::Value Scanner::ScanIdentifierOrKeyword() {
DCHECK(unicode_cache_->IsIdentifierStart(c0_));
LiteralScope literal(this);
return ScanIdentifierOrKeywordInner(&literal);
}
Token::Value Scanner::ScanIdentifierOrKeywordInner(LiteralScope* literal) {
DCHECK(unicode_cache_->IsIdentifierStart(c0_));
if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
do {
char first_char = static_cast<char>(c0_);
......@@ -1551,7 +1579,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
AddLiteralChar(first_char);
}
if (c0_ <= kMaxAscii && c0_ != '\\') {
literal.Complete();
literal->Complete();
return Token::IDENTIFIER;
}
} else if (c0_ <= kMaxAscii && c0_ != '\\') {
......@@ -1562,7 +1590,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
if (token == Token::IDENTIFIER ||
token == Token::FUTURE_STRICT_RESERVED_WORD ||
Token::IsContextualKeyword(token))
literal.Complete();
literal->Complete();
return token;
}
......@@ -1575,7 +1603,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
} while (IsAsciiIdentifier(c0_));
if (c0_ <= kMaxAscii && c0_ != '\\') {
literal.Complete();
literal->Complete();
return Token::IDENTIFIER;
}
......@@ -1590,7 +1618,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
return Token::ILLEGAL;
}
AddLiteralChar(c);
return ScanIdentifierSuffix(&literal, true);
return ScanIdentifierSuffix(literal, true);
} else {
uc32 first_char = c0_;
Advance();
......@@ -1606,7 +1634,7 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
continue;
}
// Fallthrough if no longer able to complete keyword.
return ScanIdentifierSuffix(&literal, false);
return ScanIdentifierSuffix(literal, false);
}
if (next_.literal_chars->is_one_byte()) {
......@@ -1616,10 +1644,10 @@ Token::Value Scanner::ScanIdentifierOrKeyword() {
if (token == Token::IDENTIFIER ||
token == Token::FUTURE_STRICT_RESERVED_WORD ||
Token::IsContextualKeyword(token))
literal.Complete();
literal->Complete();
return token;
}
literal.Complete();
literal->Complete();
return Token::IDENTIFIER;
}
......
......@@ -360,6 +360,12 @@ class Scanner {
bool allow_harmony_bigint() const { return allow_harmony_bigint_; }
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:
// Scoped helper for saving & restoring scanner error state.
......@@ -717,9 +723,11 @@ class Scanner {
void ScanDecimalDigits();
Token::Value ScanNumber(bool seen_period);
Token::Value ScanIdentifierOrKeyword();
Token::Value ScanIdentifierOrKeywordInner(LiteralScope* literal);
Token::Value ScanIdentifierSuffix(LiteralScope* literal, bool escaped);
Token::Value ScanString();
Token::Value ScanPrivateName();
// Scans an escape-sequence which is part of a string and adds the
// decoded character to the current literal. Returns true if a pattern
......@@ -800,8 +808,9 @@ class Scanner {
// Whether this scanner encountered an HTML comment.
bool found_html_comment_;
// Whether to recognize BIGINT tokens.
// Harmony flags to allow ESNext features.
bool allow_harmony_bigint_;
bool allow_harmony_private_fields_;
MessageTemplate::Template scanner_error_;
Location scanner_error_location_;
......
......@@ -151,6 +151,7 @@ namespace internal {
\
/* Identifiers (not keywords or future reserved words). */ \
T(IDENTIFIER, nullptr, 0) \
T(PRIVATE_NAME, nullptr, 0) \
\
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
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