| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 5ca161d94925e885fe811d7fe565512a555593c4..13d33360b0252ceaba3dadb919ba8e82f5a38010 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -130,6 +130,7 @@ class ParserBase : public Traits {
|
| };
|
|
|
| class ParserCheckpoint;
|
| + class ObjectLiteralChecker;
|
|
|
| // ---------------------------------------------------------------------------
|
| // FunctionState and BlockState together implement the parser's scope stack.
|
| @@ -476,7 +477,8 @@ class ParserBase : public Traits {
|
| ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
| ExpressionT ParseArrayLiteral(bool* ok);
|
| ExpressionT ParseObjectLiteral(bool* ok);
|
| - ObjectLiteralPropertyT ParsePropertyDefinition(bool* ok);
|
| + ObjectLiteralPropertyT ParsePropertyDefinition(ObjectLiteralChecker* checker,
|
| + bool* ok);
|
| typename Traits::Type::ExpressionList ParseArguments(bool* ok);
|
| ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
|
| ExpressionT ParseYieldExpression(bool* ok);
|
| @@ -499,6 +501,60 @@ 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.
|
| + enum PropertyKind {
|
| + kNone = 0,
|
| + // Bit patterns representing different object literal property types.
|
| + kGetterProperty = 1,
|
| + kSetterProperty = 2,
|
| + kValueProperty = 7,
|
| + // Helper constants.
|
| + kValueFlag = 4
|
| + };
|
| +
|
| + // Validation per ECMA 262 - 11.1.5 "Object Initializer".
|
| + class ObjectLiteralChecker {
|
| + public:
|
| + ObjectLiteralChecker(ParserBase* parser, StrictMode strict_mode)
|
| + : parser_(parser),
|
| + finder_(scanner()->unicode_cache()),
|
| + strict_mode_(strict_mode) {}
|
| +
|
| + void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
|
| +
|
| + private:
|
| + 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;
|
| + }
|
| + bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
| + return ((type1 | type2) & kValueFlag) == 0;
|
| + }
|
| +
|
| + ParserBase* parser_;
|
| + DuplicateFinder finder_;
|
| + StrictMode strict_mode_;
|
| + };
|
| +
|
| // If true, the next (and immediately following) function literal is
|
| // preceded by a parenthesis.
|
| // Heuristically that means that the function will be called immediately,
|
| @@ -1801,8 +1857,8 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
|
|
|
|
| template <class Traits>
|
| -typename ParserBase<Traits>::ObjectLiteralPropertyT
|
| -ParserBase<Traits>::ParsePropertyDefinition(bool* ok) {
|
| +typename ParserBase<Traits>::ObjectLiteralPropertyT ParserBase<
|
| + Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, bool* ok) {
|
| LiteralT key = this->EmptyLiteral();
|
| Token::Value next = peek();
|
| int next_pos = peek_position();
|
| @@ -1854,6 +1910,10 @@ ParserBase<Traits>::ParsePropertyDefinition(bool* ok) {
|
| name = ParseIdentifierName(
|
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| }
|
| + // Validate the property.
|
| + PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
|
| + checker->CheckProperty(next, type,
|
| + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| typename Traits::Type::FunctionLiteral value =
|
| this->ParseFunctionLiteral(
|
| name, scanner()->location(),
|
| @@ -1871,6 +1931,10 @@ ParserBase<Traits>::ParsePropertyDefinition(bool* ok) {
|
| }
|
| }
|
|
|
| + // Validate the property
|
| + checker->CheckProperty(next, kValueProperty,
|
| + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| +
|
| Expect(Token::COLON, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| ExpressionT value = this->ParseAssignmentExpression(
|
| true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| @@ -1891,12 +1955,15 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
| int number_of_boilerplate_properties = 0;
|
| bool has_function = false;
|
|
|
| + ObjectLiteralChecker checker(this, strict_mode());
|
| +
|
| Expect(Token::LBRACE, CHECK_OK);
|
|
|
| while (peek() != Token::RBRACE) {
|
| if (fni_ != NULL) fni_->Enter();
|
|
|
| - ObjectLiteralPropertyT property = this->ParsePropertyDefinition(CHECK_OK);
|
| + ObjectLiteralPropertyT property =
|
| + this->ParsePropertyDefinition(&checker, CHECK_OK);
|
|
|
| // Mark top-level object literals that contain function literals and
|
| // pretenure the literal so it can be added as a constant function
|
| @@ -2580,6 +2647,32 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression(
|
| #undef CHECK_OK_CUSTOM
|
|
|
|
|
| +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");
|
| + }
|
| + *ok = false;
|
| + }
|
| +}
|
| } } // v8::internal
|
|
|
| #endif // V8_PREPARSER_H
|
|
|