[parser] Refactor of ParseClass* and ParseNativeDeclaration

This patch moves the following parsing method to ParserBase:

- ParseClassDeclaration
- ParseClassLiteral
- ParseNativeDeclaration

R=adamk@chromium.org, marja@chromium.org
BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2368083002
Cr-Commit-Position: refs/heads/master@{#39814}
This commit is contained in:
nikolaos 2016-09-28 02:12:20 -07:00 committed by Commit bot
parent b15dd963a3
commit 7818355363
5 changed files with 364 additions and 327 deletions

View File

@ -133,7 +133,8 @@ struct FormalParametersBase {
// typedef ObjectLiteralProperty;
// typedef ClassLiteralProperty;
// typedef ExpressionList;
// typedef PropertyList;
// typedef ObjectPropertyList;
// typedef ClassPropertyList;
// typedef FormalParameters;
// typedef Statement;
// typedef StatementList;
@ -161,7 +162,6 @@ class ParserBase {
typedef typename Types::ObjectLiteralProperty ObjectLiteralPropertyT;
typedef typename Types::ClassLiteralProperty ClassLiteralPropertyT;
typedef typename Types::ExpressionList ExpressionListT;
typedef typename Types::PropertyList PropertyListT;
typedef typename Types::FormalParameters FormalParametersT;
typedef typename Types::Statement StatementT;
typedef typename Types::StatementList StatementListT;
@ -671,6 +671,25 @@ class ParserBase {
DeclarationParsingResult parsing_result;
};
struct ClassInfo {
public:
explicit ClassInfo(ParserBase* parser)
: proxy(nullptr),
extends(parser->impl()->EmptyExpression()),
properties(parser->impl()->NewClassPropertyList(4)),
instance_field_initializers(parser->impl()->NewExpressionList(0)),
constructor(parser->impl()->EmptyFunctionLiteral()),
has_seen_constructor(false),
static_initializer_var(nullptr) {}
VariableProxy* proxy;
ExpressionT extends;
typename Types::ClassPropertyList properties;
ExpressionListT instance_field_initializers;
FunctionLiteralT constructor;
bool has_seen_constructor;
Variable* static_initializer_var;
};
DeclarationScope* NewScriptScope() const {
return new (zone()) DeclarationScope(zone(), ast_value_factory());
}
@ -1174,6 +1193,10 @@ class ParserBase {
FunctionKind kind, FunctionBodyType type,
bool accept_IN, int pos, bool* ok);
ExpressionT ParseAsyncFunctionLiteral(bool* ok);
ExpressionT ParseClassLiteral(IdentifierT name,
Scanner::Location class_name_location,
bool name_is_strict_reserved,
int class_token_pos, bool* ok);
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok);
ExpressionT ParseSuperExpression(bool is_new, bool* ok);
ExpressionT ParseNewTargetExpression(bool* ok);
@ -1195,6 +1218,9 @@ class ParserBase {
StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
StatementT ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
StatementT ParseNativeDeclaration(bool* ok);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
@ -1783,7 +1809,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
case Token::CLASS: {
BindingPatternUnexpectedToken();
Consume(Token::CLASS);
int class_token_position = position();
int class_token_pos = position();
IdentifierT name = impl()->EmptyIdentifier();
bool is_strict_reserved_name = false;
Scanner::Location class_name_location = Scanner::Location::invalid();
@ -1792,9 +1818,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
CHECK_OK);
class_name_location = scanner()->location();
}
return impl()->ParseClassLiteral(name, class_name_location,
is_strict_reserved_name,
class_token_position, ok);
return ParseClassLiteral(name, class_name_location,
is_strict_reserved_name, class_token_pos, ok);
}
case Token::TEMPLATE_SPAN:
@ -2456,7 +2481,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseObjectLiteral(
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
int pos = peek_position();
PropertyListT properties = impl()->NewPropertyList(4);
typename Types::ObjectPropertyList properties =
impl()->NewObjectPropertyList(4);
int number_of_boilerplate_properties = 0;
bool has_computed_names = false;
ObjectLiteralChecker checker(this);
@ -3700,6 +3726,72 @@ ParserBase<Impl>::ParseHoistableDeclaration(
is_async, names, ok);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseClassDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
// 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
//
// The anonymous form is allowed iff [default_export] is true.
//
// 'class' is expected to be consumed by the caller.
//
// A ClassDeclaration
//
// class C { ... }
//
// has the same semantics as:
//
// let C = class C { ... };
//
// so rewrite it as such.
int class_token_pos = position();
IdentifierT name = impl()->EmptyIdentifier();
bool is_strict_reserved = false;
IdentifierT variable_name = impl()->EmptyIdentifier();
if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
impl()->GetDefaultStrings(&name, &variable_name);
} else {
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
CHECK_OK_CUSTOM(NullStatement));
variable_name = name;
}
ExpressionClassifier no_classifier(this);
ExpressionT value =
ParseClassLiteral(name, scanner()->location(), is_strict_reserved,
class_token_pos, CHECK_OK_CUSTOM(NullStatement));
int end_pos = position();
return impl()->DeclareClass(variable_name, value, names, class_token_pos,
end_pos, ok);
}
// Language extension which is only enabled for source files loaded
// through the API's extension mechanism. A native function
// declaration is resolved by looking up the function through a
// callback provided by the extension.
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseNativeDeclaration(
bool* ok) {
int pos = peek_position();
Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
// Allow "eval" or "arguments" for backward compatibility.
IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers,
CHECK_OK_CUSTOM(NullStatement));
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullStatement));
if (peek() != Token::RPAREN) {
do {
ParseIdentifier(kAllowRestrictedIdentifiers,
CHECK_OK_CUSTOM(NullStatement));
} while (Check(Token::COMMA));
}
Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullStatement));
Expect(Token::SEMICOLON, CHECK_OK_CUSTOM(NullStatement));
return impl()->DeclareNative(name, pos, ok);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseAsyncFunctionDeclaration(
@ -3931,11 +4023,71 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
function_literal->set_should_be_used_once_hint();
}
impl()->InferFunctionName(function_literal);
impl()->AddFunctionForNameInference(function_literal);
return function_literal;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
IdentifierT name, Scanner::Location class_name_location,
bool name_is_strict_reserved, int class_token_pos, bool* ok) {
// All parts of a ClassDeclaration and ClassExpression are strict code.
if (name_is_strict_reserved) {
impl()->ReportMessageAt(class_name_location,
MessageTemplate::kUnexpectedStrictReserved);
*ok = false;
return impl()->EmptyExpression();
}
if (impl()->IsEvalOrArguments(name)) {
impl()->ReportMessageAt(class_name_location,
MessageTemplate::kStrictEvalArguments);
*ok = false;
return impl()->EmptyExpression();
}
BlockState block_state(zone(), &scope_state_);
RaiseLanguageMode(STRICT);
ClassInfo class_info(this);
impl()->DeclareClassVariable(name, block_state.scope(), &class_info,
class_token_pos, CHECK_OK);
if (Check(Token::EXTENDS)) {
block_state.set_start_position(scanner()->location().end_pos);
ExpressionClassifier extends_classifier(this);
class_info.extends = ParseLeftHandSideExpression(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
} else {
block_state.set_start_position(scanner()->location().end_pos);
}
ClassLiteralChecker checker(this);
Expect(Token::LBRACE, CHECK_OK);
const bool has_extends = !impl()->IsEmptyExpression(class_info.extends);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
FuncNameInferrer::State fni_state(fni_);
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ExpressionClassifier property_classifier(this);
ClassLiteralPropertyT property = ParseClassPropertyDefinition(
&checker, has_extends, &is_computed_name,
&class_info.has_seen_constructor, CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
impl()->DeclareClassProperty(name, property, &class_info, CHECK_OK);
impl()->InferFunctionName();
}
Expect(Token::RBRACE, CHECK_OK);
return impl()->RewriteClassLiteral(name, &class_info, class_token_pos, ok);
}
template <typename Impl>
void ParserBase<Impl>::ParseAsyncFunctionBody(Scope* scope, StatementListT body,
FunctionKind kind,
@ -4287,7 +4439,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
return ParseHoistableDeclaration(nullptr, false, ok);
case Token::CLASS:
Consume(Token::CLASS);
return impl()->ParseClassDeclaration(nullptr, false, ok);
return ParseClassDeclaration(nullptr, false, ok);
case Token::VAR:
case Token::CONST:
return ParseVariableStatement(kStatementListItem, nullptr, ok);
@ -4565,7 +4717,7 @@ ParserBase<Impl>::ParseExpressionOrLabelledStatement(
if (extension_ != nullptr && peek() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorBeforeNext() && impl()->IsNative(expr) &&
!scanner()->literal_contains_escapes()) {
return impl()->ParseNativeDeclaration(ok);
return ParseNativeDeclaration(ok);
}
// Parsed expression statement, followed by semicolon.

View File

@ -1534,94 +1534,6 @@ Variable* Parser::Declare(Declaration* declaration,
return variable;
}
// Language extension which is only enabled for source files loaded
// through the API's extension mechanism. A native function
// declaration is resolved by looking up the function through a
// callback provided by the extension.
Statement* Parser::ParseNativeDeclaration(bool* ok) {
int pos = peek_position();
Expect(Token::FUNCTION, CHECK_OK);
// Allow "eval" or "arguments" for backward compatibility.
const AstRawString* name =
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
bool done = (peek() == Token::RPAREN);
while (!done) {
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
done = (peek() == Token::RPAREN);
if (!done) {
Expect(Token::COMMA, CHECK_OK);
}
}
Expect(Token::RPAREN, CHECK_OK);
Expect(Token::SEMICOLON, CHECK_OK);
// Make sure that the function containing the native declaration
// isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing
// because of lazy compilation.
GetClosureScope()->ForceEagerCompilation();
// TODO(1240846): It's weird that native function declarations are
// introduced dynamically when we meet their declarations, whereas
// other functions are set up when entering the surrounding scope.
Declaration* decl = DeclareVariable(name, VAR, pos, CHECK_OK);
NativeFunctionLiteral* lit =
factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
return factory()->NewExpressionStatement(
factory()->NewAssignment(Token::INIT, decl->proxy(), lit,
kNoSourcePosition),
pos);
}
Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
// ClassDeclaration ::
// 'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
// 'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
//
// The anonymous form is allowed iff [default_export] is true.
//
// 'class' is expected to be consumed by the caller.
//
// A ClassDeclaration
//
// class C { ... }
//
// has the same semantics as:
//
// let C = class C { ... };
//
// so rewrite it as such.
int pos = position();
const AstRawString* name;
bool is_strict_reserved;
const AstRawString* variable_name;
if (default_export && (peek() == Token::EXTENDS || peek() == Token::LBRACE)) {
name = ast_value_factory()->default_string();
is_strict_reserved = false;
variable_name = ast_value_factory()->star_default_star_string();
} else {
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
variable_name = name;
}
ExpressionClassifier no_classifier(this);
Expression* value = ParseClassLiteral(name, scanner()->location(),
is_strict_reserved, pos, CHECK_OK);
Declaration* decl = DeclareVariable(variable_name, LET, pos, CHECK_OK);
decl->proxy()->var()->set_initializer_position(position());
Assignment* assignment =
factory()->NewAssignment(Token::INIT, decl->proxy(), value, pos);
Statement* assignment_statement =
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
if (names) names->Add(variable_name, zone());
return assignment_statement;
}
Block* Parser::BuildInitializationBlock(
DeclarationParsingResult* parsing_result,
ZoneList<const AstRawString*>* names, bool* ok) {
@ -1677,6 +1589,40 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
return factory()->NewEmptyStatement(kNoSourcePosition);
}
Statement* Parser::DeclareClass(const AstRawString* variable_name,
Expression* value,
ZoneList<const AstRawString*>* names,
int class_token_pos, int end_pos, bool* ok) {
Declaration* decl =
DeclareVariable(variable_name, LET, class_token_pos, CHECK_OK);
decl->proxy()->var()->set_initializer_position(end_pos);
Assignment* assignment = factory()->NewAssignment(Token::INIT, decl->proxy(),
value, class_token_pos);
Statement* assignment_statement =
factory()->NewExpressionStatement(assignment, kNoSourcePosition);
if (names) names->Add(variable_name, zone());
return assignment_statement;
}
Statement* Parser::DeclareNative(const AstRawString* name, int pos, bool* ok) {
// Make sure that the function containing the native declaration
// isn't lazily compiled. The extension structures are only
// accessible while parsing the first time not when reparsing
// because of lazy compilation.
GetClosureScope()->ForceEagerCompilation();
// TODO(1240846): It's weird that native function declarations are
// introduced dynamically when we meet their declarations, whereas
// other functions are set up when entering the surrounding scope.
Declaration* decl = DeclareVariable(name, VAR, pos, CHECK_OK);
NativeFunctionLiteral* lit =
factory()->NewNativeFunctionLiteral(name, extension_, kNoSourcePosition);
return factory()->NewExpressionStatement(
factory()->NewAssignment(Token::INIT, decl->proxy(), lit,
kNoSourcePosition),
pos);
}
ZoneList<const AstRawString*>* Parser::DeclareLabel(
ZoneList<const AstRawString*>* labels, VariableProxy* var, bool* ok) {
const AstRawString* label = var->raw_name();
@ -3519,163 +3465,136 @@ FunctionLiteral* Parser::InsertClassFieldInitializer(
return constructor;
}
Expression* Parser::ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok) {
// All parts of a ClassDeclaration and ClassExpression are strict code.
if (name_is_strict_reserved) {
ReportMessageAt(class_name_location,
MessageTemplate::kUnexpectedStrictReserved);
*ok = false;
return nullptr;
}
if (IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
*ok = false;
return nullptr;
}
BlockState block_state(zone(), &scope_state_);
RaiseLanguageMode(STRICT);
// If a class name is specified, this method declares the class variable
// and sets class_info->proxy to point to that name.
void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope,
ClassInfo* class_info, int class_token_pos,
bool* ok) {
#ifdef DEBUG
scope()->SetScopeName(name);
#endif
VariableProxy* proxy = nullptr;
if (name != nullptr) {
proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE);
// TODO(verwaest): declare via block_state.
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, block_state.scope(), pos);
class_info->proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE);
Declaration* declaration = factory()->NewVariableDeclaration(
class_info->proxy, block_scope, class_token_pos);
Declare(declaration, DeclarationDescriptor::NORMAL, CONST,
Variable::DefaultInitializationFlag(CONST), CHECK_OK);
Variable::DefaultInitializationFlag(CONST), ok);
}
}
// This method declares a property of the given class. It updates the
// following fields of class_info, as appropriate:
// - constructor
// - static_initializer_var
// - instance_field_initializers
// - properties
void Parser::DeclareClassProperty(const AstRawString* class_name,
ClassLiteralProperty* property,
ClassInfo* class_info, bool* ok) {
if (class_info->has_seen_constructor && class_info->constructor == nullptr) {
class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral();
DCHECK_NOT_NULL(class_info->constructor);
class_info->constructor->set_raw_name(
class_name != nullptr ? class_name
: ast_value_factory()->empty_string());
return;
}
Expression* extends = nullptr;
if (Check(Token::EXTENDS)) {
block_state.set_start_position(scanner()->location().end_pos);
ExpressionClassifier extends_classifier(this);
extends = ParseLeftHandSideExpression(CHECK_OK);
RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
} else {
block_state.set_start_position(scanner()->location().end_pos);
if (property->kind() == ClassLiteralProperty::FIELD) {
DCHECK(allow_harmony_class_fields());
if (property->is_static()) {
if (class_info->static_initializer_var == nullptr) {
class_info->static_initializer_var =
NewTemporary(ast_value_factory()->empty_string());
}
// TODO(bakkot) only do this conditionally
Expression* function = InstallHomeObject(
property->value(),
factory()->NewVariableProxy(class_info->static_initializer_var));
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(2, zone());
args->Add(function, zone());
args->Add(factory()->NewVariableProxy(class_info->static_initializer_var),
zone());
Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall, args,
kNoSourcePosition);
property->set_value(call);
} else {
// if (is_computed_name) { // TODO(bakkot) figure out why this is
// necessary for non-computed names in full-codegen
ZoneList<Expression*>* to_name_args =
new (zone()) ZoneList<Expression*>(1, zone());
to_name_args->Add(property->key(), zone());
property->set_key(factory()->NewCallRuntime(
Runtime::kToName, to_name_args, kNoSourcePosition));
//}
const AstRawString* name = ClassFieldVariableName(
true, ast_value_factory(),
class_info->instance_field_initializers->length());
VariableProxy* name_proxy =
factory()->NewVariableProxy(name, NORMAL_VARIABLE);
Declaration* name_declaration = factory()->NewVariableDeclaration(
name_proxy, scope(), kNoSourcePosition);
Variable* name_var =
Declare(name_declaration, DeclarationDescriptor::NORMAL, CONST,
kNeedsInitialization, ok, scope());
DCHECK(*ok);
if (!*ok) return;
class_info->instance_field_initializers->Add(property->value(), zone());
property->set_value(factory()->NewVariableProxy(name_var));
}
}
class_info->properties->Add(property, zone());
}
ClassLiteralChecker checker(this);
ZoneList<ClassLiteral::Property*>* properties = NewClassPropertyList(4);
ZoneList<Expression*>* instance_field_initializers =
new (zone()) ZoneList<Expression*>(0, zone());
FunctionLiteral* constructor = nullptr;
bool has_seen_constructor = false;
Variable* static_initializer_var = nullptr;
// This method rewrites a class literal into a do-expression.
// It uses the following fields of class_info:
// - constructor (if missing, it updates it with a default constructor)
// - proxy
// - extends
// - static_initializer_var
// - instance_field_initializers
// - properties
Expression* Parser::RewriteClassLiteral(const AstRawString* name,
ClassInfo* class_info, int pos,
bool* ok) {
int end_pos = scanner()->location().end_pos;
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);
const bool has_extends = extends != nullptr;
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
FuncNameInferrer::State fni_state(fni_);
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ExpressionClassifier property_classifier(this);
ClassLiteral::Property* property =
ParseClassPropertyDefinition(&checker, has_extends, &is_computed_name,
&has_seen_constructor, CHECK_OK);
RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
if (has_seen_constructor && constructor == nullptr) {
constructor = GetPropertyValue(property)->AsFunctionLiteral();
DCHECK_NOT_NULL(constructor);
constructor->set_raw_name(
name != nullptr ? name : ast_value_factory()->empty_string());
} else {
if (property->kind() == ClassLiteralProperty::FIELD) {
DCHECK(allow_harmony_class_fields());
if (property->is_static()) {
if (static_initializer_var == nullptr) {
static_initializer_var =
NewTemporary(ast_value_factory()->empty_string());
}
// TODO(bakkot) only do this conditionally
Expression* function = InstallHomeObject(
property->value(),
factory()->NewVariableProxy(static_initializer_var));
ZoneList<Expression*>* args =
new (zone()) ZoneList<Expression*>(2, zone());
args->Add(function, zone());
args->Add(factory()->NewVariableProxy(static_initializer_var),
zone());
Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall,
args, kNoSourcePosition);
property->set_value(call);
} else {
// if (is_computed_name) { // TODO(bakkot) figure out why this is
// necessary for non-computed names in full-codegen
ZoneList<Expression*>* to_name_args =
new (zone()) ZoneList<Expression*>(1, zone());
to_name_args->Add(property->key(), zone());
property->set_key(factory()->NewCallRuntime(
Runtime::kToName, to_name_args, kNoSourcePosition));
//}
const AstRawString* name = ClassFieldVariableName(
true, ast_value_factory(), instance_field_initializers->length());
VariableProxy* name_proxy =
factory()->NewVariableProxy(name, NORMAL_VARIABLE);
Declaration* name_declaration = factory()->NewVariableDeclaration(
name_proxy, scope(), kNoSourcePosition);
Variable* name_var =
Declare(name_declaration, DeclarationDescriptor::NORMAL, CONST,
kNeedsInitialization, ok, scope());
DCHECK(ok);
if (!ok) return nullptr;
instance_field_initializers->Add(property->value(), zone());
property->set_value(factory()->NewVariableProxy(name_var));
}
}
properties->Add(property, zone());
}
DCHECK_NOT_NULL(fni_);
fni_->Infer();
}
Expect(Token::RBRACE, CHECK_OK);
int end_pos = scanner()->location().end_pos;
bool has_instance_fields = instance_field_initializers->length() > 0;
bool has_extends = class_info->extends != nullptr;
bool has_instance_fields =
class_info->instance_field_initializers->length() > 0;
DCHECK(!has_instance_fields || allow_harmony_class_fields());
bool has_default_constructor = constructor == nullptr;
bool has_default_constructor = class_info->constructor == nullptr;
if (has_default_constructor) {
constructor = DefaultConstructor(name, has_extends, has_instance_fields,
pos, end_pos, block_state.language_mode());
class_info->constructor =
DefaultConstructor(name, has_extends, has_instance_fields, pos, end_pos,
scope()->language_mode());
}
if (has_instance_fields && extends == nullptr) {
constructor = InsertClassFieldInitializer(constructor);
constructor->set_requires_class_field_init(true);
if (has_instance_fields && !has_extends) {
class_info->constructor =
InsertClassFieldInitializer(class_info->constructor);
class_info->constructor->set_requires_class_field_init(true);
} // The derived case is handled by rewriting super calls.
block_state.set_end_position(end_pos);
scope()->set_end_position(end_pos);
if (name != nullptr) {
DCHECK_NOT_NULL(proxy);
proxy->var()->set_initializer_position(end_pos);
DCHECK_NOT_NULL(class_info->proxy);
class_info->proxy->var()->set_initializer_position(end_pos);
}
ClassLiteral* class_literal = factory()->NewClassLiteral(
proxy, extends, constructor, properties, pos, end_pos);
class_info->proxy, class_info->extends, class_info->constructor,
class_info->properties, pos, end_pos);
if (static_initializer_var != nullptr) {
if (class_info->static_initializer_var != nullptr) {
class_literal->set_static_initializer_proxy(
factory()->NewVariableProxy(static_initializer_var));
factory()->NewVariableProxy(class_info->static_initializer_var));
}
do_block->statements()->Add(
@ -3686,8 +3605,7 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
pos),
zone());
if (allow_harmony_class_fields() &&
(has_instance_fields ||
(extends != nullptr && !has_default_constructor))) {
(has_instance_fields || (has_extends && !has_default_constructor))) {
// Default constructors for derived classes without fields will not try to
// read this variable, so there's no need to create it.
const AstRawString* init_fn_name =
@ -3697,7 +3615,7 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
Expression* initializer =
has_instance_fields
? static_cast<Expression*>(SynthesizeClassFieldInitializer(
instance_field_initializers->length()))
class_info->instance_field_initializers->length()))
: factory()->NewBooleanLiteral(false, kNoSourcePosition);
Assignment* assignment = factory()->NewAssignment(
Token::INIT, factory()->NewVariableProxy(init_fn_var), initializer,
@ -3706,7 +3624,7 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
factory()->NewExpressionStatement(assignment, kNoSourcePosition),
zone());
}
for (int i = 0; i < instance_field_initializers->length(); ++i) {
for (int i = 0; i < class_info->instance_field_initializers->length(); ++i) {
const AstRawString* function_name =
ClassFieldVariableName(false, ast_value_factory(), i);
VariableProxy* function_proxy =
@ -3716,15 +3634,14 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
Variable* function_var =
Declare(function_declaration, DeclarationDescriptor::NORMAL, CONST,
kNeedsInitialization, ok, scope());
DCHECK(ok);
if (!ok) return nullptr;
if (!*ok) return nullptr;
Property* prototype_property = factory()->NewProperty(
factory()->NewVariableProxy(result_var),
factory()->NewStringLiteral(ast_value_factory()->prototype_string(),
kNoSourcePosition),
kNoSourcePosition);
Expression* function_value = InstallHomeObject(
instance_field_initializers->at(i),
class_info->instance_field_initializers->at(i),
prototype_property); // TODO(bakkot) ideally this would be conditional,
// especially in trivial cases
Assignment* function_assignment = factory()->NewAssignment(
@ -3734,13 +3651,12 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
function_assignment, kNoSourcePosition),
zone());
}
do_block->set_scope(block_state.FinalizedBlockScope());
do_expr->set_represented_function(constructor);
do_block->set_scope(scope()->FinalizeBlockScope());
do_expr->set_represented_function(class_info->constructor);
return do_expr;
}
Literal* Parser::GetLiteralUndefined(int position) {
return factory()->NewUndefinedLiteral(position);
}

