Chromium Code Reviews| Index: src/preparser.h |
| diff --git a/src/preparser.h b/src/preparser.h |
| index e2929b827d238d120528f2393a0160b1b3c4aaa0..eb8aac36829cc736ad2e6cee93cc39505748801a 100644 |
| --- a/src/preparser.h |
| +++ b/src/preparser.h |
| @@ -161,7 +161,7 @@ class ParserBase : public Traits { |
| }; |
| class Checkpoint; |
| - class ObjectLiteralChecker; |
| + class ObjectLiteralCheckerBase; |
| // --------------------------------------------------------------------------- |
| // FunctionState and BlockState together implement the parser's scope stack. |
| @@ -512,11 +512,9 @@ class ParserBase : public Traits { |
| bool* is_static, bool* is_computed_name, |
| bool* ok); |
| ExpressionT ParseObjectLiteral(bool* ok); |
| - ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| - bool in_class, bool is_static, |
| - bool* is_computed_name, |
| - bool* has_seen_constructor, |
| - bool* ok); |
| + ObjectLiteralPropertyT ParsePropertyDefinition( |
| + ObjectLiteralCheckerBase* checker, bool in_class, bool is_static, |
| + bool* is_computed_name, bool* has_seen_constructor, bool* ok); |
| typename Traits::Type::ExpressionList ParseArguments(bool* ok); |
| ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); |
| ExpressionT ParseYieldExpression(bool* ok); |
| @@ -541,60 +539,64 @@ class ParserBase : public Traits { |
| ExpressionT expression, |
| Scanner::Location location, const char* message, bool* ok); |
| - // Used to detect duplicates in object literals. Each of the values |
| - // kGetterProperty, kSetterProperty and kValueProperty represents |
| - // a type of object literal property. When parsing a property, its |
| - // type value is stored in the DuplicateFinder for the property name. |
| - // Values are chosen so that having intersection bits means the there is |
| - // an incompatibility. |
| - // I.e., you can add a getter to a property that already has a setter, since |
| - // kGetterProperty and kSetterProperty doesn't intersect, but not if it |
| - // already has a getter or a value. Adding the getter to an existing |
| - // setter will store the value (kGetterProperty | kSetterProperty), which |
| - // is incompatible with adding any further properties. |
| + // Used to validate property names in object literals and class literals |
| enum PropertyKind { |
| - kNone = 0, |
| - // Bit patterns representing different object literal property types. |
| - kGetterProperty = 1, |
| - kSetterProperty = 2, |
| - kValueProperty = 7, |
| - // Helper constants. |
| - kValueFlag = 4 |
| + kAccessorProperty = 1, |
| + kValueProperty = 2, |
| + kMethodProperty = 3 |
|
adamk
2015/01/27 20:05:48
Given that these are no longer bit patterns, you s
arv (Not doing code reviews)
2015/01/28 02:37:15
Done.
|
| }; |
| - // Validation per ECMA 262 - 11.1.5 "Object Initializer". |
| - class ObjectLiteralChecker { |
| + class ObjectLiteralCheckerBase { |
| public: |
| - ObjectLiteralChecker(ParserBase* parser, StrictMode strict_mode) |
| - : parser_(parser), |
| - finder_(scanner()->unicode_cache()), |
| - strict_mode_(strict_mode) {} |
| + explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {} |
| - void CheckProperty(Token::Value property, PropertyKind type, bool* ok); |
| + virtual void CheckProperty(Token::Value property, PropertyKind type, |
| + bool is_static, bool is_generator, bool* ok) = 0; |
| - private: |
| + protected: |
| ParserBase* parser() const { return parser_; } |
| Scanner* scanner() const { return parser_->scanner(); } |
| - // Checks the type of conflict based on values coming from PropertyType. |
| - bool HasConflict(PropertyKind type1, PropertyKind type2) { |
| - return (type1 & type2) != 0; |
| - } |
| - bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) { |
| - return ((type1 & type2) & kValueFlag) != 0; |
| - } |
| - bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) { |
| - return ((type1 ^ type2) & kValueFlag) != 0; |
| + private: |
| + ParserBase* parser_; |
| + }; |
| + |
| + // Validation per ES6 object literals. |
| + class ObjectLiteralChecker : public ObjectLiteralCheckerBase { |
| + public: |
| + explicit ObjectLiteralChecker(ParserBase* parser) |
| + : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {} |
| + |
| + void CheckProperty(Token::Value property, PropertyKind type, bool is_static, |
| + bool is_generator, bool* ok) OVERRIDE; |
| + |
| + private: |
| + bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); } |
| + |
| + bool has_seen_proto_; |
| + }; |
| + |
| + // Validation per ES6 class literals. |
| + class ClassLiteralChecker : public ObjectLiteralCheckerBase { |
| + public: |
| + explicit ClassLiteralChecker(ParserBase* parser) |
| + : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {} |
| + |
| + void CheckProperty(Token::Value property, PropertyKind type, bool is_static, |
| + bool is_generator, bool* ok) OVERRIDE; |
| + |
| + private: |
| + bool IsConstructor() { |
| + return this->scanner()->LiteralMatches("constructor", 11); |
| } |
| - bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) { |
| - return ((type1 | type2) & kValueFlag) == 0; |
| + bool IsPrototype() { |
| + return this->scanner()->LiteralMatches("prototype", 9); |
| } |
| - ParserBase* parser_; |
| - DuplicateFinder finder_; |
| - StrictMode strict_mode_; |
| + bool has_seen_constructor_; |
| }; |
| + |
| // If true, the next (and immediately following) function literal is |
| // preceded by a parenthesis. |
| // Heuristically that means that the function will be called immediately, |
| @@ -2070,12 +2072,12 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName( |
| template <class Traits> |
| typename ParserBase<Traits>::ObjectLiteralPropertyT |
| -ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| +ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralCheckerBase* checker, |
| bool in_class, bool is_static, |
| bool* is_computed_name, |
| bool* has_seen_constructor, |
| bool* ok) { |
| - DCHECK(!in_class || is_static || has_seen_constructor != NULL); |
| + DCHECK(!in_class || is_static || has_seen_constructor != nullptr); |
| ExpressionT value = this->EmptyExpression(); |
| IdentifierT name = this->EmptyIdentifier(); |
| bool is_get = false; |
| @@ -2089,14 +2091,15 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| &name, &is_get, &is_set, &name_is_static, is_computed_name, |
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| - if (fni_ != NULL && !*is_computed_name) { |
| + if (fni_ != nullptr && !*is_computed_name) { |
| this->PushLiteralName(fni_, name); |
| } |
| if (!in_class && !is_generator && peek() == Token::COLON) { |
| // PropertyDefinition : PropertyName ':' AssignmentExpression |
| - if (!*is_computed_name && checker != NULL) { |
| - checker->CheckProperty(name_token, kValueProperty, |
| + if (!*is_computed_name) { |
| + checker->CheckProperty(name_token, kValueProperty, is_static, |
| + is_generator, |
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| } |
| Consume(Token::COLON); |
| @@ -2106,38 +2109,20 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| } else if (is_generator || |
| (allow_harmony_object_literals_ && peek() == Token::LPAREN)) { |
| // Concise Method |
| - |
| - if (is_static && this->IsPrototype(name)) { |
| - ReportMessageAt(scanner()->location(), "static_prototype"); |
| - *ok = false; |
| - return this->EmptyObjectLiteralProperty(); |
| + if (!*is_computed_name) { |
| + checker->CheckProperty(name_token, kMethodProperty, is_static, |
| + is_generator, |
| + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| } |
| FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod |
| : FunctionKind::kConciseMethod; |
| if (in_class && !is_static && this->IsConstructor(name)) { |
| - if (is_generator) { |
| - ReportMessageAt(scanner()->location(), "constructor_special_method"); |
| - *ok = false; |
| - return this->EmptyObjectLiteralProperty(); |
| - } |
| - |
| - if (*has_seen_constructor) { |
| - ReportMessageAt(scanner()->location(), "duplicate_constructor"); |
| - *ok = false; |
| - return this->EmptyObjectLiteralProperty(); |
| - } |
| - |
| *has_seen_constructor = true; |
| kind = FunctionKind::kNormalFunction; |
| } |
| - if (!*is_computed_name && checker != NULL) { |
| - checker->CheckProperty(name_token, kValueProperty, |
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| - } |
| - |
| value = this->ParseFunctionLiteral( |
| name, scanner()->location(), |
| false, // reserved words are allowed here |
| @@ -2151,8 +2136,8 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| } else if (in_class && name_is_static && !is_static) { |
| // static MethodDefinition |
| - return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL, |
| - ok); |
| + return ParsePropertyDefinition(checker, true, true, is_computed_name, |
| + nullptr, ok); |
| } else if (is_get || is_set) { |
| // Accessor |
| @@ -2164,19 +2149,9 @@ ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
| &name, &dont_care, &dont_care, &dont_care, is_computed_name, |
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| - // Validate the property. |
| - if (is_static && this->IsPrototype(name)) { |
| - ReportMessageAt(scanner()->location(), "static_prototype"); |
| - *ok = false; |
| - return this->EmptyObjectLiteralProperty(); |
| - } else if (in_class && !is_static && this->IsConstructor(name)) { |
| - ReportMessageAt(scanner()->location(), "constructor_special_method"); |
| - *ok = false; |
| - return this->EmptyObjectLiteralProperty(); |
| - } |
| - if (!*is_computed_name && checker != NULL) { |
| - checker->CheckProperty(name_token, |
| - is_get ? kGetterProperty : kSetterProperty, |
| + if (!*is_computed_name) { |
| + checker->CheckProperty(name_token, kAccessorProperty, is_static, |
| + is_generator, |
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| } |
| @@ -2234,19 +2209,18 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( |
| int number_of_boilerplate_properties = 0; |
| bool has_function = false; |
| bool has_computed_names = false; |
| - |
| - ObjectLiteralChecker checker(this, strict_mode()); |
| + ObjectLiteralChecker checker(this); |
| Expect(Token::LBRACE, CHECK_OK); |
| while (peek() != Token::RBRACE) { |
| - if (fni_ != NULL) fni_->Enter(); |
| + if (fni_ != nullptr) fni_->Enter(); |
| const bool in_class = false; |
| const bool is_static = false; |
| bool is_computed_name = false; |
| ObjectLiteralPropertyT property = this->ParsePropertyDefinition( |
| - &checker, in_class, is_static, &is_computed_name, NULL, CHECK_OK); |
| + &checker, in_class, is_static, &is_computed_name, nullptr, CHECK_OK); |
| if (is_computed_name) { |
| has_computed_names = true; |
| @@ -2269,7 +2243,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( |
| Expect(Token::COMMA, CHECK_OK); |
| } |
| - if (fni_ != NULL) { |
| + if (fni_ != nullptr) { |
| fni_->Infer(); |
| fni_->Leave(); |
| } |
| @@ -3041,28 +3015,52 @@ typename ParserBase<Traits>::ExpressionT ParserBase< |
| template <typename Traits> |
| void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( |
| - Token::Value property, PropertyKind type, bool* ok) { |
| - int old; |
| - if (property == Token::NUMBER) { |
| - old = scanner()->FindNumber(&finder_, type); |
| - } else { |
| - old = scanner()->FindSymbol(&finder_, type); |
| - } |
| - PropertyKind old_type = static_cast<PropertyKind>(old); |
| - if (HasConflict(old_type, type)) { |
| - if (IsDataDataConflict(old_type, type)) { |
| - // Both are data properties. |
| - if (strict_mode_ == SLOPPY) return; |
| - parser()->ReportMessage("strict_duplicate_property"); |
|
adamk
2015/01/27 20:05:48
If this message is now unused, you ought to be abl
arv (Not doing code reviews)
2015/01/28 02:37:15
Done.
|
| - } else if (IsDataAccessorConflict(old_type, type)) { |
| - // Both a data and an accessor property with the same name. |
| - parser()->ReportMessage("accessor_data_property"); |
| - } else { |
| - DCHECK(IsAccessorAccessorConflict(old_type, type)); |
| - // Both accessors of the same type. |
| - parser()->ReportMessage("accessor_get_set"); |
| + Token::Value property, PropertyKind type, bool is_static, bool is_generator, |
| + bool* ok) { |
| + DCHECK(!is_static); |
| + DCHECK(!is_generator || type == kMethodProperty); |
| + |
| + if (property == Token::NUMBER) return; |
| + |
| + if (type == kValueProperty && IsProto()) { |
| + if (has_seen_proto_) { |
| + this->parser()->ReportMessage("duplicate_proto"); |
| + *ok = false; |
| + return; |
| } |
| - *ok = false; |
| + has_seen_proto_ = true; |
| + return; |
| + } |
| +} |
| + |
| + |
| +template <typename Traits> |
| +void ParserBase<Traits>::ClassLiteralChecker::CheckProperty( |
| + Token::Value property, PropertyKind type, bool is_static, bool is_generator, |
| + bool* ok) { |
| + DCHECK(type == kMethodProperty); |
| + |
| + if (property == Token::NUMBER) return; |
| + |
| + if (is_static) { |
| + if (IsPrototype()) { |
| + this->parser()->ReportMessage("static_prototype"); |
| + *ok = false; |
| + return; |
| + } |
| + } else if (IsConstructor()) { |
| + if (is_generator || type == kAccessorProperty) { |
| + this->parser()->ReportMessage("constructor_special_method"); |
| + *ok = false; |
| + return; |
| + } |
| + if (has_seen_constructor_) { |
| + this->parser()->ReportMessage("duplicate_constructor"); |
| + *ok = false; |
| + return; |
| + } |
| + has_seen_constructor_ = true; |
| + return; |
| } |
| } |
| } } // v8::internal |