Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_PARSING_PARSER_BASE_H | 5 #ifndef V8_PARSING_PARSER_BASE_H |
| 6 #define V8_PARSING_PARSER_BASE_H | 6 #define V8_PARSING_PARSER_BASE_H |
| 7 | 7 |
| 8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
| 9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
| 10 #include "src/base/hashmap.h" | 10 #include "src/base/hashmap.h" |
| (...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 kAccessorProperty, | 1175 kAccessorProperty, |
| 1176 kValueProperty, | 1176 kValueProperty, |
| 1177 kMethodProperty | 1177 kMethodProperty |
| 1178 }; | 1178 }; |
| 1179 | 1179 |
| 1180 class ObjectLiteralCheckerBase { | 1180 class ObjectLiteralCheckerBase { |
| 1181 public: | 1181 public: |
| 1182 explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {} | 1182 explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {} |
| 1183 | 1183 |
| 1184 virtual void CheckProperty(Token::Value property, PropertyKind type, | 1184 virtual void CheckProperty(Token::Value property, PropertyKind type, |
| 1185 MethodKind method_type, bool* ok) = 0; | 1185 MethodKind method_type, |
| 1186 ExpressionClassifier* classifier, bool* ok) = 0; | |
| 1186 | 1187 |
| 1187 virtual ~ObjectLiteralCheckerBase() {} | 1188 virtual ~ObjectLiteralCheckerBase() {} |
| 1188 | 1189 |
| 1189 protected: | 1190 protected: |
| 1190 ParserBase* parser() const { return parser_; } | 1191 ParserBase* parser() const { return parser_; } |
| 1191 Scanner* scanner() const { return parser_->scanner(); } | 1192 Scanner* scanner() const { return parser_->scanner(); } |
| 1192 | 1193 |
| 1193 private: | 1194 private: |
| 1194 ParserBase* parser_; | 1195 ParserBase* parser_; |
| 1195 }; | 1196 }; |
| 1196 | 1197 |
| 1197 // Validation per ES6 object literals. | 1198 // Validation per ES6 object literals. |
| 1198 class ObjectLiteralChecker : public ObjectLiteralCheckerBase { | 1199 class ObjectLiteralChecker : public ObjectLiteralCheckerBase { |
| 1199 public: | 1200 public: |
| 1200 explicit ObjectLiteralChecker(ParserBase* parser) | 1201 explicit ObjectLiteralChecker(ParserBase* parser) |
| 1201 : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {} | 1202 : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {} |
| 1202 | 1203 |
| 1203 void CheckProperty(Token::Value property, PropertyKind type, | 1204 void CheckProperty(Token::Value property, PropertyKind type, |
| 1204 MethodKind method_type, bool* ok) override; | 1205 MethodKind method_type, ExpressionClassifier* classifier, |
| 1206 bool* ok) override; | |
| 1205 | 1207 |
| 1206 private: | 1208 private: |
| 1207 bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); } | 1209 bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); } |
| 1208 | 1210 |
| 1209 bool has_seen_proto_; | 1211 bool has_seen_proto_; |
| 1210 }; | 1212 }; |
| 1211 | 1213 |
| 1212 // Validation per ES6 class literals. | 1214 // Validation per ES6 class literals. |
| 1213 class ClassLiteralChecker : public ObjectLiteralCheckerBase { | 1215 class ClassLiteralChecker : public ObjectLiteralCheckerBase { |
| 1214 public: | 1216 public: |
| 1215 explicit ClassLiteralChecker(ParserBase* parser) | 1217 explicit ClassLiteralChecker(ParserBase* parser) |
| 1216 : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {} | 1218 : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {} |
| 1217 | 1219 |
| 1218 void CheckProperty(Token::Value property, PropertyKind type, | 1220 void CheckProperty(Token::Value property, PropertyKind type, |
| 1219 MethodKind method_type, bool* ok) override; | 1221 MethodKind method_type, ExpressionClassifier* classifier, |
| 1222 bool* ok) override; | |
| 1220 | 1223 |
| 1221 private: | 1224 private: |
| 1222 bool IsConstructor() { | 1225 bool IsConstructor() { |
| 1223 return this->scanner()->LiteralMatches("constructor", 11); | 1226 return this->scanner()->LiteralMatches("constructor", 11); |
| 1224 } | 1227 } |
| 1225 bool IsPrototype() { | 1228 bool IsPrototype() { |
| 1226 return this->scanner()->LiteralMatches("prototype", 9); | 1229 return this->scanner()->LiteralMatches("prototype", 9); |
| 1227 } | 1230 } |
| 1228 | 1231 |
| 1229 bool has_seen_constructor_; | 1232 bool has_seen_constructor_; |
| (...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1954 } | 1957 } |
| 1955 | 1958 |
| 1956 if (!in_class && !is_generator) { | 1959 if (!in_class && !is_generator) { |
| 1957 DCHECK(!IsStaticMethod(method_kind)); | 1960 DCHECK(!IsStaticMethod(method_kind)); |
| 1958 | 1961 |
| 1959 if (peek() == Token::COLON) { | 1962 if (peek() == Token::COLON) { |
| 1960 // PropertyDefinition | 1963 // PropertyDefinition |
| 1961 // PropertyName ':' AssignmentExpression | 1964 // PropertyName ':' AssignmentExpression |
| 1962 if (!*is_computed_name) { | 1965 if (!*is_computed_name) { |
| 1963 checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal, | 1966 checker->CheckProperty(name_token, kValueProperty, MethodKind::kNormal, |
| 1967 classifier, | |
| 1964 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 1968 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 1965 } | 1969 } |
| 1966 Consume(Token::COLON); | 1970 Consume(Token::COLON); |
| 1967 int beg_pos = peek_position(); | 1971 int beg_pos = peek_position(); |
| 1968 ExpressionT value = this->ParseAssignmentExpression( | 1972 ExpressionT value = this->ParseAssignmentExpression( |
| 1969 true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 1973 true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 1970 CheckDestructuringElement(value, classifier, beg_pos, | 1974 CheckDestructuringElement(value, classifier, beg_pos, |
| 1971 scanner()->location().end_pos); | 1975 scanner()->location().end_pos); |
| 1972 | 1976 |
| 1973 return factory()->NewObjectLiteralProperty(name_expression, value, | 1977 return factory()->NewObjectLiteralProperty(name_expression, value, |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2048 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2052 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 2049 method_kind |= MethodKind::kAsync; | 2053 method_kind |= MethodKind::kAsync; |
| 2050 } | 2054 } |
| 2051 | 2055 |
| 2052 if (is_generator || peek() == Token::LPAREN) { | 2056 if (is_generator || peek() == Token::LPAREN) { |
| 2053 // MethodDefinition | 2057 // MethodDefinition |
| 2054 // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' | 2058 // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' |
| 2055 // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' | 2059 // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' |
| 2056 if (!*is_computed_name) { | 2060 if (!*is_computed_name) { |
| 2057 checker->CheckProperty(name_token, kMethodProperty, method_kind, | 2061 checker->CheckProperty(name_token, kMethodProperty, method_kind, |
| 2062 classifier, | |
| 2058 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2063 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 2059 } | 2064 } |
| 2060 | 2065 |
| 2061 FunctionKind kind = is_generator | 2066 FunctionKind kind = is_generator |
| 2062 ? FunctionKind::kConciseGeneratorMethod | 2067 ? FunctionKind::kConciseGeneratorMethod |
| 2063 : is_async ? FunctionKind::kAsyncConciseMethod | 2068 : is_async ? FunctionKind::kAsyncConciseMethod |
| 2064 : FunctionKind::kConciseMethod; | 2069 : FunctionKind::kConciseMethod; |
| 2065 | 2070 |
| 2066 if (in_class && !IsStaticMethod(method_kind) && | 2071 if (in_class && !IsStaticMethod(method_kind) && |
| 2067 this->IsConstructor(*name)) { | 2072 this->IsConstructor(*name)) { |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 2098 *name = this->EmptyIdentifier(); | 2103 *name = this->EmptyIdentifier(); |
| 2099 bool dont_care = false; | 2104 bool dont_care = false; |
| 2100 name_token = peek(); | 2105 name_token = peek(); |
| 2101 | 2106 |
| 2102 name_expression = ParsePropertyName( | 2107 name_expression = ParsePropertyName( |
| 2103 name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier, | 2108 name, &dont_care, &dont_care, &dont_care, is_computed_name, classifier, |
| 2104 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2109 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 2105 | 2110 |
| 2106 if (!*is_computed_name) { | 2111 if (!*is_computed_name) { |
| 2107 checker->CheckProperty(name_token, kAccessorProperty, method_kind, | 2112 checker->CheckProperty(name_token, kAccessorProperty, method_kind, |
| 2113 classifier, | |
| 2108 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2114 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 2109 } | 2115 } |
| 2110 | 2116 |
| 2111 typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( | 2117 typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( |
| 2112 *name, scanner()->location(), kSkipFunctionNameCheck, | 2118 *name, scanner()->location(), kSkipFunctionNameCheck, |
| 2113 is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction, | 2119 is_get ? FunctionKind::kGetterFunction : FunctionKind::kSetterFunction, |
| 2114 kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), | 2120 kNoSourcePosition, FunctionLiteral::kAccessorOrMethod, language_mode(), |
| 2115 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2121 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
| 2116 | 2122 |
| 2117 // Make sure the name expression is a string since we need a Name for | 2123 // Make sure the name expression is a string since we need a Name for |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2402 return expression; | 2408 return expression; |
| 2403 } | 2409 } |
| 2404 | 2410 |
| 2405 // Now pending non-pattern expressions must be discarded. | 2411 // Now pending non-pattern expressions must be discarded. |
| 2406 arrow_formals_classifier.Discard(); | 2412 arrow_formals_classifier.Discard(); |
| 2407 | 2413 |
| 2408 CheckNoTailCallExpressions(classifier, CHECK_OK); | 2414 CheckNoTailCallExpressions(classifier, CHECK_OK); |
| 2409 | 2415 |
| 2410 if (IsValidPattern(expression) && peek() == Token::ASSIGN) { | 2416 if (IsValidPattern(expression) && peek() == Token::ASSIGN) { |
| 2411 classifier->ForgiveCoverInitializedNameError(); | 2417 classifier->ForgiveCoverInitializedNameError(); |
| 2418 classifier->ForgiveExpressionError(); | |
|
adamk
2016/08/18 20:35:22
Is this necessary? What fails if you don't "forgiv
gsathya
2016/08/19 20:11:18
As discussed offline -- leaving this here.
| |
| 2412 ValidateAssignmentPattern(classifier, CHECK_OK); | 2419 ValidateAssignmentPattern(classifier, CHECK_OK); |
| 2413 is_destructuring_assignment = true; | 2420 is_destructuring_assignment = true; |
| 2414 } else { | 2421 } else { |
| 2415 expression = this->CheckAndRewriteReferenceExpression( | 2422 expression = this->CheckAndRewriteReferenceExpression( |
| 2416 expression, lhs_beg_pos, scanner()->location().end_pos, | 2423 expression, lhs_beg_pos, scanner()->location().end_pos, |
| 2417 MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); | 2424 MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); |
| 2418 } | 2425 } |
| 2419 | 2426 |
| 2420 expression = this->MarkExpressionAsAssigned(expression); | 2427 expression = this->MarkExpressionAsAssigned(expression); |
| 2421 | 2428 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2432 ExpressionT right = | 2439 ExpressionT right = |
| 2433 this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK); | 2440 this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK); |
| 2434 CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK); | 2441 CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK); |
| 2435 Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK); | 2442 Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK); |
| 2436 classifier->Accumulate( | 2443 classifier->Accumulate( |
| 2437 &rhs_classifier, | 2444 &rhs_classifier, |
| 2438 ExpressionClassifier::ExpressionProductions | | 2445 ExpressionClassifier::ExpressionProductions | |
| 2439 ExpressionClassifier::CoverInitializedNameProduction | | 2446 ExpressionClassifier::CoverInitializedNameProduction | |
| 2440 ExpressionClassifier::AsyncArrowFormalParametersProduction); | 2447 ExpressionClassifier::AsyncArrowFormalParametersProduction); |
| 2441 | 2448 |
| 2449 if (!classifier->is_valid_expression()) | |
|
adamk
2016/08/18 20:35:22
Was this necessary? I wouldn't think you'd need to
gsathya
2016/08/19 20:11:18
Removed.
| |
| 2450 ReportClassifierError(classifier->expression_error()); | |
| 2451 | |
| 2442 // TODO(1231235): We try to estimate the set of properties set by | 2452 // TODO(1231235): We try to estimate the set of properties set by |
| 2443 // constructors. We define a new property whenever there is an | 2453 // constructors. We define a new property whenever there is an |
| 2444 // assignment to a property of 'this'. We should probably only add | 2454 // assignment to a property of 'this'. We should probably only add |
| 2445 // properties if we haven't seen them before. Otherwise we'll | 2455 // properties if we haven't seen them before. Otherwise we'll |
| 2446 // probably overestimate the number of properties. | 2456 // probably overestimate the number of properties. |
| 2447 if (op == Token::ASSIGN && this->IsThisProperty(expression)) { | 2457 if (op == Token::ASSIGN && this->IsThisProperty(expression)) { |
| 2448 function_state_->AddProperty(); | 2458 function_state_->AddProperty(); |
| 2449 } | 2459 } |
| 2450 | 2460 |
| 2451 this->CheckAssigningFunctionLiteralToProperty(expression, right); | 2461 this->CheckAssigningFunctionLiteralToProperty(expression, right); |
| (...skipping 1218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3670 } | 3680 } |
| 3671 } | 3681 } |
| 3672 | 3682 |
| 3673 | 3683 |
| 3674 #undef CHECK_OK | 3684 #undef CHECK_OK |
| 3675 #undef CHECK_OK_CUSTOM | 3685 #undef CHECK_OK_CUSTOM |
| 3676 | 3686 |
| 3677 template <typename Traits> | 3687 template <typename Traits> |
| 3678 void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( | 3688 void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( |
| 3679 Token::Value property, PropertyKind type, MethodKind method_type, | 3689 Token::Value property, PropertyKind type, MethodKind method_type, |
| 3680 bool* ok) { | 3690 ExpressionClassifier* classifier, bool* ok) { |
|
adamk
2016/08/18 20:35:22
Hmm, it's a little strange that this takes "ok" no
gsathya
2016/08/19 20:11:18
Yeah :/ It's the same with classifier being added
| |
| 3681 DCHECK(!IsStaticMethod(method_type)); | 3691 DCHECK(!IsStaticMethod(method_type)); |
| 3682 DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty); | 3692 DCHECK(!IsSpecialMethod(method_type) || type == kMethodProperty); |
| 3683 | 3693 |
| 3684 if (property == Token::SMI || property == Token::NUMBER) return; | 3694 if (property == Token::SMI || property == Token::NUMBER) return; |
| 3685 | 3695 |
| 3686 if (type == kValueProperty && IsProto()) { | 3696 if (type == kValueProperty && IsProto()) { |
| 3687 if (has_seen_proto_) { | 3697 if (has_seen_proto_) { |
| 3688 this->parser()->ReportMessage(MessageTemplate::kDuplicateProto); | 3698 classifier->RecordExpressionError(this->scanner()->location(), |
| 3689 *ok = false; | 3699 MessageTemplate::kDuplicateProto, |
| 3700 kSyntaxError); | |
| 3690 return; | 3701 return; |
| 3691 } | 3702 } |
| 3692 has_seen_proto_ = true; | 3703 has_seen_proto_ = true; |
| 3693 return; | |
| 3694 } | 3704 } |
| 3695 } | 3705 } |
| 3696 | 3706 |
| 3697 template <typename Traits> | 3707 template <typename Traits> |
| 3698 void ParserBase<Traits>::ClassLiteralChecker::CheckProperty( | 3708 void ParserBase<Traits>::ClassLiteralChecker::CheckProperty( |
| 3699 Token::Value property, PropertyKind type, MethodKind method_type, | 3709 Token::Value property, PropertyKind type, MethodKind method_type, |
| 3700 bool* ok) { | 3710 ExpressionClassifier* classifier, bool* ok) { |
| 3701 DCHECK(type == kMethodProperty || type == kAccessorProperty); | 3711 DCHECK(type == kMethodProperty || type == kAccessorProperty); |
| 3702 | 3712 |
| 3703 if (property == Token::SMI || property == Token::NUMBER) return; | 3713 if (property == Token::SMI || property == Token::NUMBER) return; |
| 3704 | 3714 |
| 3705 if (IsStaticMethod(method_type)) { | 3715 if (IsStaticMethod(method_type)) { |
| 3706 if (IsPrototype()) { | 3716 if (IsPrototype()) { |
| 3707 this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); | 3717 this->parser()->ReportMessage(MessageTemplate::kStaticPrototype); |
| 3708 *ok = false; | 3718 *ok = false; |
| 3709 return; | 3719 return; |
| 3710 } | 3720 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 3728 has_seen_constructor_ = true; | 3738 has_seen_constructor_ = true; |
| 3729 return; | 3739 return; |
| 3730 } | 3740 } |
| 3731 } | 3741 } |
| 3732 | 3742 |
| 3733 | 3743 |
| 3734 } // namespace internal | 3744 } // namespace internal |
| 3735 } // namespace v8 | 3745 } // namespace v8 |
| 3736 | 3746 |
| 3737 #endif // V8_PARSING_PARSER_BASE_H | 3747 #endif // V8_PARSING_PARSER_BASE_H |
| OLD | NEW |