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_PREPARSER_H | 5 #ifndef V8_PREPARSER_H |
6 #define V8_PREPARSER_H | 6 #define V8_PREPARSER_H |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/bailout-reason.h" | 10 #include "src/bailout-reason.h" |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
534 ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok); | 534 ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool* ok); |
535 void AddTemplateExpression(ExpressionT); | 535 void AddTemplateExpression(ExpressionT); |
536 | 536 |
537 // Checks if the expression is a valid reference expression (e.g., on the | 537 // Checks if the expression is a valid reference expression (e.g., on the |
538 // left-hand side of assignments). Although ruled out by ECMA as early errors, | 538 // left-hand side of assignments). Although ruled out by ECMA as early errors, |
539 // we allow calls for web compatibility and rewrite them to a runtime throw. | 539 // we allow calls for web compatibility and rewrite them to a runtime throw. |
540 ExpressionT CheckAndRewriteReferenceExpression( | 540 ExpressionT CheckAndRewriteReferenceExpression( |
541 ExpressionT expression, | 541 ExpressionT expression, |
542 Scanner::Location location, const char* message, bool* ok); | 542 Scanner::Location location, const char* message, bool* ok); |
543 | 543 |
544 // Used to detect duplicates in object literals. Each of the values | 544 // Used to validate property names in object literals and class literals |
545 // kGetterProperty, kSetterProperty and kValueProperty represents | |
546 // a type of object literal property. When parsing a property, its | |
547 // type value is stored in the DuplicateFinder for the property name. | |
548 // Values are chosen so that having intersection bits means the there is | |
549 // an incompatibility. | |
550 // I.e., you can add a getter to a property that already has a setter, since | |
551 // kGetterProperty and kSetterProperty doesn't intersect, but not if it | |
552 // already has a getter or a value. Adding the getter to an existing | |
553 // setter will store the value (kGetterProperty | kSetterProperty), which | |
554 // is incompatible with adding any further properties. | |
555 enum PropertyKind { | 545 enum PropertyKind { |
556 kNone = 0, | 546 kAccessorProperty = 1, |
557 // Bit patterns representing different object literal property types. | 547 kValueProperty = 2, |
558 kGetterProperty = 1, | 548 kMethodProperty = 3 |
559 kSetterProperty = 2, | |
560 kValueProperty = 7, | |
561 // Helper constants. | |
562 kValueFlag = 4 | |
563 }; | 549 }; |
564 | 550 |
565 // Validation per ECMA 262 - 11.1.5 "Object Initializer". | 551 // Validation per ES6 object literals and class literals. |
566 class ObjectLiteralChecker { | 552 class ObjectLiteralChecker { |
567 public: | 553 public: |
568 ObjectLiteralChecker(ParserBase* parser, StrictMode strict_mode) | 554 ObjectLiteralChecker(ParserBase* parser, bool in_class) |
569 : parser_(parser), | 555 : parser_(parser), in_class_(in_class), has_seen_special_(false) {} |
570 finder_(scanner()->unicode_cache()), | |
571 strict_mode_(strict_mode) {} | |
572 | 556 |
573 void CheckProperty(Token::Value property, PropertyKind type, bool* ok); | 557 void CheckProperty(Token::Value property, PropertyKind type, bool is_static, |
558 bool is_generator, bool* ok); | |
574 | 559 |
575 private: | 560 private: |
576 ParserBase* parser() const { return parser_; } | 561 ParserBase* parser() const { return parser_; } |
577 Scanner* scanner() const { return parser_->scanner(); } | 562 Scanner* scanner() const { return parser_->scanner(); } |
578 | 563 bool IsConstructor() { |
579 // Checks the type of conflict based on values coming from PropertyType. | 564 return scanner()->LiteralMatches("constructor", 11); |
580 bool HasConflict(PropertyKind type1, PropertyKind type2) { | |
581 return (type1 & type2) != 0; | |
582 } | 565 } |
583 bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) { | 566 bool IsProto() { return scanner()->LiteralMatches("__proto__", 9); } |
584 return ((type1 & type2) & kValueFlag) != 0; | 567 bool IsPrototype() { return scanner()->LiteralMatches("prototype", 9); } |
585 } | |
586 bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) { | |
587 return ((type1 ^ type2) & kValueFlag) != 0; | |
588 } | |
589 bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) { | |
590 return ((type1 | type2) & kValueFlag) == 0; | |
591 } | |
592 | 568 |
593 ParserBase* parser_; | 569 ParserBase* parser_; |
594 DuplicateFinder finder_; | 570 bool in_class_; |
595 StrictMode strict_mode_; | 571 |
572 // Used to keep track of constructor in classes and __proto__ in object | |
573 // literals. | |
574 bool has_seen_special_; | |
596 }; | 575 }; |
597 | 576 |
598 // If true, the next (and immediately following) function literal is | 577 // If true, the next (and immediately following) function literal is |
599 // preceded by a parenthesis. | 578 // preceded by a parenthesis. |
600 // Heuristically that means that the function will be called immediately, | 579 // Heuristically that means that the function will be called immediately, |
601 // so never lazily compile it. | 580 // so never lazily compile it. |
602 bool parenthesized_function_; | 581 bool parenthesized_function_; |
603 | 582 |
604 typename Traits::Type::Scope* scope_; // Scope stack. | 583 typename Traits::Type::Scope* scope_; // Scope stack. |
605 FunctionState* function_state_; // Function state stack. | 584 FunctionState* function_state_; // Function state stack. |
(...skipping 1462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2068 } | 2047 } |
2069 | 2048 |
2070 | 2049 |
2071 template <class Traits> | 2050 template <class Traits> |
2072 typename ParserBase<Traits>::ObjectLiteralPropertyT | 2051 typename ParserBase<Traits>::ObjectLiteralPropertyT |
2073 ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, | 2052 ParserBase<Traits>::ParsePropertyDefinition(ObjectLiteralChecker* checker, |
2074 bool in_class, bool is_static, | 2053 bool in_class, bool is_static, |
2075 bool* is_computed_name, | 2054 bool* is_computed_name, |
2076 bool* has_seen_constructor, | 2055 bool* has_seen_constructor, |
2077 bool* ok) { | 2056 bool* ok) { |
2078 DCHECK(!in_class || is_static || has_seen_constructor != NULL); | 2057 DCHECK(!in_class || is_static || has_seen_constructor != nullptr); |
2079 ExpressionT value = this->EmptyExpression(); | 2058 ExpressionT value = this->EmptyExpression(); |
2080 IdentifierT name = this->EmptyIdentifier(); | 2059 IdentifierT name = this->EmptyIdentifier(); |
2081 bool is_get = false; | 2060 bool is_get = false; |
2082 bool is_set = false; | 2061 bool is_set = false; |
2083 bool name_is_static = false; | 2062 bool name_is_static = false; |
2084 bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL); | 2063 bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL); |
2085 | 2064 |
2086 Token::Value name_token = peek(); | 2065 Token::Value name_token = peek(); |
2087 int next_pos = peek_position(); | 2066 int next_pos = peek_position(); |
2088 ExpressionT name_expression = ParsePropertyName( | 2067 ExpressionT name_expression = ParsePropertyName( |
2089 &name, &is_get, &is_set, &name_is_static, is_computed_name, | 2068 &name, &is_get, &is_set, &name_is_static, is_computed_name, |
2090 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2069 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2091 | 2070 |
2092 if (fni_ != NULL && !*is_computed_name) { | 2071 if (fni_ != nullptr && !*is_computed_name) { |
2093 this->PushLiteralName(fni_, name); | 2072 this->PushLiteralName(fni_, name); |
2094 } | 2073 } |
2095 | 2074 |
2096 if (!in_class && !is_generator && peek() == Token::COLON) { | 2075 if (!in_class && !is_generator && peek() == Token::COLON) { |
2097 // PropertyDefinition : PropertyName ':' AssignmentExpression | 2076 // PropertyDefinition : PropertyName ':' AssignmentExpression |
2098 if (!*is_computed_name && checker != NULL) { | 2077 if (!*is_computed_name && checker != nullptr) { |
2099 checker->CheckProperty(name_token, kValueProperty, | 2078 checker->CheckProperty(name_token, kValueProperty, is_static, |
2079 is_generator, | |
2100 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2080 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2101 } | 2081 } |
2102 Consume(Token::COLON); | 2082 Consume(Token::COLON); |
2103 value = this->ParseAssignmentExpression( | 2083 value = this->ParseAssignmentExpression( |
2104 true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2084 true, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2105 | 2085 |
2106 } else if (is_generator || | 2086 } else if (is_generator || |
2107 (allow_harmony_object_literals_ && peek() == Token::LPAREN)) { | 2087 (allow_harmony_object_literals_ && peek() == Token::LPAREN)) { |
2108 // Concise Method | 2088 // Concise Method |
2109 | 2089 if (!*is_computed_name && checker != nullptr) { |
2110 if (is_static && this->IsPrototype(name)) { | 2090 checker->CheckProperty(name_token, kMethodProperty, is_static, |
2111 ReportMessageAt(scanner()->location(), "static_prototype"); | 2091 is_generator, |
2112 *ok = false; | 2092 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2113 return this->EmptyObjectLiteralProperty(); | |
2114 } | 2093 } |
2115 | 2094 |
2116 FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod | 2095 FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod |
2117 : FunctionKind::kConciseMethod; | 2096 : FunctionKind::kConciseMethod; |
2118 | 2097 |
2119 if (in_class && !is_static && this->IsConstructor(name)) { | 2098 if (in_class && !is_static && this->IsConstructor(name)) { |
2120 if (is_generator) { | |
2121 ReportMessageAt(scanner()->location(), "constructor_special_method"); | |
2122 *ok = false; | |
2123 return this->EmptyObjectLiteralProperty(); | |
2124 } | |
2125 | |
2126 if (*has_seen_constructor) { | |
2127 ReportMessageAt(scanner()->location(), "duplicate_constructor"); | |
2128 *ok = false; | |
2129 return this->EmptyObjectLiteralProperty(); | |
2130 } | |
2131 | |
2132 *has_seen_constructor = true; | 2099 *has_seen_constructor = true; |
2133 kind = FunctionKind::kNormalFunction; | 2100 kind = FunctionKind::kNormalFunction; |
2134 } | 2101 } |
2135 | 2102 |
2136 if (!*is_computed_name && checker != NULL) { | |
2137 checker->CheckProperty(name_token, kValueProperty, | |
2138 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | |
2139 } | |
2140 | |
2141 value = this->ParseFunctionLiteral( | 2103 value = this->ParseFunctionLiteral( |
2142 name, scanner()->location(), | 2104 name, scanner()->location(), |
2143 false, // reserved words are allowed here | 2105 false, // reserved words are allowed here |
2144 kind, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, | 2106 kind, RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION, |
2145 FunctionLiteral::NORMAL_ARITY, | 2107 FunctionLiteral::NORMAL_ARITY, |
2146 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2108 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2147 | 2109 |
2148 return factory()->NewObjectLiteralProperty(name_expression, value, | 2110 return factory()->NewObjectLiteralProperty(name_expression, value, |
2149 ObjectLiteralProperty::COMPUTED, | 2111 ObjectLiteralProperty::COMPUTED, |
2150 is_static, *is_computed_name); | 2112 is_static, *is_computed_name); |
2151 | 2113 |
2152 } else if (in_class && name_is_static && !is_static) { | 2114 } else if (in_class && name_is_static && !is_static) { |
2153 // static MethodDefinition | 2115 // static MethodDefinition |
2154 return ParsePropertyDefinition(checker, true, true, is_computed_name, NULL, | 2116 return ParsePropertyDefinition(checker, true, true, is_computed_name, |
2155 ok); | 2117 nullptr, ok); |
2156 | 2118 |
2157 } else if (is_get || is_set) { | 2119 } else if (is_get || is_set) { |
2158 // Accessor | 2120 // Accessor |
2159 name = this->EmptyIdentifier(); | 2121 name = this->EmptyIdentifier(); |
2160 bool dont_care = false; | 2122 bool dont_care = false; |
2161 name_token = peek(); | 2123 name_token = peek(); |
2162 | 2124 |
2163 name_expression = ParsePropertyName( | 2125 name_expression = ParsePropertyName( |
2164 &name, &dont_care, &dont_care, &dont_care, is_computed_name, | 2126 &name, &dont_care, &dont_care, &dont_care, is_computed_name, |
2165 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2127 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2166 | 2128 |
2167 // Validate the property. | 2129 if (!*is_computed_name && checker != nullptr) { |
2168 if (is_static && this->IsPrototype(name)) { | 2130 checker->CheckProperty(name_token, kAccessorProperty, is_static, |
2169 ReportMessageAt(scanner()->location(), "static_prototype"); | 2131 is_generator, |
2170 *ok = false; | |
2171 return this->EmptyObjectLiteralProperty(); | |
2172 } else if (in_class && !is_static && this->IsConstructor(name)) { | |
2173 ReportMessageAt(scanner()->location(), "constructor_special_method"); | |
2174 *ok = false; | |
2175 return this->EmptyObjectLiteralProperty(); | |
2176 } | |
2177 if (!*is_computed_name && checker != NULL) { | |
2178 checker->CheckProperty(name_token, | |
2179 is_get ? kGetterProperty : kSetterProperty, | |
2180 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2132 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
2181 } | 2133 } |
2182 | 2134 |
2183 typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( | 2135 typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral( |
2184 name, scanner()->location(), | 2136 name, scanner()->location(), |
2185 false, // reserved words are allowed here | 2137 false, // reserved words are allowed here |
2186 FunctionKind::kNormalFunction, RelocInfo::kNoPosition, | 2138 FunctionKind::kNormalFunction, RelocInfo::kNoPosition, |
2187 FunctionLiteral::ANONYMOUS_EXPRESSION, | 2139 FunctionLiteral::ANONYMOUS_EXPRESSION, |
2188 is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY, | 2140 is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY, |
2189 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 2141 CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2227 bool* ok) { | 2179 bool* ok) { |
2228 // ObjectLiteral :: | 2180 // ObjectLiteral :: |
2229 // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' | 2181 // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}' |
2230 | 2182 |
2231 int pos = peek_position(); | 2183 int pos = peek_position(); |
2232 typename Traits::Type::PropertyList properties = | 2184 typename Traits::Type::PropertyList properties = |
2233 this->NewPropertyList(4, zone_); | 2185 this->NewPropertyList(4, zone_); |
2234 int number_of_boilerplate_properties = 0; | 2186 int number_of_boilerplate_properties = 0; |
2235 bool has_function = false; | 2187 bool has_function = false; |
2236 bool has_computed_names = false; | 2188 bool has_computed_names = false; |
2237 | 2189 ObjectLiteralChecker checker(this, false); |
2238 ObjectLiteralChecker checker(this, strict_mode()); | |
2239 | 2190 |
2240 Expect(Token::LBRACE, CHECK_OK); | 2191 Expect(Token::LBRACE, CHECK_OK); |
2241 | 2192 |
2242 while (peek() != Token::RBRACE) { | 2193 while (peek() != Token::RBRACE) { |
2243 if (fni_ != NULL) fni_->Enter(); | 2194 if (fni_ != nullptr) fni_->Enter(); |
2244 | 2195 |
2245 const bool in_class = false; | 2196 const bool in_class = false; |
2246 const bool is_static = false; | 2197 const bool is_static = false; |
2247 bool is_computed_name = false; | 2198 bool is_computed_name = false; |
2248 ObjectLiteralPropertyT property = this->ParsePropertyDefinition( | 2199 ObjectLiteralPropertyT property = this->ParsePropertyDefinition( |
2249 &checker, in_class, is_static, &is_computed_name, NULL, CHECK_OK); | 2200 &checker, in_class, is_static, &is_computed_name, nullptr, CHECK_OK); |
2250 | 2201 |
2251 if (is_computed_name) { | 2202 if (is_computed_name) { |
2252 has_computed_names = true; | 2203 has_computed_names = true; |
2253 } | 2204 } |
2254 | 2205 |
2255 // Mark top-level object literals that contain function literals and | 2206 // Mark top-level object literals that contain function literals and |
2256 // pretenure the literal so it can be added as a constant function | 2207 // pretenure the literal so it can be added as a constant function |
2257 // property. (Parser only.) | 2208 // property. (Parser only.) |
2258 this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property, | 2209 this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property, |
2259 &has_function); | 2210 &has_function); |
2260 | 2211 |
2261 // Count CONSTANT or COMPUTED properties to maintain the enumeration order. | 2212 // Count CONSTANT or COMPUTED properties to maintain the enumeration order. |
2262 if (!has_computed_names && this->IsBoilerplateProperty(property)) { | 2213 if (!has_computed_names && this->IsBoilerplateProperty(property)) { |
2263 number_of_boilerplate_properties++; | 2214 number_of_boilerplate_properties++; |
2264 } | 2215 } |
2265 properties->Add(property, zone()); | 2216 properties->Add(property, zone()); |
2266 | 2217 |
2267 if (peek() != Token::RBRACE) { | 2218 if (peek() != Token::RBRACE) { |
2268 // Need {} because of the CHECK_OK macro. | 2219 // Need {} because of the CHECK_OK macro. |
2269 Expect(Token::COMMA, CHECK_OK); | 2220 Expect(Token::COMMA, CHECK_OK); |
2270 } | 2221 } |
2271 | 2222 |
2272 if (fni_ != NULL) { | 2223 if (fni_ != nullptr) { |
2273 fni_->Infer(); | 2224 fni_->Infer(); |
2274 fni_->Leave(); | 2225 fni_->Leave(); |
2275 } | 2226 } |
2276 } | 2227 } |
2277 Expect(Token::RBRACE, CHECK_OK); | 2228 Expect(Token::RBRACE, CHECK_OK); |
2278 | 2229 |
2279 // Computation of literal_index must happen before pre parse bailout. | 2230 // Computation of literal_index must happen before pre parse bailout. |
2280 int literal_index = function_state_->NextMaterializedLiteralIndex(); | 2231 int literal_index = function_state_->NextMaterializedLiteralIndex(); |
2281 | 2232 |
2282 return factory()->NewObjectLiteral(properties, | 2233 return factory()->NewObjectLiteral(properties, |
(...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3034 } | 2985 } |
3035 } | 2986 } |
3036 | 2987 |
3037 | 2988 |
3038 #undef CHECK_OK | 2989 #undef CHECK_OK |
3039 #undef CHECK_OK_CUSTOM | 2990 #undef CHECK_OK_CUSTOM |
3040 | 2991 |
3041 | 2992 |
3042 template <typename Traits> | 2993 template <typename Traits> |
3043 void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( | 2994 void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( |
3044 Token::Value property, PropertyKind type, bool* ok) { | 2995 Token::Value property, PropertyKind type, bool is_static, bool is_generator, |
3045 int old; | 2996 bool* ok) { |
3046 if (property == Token::NUMBER) { | 2997 DCHECK(in_class_ || !is_static); |
3047 old = scanner()->FindNumber(&finder_, type); | 2998 DCHECK(!in_class_ || type != kValueProperty); |
3048 } else { | 2999 DCHECK(!is_generator || type == kMethodProperty); |
3049 old = scanner()->FindSymbol(&finder_, type); | 3000 |
3050 } | 3001 if (property == Token::NUMBER) return; |
3051 PropertyKind old_type = static_cast<PropertyKind>(old); | 3002 |
3052 if (HasConflict(old_type, type)) { | 3003 if (in_class_) { |
adamk
2015/01/24 00:18:07
Did you consider having two separate checkers, one
| |
3053 if (IsDataDataConflict(old_type, type)) { | 3004 if (is_static) { |
3054 // Both are data properties. | 3005 if (IsPrototype()) { |
3055 if (strict_mode_ == SLOPPY) return; | 3006 parser()->ReportMessage("static_prototype"); |
3056 parser()->ReportMessage("strict_duplicate_property"); | 3007 *ok = false; |
3057 } else if (IsDataAccessorConflict(old_type, type)) { | 3008 return; |
3058 // Both a data and an accessor property with the same name. | 3009 } |
3059 parser()->ReportMessage("accessor_data_property"); | 3010 } else if (IsConstructor()) { |
3060 } else { | 3011 if (is_generator || type == kAccessorProperty) { |
3061 DCHECK(IsAccessorAccessorConflict(old_type, type)); | 3012 parser()->ReportMessage("constructor_special_method"); |
3062 // Both accessors of the same type. | 3013 *ok = false; |
3063 parser()->ReportMessage("accessor_get_set"); | 3014 return; |
3015 } | |
3016 if (has_seen_special_) { | |
3017 parser()->ReportMessage("duplicate_constructor"); | |
3018 *ok = false; | |
3019 return; | |
3020 } | |
3021 has_seen_special_ = true; | |
3022 return; | |
3064 } | 3023 } |
3065 *ok = false; | 3024 } else if (type == kValueProperty && IsProto()) { |
3025 if (has_seen_special_) { | |
3026 parser()->ReportMessage("duplicate_proto"); | |
3027 *ok = false; | |
3028 return; | |
3029 } | |
3030 has_seen_special_ = true; | |
3031 return; | |
3066 } | 3032 } |
3067 } | 3033 } |
3068 } } // v8::internal | 3034 } } // v8::internal |
3069 | 3035 |
3070 #endif // V8_PREPARSER_H | 3036 #endif // V8_PREPARSER_H |
OLD | NEW |