| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/parser.h" | 5 #include "vm/parser.h" |
| 6 | 6 |
| 7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
| 8 #include "vm/class_finalizer.h" | 8 #include "vm/class_finalizer.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/compiler_stats.h" | 10 #include "vm/compiler_stats.h" |
| (...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 // Static const fields must have an initializer. | 750 // Static const fields must have an initializer. |
| 751 ExpectToken(Token::kASSIGN); | 751 ExpectToken(Token::kASSIGN); |
| 752 | 752 |
| 753 // We don't want to use ParseConstExpr() here because we don't want | 753 // We don't want to use ParseConstExpr() here because we don't want |
| 754 // the constant folding code to create, compile and execute a code | 754 // the constant folding code to create, compile and execute a code |
| 755 // fragment to evaluate the expression. Instead, we just make sure | 755 // fragment to evaluate the expression. Instead, we just make sure |
| 756 // the static const field initializer is a constant expression and | 756 // the static const field initializer is a constant expression and |
| 757 // leave the evaluation to the getter function. | 757 // leave the evaluation to the getter function. |
| 758 const intptr_t expr_pos = TokenPos(); | 758 const intptr_t expr_pos = TokenPos(); |
| 759 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); | 759 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
| 760 if (field.is_const()) { | 760 // TODO(hausner): Remove is_final check below once we support |
| 761 // non-const finals. |
| 762 if (field.is_const() || field.is_final()) { |
| 761 // This getter will only be called once at compile time. | 763 // This getter will only be called once at compile time. |
| 762 if (expr->EvalConstExpr() == NULL) { | 764 if (expr->EvalConstExpr() == NULL) { |
| 763 ErrorMsg(expr_pos, "initializer must be a compile time constant"); | 765 ErrorMsg(expr_pos, "initializer must be a compile time constant"); |
| 764 } | 766 } |
| 765 ReturnNode* return_node = new ReturnNode(TokenPos(), expr); | 767 ReturnNode* return_node = new ReturnNode(TokenPos(), expr); |
| 766 current_block_->statements->Add(return_node); | 768 current_block_->statements->Add(return_node); |
| 767 } else { | 769 } else { |
| 768 // This getter may be called each time the static field is accessed. | 770 // This getter may be called each time the static field is accessed. |
| 769 // The following generated code lazily initializes the field: | 771 // The following generated code lazily initializes the field: |
| 770 // if (field.value === transition_sentinel) { | 772 // if (field.value === transition_sentinel) { |
| (...skipping 1702 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2473 void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) { | 2475 void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) { |
| 2474 TRACE_PARSER("ParseFieldDefinition"); | 2476 TRACE_PARSER("ParseFieldDefinition"); |
| 2475 // The parser has read the first field name and is now at the token | 2477 // The parser has read the first field name and is now at the token |
| 2476 // after the field name. | 2478 // after the field name. |
| 2477 ASSERT(CurrentToken() == Token::kSEMICOLON || | 2479 ASSERT(CurrentToken() == Token::kSEMICOLON || |
| 2478 CurrentToken() == Token::kCOMMA || | 2480 CurrentToken() == Token::kCOMMA || |
| 2479 CurrentToken() == Token::kASSIGN); | 2481 CurrentToken() == Token::kASSIGN); |
| 2480 ASSERT(field->type != NULL); | 2482 ASSERT(field->type != NULL); |
| 2481 ASSERT(field->name_pos > 0); | 2483 ASSERT(field->name_pos > 0); |
| 2482 ASSERT(current_member_ == field); | 2484 ASSERT(current_member_ == field); |
| 2485 ASSERT(!field->has_const || field->has_final); |
| 2483 | 2486 |
| 2484 if (field->has_const) { | |
| 2485 ErrorMsg("keyword 'const' not allowed in field declaration"); | |
| 2486 } | |
| 2487 if (field->has_abstract) { | 2487 if (field->has_abstract) { |
| 2488 ErrorMsg("keyword 'abstract' not allowed in field declaration"); | 2488 ErrorMsg("keyword 'abstract' not allowed in field declaration"); |
| 2489 } | 2489 } |
| 2490 if (field->has_factory) { | 2490 if (field->has_factory) { |
| 2491 ErrorMsg("keyword 'factory' not allowed in field declaration"); | 2491 ErrorMsg("keyword 'factory' not allowed in field declaration"); |
| 2492 } | 2492 } |
| 2493 if (members->FieldNameExists(*field->name)) { | 2493 if (members->FieldNameExists(*field->name)) { |
| 2494 ErrorMsg(field->name_pos, | 2494 ErrorMsg(field->name_pos, |
| 2495 "'%s' field/method already defined\n", field->name->ToCString()); | 2495 "'%s' field/method already defined\n", field->name->ToCString()); |
| 2496 } | 2496 } |
| 2497 Function& getter = Function::Handle(); | 2497 Function& getter = Function::Handle(); |
| 2498 Function& setter = Function::Handle(); | 2498 Function& setter = Function::Handle(); |
| 2499 Field& class_field = Field::Handle(); | 2499 Field& class_field = Field::Handle(); |
| 2500 while (true) { | 2500 while (true) { |
| 2501 bool has_initializer = CurrentToken() == Token::kASSIGN; | 2501 bool has_initializer = CurrentToken() == Token::kASSIGN; |
| 2502 if (has_initializer) { | 2502 if (has_initializer) { |
| 2503 ConsumeToken(); | 2503 ConsumeToken(); |
| 2504 // For static final fields, the initialization expression | 2504 // For static final fields, the initialization expression |
| 2505 // will be parsed through the kConstImplicitGetter method | 2505 // will be parsed through the kConstImplicitGetter method |
| 2506 // invocation/compilation. | 2506 // invocation/compilation. |
| 2507 // For instance fields, the expression is parsed when a constructor | 2507 // For instance fields, the expression is parsed when a constructor |
| 2508 // is compiled. | 2508 // is compiled. |
| 2509 SkipExpr(); | 2509 SkipExpr(); |
| 2510 } else { | 2510 } else { |
| 2511 if (field->has_static && field->has_final) { | 2511 if (field->has_const || (field->has_static && field->has_final)) { |
| 2512 ErrorMsg(field->name_pos, | 2512 ErrorMsg(field->name_pos, |
| 2513 "static final field '%s' must have an initializer expression", | 2513 "%s%s field '%s' must have an initializer expression", |
| 2514 field->has_static ? "static " : "", |
| 2515 field->has_const ? "const" : "final", |
| 2514 field->name->ToCString()); | 2516 field->name->ToCString()); |
| 2515 } | 2517 } |
| 2516 } | 2518 } |
| 2517 | 2519 |
| 2518 // Create the field object. | 2520 // Create the field object. |
| 2521 // TODO(hausner): For now, all static final fields are constant. Remove |
| 2522 // this when lazy init of static variables is implemented. |
| 2519 class_field = Field::New(*field->name, | 2523 class_field = Field::New(*field->name, |
| 2520 field->has_static, | 2524 field->has_static, |
| 2521 field->has_final, | 2525 field->has_final, |
| 2526 field->has_const || field->has_final, |
| 2522 field->name_pos); | 2527 field->name_pos); |
| 2523 class_field.set_type(*field->type); | 2528 class_field.set_type(*field->type); |
| 2524 class_field.set_has_initializer(has_initializer); | 2529 class_field.set_has_initializer(has_initializer); |
| 2525 members->AddField(class_field); | 2530 members->AddField(class_field); |
| 2526 | 2531 |
| 2527 // For static final fields, set value to "uninitialized" and | 2532 // For static final fields, set value to "uninitialized" and |
| 2528 // create a kConstImplicitGetter getter method. | 2533 // create a kConstImplicitGetter getter method. |
| 2529 if (field->has_static && has_initializer) { | 2534 if (field->has_static && has_initializer) { |
| 2530 class_field.set_value(Instance::Handle(Object::sentinel())); | 2535 class_field.set_value(Instance::Handle(Object::sentinel())); |
| 2531 String& getter_name = String::Handle(Field::GetterSymbol(*field->name)); | 2536 String& getter_name = String::Handle(Field::GetterSymbol(*field->name)); |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2791 member.type = &Type::ZoneHandle(Type::DynamicType()); | 2796 member.type = &Type::ZoneHandle(Type::DynamicType()); |
| 2792 } | 2797 } |
| 2793 ParseMethodOrConstructor(members, &member); | 2798 ParseMethodOrConstructor(members, &member); |
| 2794 if (operator_token != Token::kILLEGAL) { | 2799 if (operator_token != Token::kILLEGAL) { |
| 2795 CheckOperatorArity(member, operator_token); | 2800 CheckOperatorArity(member, operator_token); |
| 2796 } | 2801 } |
| 2797 } else if (CurrentToken() == Token::kSEMICOLON || | 2802 } else if (CurrentToken() == Token::kSEMICOLON || |
| 2798 CurrentToken() == Token::kCOMMA || | 2803 CurrentToken() == Token::kCOMMA || |
| 2799 CurrentToken() == Token::kASSIGN) { | 2804 CurrentToken() == Token::kASSIGN) { |
| 2800 // Field definition. | 2805 // Field definition. |
| 2806 if (member.has_const) { |
| 2807 // const fields are implicitly final. |
| 2808 member.has_final = true; |
| 2809 } |
| 2801 if (member.type == NULL) { | 2810 if (member.type == NULL) { |
| 2802 if (member.has_final) { | 2811 if (member.has_final) { |
| 2803 member.type = &Type::ZoneHandle(Type::DynamicType()); | 2812 member.type = &Type::ZoneHandle(Type::DynamicType()); |
| 2804 } else { | 2813 } else { |
| 2805 ErrorMsg("missing 'var', 'final' or type in field declaration"); | 2814 ErrorMsg("missing 'var', 'final', 'const' or type" |
| 2815 " in field declaration"); |
| 2806 } | 2816 } |
| 2807 } | 2817 } |
| 2808 if (members->is_interface() && member.has_static && !member.has_final) { | 2818 if (members->is_interface() && member.has_static && !member.has_final) { |
| 2809 ErrorMsg("static non-final fields are not allowed in interfaces"); | 2819 ErrorMsg("static non-final fields are not allowed in interfaces"); |
| 2810 } | 2820 } |
| 2811 ParseFieldDefinition(members, &member); | 2821 ParseFieldDefinition(members, &member); |
| 2812 } else { | 2822 } else { |
| 2813 UnexpectedToken(); | 2823 UnexpectedToken(); |
| 2814 } | 2824 } |
| 2815 current_member_ = NULL; | 2825 current_member_ = NULL; |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3425 } | 3435 } |
| 3426 } | 3436 } |
| 3427 cls_interfaces = Array::MakeArray(all_interfaces); | 3437 cls_interfaces = Array::MakeArray(all_interfaces); |
| 3428 cls.set_interfaces(cls_interfaces); | 3438 cls.set_interfaces(cls_interfaces); |
| 3429 } | 3439 } |
| 3430 | 3440 |
| 3431 | 3441 |
| 3432 void Parser::ParseTopLevelVariable(TopLevel* top_level) { | 3442 void Parser::ParseTopLevelVariable(TopLevel* top_level) { |
| 3433 TRACE_PARSER("ParseTopLevelVariable"); | 3443 TRACE_PARSER("ParseTopLevelVariable"); |
| 3434 const bool is_final = (CurrentToken() == Token::kFINAL); | 3444 const bool is_final = (CurrentToken() == Token::kFINAL); |
| 3445 const bool is_const = (CurrentToken() == Token::kCONST); |
| 3435 const bool is_static = true; | 3446 const bool is_static = true; |
| 3436 const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( | 3447 const AbstractType& type = |
| 3437 FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : | 3448 AbstractType::ZoneHandle(ParseConstFinalVarOrType( |
| 3438 ClassFinalizer::kIgnore)); | 3449 FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : |
| 3450 ClassFinalizer::kIgnore)); |
| 3439 Field& field = Field::Handle(); | 3451 Field& field = Field::Handle(); |
| 3440 Function& getter = Function::Handle(); | 3452 Function& getter = Function::Handle(); |
| 3441 while (true) { | 3453 while (true) { |
| 3442 const intptr_t name_pos = TokenPos(); | 3454 const intptr_t name_pos = TokenPos(); |
| 3443 String& var_name = *ExpectIdentifier("variable name expected"); | 3455 String& var_name = *ExpectIdentifier("variable name expected"); |
| 3444 | 3456 |
| 3445 if (library_.LookupObject(var_name) != Object::null()) { | 3457 if (library_.LookupObject(var_name) != Object::null()) { |
| 3446 ErrorMsg(name_pos, "'%s' is already defined", var_name.ToCString()); | 3458 ErrorMsg(name_pos, "'%s' is already defined", var_name.ToCString()); |
| 3447 } | 3459 } |
| 3448 String& accessor_name = String::Handle(Field::GetterName(var_name)); | 3460 String& accessor_name = String::Handle(Field::GetterName(var_name)); |
| 3449 if (library_.LookupObject(accessor_name) != Object::null()) { | 3461 if (library_.LookupObject(accessor_name) != Object::null()) { |
| 3450 ErrorMsg(name_pos, "getter for '%s' is already defined", | 3462 ErrorMsg(name_pos, "getter for '%s' is already defined", |
| 3451 var_name.ToCString()); | 3463 var_name.ToCString()); |
| 3452 } | 3464 } |
| 3453 accessor_name = Field::SetterName(var_name); | 3465 accessor_name = Field::SetterName(var_name); |
| 3454 if (library_.LookupObject(accessor_name) != Object::null()) { | 3466 if (library_.LookupObject(accessor_name) != Object::null()) { |
| 3455 ErrorMsg(name_pos, "setter for '%s' is already defined", | 3467 ErrorMsg(name_pos, "setter for '%s' is already defined", |
| 3456 var_name.ToCString()); | 3468 var_name.ToCString()); |
| 3457 } | 3469 } |
| 3458 | 3470 |
| 3459 field = Field::New(var_name, is_static, is_final, name_pos); | 3471 field = Field::New(var_name, is_static, is_final, is_const, name_pos); |
| 3460 field.set_type(type); | 3472 field.set_type(type); |
| 3461 field.set_value(Instance::Handle(Instance::null())); | 3473 field.set_value(Instance::Handle(Instance::null())); |
| 3462 top_level->fields.Add(field); | 3474 top_level->fields.Add(field); |
| 3463 library_.AddObject(field, var_name); | 3475 library_.AddObject(field, var_name); |
| 3464 if (CurrentToken() == Token::kASSIGN) { | 3476 if (CurrentToken() == Token::kASSIGN) { |
| 3465 ConsumeToken(); | 3477 ConsumeToken(); |
| 3466 SkipExpr(); | 3478 SkipExpr(); |
| 3467 field.set_value(Instance::Handle(Object::sentinel())); | 3479 field.set_value(Instance::Handle(Object::sentinel())); |
| 3468 // Create a static const getter. | 3480 // Create a static const getter. |
| 3469 String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name)); | 3481 String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name)); |
| 3470 getter = Function::New(getter_name, RawFunction::kConstImplicitGetter, | 3482 getter = Function::New(getter_name, RawFunction::kConstImplicitGetter, |
| 3471 is_static, is_final, name_pos); | 3483 is_static, is_final, name_pos); |
| 3472 getter.set_result_type(type); | 3484 getter.set_result_type(type); |
| 3473 top_level->functions.Add(getter); | 3485 top_level->functions.Add(getter); |
| 3474 } else if (is_final) { | 3486 } else if (is_final || is_const) { |
| 3475 ErrorMsg(name_pos, "missing initializer for final variable"); | 3487 ErrorMsg(name_pos, "missing initializer for final or const variable"); |
| 3476 } | 3488 } |
| 3477 | 3489 |
| 3478 if (CurrentToken() == Token::kCOMMA) { | 3490 if (CurrentToken() == Token::kCOMMA) { |
| 3479 ConsumeToken(); | 3491 ConsumeToken(); |
| 3480 } else if (CurrentToken() == Token::kSEMICOLON) { | 3492 } else if (CurrentToken() == Token::kSEMICOLON) { |
| 3481 ConsumeToken(); | 3493 ConsumeToken(); |
| 3482 break; | 3494 break; |
| 3483 } else { | 3495 } else { |
| 3484 ExpectSemicolon(); // Reports error. | 3496 ExpectSemicolon(); // Reports error. |
| 3485 } | 3497 } |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4058 | 4070 |
| 4059 | 4071 |
| 4060 AstNode* Parser::CallGetter(intptr_t token_pos, | 4072 AstNode* Parser::CallGetter(intptr_t token_pos, |
| 4061 AstNode* object, | 4073 AstNode* object, |
| 4062 const String& name) { | 4074 const String& name) { |
| 4063 return new InstanceGetterNode(TokenPos(), object, name); | 4075 return new InstanceGetterNode(TokenPos(), object, name); |
| 4064 } | 4076 } |
| 4065 | 4077 |
| 4066 | 4078 |
| 4067 // Returns ast nodes of the variable initialization. | 4079 // Returns ast nodes of the variable initialization. |
| 4068 AstNode* Parser::ParseVariableDeclaration( | 4080 AstNode* Parser::ParseVariableDeclaration(const AbstractType& type, |
| 4069 const AbstractType& type, bool is_final) { | 4081 bool is_final, |
| 4082 bool is_const) { |
| 4070 TRACE_PARSER("ParseVariableDeclaration"); | 4083 TRACE_PARSER("ParseVariableDeclaration"); |
| 4071 ASSERT(IsIdentifier()); | 4084 ASSERT(IsIdentifier()); |
| 4072 const intptr_t ident_pos = TokenPos(); | 4085 const intptr_t ident_pos = TokenPos(); |
| 4073 LocalVariable* variable = | 4086 LocalVariable* variable = |
| 4074 new LocalVariable(ident_pos, *CurrentLiteral(), type); | 4087 new LocalVariable(ident_pos, *CurrentLiteral(), type); |
| 4075 ASSERT(current_block_ != NULL); | 4088 ASSERT(current_block_ != NULL); |
| 4076 ASSERT(current_block_->scope != NULL); | 4089 ASSERT(current_block_->scope != NULL); |
| 4077 ConsumeToken(); // Variable identifier. | 4090 ConsumeToken(); // Variable identifier. |
| 4078 AstNode* initialization = NULL; | 4091 AstNode* initialization = NULL; |
| 4079 if (CurrentToken() == Token::kASSIGN) { | 4092 if (CurrentToken() == Token::kASSIGN) { |
| 4080 // Variable initialization. | 4093 // Variable initialization. |
| 4081 const intptr_t assign_pos = TokenPos(); | 4094 const intptr_t assign_pos = TokenPos(); |
| 4082 ConsumeToken(); | 4095 ConsumeToken(); |
| 4083 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); | 4096 AstNode* expr = ParseExpr(is_const, kConsumeCascades); |
| 4084 initialization = new StoreLocalNode(assign_pos, *variable, expr); | 4097 initialization = new StoreLocalNode(assign_pos, *variable, expr); |
| 4085 } else if (is_final) { | 4098 } else if (is_final || is_const) { |
| 4086 ErrorMsg(ident_pos, "missing initialization of 'final' variable"); | 4099 ErrorMsg(ident_pos, |
| 4100 "missing initialization of 'final' or 'const' variable"); |
| 4087 } else { | 4101 } else { |
| 4088 // Initialize variable with null. | 4102 // Initialize variable with null. |
| 4089 AstNode* null_expr = new LiteralNode(ident_pos, Instance::ZoneHandle()); | 4103 AstNode* null_expr = new LiteralNode(ident_pos, Instance::ZoneHandle()); |
| 4090 initialization = new StoreLocalNode(ident_pos, *variable, null_expr); | 4104 initialization = new StoreLocalNode(ident_pos, *variable, null_expr); |
| 4091 } | 4105 } |
| 4092 // Add variable to cope after parsing the initalizer expression. | 4106 // Add variable to scope after parsing the initalizer expression. |
| 4093 // The expression must not be able to refer to the variable. | 4107 // The expression must not be able to refer to the variable. |
| 4094 if (!current_block_->scope->AddVariable(variable)) { | 4108 if (!current_block_->scope->AddVariable(variable)) { |
| 4095 ErrorMsg(ident_pos, "identifier '%s' already defined", | 4109 ErrorMsg(ident_pos, "identifier '%s' already defined", |
| 4096 variable->name().ToCString()); | 4110 variable->name().ToCString()); |
| 4097 } | 4111 } |
| 4098 if (is_final) { | 4112 if (is_final || is_const) { |
| 4099 variable->set_is_final(); | 4113 variable->set_is_final(); |
| 4100 } | 4114 } |
| 4101 return initialization; | 4115 return initialization; |
| 4102 } | 4116 } |
| 4103 | 4117 |
| 4104 | 4118 |
| 4105 // Parses ('var' | 'final' [type] | type). | 4119 // Parses ('var' | 'final' [type] | 'const' [type] | type). |
| 4106 // The presence of 'final' must be detected and remembered before the call. | 4120 // The presence of 'final' or 'const' must be detected and remembered |
| 4107 // If a type is parsed, it may be resolved and finalized according to the given | 4121 // before the call. If a type is parsed, it may be resolved and finalized |
| 4108 // type finalization mode. | 4122 // according to the given type finalization mode. |
| 4109 RawAbstractType* Parser::ParseFinalVarOrType( | 4123 RawAbstractType* Parser::ParseConstFinalVarOrType( |
| 4110 ClassFinalizer::FinalizationKind finalization) { | 4124 ClassFinalizer::FinalizationKind finalization) { |
| 4111 TRACE_PARSER("ParseFinalVarOrType"); | 4125 TRACE_PARSER("ParseConstFinalVarOrType"); |
| 4112 if (CurrentToken() == Token::kVAR) { | 4126 if (CurrentToken() == Token::kVAR) { |
| 4113 ConsumeToken(); | 4127 ConsumeToken(); |
| 4114 return Type::DynamicType(); | 4128 return Type::DynamicType(); |
| 4115 } | 4129 } |
| 4116 bool type_is_optional = false; | 4130 bool type_is_optional = false; |
| 4117 if (CurrentToken() == Token::kFINAL) { | 4131 if ((CurrentToken() == Token::kFINAL) || (CurrentToken() == Token::kCONST)) { |
| 4118 ConsumeToken(); | 4132 ConsumeToken(); |
| 4119 type_is_optional = true; | 4133 type_is_optional = true; |
| 4120 } | 4134 } |
| 4121 if (CurrentToken() != Token::kIDENT) { | 4135 if (CurrentToken() != Token::kIDENT) { |
| 4122 if (type_is_optional) { | 4136 if (type_is_optional) { |
| 4123 return Type::DynamicType(); | 4137 return Type::DynamicType(); |
| 4124 } else { | 4138 } else { |
| 4125 ErrorMsg("type name expected"); | 4139 ErrorMsg("type name expected"); |
| 4126 } | 4140 } |
| 4127 } | 4141 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4139 return ParseType(finalization); | 4153 return ParseType(finalization); |
| 4140 } | 4154 } |
| 4141 | 4155 |
| 4142 | 4156 |
| 4143 // Returns ast nodes of the variable initialization. Variables without an | 4157 // Returns ast nodes of the variable initialization. Variables without an |
| 4144 // explicit initializer are initialized to null. If several variables are | 4158 // explicit initializer are initialized to null. If several variables are |
| 4145 // declared, the individual initializers are collected in a sequence node. | 4159 // declared, the individual initializers are collected in a sequence node. |
| 4146 AstNode* Parser::ParseVariableDeclarationList() { | 4160 AstNode* Parser::ParseVariableDeclarationList() { |
| 4147 TRACE_PARSER("ParseVariableDeclarationList"); | 4161 TRACE_PARSER("ParseVariableDeclarationList"); |
| 4148 bool is_final = (CurrentToken() == Token::kFINAL); | 4162 bool is_final = (CurrentToken() == Token::kFINAL); |
| 4149 const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( | 4163 bool is_const = (CurrentToken() == Token::kCONST); |
| 4164 const AbstractType& type = AbstractType::ZoneHandle(ParseConstFinalVarOrType( |
| 4150 FLAG_enable_type_checks ? ClassFinalizer::kCanonicalize : | 4165 FLAG_enable_type_checks ? ClassFinalizer::kCanonicalize : |
| 4151 ClassFinalizer::kIgnore)); | 4166 ClassFinalizer::kIgnore)); |
| 4152 if (!IsIdentifier()) { | 4167 if (!IsIdentifier()) { |
| 4153 ErrorMsg("identifier expected"); | 4168 ErrorMsg("identifier expected"); |
| 4154 } | 4169 } |
| 4155 | 4170 |
| 4156 AstNode* initializers = ParseVariableDeclaration(type, is_final); | 4171 AstNode* initializers = ParseVariableDeclaration(type, is_final, is_const); |
| 4157 ASSERT(initializers != NULL); | 4172 ASSERT(initializers != NULL); |
| 4158 while (CurrentToken() == Token::kCOMMA) { | 4173 while (CurrentToken() == Token::kCOMMA) { |
| 4159 ConsumeToken(); | 4174 ConsumeToken(); |
| 4160 if (!IsIdentifier()) { | 4175 if (!IsIdentifier()) { |
| 4161 ErrorMsg("identifier expected after comma"); | 4176 ErrorMsg("identifier expected after comma"); |
| 4162 } | 4177 } |
| 4163 // We have a second initializer. Allocate a sequence node now. | 4178 // We have a second initializer. Allocate a sequence node now. |
| 4164 // The sequence does not own the current scope. Set its own scope to NULL. | 4179 // The sequence does not own the current scope. Set its own scope to NULL. |
| 4165 SequenceNode* sequence = NodeAsSequenceNode(initializers->token_pos(), | 4180 SequenceNode* sequence = NodeAsSequenceNode(initializers->token_pos(), |
| 4166 initializers, | 4181 initializers, |
| 4167 NULL); | 4182 NULL); |
| 4168 sequence->Add(ParseVariableDeclaration(type, is_final)); | 4183 sequence->Add(ParseVariableDeclaration(type, is_final, is_const)); |
| 4169 initializers = sequence; | 4184 initializers = sequence; |
| 4170 } | 4185 } |
| 4171 return initializers; | 4186 return initializers; |
| 4172 } | 4187 } |
| 4173 | 4188 |
| 4174 | 4189 |
| 4175 AstNode* Parser::ParseFunctionStatement(bool is_literal) { | 4190 AstNode* Parser::ParseFunctionStatement(bool is_literal) { |
| 4176 TRACE_PARSER("ParseFunctionStatement"); | 4191 TRACE_PARSER("ParseFunctionStatement"); |
| 4177 AbstractType& result_type = AbstractType::Handle(); | 4192 AbstractType& result_type = AbstractType::Handle(); |
| 4178 const String* variable_name = NULL; | 4193 const String* variable_name = NULL; |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4431 return true; | 4446 return true; |
| 4432 } else if (CurrentToken() == Token::kIDENT) { | 4447 } else if (CurrentToken() == Token::kIDENT) { |
| 4433 return TryParseOptionalType(); | 4448 return TryParseOptionalType(); |
| 4434 } | 4449 } |
| 4435 return false; | 4450 return false; |
| 4436 } | 4451 } |
| 4437 | 4452 |
| 4438 | 4453 |
| 4439 // Look ahead to detect whether the next tokens should be parsed as | 4454 // Look ahead to detect whether the next tokens should be parsed as |
| 4440 // a variable declaration. Returns true if we detect the token pattern: | 4455 // a variable declaration. Returns true if we detect the token pattern: |
| 4441 // ('var' | 'final' | type ident (';' | '=' | ',')) | 4456 // 'var' |
| 4457 // | 'final' |
| 4458 // | const [type] ident (';' | '=' | ',') |
| 4459 // | type ident (';' | '=' | ',') |
| 4442 // Token position remains unchanged. | 4460 // Token position remains unchanged. |
| 4443 bool Parser::IsVariableDeclaration() { | 4461 bool Parser::IsVariableDeclaration() { |
| 4444 if ((CurrentToken() == Token::kVAR) || | 4462 if ((CurrentToken() == Token::kVAR) || |
| 4445 (CurrentToken() == Token::kFINAL)) { | 4463 (CurrentToken() == Token::kFINAL)) { |
| 4446 return true; | 4464 return true; |
| 4447 } | 4465 } |
| 4448 if (CurrentToken() != Token::kIDENT) { | 4466 if ((CurrentToken() != Token::kIDENT) && (CurrentToken() != Token::kCONST)) { |
| 4449 // Not a legal type identifier. | 4467 // Not a legal type identifier or const keyword |
| 4450 return false; | 4468 return false; |
| 4451 } | 4469 } |
| 4452 const intptr_t saved_pos = TokenPos(); | 4470 const intptr_t saved_pos = TokenPos(); |
| 4453 bool is_var_decl = false; | 4471 bool is_var_decl = false; |
| 4454 if (TryParseOptionalType()) { | 4472 bool have_type = false; |
| 4455 if (IsIdentifier()) { | 4473 if (CurrentToken() == Token::kCONST) { |
| 4474 ConsumeToken(); |
| 4475 have_type = true; // Type is Dynamic. |
| 4476 } |
| 4477 if (IsIdentifier()) { // Type or variable name. |
| 4478 Token::Kind follower = LookaheadToken(1); |
| 4479 if ((follower == Token::kLT) || // Parameterized type. |
| 4480 (follower == Token::kPERIOD) || // Qualified class name of type. |
| 4481 Token::IsIdentifier(follower)) { // Variable name following a type. |
| 4482 // We see the beginning of something that could be a type. |
| 4483 const intptr_t type_pos = TokenPos(); |
| 4484 if (TryParseOptionalType()) { |
| 4485 have_type = true; |
| 4486 } else { |
| 4487 SetPosition(type_pos); |
| 4488 } |
| 4489 } |
| 4490 if (have_type && IsIdentifier()) { |
| 4456 ConsumeToken(); | 4491 ConsumeToken(); |
| 4457 if ((CurrentToken() == Token::kSEMICOLON) || | 4492 if ((CurrentToken() == Token::kSEMICOLON) || |
| 4458 (CurrentToken() == Token::kCOMMA) || | 4493 (CurrentToken() == Token::kCOMMA) || |
| 4459 (CurrentToken() == Token::kASSIGN)) { | 4494 (CurrentToken() == Token::kASSIGN)) { |
| 4460 is_var_decl = true; | 4495 is_var_decl = true; |
| 4461 } | 4496 } |
| 4462 } | 4497 } |
| 4463 } | 4498 } |
| 4464 SetPosition(saved_pos); | 4499 SetPosition(saved_pos); |
| 4465 return is_var_decl; | 4500 return is_var_decl; |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4869 ExpectToken(Token::kRPAREN); | 4904 ExpectToken(Token::kRPAREN); |
| 4870 ExpectSemicolon(); | 4905 ExpectSemicolon(); |
| 4871 return new DoWhileNode(do_pos, label, cond_expr, dowhile_body); | 4906 return new DoWhileNode(do_pos, label, cond_expr, dowhile_body); |
| 4872 } | 4907 } |
| 4873 | 4908 |
| 4874 | 4909 |
| 4875 AstNode* Parser::ParseForInStatement(intptr_t forin_pos, | 4910 AstNode* Parser::ParseForInStatement(intptr_t forin_pos, |
| 4876 SourceLabel* label) { | 4911 SourceLabel* label) { |
| 4877 TRACE_PARSER("ParseForInStatement"); | 4912 TRACE_PARSER("ParseForInStatement"); |
| 4878 bool is_final = (CurrentToken() == Token::kFINAL); | 4913 bool is_final = (CurrentToken() == Token::kFINAL); |
| 4914 if (CurrentToken() == Token::kCONST) { |
| 4915 ErrorMsg("Loop variable cannot be 'const'"); |
| 4916 } |
| 4879 const String* loop_var_name = NULL; | 4917 const String* loop_var_name = NULL; |
| 4880 LocalVariable* loop_var = NULL; | 4918 LocalVariable* loop_var = NULL; |
| 4881 intptr_t loop_var_pos = 0; | 4919 intptr_t loop_var_pos = 0; |
| 4882 if (LookaheadToken(1) == Token::kIN) { | 4920 if (LookaheadToken(1) == Token::kIN) { |
| 4883 loop_var_pos = TokenPos(); | 4921 loop_var_pos = TokenPos(); |
| 4884 loop_var_name = ExpectIdentifier("variable name expected"); | 4922 loop_var_name = ExpectIdentifier("variable name expected"); |
| 4885 } else { | 4923 } else { |
| 4886 // The case without a type is handled above, so require a type here. | 4924 // The case without a type is handled above, so require a type here. |
| 4887 const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( | 4925 const AbstractType& type = |
| 4888 FLAG_enable_type_checks ? ClassFinalizer::kCanonicalize : | 4926 AbstractType::ZoneHandle(ParseConstFinalVarOrType( |
| 4889 ClassFinalizer::kIgnore)); | 4927 FLAG_enable_type_checks ? ClassFinalizer::kCanonicalize : |
| 4928 ClassFinalizer::kIgnore)); |
| 4890 loop_var_pos = TokenPos(); | 4929 loop_var_pos = TokenPos(); |
| 4891 loop_var_name = ExpectIdentifier("variable name expected"); | 4930 loop_var_name = ExpectIdentifier("variable name expected"); |
| 4892 loop_var = new LocalVariable(loop_var_pos, *loop_var_name, type); | 4931 loop_var = new LocalVariable(loop_var_pos, *loop_var_name, type); |
| 4893 if (is_final) { | 4932 if (is_final) { |
| 4894 loop_var->set_is_final(); | 4933 loop_var->set_is_final(); |
| 4895 } | 4934 } |
| 4896 } | 4935 } |
| 4897 ExpectToken(Token::kIN); | 4936 ExpectToken(Token::kIN); |
| 4898 const intptr_t collection_pos = TokenPos(); | 4937 const intptr_t collection_pos = TokenPos(); |
| 4899 AstNode* collection_expr = ParseExpr(kAllowConst, kConsumeCascades); | 4938 AstNode* collection_expr = ParseExpr(kAllowConst, kConsumeCascades); |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5130 }; | 5169 }; |
| 5131 | 5170 |
| 5132 | 5171 |
| 5133 // Parse the parameter specified in the catch clause. | 5172 // Parse the parameter specified in the catch clause. |
| 5134 void Parser::ParseCatchParameter(CatchParamDesc* catch_param) { | 5173 void Parser::ParseCatchParameter(CatchParamDesc* catch_param) { |
| 5135 TRACE_PARSER("ParseCatchParameter"); | 5174 TRACE_PARSER("ParseCatchParameter"); |
| 5136 ASSERT(catch_param != NULL); | 5175 ASSERT(catch_param != NULL); |
| 5137 catch_param->is_final = (CurrentToken() == Token::kFINAL); | 5176 catch_param->is_final = (CurrentToken() == Token::kFINAL); |
| 5138 // The type of the catch parameter must always be resolved, even in unchecked | 5177 // The type of the catch parameter must always be resolved, even in unchecked |
| 5139 // mode. | 5178 // mode. |
| 5179 if (CurrentToken() == Token::kCONST) { |
| 5180 ErrorMsg("Catch parameter cannot be 'const'"); |
| 5181 } |
| 5140 catch_param->type = &AbstractType::ZoneHandle( | 5182 catch_param->type = &AbstractType::ZoneHandle( |
| 5141 ParseFinalVarOrType(ClassFinalizer::kCanonicalizeWellFormed)); | 5183 ParseConstFinalVarOrType(ClassFinalizer::kCanonicalizeWellFormed)); |
| 5142 catch_param->token_pos = TokenPos(); | 5184 catch_param->token_pos = TokenPos(); |
| 5143 catch_param->var = ExpectIdentifier("identifier expected"); | 5185 catch_param->var = ExpectIdentifier("identifier expected"); |
| 5144 } | 5186 } |
| 5145 | 5187 |
| 5146 | 5188 |
| 5147 // Populate local scope of the catch block with the catch parameters. | 5189 // Populate local scope of the catch block with the catch parameters. |
| 5148 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, | 5190 void Parser::AddCatchParamsToScope(const CatchParamDesc& exception_param, |
| 5149 const CatchParamDesc& stack_trace_param, | 5191 const CatchParamDesc& stack_trace_param, |
| 5150 LocalScope* scope) { | 5192 LocalScope* scope) { |
| 5151 ASSERT(exception_param.var != NULL); | 5193 ASSERT(exception_param.var != NULL); |
| (...skipping 1375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6527 intptr_t ident_pos) { | 6569 intptr_t ident_pos) { |
| 6528 // If the static field has an initializer, initialize the field at compile | 6570 // If the static field has an initializer, initialize the field at compile |
| 6529 // time, which is only possible if the field is const. | 6571 // time, which is only possible if the field is const. |
| 6530 AstNode* initializing_getter = RunStaticFieldInitializer(field); | 6572 AstNode* initializing_getter = RunStaticFieldInitializer(field); |
| 6531 if (initializing_getter != NULL) { | 6573 if (initializing_getter != NULL) { |
| 6532 // The field is not yet initialized and could not be initialized at compile | 6574 // The field is not yet initialized and could not be initialized at compile |
| 6533 // time. The getter will initialize the field. | 6575 // time. The getter will initialize the field. |
| 6534 return initializing_getter; | 6576 return initializing_getter; |
| 6535 } | 6577 } |
| 6536 // The field is initialized. | 6578 // The field is initialized. |
| 6537 if (field.is_const()) { | 6579 // TODO(hausner): Remove the is_final check when we support non-const |
| 6580 // final static variables. |
| 6581 if (field.is_const() || field.is_final()) { |
| 6538 ASSERT(field.value() != Object::sentinel()); | 6582 ASSERT(field.value() != Object::sentinel()); |
| 6539 ASSERT(field.value() != Object::transition_sentinel()); | 6583 ASSERT(field.value() != Object::transition_sentinel()); |
| 6540 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); | 6584 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); |
| 6541 } | 6585 } |
| 6542 // Access the field directly. | 6586 // Access the field directly. |
| 6543 return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw())); | 6587 return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw())); |
| 6544 } | 6588 } |
| 6545 | 6589 |
| 6546 | 6590 |
| 6547 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, | 6591 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6985 } | 7029 } |
| 6986 | 7030 |
| 6987 | 7031 |
| 6988 // If the field is already initialized, return no ast (NULL). | 7032 // If the field is already initialized, return no ast (NULL). |
| 6989 // Otherwise, if the field is constant, initialize the field and return no ast. | 7033 // Otherwise, if the field is constant, initialize the field and return no ast. |
| 6990 // If the field is not initialized and not const, return the ast for the getter. | 7034 // If the field is not initialized and not const, return the ast for the getter. |
| 6991 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { | 7035 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { |
| 6992 ASSERT(field.is_static()); | 7036 ASSERT(field.is_static()); |
| 6993 const Instance& value = Instance::Handle(field.value()); | 7037 const Instance& value = Instance::Handle(field.value()); |
| 6994 if (value.raw() == Object::transition_sentinel()) { | 7038 if (value.raw() == Object::transition_sentinel()) { |
| 6995 if (field.is_const()) { | 7039 // TODO(hausner): Remove the check for is_final() once we support |
| 7040 // non-const final fields. |
| 7041 if (field.is_const() || field.is_final()) { |
| 6996 ErrorMsg("circular dependency while initializing static field '%s'", | 7042 ErrorMsg("circular dependency while initializing static field '%s'", |
| 6997 String::Handle(field.name()).ToCString()); | 7043 String::Handle(field.name()).ToCString()); |
| 6998 } else { | 7044 } else { |
| 6999 // The implicit static getter will throw the exception if necessary. | 7045 // The implicit static getter will throw the exception if necessary. |
| 7000 return new StaticGetterNode(TokenPos(), | 7046 return new StaticGetterNode(TokenPos(), |
| 7001 NULL, | 7047 NULL, |
| 7002 Class::ZoneHandle(field.owner()), | 7048 Class::ZoneHandle(field.owner()), |
| 7003 String::ZoneHandle(field.name())); | 7049 String::ZoneHandle(field.name())); |
| 7004 } | 7050 } |
| 7005 } else if (value.raw() == Object::sentinel()) { | 7051 } else if (value.raw() == Object::sentinel()) { |
| 7006 // This field has not been referenced yet and thus the value has | 7052 // This field has not been referenced yet and thus the value has |
| 7007 // not been evaluated. If the field is const, call the static getter method | 7053 // not been evaluated. If the field is const, call the static getter method |
| 7008 // to evaluate the expression and canonicalize the value. | 7054 // to evaluate the expression and canonicalize the value. |
| 7009 if (field.is_const()) { | 7055 // TODO(hausner): Remove the check for is_final() once we support |
| 7056 // non-const final fields. |
| 7057 if (field.is_const() || field.is_final()) { |
| 7010 field.set_value(Instance::Handle(Object::transition_sentinel())); | 7058 field.set_value(Instance::Handle(Object::transition_sentinel())); |
| 7011 const String& field_name = String::Handle(field.name()); | 7059 const String& field_name = String::Handle(field.name()); |
| 7012 const String& getter_name = | 7060 const String& getter_name = |
| 7013 String::Handle(Field::GetterName(field_name)); | 7061 String::Handle(Field::GetterName(field_name)); |
| 7014 const Class& cls = Class::Handle(field.owner()); | 7062 const Class& cls = Class::Handle(field.owner()); |
| 7015 GrowableArray<const Object*> arguments; // no arguments. | 7063 GrowableArray<const Object*> arguments; // no arguments. |
| 7016 const int kNumArguments = 0; // no arguments. | 7064 const int kNumArguments = 0; // no arguments. |
| 7017 const Array& kNoArgumentNames = Array::Handle(); | 7065 const Array& kNoArgumentNames = Array::Handle(); |
| 7018 const Function& func = | 7066 const Function& func = |
| 7019 Function::Handle(Resolver::ResolveStatic(cls, | 7067 Function::Handle(Resolver::ResolveStatic(cls, |
| (...skipping 1159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8179 expr = ResolveIdent(TokenPos(), *CurrentLiteral(), true); | 8227 expr = ResolveIdent(TokenPos(), *CurrentLiteral(), true); |
| 8180 ConsumeToken(); | 8228 ConsumeToken(); |
| 8181 } else { | 8229 } else { |
| 8182 ASSERT(CurrentToken() == Token::kINTERPOL_START); | 8230 ASSERT(CurrentToken() == Token::kINTERPOL_START); |
| 8183 ConsumeToken(); | 8231 ConsumeToken(); |
| 8184 expr = ParseExpr(kAllowConst, kConsumeCascades); | 8232 expr = ParseExpr(kAllowConst, kConsumeCascades); |
| 8185 ExpectToken(Token::kINTERPOL_END); | 8233 ExpectToken(Token::kINTERPOL_END); |
| 8186 } | 8234 } |
| 8187 // Check if this interpolated string is still considered a compile time | 8235 // Check if this interpolated string is still considered a compile time |
| 8188 // constant. If it is we need to evaluate if the current string part is | 8236 // constant. If it is we need to evaluate if the current string part is |
| 8189 // a constant or not. | 8237 // a constant or not. Only stings, numbers, booleans and null values |
| 8238 // are allowed in compile time const interpolations. |
| 8190 if (is_compiletime_const) { | 8239 if (is_compiletime_const) { |
| 8191 const Object* const_expr = expr->EvalConstExpr(); | 8240 const Object* const_expr = expr->EvalConstExpr(); |
| 8192 if (const_expr != NULL) { | 8241 if ((const_expr != NULL) && |
| 8242 (const_expr->IsNumber() || |
| 8243 const_expr->IsString() || |
| 8244 const_expr->IsBool() || |
| 8245 const_expr->IsNull())) { |
| 8193 // Change expr into a literal. | 8246 // Change expr into a literal. |
| 8194 expr = new LiteralNode(expr_pos, EvaluateConstExpr(expr)); | 8247 expr = new LiteralNode(expr_pos, EvaluateConstExpr(expr)); |
| 8195 } else { | 8248 } else { |
| 8196 is_compiletime_const = false; | 8249 is_compiletime_const = false; |
| 8197 } | 8250 } |
| 8198 } | 8251 } |
| 8199 values->AddElement(expr); | 8252 values->AddElement(expr); |
| 8200 } | 8253 } |
| 8201 } | 8254 } |
| 8202 if (is_compiletime_const) { | 8255 if (is_compiletime_const) { |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8678 void Parser::SkipQualIdent() { | 8731 void Parser::SkipQualIdent() { |
| 8679 ASSERT(IsIdentifier()); | 8732 ASSERT(IsIdentifier()); |
| 8680 ConsumeToken(); | 8733 ConsumeToken(); |
| 8681 if (CurrentToken() == Token::kPERIOD) { | 8734 if (CurrentToken() == Token::kPERIOD) { |
| 8682 ConsumeToken(); // Consume the kPERIOD token. | 8735 ConsumeToken(); // Consume the kPERIOD token. |
| 8683 ExpectIdentifier("identifier expected after '.'"); | 8736 ExpectIdentifier("identifier expected after '.'"); |
| 8684 } | 8737 } |
| 8685 } | 8738 } |
| 8686 | 8739 |
| 8687 } // namespace dart | 8740 } // namespace dart |
| OLD | NEW |