Commit f3d5b13e authored by arv's avatar arv Committed by Commit bot

Classes: Implement correct name binding

Named class declarations and class expression have a const binding for
the name that is in TDZ for the extends expression.

BUG=v8:3330
LOG=Y
R=dslomov@chromium.org, adamk

Review URL: https://codereview.chromium.org/722793005

Cr-Commit-Position: refs/heads/master@{#25360}
parent a210f368
...@@ -448,6 +448,9 @@ void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) { ...@@ -448,6 +448,9 @@ void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) {
node->set_base_id(ReserveIdRange(ClassLiteral::num_ids())); node->set_base_id(ReserveIdRange(ClassLiteral::num_ids()));
if (node->extends()) Visit(node->extends()); if (node->extends()) Visit(node->extends());
if (node->constructor()) Visit(node->constructor()); if (node->constructor()) Visit(node->constructor());
if (node->class_variable_proxy()) {
VisitVariableProxy(node->class_variable_proxy());
}
for (int i = 0; i < node->properties()->length(); i++) { for (int i = 0; i < node->properties()->length(); i++) {
VisitObjectLiteralProperty(node->properties()->at(i)); VisitObjectLiteralProperty(node->properties()->at(i));
} }
......
...@@ -2641,6 +2641,8 @@ class ClassLiteral FINAL : public Expression { ...@@ -2641,6 +2641,8 @@ class ClassLiteral FINAL : public Expression {
Handle<String> name() const { return raw_name_->string(); } Handle<String> name() const { return raw_name_->string(); }
const AstRawString* raw_name() const { return raw_name_; } const AstRawString* raw_name() const { return raw_name_; }
Scope* scope() const { return scope_; }
VariableProxy* class_variable_proxy() const { return class_variable_proxy_; }
Expression* extends() const { return extends_; } Expression* extends() const { return extends_; }
Expression* constructor() const { return constructor_; } Expression* constructor() const { return constructor_; }
ZoneList<Property*>* properties() const { return properties_; } ZoneList<Property*>* properties() const { return properties_; }
...@@ -2648,11 +2650,14 @@ class ClassLiteral FINAL : public Expression { ...@@ -2648,11 +2650,14 @@ class ClassLiteral FINAL : public Expression {
int end_position() const { return end_position_; } int end_position() const { return end_position_; }
protected: protected:
ClassLiteral(Zone* zone, const AstRawString* name, Expression* extends, ClassLiteral(Zone* zone, const AstRawString* name, Scope* scope,
VariableProxy* class_variable_proxy, Expression* extends,
Expression* constructor, ZoneList<Property*>* properties, Expression* constructor, ZoneList<Property*>* properties,
int start_position, int end_position) int start_position, int end_position)
: Expression(zone, start_position), : Expression(zone, start_position),
raw_name_(name), raw_name_(name),
scope_(scope),
class_variable_proxy_(class_variable_proxy),
extends_(extends), extends_(extends),
constructor_(constructor), constructor_(constructor),
properties_(properties), properties_(properties),
...@@ -2660,6 +2665,8 @@ class ClassLiteral FINAL : public Expression { ...@@ -2660,6 +2665,8 @@ class ClassLiteral FINAL : public Expression {
private: private:
const AstRawString* raw_name_; const AstRawString* raw_name_;
Scope* scope_;
VariableProxy* class_variable_proxy_;
Expression* extends_; Expression* extends_;
Expression* constructor_; Expression* constructor_;
ZoneList<Property*>* properties_; ZoneList<Property*>* properties_;
...@@ -3500,11 +3507,13 @@ class AstNodeFactory FINAL BASE_EMBEDDED { ...@@ -3500,11 +3507,13 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
position); position);
} }
ClassLiteral* NewClassLiteral(const AstRawString* name, Expression* extends, ClassLiteral* NewClassLiteral(const AstRawString* name, Scope* scope,
VariableProxy* proxy, Expression* extends,
Expression* constructor, Expression* constructor,
ZoneList<ObjectLiteral::Property*>* properties, ZoneList<ObjectLiteral::Property*>* properties,
int start_position, int end_position) { int start_position, int end_position) {
return new (zone_) ClassLiteral(zone_, name, extends, constructor, return new (zone_)
ClassLiteral(zone_, name, scope, proxy, extends, constructor,
properties, start_position, end_position); properties, start_position, end_position);
} }
......
...@@ -1073,41 +1073,12 @@ void FullCodeGenerator::VisitBlock(Block* stmt) { ...@@ -1073,41 +1073,12 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
NestedBlock nested_block(this, stmt); NestedBlock nested_block(this, stmt);
SetStatementPosition(stmt); SetStatementPosition(stmt);
Scope* saved_scope = scope(); {
// Push a block context when entering a block with block scoped variables. EnterBlockScopeIfNeeded block_scope_state(
if (stmt->scope() == NULL) { this, stmt->scope(), stmt->EntryId(), stmt->DeclsId(), stmt->ExitId());
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
} else {
scope_ = stmt->scope();
DCHECK(!scope_->is_module_scope());
{ Comment cmnt(masm_, "[ Extend block context");
__ Push(scope_->GetScopeInfo());
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushBlockContext, 2);
// Replace the context stored in the frame.
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
}
{ Comment cmnt(masm_, "[ Declarations");
VisitDeclarations(scope_->declarations());
PrepareForBailoutForId(stmt->DeclsId(), NO_REGISTERS);
}
}
VisitStatements(stmt->statements()); VisitStatements(stmt->statements());
scope_ = saved_scope;
__ bind(nested_block.break_label()); __ bind(nested_block.break_label());
// Pop block context if necessary.
if (stmt->scope() != NULL) {
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
// Update local stack frame context field.
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
} }
PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
} }
...@@ -1608,6 +1579,11 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { ...@@ -1608,6 +1579,11 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
Comment cmnt(masm_, "[ ClassLiteral"); Comment cmnt(masm_, "[ ClassLiteral");
{
EnterBlockScopeIfNeeded block_scope_state(
this, lit->scope(), BailoutId::None(), BailoutId::None(),
BailoutId::None());
if (lit->raw_name() != NULL) { if (lit->raw_name() != NULL) {
__ Push(lit->name()); __ Push(lit->name());
} else { } else {
...@@ -1629,6 +1605,13 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { ...@@ -1629,6 +1605,13 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
__ CallRuntime(Runtime::kDefineClass, 6); __ CallRuntime(Runtime::kDefineClass, 6);
EmitClassDefineProperties(lit); EmitClassDefineProperties(lit);
if (lit->scope() != NULL) {
DCHECK_NOT_NULL(lit->class_variable_proxy());
EmitVariableAssignment(lit->class_variable_proxy()->var(),
Token::INIT_CONST);
}
}
context()->Plug(result_register()); context()->Plug(result_register());
} }
...@@ -1795,6 +1778,49 @@ bool BackEdgeTable::Verify(Isolate* isolate, Code* unoptimized) { ...@@ -1795,6 +1778,49 @@ bool BackEdgeTable::Verify(Isolate* isolate, Code* unoptimized) {
#endif // DEBUG #endif // DEBUG
FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded(
FullCodeGenerator* codegen, Scope* scope, BailoutId entry_id,
BailoutId declarations_id, BailoutId exit_id)
: codegen_(codegen), scope_(scope), exit_id_(exit_id) {
saved_scope_ = codegen_->scope();
if (scope == NULL) {
codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
} else {
codegen_->scope_ = scope;
{
Comment cmnt(masm(), "[ Extend block context");
__ Push(scope->GetScopeInfo());
codegen_->PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushBlockContext, 2);
// Replace the context stored in the frame.
codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
codegen_->context_register());
codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
}
{
Comment cmnt(masm(), "[ Declarations");
codegen_->VisitDeclarations(scope->declarations());
codegen_->PrepareForBailoutForId(declarations_id, NO_REGISTERS);
}
}
}
FullCodeGenerator::EnterBlockScopeIfNeeded::~EnterBlockScopeIfNeeded() {
if (scope_ != NULL) {
codegen_->LoadContextField(codegen_->context_register(),
Context::PREVIOUS_INDEX);
// Update local stack frame context field.
codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
codegen_->context_register());
}
codegen_->PrepareForBailoutForId(exit_id_, NO_REGISTERS);
codegen_->scope_ = saved_scope_;
}
#undef __ #undef __
......
...@@ -882,6 +882,22 @@ class FullCodeGenerator: public AstVisitor { ...@@ -882,6 +882,22 @@ class FullCodeGenerator: public AstVisitor {
virtual bool IsEffect() const { return true; } virtual bool IsEffect() const { return true; }
}; };
class EnterBlockScopeIfNeeded {
public:
EnterBlockScopeIfNeeded(FullCodeGenerator* codegen, Scope* scope,
BailoutId entry_id, BailoutId declarations_id,
BailoutId exit_id);
~EnterBlockScopeIfNeeded();
private:
MacroAssembler* masm() const { return codegen_->masm(); }
FullCodeGenerator* codegen_;
Scope* scope_;
Scope* saved_scope_;
BailoutId exit_id_;
};
MacroAssembler* masm_; MacroAssembler* masm_;
CompilationInfo* info_; CompilationInfo* info_;
Scope* scope_; Scope* scope_;
......
...@@ -685,13 +685,6 @@ Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory, ...@@ -685,13 +685,6 @@ Expression* ParserTraits::SuperReference(Scope* scope, AstNodeFactory* factory,
pos); pos);
} }
Expression* ParserTraits::ClassExpression(
const AstRawString* name, Expression* extends, Expression* constructor,
ZoneList<ObjectLiteral::Property*>* properties, int start_position,
int end_position, AstNodeFactory* factory) {
return factory->NewClassLiteral(name, extends, constructor, properties,
start_position, end_position);
}
Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope, Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
int pos, int end_pos) { int pos, int end_pos) {
...@@ -777,6 +770,14 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( ...@@ -777,6 +770,14 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
} }
ClassLiteral* ParserTraits::ParseClassLiteral(
const AstRawString* name, Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos, bool* ok) {
return parser_->ParseClassLiteral(name, class_name_location,
name_is_strict_reserved, pos, ok);
}
Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
: ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit, : ParserBase<ParserTraits>(&scanner_, parse_info->stack_limit,
info->extension(), NULL, info->zone(), this), info->extension(), NULL, info->zone(), this),
...@@ -1993,7 +1994,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names, ...@@ -1993,7 +1994,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool is_strict_reserved = false; bool is_strict_reserved = false;
const AstRawString* name = const AstRawString* name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
Expression* value = ParseClassLiteral(name, scanner()->location(), ClassLiteral* value = ParseClassLiteral(name, scanner()->location(),
is_strict_reserved, pos, CHECK_OK); is_strict_reserved, pos, CHECK_OK);
VariableProxy* proxy = NewUnresolved(name, LET, Interface::NewValue()); VariableProxy* proxy = NewUnresolved(name, LET, Interface::NewValue());
...@@ -3893,6 +3894,90 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( ...@@ -3893,6 +3894,90 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
} }
ClassLiteral* 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, "unexpected_strict_reserved");
*ok = false;
return NULL;
}
if (IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, "strict_eval_arguments");
*ok = false;
return NULL;
}
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, block_scope);
scope_->SetStrictMode(STRICT);
scope_->SetScopeName(name);
VariableProxy* proxy = NULL;
if (name != NULL) {
proxy = NewUnresolved(name, CONST, Interface::NewConst());
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
Declare(declaration, true, CHECK_OK);
}
Expression* extends = NULL;
if (Check(Token::EXTENDS)) {
block_scope->set_start_position(scanner()->location().end_pos);
extends = ParseLeftHandSideExpression(CHECK_OK);
} else {
block_scope->set_start_position(scanner()->location().end_pos);
}
ZoneList<ObjectLiteral::Property*>* properties = NewPropertyList(4, zone());
Expression* constructor = NULL;
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
if (fni_ != NULL) fni_->Enter();
const bool in_class = true;
const bool is_static = false;
ObjectLiteral::Property* property = ParsePropertyDefinition(
NULL, in_class, is_static, &has_seen_constructor, CHECK_OK);
if (has_seen_constructor && constructor == NULL) {
constructor = GetPropertyValue(property);
} else {
properties->Add(property, zone());
}
if (fni_ != NULL) {
fni_->Infer();
fni_->Leave();
}
}
Expect(Token::RBRACE, CHECK_OK);
int end_pos = scanner()->location().end_pos;
if (constructor == NULL) {
constructor =
DefaultConstructor(extends != NULL, block_scope, pos, end_pos);
}
block_scope->set_end_position(end_pos);
block_scope = block_scope->FinalizeBlockScope();
if (name != NULL) {
DCHECK_NOT_NULL(proxy);
DCHECK_NOT_NULL(block_scope);
proxy->var()->set_initializer_position(end_pos);
}
return factory()->NewClassLiteral(name, block_scope, proxy, extends,
constructor, properties, pos, end_pos);
}
Expression* Parser::ParseV8Intrinsic(bool* ok) { Expression* Parser::ParseV8Intrinsic(bool* ok) {
// CallRuntime :: // CallRuntime ::
// '%' Identifier Arguments // '%' Identifier Arguments
......
...@@ -538,12 +538,6 @@ class ParserTraits { ...@@ -538,12 +538,6 @@ class ParserTraits {
int pos = RelocInfo::kNoPosition); int pos = RelocInfo::kNoPosition);
Expression* SuperReference(Scope* scope, AstNodeFactory* factory, Expression* SuperReference(Scope* scope, AstNodeFactory* factory,
int pos = RelocInfo::kNoPosition); int pos = RelocInfo::kNoPosition);
Expression* ClassExpression(const AstRawString* name, Expression* extends,
Expression* constructor,
ZoneList<ObjectLiteral::Property*>* properties,
int start_position, int end_position,
AstNodeFactory* factory);
Expression* DefaultConstructor(bool call_super, Scope* scope, int pos, Expression* DefaultConstructor(bool call_super, Scope* scope, int pos,
int end_pos); int end_pos);
Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner, Literal* ExpressionFromLiteral(Token::Value token, int pos, Scanner* scanner,
...@@ -583,6 +577,12 @@ class ParserTraits { ...@@ -583,6 +577,12 @@ class ParserTraits {
V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody( V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
const AstRawString* name, int pos, Variable* fvar, const AstRawString* name, int pos, Variable* fvar,
Token::Value fvar_init_op, bool is_generator, bool* ok); Token::Value fvar_init_op, bool is_generator, bool* ok);
ClassLiteral* ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope, V8_INLINE void CheckConflictingVarDeclarations(v8::internal::Scope* scope,
bool* ok); bool* ok);
...@@ -763,6 +763,12 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -763,6 +763,12 @@ class Parser : public ParserBase<ParserTraits> {
int function_token_position, FunctionLiteral::FunctionType type, int function_token_position, FunctionLiteral::FunctionType type,
FunctionLiteral::ArityRestriction arity_restriction, bool* ok); FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
ClassLiteral* ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
// Magical syntax support. // Magical syntax support.
Expression* ParseV8Intrinsic(bool* ok); Expression* ParseV8Intrinsic(bool* ok);
......
...@@ -132,6 +132,14 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction( ...@@ -132,6 +132,14 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
} }
PreParserExpression PreParserTraits::ParseClassLiteral(
PreParserIdentifier name, Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos, bool* ok) {
return pre_parser_->ParseClassLiteral(name, class_name_location,
name_is_strict_reserved, pos, ok);
}
// Preparsing checks a JavaScript program and emits preparse-data that helps // Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster. // a later parsing to be faster.
// See preparser-data.h for the data. // See preparser-data.h for the data.
...@@ -928,6 +936,47 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok) { ...@@ -928,6 +936,47 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
} }
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, "unexpected_strict_reserved");
*ok = false;
return EmptyExpression();
}
if (IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, "strict_eval_arguments");
*ok = false;
return EmptyExpression();
}
PreParserScope scope = NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, &scope);
scope_->SetStrictMode(STRICT);
scope_->SetScopeName(name);
if (Check(Token::EXTENDS)) {
ParseLeftHandSideExpression(CHECK_OK);
}
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
const bool in_class = true;
const bool is_static = false;
ParsePropertyDefinition(NULL, in_class, is_static, &has_seen_constructor,
CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
return Expression::Default();
}
PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
// CallRuntime :: // CallRuntime ::
// '%' Identifier Arguments // '%' Identifier Arguments
......
...@@ -490,10 +490,6 @@ class ParserBase : public Traits { ...@@ -490,10 +490,6 @@ class ParserBase : public Traits {
bool* ok); bool* ok);
ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast, ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast,
bool* ok); bool* ok);
ExpressionT ParseClassLiteral(IdentifierT name,
Scanner::Location function_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
// Checks if the expression is a valid reference expression (e.g., on the // Checks if the expression is a valid reference expression (e.g., on the
// left-hand side of assignments). Although ruled out by ECMA as early errors, // left-hand side of assignments). Although ruled out by ECMA as early errors,
...@@ -1090,12 +1086,13 @@ class PreParserFactory { ...@@ -1090,12 +1086,13 @@ class PreParserFactory {
int position) { int position) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
PreParserExpression NewClassLiteral(PreParserIdentifier name,
PreParserExpression extends, // Return the object itself as AstVisitor and implement the needed
PreParserExpression constructor, // dummy method right in this class.
PreParserExpressionList properties, PreParserFactory* visitor() { return this; }
int start_position, int end_position) { int* ast_properties() {
return PreParserExpression::Default(); static int dummy = 42;
return &dummy;
} }
}; };
...@@ -1308,13 +1305,6 @@ class PreParserTraits { ...@@ -1308,13 +1305,6 @@ class PreParserTraits {
return PreParserExpression::Super(); return PreParserExpression::Super();
} }
static PreParserExpression ClassExpression(
PreParserIdentifier name, PreParserExpression extends,
PreParserExpression constructor, PreParserExpressionList properties,
int start_position, int end_position, PreParserFactory* factory) {
return PreParserExpression::Default();
}
static PreParserExpression DefaultConstructor(bool call_super, static PreParserExpression DefaultConstructor(bool call_super,
PreParserScope* scope, int pos, PreParserScope* scope, int pos,
int end_pos) { int end_pos) {
...@@ -1387,6 +1377,11 @@ class PreParserTraits { ...@@ -1387,6 +1377,11 @@ class PreParserTraits {
int function_token_position, FunctionLiteral::FunctionType type, int function_token_position, FunctionLiteral::FunctionType type,
FunctionLiteral::ArityRestriction arity_restriction, bool* ok); FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
PreParserExpression ParseClassLiteral(PreParserIdentifier name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
private: private:
PreParser* pre_parser_; PreParser* pre_parser_;
}; };
...@@ -1524,6 +1519,11 @@ class PreParser : public ParserBase<PreParserTraits> { ...@@ -1524,6 +1519,11 @@ class PreParser : public ParserBase<PreParserTraits> {
FunctionLiteral::ArityRestriction arity_restriction, bool* ok); FunctionLiteral::ArityRestriction arity_restriction, bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok); void ParseLazyFunctionLiteralBody(bool* ok);
PreParserExpression ParseClassLiteral(PreParserIdentifier name,
Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos,
bool* ok);
bool CheckInOrOf(bool accept_OF); bool CheckInOrOf(bool accept_OF);
}; };
...@@ -2722,78 +2722,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase< ...@@ -2722,78 +2722,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
} }
template <class Traits>
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseClassLiteral(
IdentifierT name, Scanner::Location class_name_location,
bool name_is_strict_reserved, int pos, bool* ok) {
// All parts of a ClassDeclaration or a ClassExpression are strict code.
if (name_is_strict_reserved) {
ReportMessageAt(class_name_location, "unexpected_strict_reserved");
*ok = false;
return this->EmptyExpression();
}
if (this->IsEvalOrArguments(name)) {
ReportMessageAt(class_name_location, "strict_eval_arguments");
*ok = false;
return this->EmptyExpression();
}
bool has_extends = false;
ExpressionT extends = this->EmptyExpression();
if (Check(Token::EXTENDS)) {
typename Traits::Type::ScopePtr scope = this->NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, Traits::Type::ptr_to_scope(scope));
scope_->SetStrictMode(STRICT);
extends = this->ParseLeftHandSideExpression(CHECK_OK);
has_extends = true;
}
// TODO(arv): Implement scopes and name binding in class body only.
typename Traits::Type::ScopePtr scope = this->NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, Traits::Type::ptr_to_scope(scope));
scope_->SetStrictMode(STRICT);
scope_->SetScopeName(name);
typename Traits::Type::PropertyList properties =
this->NewPropertyList(4, zone_);
ExpressionT constructor = this->EmptyExpression();
bool has_seen_constructor = false;
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
if (Check(Token::SEMICOLON)) continue;
if (fni_ != NULL) fni_->Enter();
const bool in_class = true;
const bool is_static = false;
bool old_has_seen_constructor = has_seen_constructor;
ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
NULL, in_class, is_static, &has_seen_constructor, CHECK_OK);
if (has_seen_constructor != old_has_seen_constructor) {
constructor = this->GetPropertyValue(property);
} else {
properties->Add(property, zone());
}
if (fni_ != NULL) {
fni_->Infer();
fni_->Leave();
}
}
int end_pos = peek_position();
Expect(Token::RBRACE, CHECK_OK);
if (!has_seen_constructor) {
constructor =
this->DefaultConstructor(has_extends, scope_, pos, end_pos + 1);
}
return this->ClassExpression(name, extends, constructor, properties, pos,
end_pos + 1, factory());
}
template <typename Traits> template <typename Traits>
typename ParserBase<Traits>::ExpressionT typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::CheckAndRewriteReferenceExpression( ParserBase<Traits>::CheckAndRewriteReferenceExpression(
......
...@@ -673,15 +673,98 @@ function assertAccessorDescriptor(object, name) { ...@@ -673,15 +673,98 @@ function assertAccessorDescriptor(object, name) {
})(); })();
/* TODO(arv): Implement (function TestNameBindingConst() {
(function TestNameBindingInConstructor() { assertThrows('class C { constructor() { C = 42; } }', SyntaxError);
assertThrows('(class C { constructor() { C = 42; } })', SyntaxError);
assertThrows('class C { m() { C = 42; } }', SyntaxError);
assertThrows('(class C { m() { C = 42; } })', SyntaxError);
assertThrows('class C { get x() { C = 42; } }', SyntaxError);
assertThrows('(class C { get x() { C = 42; } })', SyntaxError);
assertThrows('class C { set x(_) { C = 42; } }', SyntaxError);
assertThrows('(class C { set x(_) { C = 42; } })', SyntaxError);
})();
(function TestNameBinding() {
var C2;
class C { class C {
constructor() { constructor() {
assertThrows(function() { C2 = C;
C = 42; }
}, ReferenceError); m() {
C2 = C;
}
get x() {
C2 = C;
}
set x(_) {
C2 = C;
} }
} }
new C(); new C();
assertEquals(C, C2);
C2 = undefined;
new C().m();
assertEquals(C, C2);
C2 = undefined;
new C().x;
assertEquals(C, C2);
C2 = undefined;
new C().x = 1;
assertEquals(C, C2);
})();
(function TestNameBindingExpression() {
var C3;
var C = class C2 {
constructor() {
assertEquals(C2, C);
C3 = C2;
}
m() {
assertEquals(C2, C);
C3 = C2;
}
get x() {
assertEquals(C2, C);
C3 = C2;
}
set x(_) {
assertEquals(C2, C);
C3 = C2;
}
}
new C();
assertEquals(C, C3);
C3 = undefined;
new C().m();
assertEquals(C, C3);
C3 = undefined;
new C().x;
assertEquals(C, C3);
C3 = undefined;
new C().x = 1;
assertEquals(C, C3);
})();
(function TestNameBindingInExtendsExpression() {
assertThrows(function() {
class x extends x {}
}, ReferenceError);
assertThrows(function() {
(class x extends x {});
}, ReferenceError);
assertThrows(function() {
var x = (class x extends x {});
}, ReferenceError);
})(); })();
*/
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