Index: src/parsing/parser-base.h |
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h |
index 0781f0ec9c98b0345fadfeb617c005d43110e2a1..fac3ec694afaa90ad2dc3c213572b8f60d6baede 100644 |
--- a/src/parsing/parser-base.h |
+++ b/src/parsing/parser-base.h |
@@ -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); |
@@ -3701,6 +3727,72 @@ ParserBase<Impl>::ParseHoistableDeclaration( |
} |
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( |
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { |
@@ -3931,12 +4023,72 @@ 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, |
FunctionBodyType body_type, |
@@ -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. |