Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index e2929b827d238d120528f2393a0160b1b3c4aaa0..3ba48826194bb5df1924fad039b03c4a4805997d 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,58 +539,63 @@ 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, |
+ kValueProperty, |
+ kMethodProperty |
}; |
- // 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: |
+ virtual ~ObjectLiteralCheckerBase() {} |
+ |
+ 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 |
@@ -2070,12 +2073,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 +2092,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 +2110,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 +2137,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 +2150,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 +2210,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 +2244,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 +3016,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"); |
- } 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 || type == kAccessorProperty); |
+ |
+ 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 |