| Index: src/parsing/parser.cc
|
| diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
|
| index cd87da8d14bfb46babba23408e08a987b795a9ca..2e2ac1c7ad3c19ed95e4440416a5bede71658fe4 100644
|
| --- a/src/parsing/parser.cc
|
| +++ b/src/parsing/parser.cc
|
| @@ -1532,94 +1532,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) {
|
| @@ -1675,6 +1587,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();
|
| @@ -3512,163 +3458,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);
|
| - }
|
| -
|
| - 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);
|
| + 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;
|
| }
|
|
|
| -
|
| - 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;
|
| -
|
| - 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));
|
| - }
|
| + 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());
|
| }
|
| - properties->Add(property, zone());
|
| + // 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));
|
| }
|
| -
|
| - DCHECK_NOT_NULL(fni_);
|
| - fni_->Infer();
|
| }
|
| + class_info->properties->Add(property, zone());
|
| +}
|
|
|
| - Expect(Token::RBRACE, CHECK_OK);
|
| +// 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);
|
|
|
| - 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(
|
| @@ -3679,8 +3598,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 =
|
| @@ -3690,7 +3608,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,
|
| @@ -3699,7 +3617,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 =
|
| @@ -3709,15 +3627,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(
|
| @@ -3727,13 +3644,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);
|
| }
|
|
|