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 #include "src/parsing/parser.h" | 5 #include "src/parsing/parser.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/ast/ast-expression-rewriter.h" | 10 #include "src/ast/ast-expression-rewriter.h" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 DCHECK_NULL(cached_parse_data_); | 157 DCHECK_NULL(cached_parse_data_); |
158 if (consume_cached_parse_data()) { | 158 if (consume_cached_parse_data()) { |
159 if (allow_lazy_) { | 159 if (allow_lazy_) { |
160 cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); | 160 cached_parse_data_ = ParseData::FromCachedData(*info->cached_data()); |
161 if (cached_parse_data_ != nullptr) return; | 161 if (cached_parse_data_ != nullptr) return; |
162 } | 162 } |
163 compile_options_ = ScriptCompiler::kNoCompileOptions; | 163 compile_options_ = ScriptCompiler::kNoCompileOptions; |
164 } | 164 } |
165 } | 165 } |
166 | 166 |
167 Expression* Parser::CallClassFieldInitializer(Scope* scope, | |
168 Expression* this_expr) { | |
169 // This produces the expression | |
170 // `.class_field_intializer(this_expr)`, where '.class_field_intializer' is | |
171 // the name | |
172 // of a synthetic variable. | |
173 // 'this_expr' will be 'this' in a base constructor and the result of calling | |
174 // 'super' in a derived one. | |
175 const AstRawString* init_fn_name = | |
176 ast_value_factory()->dot_class_field_init_string(); | |
177 VariableProxy* init_fn_proxy = scope->NewUnresolved(factory(), init_fn_name); | |
178 ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); | |
179 args->Add(init_fn_proxy, zone()); | |
180 args->Add(this_expr, zone()); | |
181 return factory()->NewCallRuntime(Runtime::kInlineCall, args, | |
182 kNoSourcePosition); | |
183 } | |
184 | |
185 Expression* Parser::RewriteSuperCall(Expression* super_call) { | |
186 // TODO(bakkot) find a way to avoid this for classes without fields. | |
187 if (!allow_harmony_class_fields()) { | |
188 return super_call; | |
189 } | |
190 // This turns a super call `super()` into a do expression of the form | |
191 // do { | |
192 // tmp x = super(); | |
193 // if (.class-field-init) | |
194 // .class-field-init(x) | |
195 // x; // This isn't actually present; our do-expression representation | |
196 // allows specifying that the expression returns x directly. | |
197 // } | |
198 Variable* var_tmp = | |
199 scope()->NewTemporary(ast_value_factory()->empty_string()); | |
200 Block* block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); | |
201 Assignment* assignment = factory()->NewAssignment( | |
202 Token::ASSIGN, factory()->NewVariableProxy(var_tmp), super_call, | |
203 kNoSourcePosition); | |
204 block->statements()->Add( | |
205 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | |
206 const AstRawString* init_fn_name = | |
207 ast_value_factory()->dot_class_field_init_string(); | |
208 VariableProxy* init_fn_proxy = | |
209 scope()->NewUnresolved(factory(), init_fn_name); | |
210 Expression* condition = init_fn_proxy; | |
211 Statement* initialize = factory()->NewExpressionStatement( | |
212 CallClassFieldInitializer(scope(), factory()->NewVariableProxy(var_tmp)), | |
213 kNoSourcePosition); | |
214 IfStatement* if_statement = factory()->NewIfStatement( | |
215 condition, initialize, factory()->NewEmptyStatement(kNoSourcePosition), | |
216 kNoSourcePosition); | |
217 block->statements()->Add(if_statement, zone()); | |
218 return factory()->NewDoExpression(block, var_tmp, kNoSourcePosition); | |
219 } | |
220 | |
221 FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, | 167 FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name, |
222 bool call_super, | 168 bool call_super, |
223 bool requires_class_field_init, | |
224 int pos, int end_pos, | 169 int pos, int end_pos, |
225 LanguageMode language_mode) { | 170 LanguageMode language_mode) { |
226 int materialized_literal_count = -1; | 171 int materialized_literal_count = -1; |
227 int expected_property_count = -1; | 172 int expected_property_count = -1; |
228 const int parameter_count = 0; | 173 const int parameter_count = 0; |
229 if (name == nullptr) name = ast_value_factory()->empty_string(); | 174 if (name == nullptr) name = ast_value_factory()->empty_string(); |
230 | 175 |
231 FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor | 176 FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor |
232 : FunctionKind::kDefaultBaseConstructor; | 177 : FunctionKind::kDefaultBaseConstructor; |
233 DeclarationScope* function_scope = NewFunctionScope(kind); | 178 DeclarationScope* function_scope = NewFunctionScope(kind); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 expected_property_count = function_state.expected_property_count(); | 213 expected_property_count = function_state.expected_property_count(); |
269 } | 214 } |
270 | 215 |
271 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | 216 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( |
272 name, function_scope, body, materialized_literal_count, | 217 name, function_scope, body, materialized_literal_count, |
273 expected_property_count, parameter_count, parameter_count, | 218 expected_property_count, parameter_count, parameter_count, |
274 FunctionLiteral::kNoDuplicateParameters, | 219 FunctionLiteral::kNoDuplicateParameters, |
275 FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, | 220 FunctionLiteral::kAnonymousExpression, default_eager_compile_hint(), pos, |
276 true, GetNextFunctionLiteralId()); | 221 true, GetNextFunctionLiteralId()); |
277 | 222 |
278 function_literal->set_requires_class_field_init(requires_class_field_init); | |
279 | |
280 return function_literal; | 223 return function_literal; |
281 } | 224 } |
282 | 225 |
283 // ---------------------------------------------------------------------------- | 226 // ---------------------------------------------------------------------------- |
284 // The CHECK_OK macro is a convenient macro to enforce error | 227 // The CHECK_OK macro is a convenient macro to enforce error |
285 // handling for functions that may fail (by returning !*ok). | 228 // handling for functions that may fail (by returning !*ok). |
286 // | 229 // |
287 // CAUTION: This macro appends extra statements after a call, | 230 // CAUTION: This macro appends extra statements after a call, |
288 // thus it must never be used where only a single statement | 231 // thus it must never be used where only a single statement |
289 // is correct (e.g. an if statement branch w/o braces)! | 232 // is correct (e.g. an if statement branch w/o braces)! |
(...skipping 698 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
988 DCHECK(expression->IsFunctionLiteral()); | 931 DCHECK(expression->IsFunctionLiteral()); |
989 result = expression->AsFunctionLiteral(); | 932 result = expression->AsFunctionLiteral(); |
990 } else { | 933 } else { |
991 ok = false; | 934 ok = false; |
992 } | 935 } |
993 } | 936 } |
994 } | 937 } |
995 } else if (IsDefaultConstructor(kind)) { | 938 } else if (IsDefaultConstructor(kind)) { |
996 DCHECK_EQ(scope(), outer); | 939 DCHECK_EQ(scope(), outer); |
997 bool is_subclass_constructor = IsSubclassConstructor(kind); | 940 bool is_subclass_constructor = IsSubclassConstructor(kind); |
998 result = DefaultConstructor( | 941 result = DefaultConstructor(raw_name, is_subclass_constructor, |
999 raw_name, is_subclass_constructor, info->requires_class_field_init(), | 942 info->start_position(), info->end_position(), |
1000 info->start_position(), info->end_position(), info->language_mode()); | 943 info->language_mode()); |
1001 if (!is_subclass_constructor && info->requires_class_field_init()) { | |
1002 result = InsertClassFieldInitializer(result); | |
1003 } | |
1004 } else if (info->is_class_field_initializer()) { | |
1005 Handle<SharedFunctionInfo> shared_info = info->shared_info(); | |
1006 DCHECK(!shared_info.is_null()); | |
1007 if (shared_info->length() == 0) { | |
1008 result = ParseClassFieldForInitializer( | |
1009 info->start_position() != info->end_position(), &ok); | |
1010 } else { | |
1011 result = SynthesizeClassFieldInitializer(shared_info->length()); | |
1012 } | |
1013 } else { | 944 } else { |
1014 result = ParseFunctionLiteral( | 945 result = ParseFunctionLiteral( |
1015 raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, | 946 raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck, kind, |
1016 kNoSourcePosition, function_type, info->language_mode(), &ok); | 947 kNoSourcePosition, function_type, info->language_mode(), &ok); |
1017 if (info->requires_class_field_init()) { | |
1018 result = InsertClassFieldInitializer(result); | |
1019 } | |
1020 } | 948 } |
1021 // Make sure the results agree. | 949 // Make sure the results agree. |
1022 DCHECK(ok == (result != nullptr)); | 950 DCHECK(ok == (result != nullptr)); |
1023 } | 951 } |
1024 | 952 |
1025 // Make sure the target stack is empty. | 953 // Make sure the target stack is empty. |
1026 DCHECK_NULL(target_stack_); | 954 DCHECK_NULL(target_stack_); |
1027 DCHECK_IMPLIES(result, | 955 DCHECK_IMPLIES(result, |
1028 info->function_literal_id() == result->function_literal_id()); | 956 info->function_literal_id() == result->function_literal_id()); |
1029 return result; | 957 return result; |
(...skipping 2301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3331 } else { | 3259 } else { |
3332 statement = factory()->NewEmptyStatement(kNoSourcePosition); | 3260 statement = factory()->NewEmptyStatement(kNoSourcePosition); |
3333 } | 3261 } |
3334 result->Set(kFunctionNameAssignmentIndex, statement); | 3262 result->Set(kFunctionNameAssignmentIndex, statement); |
3335 } | 3263 } |
3336 | 3264 |
3337 MarkCollectedTailCallExpressions(); | 3265 MarkCollectedTailCallExpressions(); |
3338 return result; | 3266 return result; |
3339 } | 3267 } |
3340 | 3268 |
3341 Expression* Parser::InstallHomeObject(Expression* function_literal, | |
3342 Expression* home_object) { | |
3343 Block* do_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition); | |
3344 Variable* result_var = | |
3345 scope()->NewTemporary(ast_value_factory()->empty_string()); | |
3346 DoExpression* do_expr = | |
3347 factory()->NewDoExpression(do_block, result_var, kNoSourcePosition); | |
3348 Assignment* init = factory()->NewAssignment( | |
3349 Token::ASSIGN, factory()->NewVariableProxy(result_var), function_literal, | |
3350 kNoSourcePosition); | |
3351 do_block->statements()->Add( | |
3352 factory()->NewExpressionStatement(init, kNoSourcePosition), zone()); | |
3353 Property* home_object_property = factory()->NewProperty( | |
3354 factory()->NewVariableProxy(result_var), | |
3355 factory()->NewSymbolLiteral("home_object_symbol", kNoSourcePosition), | |
3356 kNoSourcePosition); | |
3357 Assignment* assignment = factory()->NewAssignment( | |
3358 Token::ASSIGN, home_object_property, home_object, kNoSourcePosition); | |
3359 do_block->statements()->Add( | |
3360 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | |
3361 return do_expr; | |
3362 } | |
3363 | |
3364 const AstRawString* ClassFieldVariableName(bool is_name, | |
3365 AstValueFactory* ast_value_factory, | |
3366 int index) { | |
3367 std::string name = | |
3368 ".class-field-" + std::to_string(index) + (is_name ? "-name" : "-func"); | |
3369 return ast_value_factory->GetOneByteString(name.c_str()); | |
3370 } | |
3371 | |
3372 FunctionLiteral* Parser::SynthesizeClassFieldInitializer(int count) { | |
3373 DCHECK(count > 0); | |
3374 // Makes a function which reads the names and initializers for each class | |
3375 // field out of deterministically named local variables and sets each property | |
3376 // to the result of evaluating its corresponding initializer in turn. | |
3377 | |
3378 // This produces a function which looks like | |
3379 // function () { | |
3380 // this[.class-field-0-name] = .class-field-0-func(); | |
3381 // this[.class-field-1-name] = .class-field-1-func(); | |
3382 // [...] | |
3383 // this[.class-field-n-name] = .class-field-n-func(); | |
3384 // return this; | |
3385 // } | |
3386 // except that it performs defineProperty, so that instead of '=' it has | |
3387 // %DefineDataPropertyInLiteral(this, .class-field-0-name, | |
3388 // .class-field-0-func(), | |
3389 // DONT_ENUM, false) | |
3390 | |
3391 RaiseLanguageMode(STRICT); | |
3392 FunctionKind kind = FunctionKind::kConciseMethod; | |
3393 DeclarationScope* initializer_scope = NewFunctionScope(kind); | |
3394 SetLanguageMode(initializer_scope, language_mode()); | |
3395 initializer_scope->set_start_position(scanner()->location().end_pos); | |
3396 initializer_scope->set_end_position(scanner()->location().end_pos); | |
3397 FunctionState initializer_state(&function_state_, &scope_state_, | |
3398 initializer_scope); | |
3399 ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(count, zone()); | |
3400 for (int i = 0; i < count; ++i) { | |
3401 const AstRawString* name = | |
3402 ClassFieldVariableName(true, ast_value_factory(), i); | |
3403 VariableProxy* name_proxy = scope()->NewUnresolved(factory(), name); | |
3404 const AstRawString* function_name = | |
3405 ClassFieldVariableName(false, ast_value_factory(), i); | |
3406 VariableProxy* function_proxy = | |
3407 scope()->NewUnresolved(factory(), function_name); | |
3408 ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(2, zone()); | |
3409 args->Add(function_proxy, zone()); | |
3410 args->Add(ThisExpression(kNoSourcePosition), zone()); | |
3411 Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall, args, | |
3412 kNoSourcePosition); | |
3413 ZoneList<Expression*>* define_property_args = | |
3414 new (zone()) ZoneList<Expression*>(5, zone()); | |
3415 define_property_args->Add(ThisExpression(kNoSourcePosition), zone()); | |
3416 define_property_args->Add(name_proxy, zone()); | |
3417 define_property_args->Add(call, zone()); | |
3418 define_property_args->Add( | |
3419 factory()->NewNumberLiteral(DONT_ENUM, kNoSourcePosition), zone()); | |
3420 define_property_args->Add( | |
3421 factory()->NewNumberLiteral( | |
3422 false, // TODO(bakkot) function name inference a la class { x = | |
3423 // function(){}; static y = function(){}; } | |
3424 kNoSourcePosition), | |
3425 zone()); | |
3426 body->Add(factory()->NewExpressionStatement( | |
3427 factory()->NewCallRuntime( | |
3428 Runtime::kDefineDataProperty, | |
3429 define_property_args, // TODO(bakkot) verify that this is | |
3430 // the same as object_define_property | |
3431 kNoSourcePosition), | |
3432 kNoSourcePosition), | |
3433 zone()); | |
3434 } | |
3435 body->Add(factory()->NewReturnStatement(ThisExpression(kNoSourcePosition), | |
3436 kNoSourcePosition), | |
3437 zone()); | |
3438 FunctionLiteral* function_literal = factory()->NewFunctionLiteral( | |
3439 ast_value_factory()->empty_string(), initializer_scope, body, | |
3440 initializer_state.materialized_literal_count(), | |
3441 initializer_state.expected_property_count(), 0, count, | |
3442 FunctionLiteral::kNoDuplicateParameters, | |
3443 FunctionLiteral::kAnonymousExpression, | |
3444 FunctionLiteral::kShouldLazyCompile, initializer_scope->start_position(), | |
3445 true, GetNextFunctionLiteralId()); | |
3446 function_literal->set_is_class_field_initializer(true); | |
3447 return function_literal; | |
3448 } | |
3449 | |
3450 FunctionLiteral* Parser::InsertClassFieldInitializer( | |
3451 FunctionLiteral* constructor) { | |
3452 Statement* call_initializer = factory()->NewExpressionStatement( | |
3453 CallClassFieldInitializer( | |
3454 constructor->scope(), | |
3455 constructor->scope()->NewUnresolved( | |
3456 factory(), ast_value_factory()->this_string(), kNoSourcePosition, | |
3457 THIS_VARIABLE)), | |
3458 kNoSourcePosition); | |
3459 constructor->body()->InsertAt(0, call_initializer, zone()); | |
3460 return constructor; | |
3461 } | |
3462 | |
3463 // If a class name is specified, this method declares the class variable | |
3464 // and sets class_info->proxy to point to that name. | |
3465 void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope, | 3269 void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope, |
3466 ClassInfo* class_info, int class_token_pos, | 3270 ClassInfo* class_info, int class_token_pos, |
3467 bool* ok) { | 3271 bool* ok) { |
3468 #ifdef DEBUG | 3272 #ifdef DEBUG |
3469 scope()->SetScopeName(name); | 3273 scope()->SetScopeName(name); |
3470 #endif | 3274 #endif |
3471 | 3275 |
3472 if (name != nullptr) { | 3276 if (name != nullptr) { |
3473 class_info->proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE); | 3277 class_info->proxy = factory()->NewVariableProxy(name, NORMAL_VARIABLE); |
3474 Declaration* declaration = factory()->NewVariableDeclaration( | 3278 Declaration* declaration = factory()->NewVariableDeclaration( |
3475 class_info->proxy, block_scope, class_token_pos); | 3279 class_info->proxy, block_scope, class_token_pos); |
3476 Declare(declaration, DeclarationDescriptor::NORMAL, CONST, | 3280 Declare(declaration, DeclarationDescriptor::NORMAL, CONST, |
3477 Variable::DefaultInitializationFlag(CONST), ok); | 3281 Variable::DefaultInitializationFlag(CONST), ok); |
3478 } | 3282 } |
3479 } | 3283 } |
3480 | 3284 |
3481 // This method declares a property of the given class. It updates the | 3285 // This method declares a property of the given class. It updates the |
3482 // following fields of class_info, as appropriate: | 3286 // following fields of class_info, as appropriate: |
3483 // - constructor | 3287 // - constructor |
3484 // - static_initializer_var | |
3485 // - instance_field_initializers | |
3486 // - properties | 3288 // - properties |
3487 void Parser::DeclareClassProperty(const AstRawString* class_name, | 3289 void Parser::DeclareClassProperty(const AstRawString* class_name, |
3488 ClassLiteralProperty* property, | 3290 ClassLiteralProperty* property, |
3489 ClassLiteralProperty::Kind kind, | 3291 ClassLiteralProperty::Kind kind, |
3490 bool is_static, bool is_constructor, | 3292 bool is_static, bool is_constructor, |
3491 ClassInfo* class_info, bool* ok) { | 3293 ClassInfo* class_info, bool* ok) { |
3492 if (is_constructor) { | 3294 if (is_constructor) { |
3493 DCHECK(!class_info->constructor); | 3295 DCHECK(!class_info->constructor); |
3494 class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral(); | 3296 class_info->constructor = GetPropertyValue(property)->AsFunctionLiteral(); |
3495 DCHECK_NOT_NULL(class_info->constructor); | 3297 DCHECK_NOT_NULL(class_info->constructor); |
3496 class_info->constructor->set_raw_name( | 3298 class_info->constructor->set_raw_name( |
3497 class_name != nullptr ? class_name | 3299 class_name != nullptr ? class_name |
3498 : ast_value_factory()->empty_string()); | 3300 : ast_value_factory()->empty_string()); |
3499 return; | 3301 return; |
3500 } | 3302 } |
3501 | 3303 |
3502 if (property->kind() == ClassLiteralProperty::FIELD) { | 3304 if (property->kind() == ClassLiteralProperty::FIELD) { |
3503 DCHECK(allow_harmony_class_fields()); | 3305 DCHECK(allow_harmony_class_fields()); |
3504 if (property->is_static()) { | 3306 // TODO(littledan): Implement class fields |
3505 if (class_info->static_initializer_var == nullptr) { | |
3506 class_info->static_initializer_var = | |
3507 NewTemporary(ast_value_factory()->empty_string()); | |
3508 } | |
3509 // TODO(bakkot) only do this conditionally | |
3510 Expression* function = InstallHomeObject( | |
3511 property->value(), | |
3512 factory()->NewVariableProxy(class_info->static_initializer_var)); | |
3513 ZoneList<Expression*>* args = | |
3514 new (zone()) ZoneList<Expression*>(2, zone()); | |
3515 args->Add(function, zone()); | |
3516 args->Add(factory()->NewVariableProxy(class_info->static_initializer_var), | |
3517 zone()); | |
3518 Expression* call = factory()->NewCallRuntime(Runtime::kInlineCall, args, | |
3519 kNoSourcePosition); | |
3520 property->set_value(call); | |
3521 } else { | |
3522 // if (is_computed_name) { // TODO(bakkot) figure out why this is | |
3523 // necessary for non-computed names in full-codegen | |
3524 ZoneList<Expression*>* to_name_args = | |
3525 new (zone()) ZoneList<Expression*>(1, zone()); | |
3526 to_name_args->Add(property->key(), zone()); | |
3527 property->set_key(factory()->NewCallRuntime( | |
3528 Runtime::kToName, to_name_args, kNoSourcePosition)); | |
3529 //} | |
3530 const AstRawString* name = ClassFieldVariableName( | |
3531 true, ast_value_factory(), | |
3532 class_info->instance_field_initializers->length()); | |
3533 VariableProxy* name_proxy = | |
3534 factory()->NewVariableProxy(name, NORMAL_VARIABLE); | |
3535 Declaration* name_declaration = factory()->NewVariableDeclaration( | |
3536 name_proxy, scope(), kNoSourcePosition); | |
3537 Variable* name_var = | |
3538 Declare(name_declaration, DeclarationDescriptor::NORMAL, CONST, | |
3539 kNeedsInitialization, ok, scope()); | |
3540 DCHECK(*ok); | |
3541 if (!*ok) return; | |
3542 class_info->instance_field_initializers->Add(property->value(), zone()); | |
3543 property->set_value(factory()->NewVariableProxy(name_var)); | |
3544 } | |
3545 } | 3307 } |
3546 class_info->properties->Add(property, zone()); | 3308 class_info->properties->Add(property, zone()); |
3547 } | 3309 } |
3548 | 3310 |
3549 // This method rewrites a class literal into a do-expression. | 3311 // This method rewrites a class literal into a do-expression. |
3550 // It uses the following fields of class_info: | 3312 // It uses the following fields of class_info: |
3551 // - constructor (if missing, it updates it with a default constructor) | 3313 // - constructor (if missing, it updates it with a default constructor) |
3552 // - proxy | 3314 // - proxy |
3553 // - extends | 3315 // - extends |
3554 // - static_initializer_var | |
3555 // - instance_field_initializers | |
3556 // - properties | 3316 // - properties |
3557 // - has_name_static_property | 3317 // - has_name_static_property |
3558 // - has_static_computed_names | 3318 // - has_static_computed_names |
3559 Expression* Parser::RewriteClassLiteral(const AstRawString* name, | 3319 Expression* Parser::RewriteClassLiteral(const AstRawString* name, |
3560 ClassInfo* class_info, int pos, | 3320 ClassInfo* class_info, int pos, |
3561 bool* ok) { | 3321 bool* ok) { |
3562 int end_pos = scanner()->location().end_pos; | 3322 int end_pos = scanner()->location().end_pos; |
3563 Block* do_block = factory()->NewBlock(nullptr, 1, false, pos); | 3323 Block* do_block = factory()->NewBlock(nullptr, 1, false, pos); |
3564 Variable* result_var = NewTemporary(ast_value_factory()->empty_string()); | 3324 Variable* result_var = NewTemporary(ast_value_factory()->empty_string()); |
3565 DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos); | 3325 DoExpression* do_expr = factory()->NewDoExpression(do_block, result_var, pos); |
3566 | 3326 |
3567 bool has_extends = class_info->extends != nullptr; | 3327 bool has_extends = class_info->extends != nullptr; |
3568 bool has_instance_fields = | |
3569 class_info->instance_field_initializers->length() > 0; | |
3570 DCHECK(!has_instance_fields || allow_harmony_class_fields()); | |
3571 bool has_default_constructor = class_info->constructor == nullptr; | 3328 bool has_default_constructor = class_info->constructor == nullptr; |
3572 if (has_default_constructor) { | 3329 if (has_default_constructor) { |
3573 class_info->constructor = | 3330 class_info->constructor = DefaultConstructor( |
3574 DefaultConstructor(name, has_extends, has_instance_fields, pos, end_pos, | 3331 name, has_extends, pos, end_pos, scope()->language_mode()); |
3575 scope()->language_mode()); | |
3576 } | 3332 } |
3577 | 3333 |
3578 if (has_instance_fields && !has_extends) { | |
3579 class_info->constructor = | |
3580 InsertClassFieldInitializer(class_info->constructor); | |
3581 class_info->constructor->set_requires_class_field_init(true); | |
3582 } // The derived case is handled by rewriting super calls. | |
3583 | |
3584 scope()->set_end_position(end_pos); | 3334 scope()->set_end_position(end_pos); |
3585 | 3335 |
3586 if (name != nullptr) { | 3336 if (name != nullptr) { |
3587 DCHECK_NOT_NULL(class_info->proxy); | 3337 DCHECK_NOT_NULL(class_info->proxy); |
3588 class_info->proxy->var()->set_initializer_position(end_pos); | 3338 class_info->proxy->var()->set_initializer_position(end_pos); |
3589 } | 3339 } |
3590 | 3340 |
3591 ClassLiteral* class_literal = factory()->NewClassLiteral( | 3341 ClassLiteral* class_literal = factory()->NewClassLiteral( |
3592 class_info->proxy, class_info->extends, class_info->constructor, | 3342 class_info->proxy, class_info->extends, class_info->constructor, |
3593 class_info->properties, pos, end_pos, | 3343 class_info->properties, pos, end_pos, |
3594 class_info->has_name_static_property, | 3344 class_info->has_name_static_property, |
3595 class_info->has_static_computed_names); | 3345 class_info->has_static_computed_names); |
3596 | 3346 |
3597 if (class_info->static_initializer_var != nullptr) { | |
3598 class_literal->set_static_initializer_proxy( | |
3599 factory()->NewVariableProxy(class_info->static_initializer_var)); | |
3600 } | |
3601 | |
3602 do_block->statements()->Add( | 3347 do_block->statements()->Add( |
3603 factory()->NewExpressionStatement( | 3348 factory()->NewExpressionStatement( |
3604 factory()->NewAssignment(Token::ASSIGN, | 3349 factory()->NewAssignment(Token::ASSIGN, |
3605 factory()->NewVariableProxy(result_var), | 3350 factory()->NewVariableProxy(result_var), |
3606 class_literal, kNoSourcePosition), | 3351 class_literal, kNoSourcePosition), |
3607 pos), | 3352 pos), |
3608 zone()); | 3353 zone()); |
3609 if (allow_harmony_class_fields() && | |
3610 (has_instance_fields || (has_extends && !has_default_constructor))) { | |
3611 // Default constructors for derived classes without fields will not try to | |
3612 // read this variable, so there's no need to create it. | |
3613 const AstRawString* init_fn_name = | |
3614 ast_value_factory()->dot_class_field_init_string(); | |
3615 Variable* init_fn_var = scope()->DeclareLocal( | |
3616 init_fn_name, CONST, kCreatedInitialized, NORMAL_VARIABLE); | |
3617 Expression* initializer = | |
3618 has_instance_fields | |
3619 ? static_cast<Expression*>(SynthesizeClassFieldInitializer( | |
3620 class_info->instance_field_initializers->length())) | |
3621 : factory()->NewBooleanLiteral(false, kNoSourcePosition); | |
3622 Assignment* assignment = factory()->NewAssignment( | |
3623 Token::INIT, factory()->NewVariableProxy(init_fn_var), initializer, | |
3624 kNoSourcePosition); | |
3625 do_block->statements()->Add( | |
3626 factory()->NewExpressionStatement(assignment, kNoSourcePosition), | |
3627 zone()); | |
3628 } | |
3629 for (int i = 0; i < class_info->instance_field_initializers->length(); ++i) { | |
3630 const AstRawString* function_name = | |
3631 ClassFieldVariableName(false, ast_value_factory(), i); | |
3632 VariableProxy* function_proxy = | |
3633 factory()->NewVariableProxy(function_name, NORMAL_VARIABLE); | |
3634 Declaration* function_declaration = factory()->NewVariableDeclaration( | |
3635 function_proxy, scope(), kNoSourcePosition); | |
3636 Variable* function_var = | |
3637 Declare(function_declaration, DeclarationDescriptor::NORMAL, CONST, | |
3638 kNeedsInitialization, ok, scope()); | |
3639 if (!*ok) return nullptr; | |
3640 Property* prototype_property = factory()->NewProperty( | |
3641 factory()->NewVariableProxy(result_var), | |
3642 factory()->NewStringLiteral(ast_value_factory()->prototype_string(), | |
3643 kNoSourcePosition), | |
3644 kNoSourcePosition); | |
3645 Expression* function_value = InstallHomeObject( | |
3646 class_info->instance_field_initializers->at(i), | |
3647 prototype_property); // TODO(bakkot) ideally this would be conditional, | |
3648 // especially in trivial cases | |
3649 Assignment* function_assignment = factory()->NewAssignment( | |
3650 Token::INIT, factory()->NewVariableProxy(function_var), function_value, | |
3651 kNoSourcePosition); | |
3652 do_block->statements()->Add(factory()->NewExpressionStatement( | |
3653 function_assignment, kNoSourcePosition), | |
3654 zone()); | |
3655 } | |
3656 do_block->set_scope(scope()->FinalizeBlockScope()); | 3354 do_block->set_scope(scope()->FinalizeBlockScope()); |
3657 do_expr->set_represented_function(class_info->constructor); | 3355 do_expr->set_represented_function(class_info->constructor); |
3658 AddFunctionForNameInference(class_info->constructor); | 3356 AddFunctionForNameInference(class_info->constructor); |
3659 | 3357 |
3660 return do_expr; | 3358 return do_expr; |
3661 } | 3359 } |
3662 | 3360 |
3663 Literal* Parser::GetLiteralUndefined(int position) { | 3361 Literal* Parser::GetLiteralUndefined(int position) { |
3664 return factory()->NewUndefinedLiteral(position); | 3362 return factory()->NewUndefinedLiteral(position); |
3665 } | 3363 } |
(...skipping 1763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5429 | 5127 |
5430 return final_loop; | 5128 return final_loop; |
5431 } | 5129 } |
5432 | 5130 |
5433 #undef CHECK_OK | 5131 #undef CHECK_OK |
5434 #undef CHECK_OK_VOID | 5132 #undef CHECK_OK_VOID |
5435 #undef CHECK_FAILED | 5133 #undef CHECK_FAILED |
5436 | 5134 |
5437 } // namespace internal | 5135 } // namespace internal |
5438 } // namespace v8 | 5136 } // namespace v8 |
OLD | NEW |