View File

@ -152,7 +152,8 @@ struct ParserTypes<Parser> {
typedef ObjectLiteral::Property* ObjectLiteralProperty;
typedef ClassLiteral::Property* ClassLiteralProperty;
typedef ZoneList<v8::internal::Expression*>* ExpressionList;
typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
typedef ZoneList<ObjectLiteral::Property*>* ObjectPropertyList;
typedef ZoneList<ClassLiteral::Property*>* ClassPropertyList;
typedef ParserFormalParameters FormalParameters;
typedef v8::internal::Statement* Statement;
typedef ZoneList<v8::internal::Statement*>* StatementList;
@ -269,9 +270,6 @@ class Parser : public ParserBase<Parser> {
};
ZoneList<const NamedImport*>* ParseNamedImports(int pos, bool* ok);
Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement* ParseNativeDeclaration(bool* ok);
Block* BuildInitializationBlock(DeclarationParsingResult* parsing_result,
ZoneList<const AstRawString*>* names,
bool* ok);
@ -297,6 +295,21 @@ class Parser : public ParserBase<Parser> {
FunctionLiteral* function, int pos,
bool is_generator, bool is_async,
ZoneList<const AstRawString*>* names, bool* ok);
V8_INLINE Statement* DeclareClass(const AstRawString* variable_name,
Expression* value,
ZoneList<const AstRawString*>* names,
int class_token_pos, int end_pos, bool* ok);
V8_INLINE void DeclareClassVariable(const AstRawString* name,
Scope* block_scope, ClassInfo* class_info,
int class_token_pos, bool* ok);
V8_INLINE void DeclareClassProperty(const AstRawString* class_name,
ClassLiteralProperty* property,
ClassInfo* class_info, bool* ok);
V8_INLINE Expression* RewriteClassLiteral(const AstRawString* name,
ClassInfo* class_info, int pos,
bool* ok);
V8_INLINE Statement* DeclareNative(const AstRawString* name, int pos,
bool* ok);
Expression* ParseYieldStarExpression(bool* ok);
@ -419,11 +432,6 @@ class Parser : public ParserBase<Parser> {
FunctionLiteral* SynthesizeClassFieldInitializer(int count);
FunctionLiteral* InsertClassFieldInitializer(FunctionLiteral* constructor);
Expression* ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
// Get odd-ball literals.
Literal* GetLiteralUndefined(int position);
@ -739,10 +747,16 @@ class Parser : public ParserBase<Parser> {
fni_->PushEnclosingName(name);
}
V8_INLINE void InferFunctionName(FunctionLiteral* func_to_infer) {
V8_INLINE void AddFunctionForNameInference(FunctionLiteral* func_to_infer) {
DCHECK_NOT_NULL(fni_);
fni_->AddFunction(func_to_infer);
}
V8_INLINE void InferFunctionName() {
DCHECK_NOT_NULL(fni_);
fni_->Infer();
}
// If we assign a function literal to a property we pretenure the
// literal so it can be added as a constant function property.
V8_INLINE static void CheckAssigningFunctionLiteralToProperty(
@ -936,7 +950,7 @@ class Parser : public ParserBase<Parser> {
V8_INLINE ZoneList<Expression*>* NewExpressionList(int size) const {
return new (zone()) ZoneList<Expression*>(size, zone());
}
V8_INLINE ZoneList<ObjectLiteral::Property*>* NewPropertyList(
V8_INLINE ZoneList<ObjectLiteral::Property*>* NewObjectPropertyList(
int size) const {
return new (zone()) ZoneList<ObjectLiteral::Property*>(size, zone());
}

View File

@ -135,18 +135,6 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
PreParser::Statement PreParser::ParseClassDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
int pos = position();
bool is_strict_reserved = false;
Identifier name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
ExpressionClassifier no_classifier(this);
ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos,
CHECK_OK);
return Statement::Default();
}
PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
Consume(Token::FUNCTION);
int pos = position();
@ -251,57 +239,6 @@ PreParser::LazyParsingResult PreParser::ParseLazyFunctionLiteralBody(
return kLazyParsingComplete;
}
PreParserExpression PreParser::ParseClassLiteral(
PreParserIdentifier name, Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos, bool* ok) {
// All parts of a ClassDeclaration and ClassExpression are strict code.
if (name_is_strict_reserved) {
ReportMessageAt(class_name_location,
MessageTemplate::kUnexpectedStrictReserved);
*ok = false;
return EmptyExpression();
}
if (IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
*ok = false;
return EmptyExpression();
}
LanguageMode class_language_mode = language_mode();
BlockState block_state(zone(), &scope_state_);
scope()->SetLanguageMode(
static_cast<LanguageMode>(class_language_mode | STRICT));
// TODO(marja): Make PreParser use scope names too.
// this->scope()->SetScopeName(name);
bool has_extends = Check(Token::EXTENDS);
if (has_extends) {
ExpressionClassifier extends_classifier(this);
ParseLeftHandSideExpression(CHECK_OK);
ValidateExpression(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
}
ClassLiteralChecker checker(this);
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
bool is_computed_name = false; // Classes do not care about computed
// property names here.
ExpressionClassifier property_classifier(this);
ParseClassPropertyDefinition(&checker, has_extends, &is_computed_name,
&has_seen_constructor, CHECK_OK);
ValidateExpression(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
}
Expect(Token::RBRACE, CHECK_OK);
return Expression::Default();
}
PreParserExpression PreParser::ExpressionFromIdentifier(
PreParserIdentifier name, int start_position, int end_position,
InferName infer) {

View File

@ -728,7 +728,8 @@ struct ParserTypes<PreParser> {
typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression ClassLiteralProperty;
typedef PreParserExpressionList ExpressionList;
typedef PreParserExpressionList PropertyList;
typedef PreParserExpressionList ObjectPropertyList;
typedef PreParserExpressionList ClassPropertyList;
typedef PreParserFormalParameters FormalParameters;
typedef PreParserStatement Statement;
typedef PreParserStatementList StatementList;
@ -837,8 +838,6 @@ class PreParser : public ParserBase<PreParser> {
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseObjectLiteral(bool* ok);
@ -860,11 +859,6 @@ class PreParser : public ParserBase<PreParser> {
LanguageMode language_mode, bool* ok);
LazyParsingResult ParseLazyFunctionLiteralBody(bool may_abort, bool* ok);
PreParserExpression ParseClassLiteral(PreParserIdentifier name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
struct TemplateLiteralState {};
V8_INLINE TemplateLiteralState OpenTemplateLiteral(int pos) {
@ -946,11 +940,6 @@ class PreParser : public ParserBase<PreParser> {
return labels;
}
V8_INLINE PreParserStatement ParseNativeDeclaration(bool* ok) {
UNREACHABLE();
return PreParserStatement::Default();
}
// TODO(nikolaos): The preparser currently does not keep track of labels.
V8_INLINE bool ContainsLabel(ZoneList<const AstRawString*>* labels,
PreParserIdentifier label) {
@ -997,6 +986,29 @@ class PreParser : public ParserBase<PreParser> {
return Statement::Default();
}
V8_INLINE PreParserStatement
DeclareClass(PreParserIdentifier variable_name, PreParserExpression value,
ZoneList<const AstRawString*>* names, int class_token_pos,
int end_pos, bool* ok) {
return PreParserStatement::Default();
}
V8_INLINE void DeclareClassVariable(PreParserIdentifier name,
Scope* block_scope, ClassInfo* class_info,
int class_token_pos, bool* ok) {}
V8_INLINE void DeclareClassProperty(PreParserIdentifier class_name,
PreParserExpression property,
ClassInfo* class_info, bool* ok) {}
V8_INLINE PreParserExpression RewriteClassLiteral(PreParserIdentifier name,
ClassInfo* class_info,
int pos, bool* ok) {
return PreParserExpression::Default();
}
V8_INLINE PreParserStatement DeclareNative(PreParserIdentifier name, int pos,
bool* ok) {
return PreParserStatement::Default();
}
V8_INLINE void QueueDestructuringAssignmentForRewriting(
PreParserExpression assignment) {}
V8_INLINE void QueueNonPatternForRewriting(PreParserExpression expr,
@ -1103,7 +1115,9 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE static void PushVariableName(PreParserIdentifier id) {}
V8_INLINE void PushPropertyName(PreParserExpression expression) {}
V8_INLINE void PushEnclosingName(PreParserIdentifier name) {}
V8_INLINE static void InferFunctionName(PreParserExpression expression) {}
V8_INLINE static void AddFunctionForNameInference(
PreParserExpression expression) {}
V8_INLINE static void InferFunctionName() {}
V8_INLINE static void CheckAssigningFunctionLiteralToProperty(
PreParserExpression left, PreParserExpression right) {}
@ -1318,7 +1332,11 @@ class PreParser : public ParserBase<PreParser> {
return PreParserExpressionList();
}
V8_INLINE PreParserExpressionList NewPropertyList(int size) const {
V8_INLINE PreParserExpressionList NewObjectPropertyList(int size) const {
return PreParserExpressionList();
}
V8_INLINE PreParserExpressionList NewClassPropertyList(int size) const {
return PreParserExpressionList();
}