Chromium Code Reviews| 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 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 ((instantiator != NULL) && instantiator->is_captured())) { | 763 ((instantiator != NULL) && instantiator->is_captured())) { |
| 764 parsed_function->set_instantiator( | 764 parsed_function->set_instantiator( |
| 765 new LoadLocalNode(node_sequence->token_pos(), instantiator)); | 765 new LoadLocalNode(node_sequence->token_pos(), instantiator)); |
| 766 } | 766 } |
| 767 } | 767 } |
| 768 | 768 |
| 769 parsed_function->set_default_parameter_values(default_parameter_values); | 769 parsed_function->set_default_parameter_values(default_parameter_values); |
| 770 } | 770 } |
| 771 | 771 |
| 772 | 772 |
| 773 // TODO(regis): Implement support for non-const final static fields (currently | |
| 774 // supported "final" fields are actually const fields). | |
| 775 // TODO(regis): Since a const variable is implicitly final, | 773 // TODO(regis): Since a const variable is implicitly final, |
| 776 // rename ParseStaticConstGetter to ParseStaticFinalGetter and | 774 // rename ParseStaticConstGetter to ParseStaticFinalGetter and |
| 777 // rename kConstImplicitGetter to kImplicitFinalGetter. | 775 // rename kConstImplicitGetter to kImplicitFinalGetter. |
| 778 SequenceNode* Parser::ParseStaticConstGetter(const Function& func) { | 776 SequenceNode* Parser::ParseStaticConstGetter(const Function& func) { |
| 779 TRACE_PARSER("ParseStaticConstGetter"); | 777 TRACE_PARSER("ParseStaticConstGetter"); |
| 780 ParamList params; | 778 ParamList params; |
| 781 ASSERT(func.num_fixed_parameters() == 0); // static. | 779 ASSERT(func.num_fixed_parameters() == 0); // static. |
| 782 ASSERT(!func.HasOptionalParameters()); | 780 ASSERT(!func.HasOptionalParameters()); |
| 783 ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); | 781 ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); |
| 784 | 782 |
| 785 // Build local scope for function and populate with the formal parameters. | 783 // Build local scope for function and populate with the formal parameters. |
| 786 OpenFunctionBlock(func); | 784 OpenFunctionBlock(func); |
| 787 AddFormalParamsToScope(¶ms, current_block_->scope); | 785 AddFormalParamsToScope(¶ms, current_block_->scope); |
| 788 | 786 |
| 789 const String& field_name = *ExpectIdentifier("field name expected"); | 787 const String& field_name = *ExpectIdentifier("field name expected"); |
| 790 const Class& field_class = Class::Handle(func.Owner()); | 788 const Class& field_class = Class::Handle(func.Owner()); |
| 791 const Field& field = | 789 const Field& field = |
| 792 Field::ZoneHandle(field_class.LookupStaticField(field_name)); | 790 Field::ZoneHandle(field_class.LookupStaticField(field_name)); |
| 793 | 791 |
| 794 // Static const fields must have an initializer. | 792 // Static const fields must have an initializer. |
| 795 ExpectToken(Token::kASSIGN); | 793 ExpectToken(Token::kASSIGN); |
| 796 | 794 |
| 797 // We don't want to use ParseConstExpr() here because we don't want | 795 // We don't want to use ParseConstExpr() here because we don't want |
| 798 // the constant folding code to create, compile and execute a code | 796 // the constant folding code to create, compile and execute a code |
| 799 // fragment to evaluate the expression. Instead, we just make sure | 797 // fragment to evaluate the expression. Instead, we just make sure |
| 800 // the static const field initializer is a constant expression and | 798 // the static const field initializer is a constant expression and |
| 801 // leave the evaluation to the getter function. | 799 // leave the evaluation to the getter function. |
| 802 const intptr_t expr_pos = TokenPos(); | 800 const intptr_t expr_pos = TokenPos(); |
| 803 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); | 801 AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades); |
| 804 // TODO(hausner): Remove is_final check below once we support | 802 |
| 805 // non-const finals. | 803 if (field.is_const()) { |
| 806 if (field.is_const() || field.is_final()) { | |
| 807 // This getter will only be called once at compile time. | 804 // This getter will only be called once at compile time. |
| 808 if (expr->EvalConstExpr() == NULL) { | 805 if (expr->EvalConstExpr() == NULL) { |
| 809 ErrorMsg(expr_pos, "initializer must be a compile time constant"); | 806 ErrorMsg(expr_pos, "initializer must be a compile-time constant"); |
| 810 } | 807 } |
| 811 ReturnNode* return_node = new ReturnNode(TokenPos(), expr); | 808 ReturnNode* return_node = new ReturnNode(TokenPos(), expr); |
| 812 current_block_->statements->Add(return_node); | 809 current_block_->statements->Add(return_node); |
| 813 } else { | 810 } else { |
| 814 // This getter may be called each time the static field is accessed. | 811 // This getter may be called each time the static field is accessed. |
| 815 // The following generated code lazily initializes the field: | 812 // The following generated code lazily initializes the field: |
| 816 // if (field.value === transition_sentinel) { | 813 // if (field.value === transition_sentinel) { |
| 817 // field.value = null; | 814 // field.value = null; |
| 818 // throw("circular dependency in field initialization"); | 815 // throw("circular dependency in field initialization"); |
| 819 // } | 816 // } |
| 820 // if (field.value === sentinel) { | 817 // if (field.value === sentinel) { |
| 821 // field.value = transition_sentinel; | 818 // field.value = transition_sentinel; |
| 822 // field.value = expr; | 819 // field.value = expr; |
| 823 // } | 820 // } |
| 824 // return field.value; // Type check is executed here in checked mode. | 821 // return field.value; // Type check is executed here in checked mode. |
| 825 | 822 |
| 826 // TODO(regis): Remove this check once we support proper const fields. | |
| 827 if (expr->EvalConstExpr() == NULL) { | |
| 828 ErrorMsg(expr_pos, "initializer must be a compile time constant"); | |
| 829 } | |
| 830 | |
| 831 // Generate code checking for circular dependency in field initialization. | 823 // Generate code checking for circular dependency in field initialization. |
| 832 AstNode* compare_circular = new ComparisonNode( | 824 AstNode* compare_circular = new ComparisonNode( |
| 833 TokenPos(), | 825 TokenPos(), |
| 834 Token::kEQ_STRICT, | 826 Token::kEQ_STRICT, |
| 835 new LoadStaticFieldNode(TokenPos(), field), | 827 new LoadStaticFieldNode(TokenPos(), field), |
| 836 new LiteralNode(TokenPos(), | 828 new LiteralNode(TokenPos(), |
| 837 Instance::ZoneHandle(Object::transition_sentinel()))); | 829 Instance::ZoneHandle(Object::transition_sentinel()))); |
| 838 // Set field to null prior to throwing exception, so that subsequent | 830 // Set field to null prior to throwing exception, so that subsequent |
| 839 // accesses to the field do not throw again, since initializers should only | 831 // accesses to the field do not throw again, since initializers should only |
| 840 // be executed once. | 832 // be executed once. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 863 new LiteralNode(TokenPos(), | 855 new LiteralNode(TokenPos(), |
| 864 Instance::ZoneHandle(Object::sentinel()))); | 856 Instance::ZoneHandle(Object::sentinel()))); |
| 865 SequenceNode* initialize_field = new SequenceNode(TokenPos(), NULL); | 857 SequenceNode* initialize_field = new SequenceNode(TokenPos(), NULL); |
| 866 initialize_field->Add( | 858 initialize_field->Add( |
| 867 new StoreStaticFieldNode( | 859 new StoreStaticFieldNode( |
| 868 TokenPos(), | 860 TokenPos(), |
| 869 field, | 861 field, |
| 870 new LiteralNode( | 862 new LiteralNode( |
| 871 TokenPos(), | 863 TokenPos(), |
| 872 Instance::ZoneHandle(Object::transition_sentinel())))); | 864 Instance::ZoneHandle(Object::transition_sentinel())))); |
| 865 // TODO(hausner): If evaluation of the field value throws an exception, | |
| 866 // we leave the field value as 'transition_sentinel', which is wrong. | |
| 867 // A second reference to the field later throws a circular dependency | |
| 868 // exception. The field should instead be set to null after an exception. | |
|
regis
2012/09/12 23:46:58
This contradicts the comment on line 814 stating t
hausner
2012/09/12 23:51:54
No. The comment refers to the code under condition
regis
2012/09/12 23:59:04
I stand corrected :-)
Btw, there was an email disc
| |
| 873 initialize_field->Add(new StoreStaticFieldNode(TokenPos(), field, expr)); | 869 initialize_field->Add(new StoreStaticFieldNode(TokenPos(), field, expr)); |
| 874 AstNode* uninitialized_check = | 870 AstNode* uninitialized_check = |
| 875 new IfNode(TokenPos(), compare_uninitialized, initialize_field, NULL); | 871 new IfNode(TokenPos(), compare_uninitialized, initialize_field, NULL); |
| 876 current_block_->statements->Add(uninitialized_check); | 872 current_block_->statements->Add(uninitialized_check); |
| 877 | 873 |
| 878 // Generate code returning the field value. | 874 // Generate code returning the field value. |
| 879 ReturnNode* return_node = | 875 ReturnNode* return_node = |
| 880 new ReturnNode(TokenPos(), | 876 new ReturnNode(TokenPos(), |
| 881 new LoadStaticFieldNode(TokenPos(), field)); | 877 new LoadStaticFieldNode(TokenPos(), field)); |
| 882 current_block_->statements->Add(return_node); | 878 current_block_->statements->Add(return_node); |
| (...skipping 1786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2669 if (field->has_const || (field->has_static && field->has_final)) { | 2665 if (field->has_const || (field->has_static && field->has_final)) { |
| 2670 ErrorMsg(field->name_pos, | 2666 ErrorMsg(field->name_pos, |
| 2671 "%s%s field '%s' must have an initializer expression", | 2667 "%s%s field '%s' must have an initializer expression", |
| 2672 field->has_static ? "static " : "", | 2668 field->has_static ? "static " : "", |
| 2673 field->has_const ? "const" : "final", | 2669 field->has_const ? "const" : "final", |
| 2674 field->name->ToCString()); | 2670 field->name->ToCString()); |
| 2675 } | 2671 } |
| 2676 } | 2672 } |
| 2677 | 2673 |
| 2678 // Create the field object. | 2674 // Create the field object. |
| 2679 // TODO(hausner): For now, all static final fields are constant. Remove | |
| 2680 // this when lazy init of static variables is implemented. | |
| 2681 class_field = Field::New(*field->name, | 2675 class_field = Field::New(*field->name, |
| 2682 field->has_static, | 2676 field->has_static, |
| 2683 field->has_final, | 2677 field->has_final, |
| 2684 field->has_const || field->has_final, | 2678 field->has_const, |
| 2685 current_class(), | 2679 current_class(), |
| 2686 field->name_pos); | 2680 field->name_pos); |
| 2687 class_field.set_type(*field->type); | 2681 class_field.set_type(*field->type); |
| 2688 class_field.set_has_initializer(has_initializer); | 2682 class_field.set_has_initializer(has_initializer); |
| 2689 members->AddField(class_field); | 2683 members->AddField(class_field); |
| 2690 | 2684 |
| 2691 // For static const fields, set value to "uninitialized" and | 2685 // For static const fields, set value to "uninitialized" and |
| 2692 // create a kConstImplicitGetter getter method. | 2686 // create a kConstImplicitGetter getter method. |
| 2693 if (field->has_static && has_initializer) { | 2687 if (field->has_static && has_initializer) { |
| 2694 class_field.set_value(init_value); | 2688 class_field.set_value(init_value); |
| 2695 if (!has_simple_literal) { | 2689 if (!has_simple_literal) { |
| 2696 String& getter_name = String::Handle(Field::GetterSymbol(*field->name)); | 2690 String& getter_name = String::Handle(Field::GetterSymbol(*field->name)); |
| 2697 getter = Function::New(getter_name, | 2691 getter = Function::New(getter_name, |
| 2698 RawFunction::kConstImplicitGetter, | 2692 RawFunction::kConstImplicitGetter, |
| 2699 field->has_static, | 2693 field->has_static, |
| 2700 field->has_final, | 2694 field->has_const, |
| 2701 /* is_abstract = */ false, | 2695 /* is_abstract = */ false, |
| 2702 /* is_external = */ false, | 2696 /* is_external = */ false, |
| 2703 current_class(), | 2697 current_class(), |
| 2704 field->name_pos); | 2698 field->name_pos); |
| 2705 getter.set_result_type(*field->type); | 2699 getter.set_result_type(*field->type); |
| 2706 members->AddFunction(getter); | 2700 members->AddFunction(getter); |
| 2707 } | 2701 } |
| 2708 } | 2702 } |
| 2709 | 2703 |
| 2710 // For instance fields, we create implicit getter and setter methods. | 2704 // For instance fields, we create implicit getter and setter methods. |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3058 ErrorMsg(classname_pos, "'%s' %s", | 3052 ErrorMsg(classname_pos, "'%s' %s", |
| 3059 class_name.ToCString(), | 3053 class_name.ToCString(), |
| 3060 is_patch ? | 3054 is_patch ? |
| 3061 "interface cannot be patched" : | 3055 "interface cannot be patched" : |
| 3062 "is already defined as interface"); | 3056 "is already defined as interface"); |
| 3063 } else if (is_patch) { | 3057 } else if (is_patch) { |
| 3064 String& patch = String::Handle(Symbols::New("patch ")); | 3058 String& patch = String::Handle(Symbols::New("patch ")); |
| 3065 patch = String::Concat(patch, class_name); | 3059 patch = String::Concat(patch, class_name); |
| 3066 patch = Symbols::New(patch); | 3060 patch = Symbols::New(patch); |
| 3067 cls = Class::New(patch, script_, classname_pos); | 3061 cls = Class::New(patch, script_, classname_pos); |
| 3068 cls.set_library(library_); | |
| 3069 } else { | 3062 } else { |
| 3070 // Not patching a class, but it has been found. This must be one of the | 3063 // Not patching a class, but it has been found. This must be one of the |
| 3071 // pre-registered classes from object.cc or a duplicate definition. | 3064 // pre-registered classes from object.cc or a duplicate definition. |
| 3072 if (cls.functions() != Object::empty_array()) { | 3065 if (cls.functions() != Object::empty_array()) { |
| 3073 ErrorMsg(classname_pos, "class '%s' is already defined", | 3066 ErrorMsg(classname_pos, "class '%s' is already defined", |
| 3074 class_name.ToCString()); | 3067 class_name.ToCString()); |
| 3075 } | 3068 } |
| 3076 // Pre-registered classes need their scripts connected at this time. | 3069 // Pre-registered classes need their scripts connected at this time. |
| 3077 cls.set_script(script_); | 3070 cls.set_script(script_); |
| 3078 } | 3071 } |
| (...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3732 } | 3725 } |
| 3733 AddInterfaceIfUnique(interfaces_pos, all_interfaces, interface); | 3726 AddInterfaceIfUnique(interfaces_pos, all_interfaces, interface); |
| 3734 } | 3727 } |
| 3735 cls_interfaces = Array::MakeArray(all_interfaces); | 3728 cls_interfaces = Array::MakeArray(all_interfaces); |
| 3736 cls.set_interfaces(cls_interfaces); | 3729 cls.set_interfaces(cls_interfaces); |
| 3737 } | 3730 } |
| 3738 | 3731 |
| 3739 | 3732 |
| 3740 void Parser::ParseTopLevelVariable(TopLevel* top_level) { | 3733 void Parser::ParseTopLevelVariable(TopLevel* top_level) { |
| 3741 TRACE_PARSER("ParseTopLevelVariable"); | 3734 TRACE_PARSER("ParseTopLevelVariable"); |
| 3742 const bool is_final = (CurrentToken() == Token::kFINAL); | |
| 3743 const bool is_const = (CurrentToken() == Token::kCONST); | 3735 const bool is_const = (CurrentToken() == Token::kCONST); |
| 3736 // Const fields are implicitly final. | |
| 3737 const bool is_final = is_const || (CurrentToken() == Token::kFINAL); | |
| 3744 const bool is_static = true; | 3738 const bool is_static = true; |
| 3745 const AbstractType& type = | 3739 const AbstractType& type = |
| 3746 AbstractType::ZoneHandle(ParseConstFinalVarOrType( | 3740 AbstractType::ZoneHandle(ParseConstFinalVarOrType( |
| 3747 FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : | 3741 FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : |
| 3748 ClassFinalizer::kIgnore)); | 3742 ClassFinalizer::kIgnore)); |
| 3749 Field& field = Field::Handle(); | 3743 Field& field = Field::Handle(); |
| 3750 Function& getter = Function::Handle(); | 3744 Function& getter = Function::Handle(); |
| 3751 while (true) { | 3745 while (true) { |
| 3752 const intptr_t name_pos = TokenPos(); | 3746 const intptr_t name_pos = TokenPos(); |
| 3753 String& var_name = *ExpectIdentifier("variable name expected"); | 3747 String& var_name = *ExpectIdentifier("variable name expected"); |
| 3754 | 3748 |
| 3755 if (library_.LookupLocalObject(var_name) != Object::null()) { | 3749 if (library_.LookupLocalObject(var_name) != Object::null()) { |
| 3756 ErrorMsg(name_pos, "'%s' is already defined", var_name.ToCString()); | 3750 ErrorMsg(name_pos, "'%s' is already defined", var_name.ToCString()); |
| 3757 } | 3751 } |
| 3758 String& accessor_name = String::Handle(Field::GetterName(var_name)); | 3752 String& accessor_name = String::Handle(Field::GetterName(var_name)); |
| 3759 if (library_.LookupLocalObject(accessor_name) != Object::null()) { | 3753 if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| 3760 ErrorMsg(name_pos, "getter for '%s' is already defined", | 3754 ErrorMsg(name_pos, "getter for '%s' is already defined", |
| 3761 var_name.ToCString()); | 3755 var_name.ToCString()); |
| 3762 } | 3756 } |
| 3763 accessor_name = Field::SetterName(var_name); | 3757 accessor_name = Field::SetterName(var_name); |
| 3764 if (library_.LookupLocalObject(accessor_name) != Object::null()) { | 3758 if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| 3765 ErrorMsg(name_pos, "setter for '%s' is already defined", | 3759 ErrorMsg(name_pos, "setter for '%s' is already defined", |
| 3766 var_name.ToCString()); | 3760 var_name.ToCString()); |
| 3767 } | 3761 } |
| 3768 | 3762 |
| 3769 // TODO(hausner): const and final are equivalent at the moment. | 3763 field = Field::New(var_name, is_static, is_final, is_const, |
| 3770 field = Field::New(var_name, | 3764 current_class(), name_pos); |
| 3771 is_static, | |
| 3772 is_final || is_const, // Const fields are also final. | |
| 3773 is_const || is_final, | |
| 3774 current_class(), | |
| 3775 name_pos); | |
| 3776 field.set_type(type); | 3765 field.set_type(type); |
| 3777 field.set_value(Instance::Handle(Instance::null())); | 3766 field.set_value(Instance::Handle(Instance::null())); |
| 3778 top_level->fields.Add(field); | 3767 top_level->fields.Add(field); |
| 3779 library_.AddObject(field, var_name); | 3768 library_.AddObject(field, var_name); |
| 3780 if (CurrentToken() == Token::kASSIGN) { | 3769 if (CurrentToken() == Token::kASSIGN) { |
| 3781 ConsumeToken(); | 3770 ConsumeToken(); |
| 3782 Instance& field_value = Instance::Handle(Object::sentinel()); | 3771 Instance& field_value = Instance::Handle(Object::sentinel()); |
| 3783 bool has_simple_literal = false; | 3772 bool has_simple_literal = false; |
| 3784 if ((is_final || is_const) && (LookaheadToken(1) == Token::kSEMICOLON)) { | 3773 if (is_final && (LookaheadToken(1) == Token::kSEMICOLON)) { |
| 3785 has_simple_literal = IsSimpleLiteral(type, &field_value); | 3774 has_simple_literal = IsSimpleLiteral(type, &field_value); |
| 3786 } | 3775 } |
| 3787 SkipExpr(); | 3776 SkipExpr(); |
| 3788 field.set_value(field_value); | 3777 field.set_value(field_value); |
| 3789 if (!has_simple_literal) { | 3778 if (!has_simple_literal) { |
| 3790 // Create a static const getter. | 3779 // Create a static const getter. |
| 3791 String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name)); | 3780 String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name)); |
| 3792 getter = Function::New(getter_name, | 3781 getter = Function::New(getter_name, |
| 3793 RawFunction::kConstImplicitGetter, | 3782 RawFunction::kConstImplicitGetter, |
| 3794 is_static, | 3783 is_static, |
| 3795 is_final, | 3784 is_const, |
| 3796 /* is_abstract = */ false, | 3785 /* is_abstract = */ false, |
| 3797 /* is_external = */ false, | 3786 /* is_external = */ false, |
| 3798 current_class(), | 3787 current_class(), |
| 3799 name_pos); | 3788 name_pos); |
| 3800 getter.set_result_type(type); | 3789 getter.set_result_type(type); |
| 3801 top_level->functions.Add(getter); | 3790 top_level->functions.Add(getter); |
| 3802 } | 3791 } |
| 3803 | 3792 } else if (is_final) { |
| 3804 } else if (is_final || is_const) { | |
| 3805 ErrorMsg(name_pos, "missing initializer for final or const variable"); | 3793 ErrorMsg(name_pos, "missing initializer for final or const variable"); |
| 3806 } | 3794 } |
| 3807 | 3795 |
| 3808 if (CurrentToken() == Token::kCOMMA) { | 3796 if (CurrentToken() == Token::kCOMMA) { |
| 3809 ConsumeToken(); | 3797 ConsumeToken(); |
| 3810 } else if (CurrentToken() == Token::kSEMICOLON) { | 3798 } else if (CurrentToken() == Token::kSEMICOLON) { |
| 3811 ConsumeToken(); | 3799 ConsumeToken(); |
| 3812 break; | 3800 break; |
| 3813 } else { | 3801 } else { |
| 3814 ExpectSemicolon(); // Reports error. | 3802 ExpectSemicolon(); // Reports error. |
| (...skipping 2965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6780 } | 6768 } |
| 6781 | 6769 |
| 6782 | 6770 |
| 6783 // Evaluates the value of the compile time constant expression | 6771 // Evaluates the value of the compile time constant expression |
| 6784 // and returns a literal node for the value. | 6772 // and returns a literal node for the value. |
| 6785 AstNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) { | 6773 AstNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) { |
| 6786 if (expr->IsLiteralNode()) { | 6774 if (expr->IsLiteralNode()) { |
| 6787 return expr; | 6775 return expr; |
| 6788 } | 6776 } |
| 6789 if (expr->EvalConstExpr() == NULL) { | 6777 if (expr->EvalConstExpr() == NULL) { |
| 6790 ErrorMsg(expr_pos, "expression must be a compile time constant"); | 6778 ErrorMsg(expr_pos, "expression must be a compile-time constant"); |
| 6791 } | 6779 } |
| 6792 return new LiteralNode(expr_pos, EvaluateConstExpr(expr)); | 6780 return new LiteralNode(expr_pos, EvaluateConstExpr(expr)); |
| 6793 } | 6781 } |
| 6794 | 6782 |
| 6795 | 6783 |
| 6796 // A compound assignment consists of a store and a load part. In order | 6784 // A compound assignment consists of a store and a load part. In order |
| 6797 // to control inputs with potential side effects, the store part stores any | 6785 // to control inputs with potential side effects, the store part stores any |
| 6798 // side effect creating inputs into locals. The load part reads then from | 6786 // side effect creating inputs into locals. The load part reads then from |
| 6799 // those locals. If expr may have side effects, it will be split into two new | 6787 // those locals. If expr may have side effects, it will be split into two new |
| 6800 // left and right nodes. 'expr' becomes the right node, left node is returned as | 6788 // left and right nodes. 'expr' becomes the right node, left node is returned as |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6935 expr = FoldConstExpr(expr_pos, expr); | 6923 expr = FoldConstExpr(expr_pos, expr); |
| 6936 } | 6924 } |
| 6937 return expr; | 6925 return expr; |
| 6938 } | 6926 } |
| 6939 // Assignment expressions. | 6927 // Assignment expressions. |
| 6940 Token::Kind assignment_op = CurrentToken(); | 6928 Token::Kind assignment_op = CurrentToken(); |
| 6941 const intptr_t assignment_pos = TokenPos(); | 6929 const intptr_t assignment_pos = TokenPos(); |
| 6942 ConsumeToken(); | 6930 ConsumeToken(); |
| 6943 const intptr_t right_expr_pos = TokenPos(); | 6931 const intptr_t right_expr_pos = TokenPos(); |
| 6944 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { | 6932 if (require_compiletime_const && (assignment_op != Token::kASSIGN)) { |
| 6945 ErrorMsg(right_expr_pos, "expression must be a compile time constant"); | 6933 ErrorMsg(right_expr_pos, "expression must be a compile-time constant"); |
| 6946 } | 6934 } |
| 6947 AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades); | 6935 AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades); |
| 6948 AstNode* left_expr = expr; | 6936 AstNode* left_expr = expr; |
| 6949 if (assignment_op != Token::kASSIGN) { | 6937 if (assignment_op != Token::kASSIGN) { |
| 6950 // Compound assignment: store inputs with side effects into temp. locals. | 6938 // Compound assignment: store inputs with side effects into temp. locals. |
| 6951 left_expr = PrepareCompoundAssignmentNodes(&expr); | 6939 left_expr = PrepareCompoundAssignmentNodes(&expr); |
| 6952 } | 6940 } |
| 6953 right_expr = | 6941 right_expr = |
| 6954 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); | 6942 ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr); |
| 6955 AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr); | 6943 AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7174 intptr_t ident_pos) { | 7162 intptr_t ident_pos) { |
| 7175 // If the static field has an initializer, initialize the field at compile | 7163 // If the static field has an initializer, initialize the field at compile |
| 7176 // time, which is only possible if the field is const. | 7164 // time, which is only possible if the field is const. |
| 7177 AstNode* initializing_getter = RunStaticFieldInitializer(field); | 7165 AstNode* initializing_getter = RunStaticFieldInitializer(field); |
| 7178 if (initializing_getter != NULL) { | 7166 if (initializing_getter != NULL) { |
| 7179 // The field is not yet initialized and could not be initialized at compile | 7167 // The field is not yet initialized and could not be initialized at compile |
| 7180 // time. The getter will initialize the field. | 7168 // time. The getter will initialize the field. |
| 7181 return initializing_getter; | 7169 return initializing_getter; |
| 7182 } | 7170 } |
| 7183 // The field is initialized. | 7171 // The field is initialized. |
| 7184 // TODO(hausner): Remove the is_final check when we support non-const | 7172 if (field.is_const()) { |
| 7185 // final static variables. | |
| 7186 if (field.is_const() || field.is_final()) { | |
| 7187 ASSERT(field.value() != Object::sentinel()); | 7173 ASSERT(field.value() != Object::sentinel()); |
| 7188 ASSERT(field.value() != Object::transition_sentinel()); | 7174 ASSERT(field.value() != Object::transition_sentinel()); |
| 7189 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); | 7175 return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value())); |
| 7190 } | 7176 } |
| 7191 // Access the field directly. | 7177 // Access the field directly. |
| 7192 return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw())); | 7178 return new LoadStaticFieldNode(ident_pos, Field::ZoneHandle(field.raw())); |
| 7193 } | 7179 } |
| 7194 | 7180 |
| 7195 | 7181 |
| 7196 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, | 7182 AstNode* Parser::ParseStaticFieldAccess(const Class& cls, |
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7745 } | 7731 } |
| 7746 | 7732 |
| 7747 | 7733 |
| 7748 // If the field is already initialized, return no ast (NULL). | 7734 // If the field is already initialized, return no ast (NULL). |
| 7749 // Otherwise, if the field is constant, initialize the field and return no ast. | 7735 // Otherwise, if the field is constant, initialize the field and return no ast. |
| 7750 // If the field is not initialized and not const, return the ast for the getter. | 7736 // If the field is not initialized and not const, return the ast for the getter. |
| 7751 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { | 7737 AstNode* Parser::RunStaticFieldInitializer(const Field& field) { |
| 7752 ASSERT(field.is_static()); | 7738 ASSERT(field.is_static()); |
| 7753 const Instance& value = Instance::Handle(field.value()); | 7739 const Instance& value = Instance::Handle(field.value()); |
| 7754 if (value.raw() == Object::transition_sentinel()) { | 7740 if (value.raw() == Object::transition_sentinel()) { |
| 7755 // TODO(hausner): Remove the check for is_final() once we support | 7741 if (field.is_const()) { |
| 7756 // non-const final fields. | |
| 7757 if (field.is_const() || field.is_final()) { | |
| 7758 ErrorMsg("circular dependency while initializing static field '%s'", | 7742 ErrorMsg("circular dependency while initializing static field '%s'", |
| 7759 String::Handle(field.name()).ToCString()); | 7743 String::Handle(field.name()).ToCString()); |
| 7760 } else { | 7744 } else { |
| 7761 // The implicit static getter will throw the exception if necessary. | 7745 // The implicit static getter will throw the exception if necessary. |
| 7762 return new StaticGetterNode(TokenPos(), | 7746 return new StaticGetterNode(TokenPos(), |
| 7763 NULL, | 7747 NULL, |
| 7764 false, | 7748 false, |
| 7765 Class::ZoneHandle(field.owner()), | 7749 Class::ZoneHandle(field.owner()), |
| 7766 String::ZoneHandle(field.name())); | 7750 String::ZoneHandle(field.name())); |
| 7767 } | 7751 } |
| 7768 } else if (value.raw() == Object::sentinel()) { | 7752 } else if (value.raw() == Object::sentinel()) { |
| 7769 // This field has not been referenced yet and thus the value has | 7753 // This field has not been referenced yet and thus the value has |
| 7770 // not been evaluated. If the field is const, call the static getter method | 7754 // not been evaluated. If the field is const, call the static getter method |
| 7771 // to evaluate the expression and canonicalize the value. | 7755 // to evaluate the expression and canonicalize the value. |
| 7772 // TODO(hausner): Remove the check for is_final() once we support | 7756 if (field.is_const()) { |
| 7773 // non-const final fields. | |
| 7774 if (field.is_const() || field.is_final()) { | |
| 7775 field.set_value(Instance::Handle(Object::transition_sentinel())); | 7757 field.set_value(Instance::Handle(Object::transition_sentinel())); |
| 7776 const String& field_name = String::Handle(field.name()); | 7758 const String& field_name = String::Handle(field.name()); |
| 7777 const String& getter_name = | 7759 const String& getter_name = |
| 7778 String::Handle(Field::GetterName(field_name)); | 7760 String::Handle(Field::GetterName(field_name)); |
| 7779 const Class& cls = Class::Handle(field.owner()); | 7761 const Class& cls = Class::Handle(field.owner()); |
| 7780 GrowableArray<const Object*> arguments; // no arguments. | 7762 GrowableArray<const Object*> arguments; // no arguments. |
| 7781 const int kNumArguments = 0; // no arguments. | 7763 const int kNumArguments = 0; // no arguments. |
| 7782 const Array& kNoArgumentNames = Array::Handle(); | 7764 const Array& kNoArgumentNames = Array::Handle(); |
| 7783 const Function& func = | 7765 const Function& func = |
| 7784 Function::Handle(Resolver::ResolveStatic(cls, | 7766 Function::Handle(Resolver::ResolveStatic(cls, |
| 7785 getter_name, | 7767 getter_name, |
| 7786 kNumArguments, | 7768 kNumArguments, |
| 7787 kNoArgumentNames, | 7769 kNoArgumentNames, |
| 7788 Resolver::kIsQualified)); | 7770 Resolver::kIsQualified)); |
| 7789 ASSERT(!func.IsNull()); | 7771 ASSERT(!func.IsNull()); |
| 7790 ASSERT(func.kind() == RawFunction::kConstImplicitGetter); | 7772 ASSERT(func.kind() == RawFunction::kConstImplicitGetter); |
| 7791 Object& const_value = Object::Handle( | 7773 Object& const_value = Object::Handle( |
| 7792 DartEntry::InvokeStatic(func, arguments, kNoArgumentNames)); | 7774 DartEntry::InvokeStatic(func, arguments, kNoArgumentNames)); |
| 7793 if (const_value.IsError()) { | 7775 if (const_value.IsError()) { |
| 7794 const Error& error = Error::Cast(const_value); | 7776 const Error& error = Error::Cast(const_value); |
| 7795 if (error.IsUnhandledException()) { | 7777 if (error.IsUnhandledException()) { |
| 7796 field.set_value(Instance::Handle()); | 7778 field.set_value(Instance::Handle()); |
| 7797 // It is a compile-time error if evaluation of a compile-time constant | 7779 // It is a compile-time error if evaluation of a compile-time constant |
| 7798 // would raise an exception. | 7780 // would raise an exception. |
| 7799 AppendErrorMsg(error, TokenPos(), | 7781 AppendErrorMsg(error, TokenPos(), |
| 7800 "error initializing final field '%s'", | 7782 "error initializing const field '%s'", |
| 7801 String::Handle(field.name()).ToCString()); | 7783 String::Handle(field.name()).ToCString()); |
| 7802 } else { | 7784 } else { |
| 7803 Isolate::Current()->long_jump_base()->Jump(1, error); | 7785 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 7804 } | 7786 } |
| 7805 } | 7787 } |
| 7806 ASSERT(const_value.IsNull() || const_value.IsInstance()); | 7788 ASSERT(const_value.IsNull() || const_value.IsInstance()); |
| 7807 Instance& instance = Instance::Handle(); | 7789 Instance& instance = Instance::Handle(); |
| 7808 instance ^= const_value.raw(); | 7790 instance ^= const_value.raw(); |
| 7809 if (!instance.IsNull()) { | 7791 if (!instance.IsNull()) { |
| 7810 instance ^= instance.Canonicalize(); | 7792 instance ^= instance.Canonicalize(); |
| (...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8560 // comma after the last entry. | 8542 // comma after the last entry. |
| 8561 const String& dst_name = String::ZoneHandle(Symbols::ListLiteralElement()); | 8543 const String& dst_name = String::ZoneHandle(Symbols::ListLiteralElement()); |
| 8562 while (CurrentToken() != Token::kRBRACE) { | 8544 while (CurrentToken() != Token::kRBRACE) { |
| 8563 AstNode* key = NULL; | 8545 AstNode* key = NULL; |
| 8564 if (CurrentToken() == Token::kSTRING) { | 8546 if (CurrentToken() == Token::kSTRING) { |
| 8565 key = ParseStringLiteral(); | 8547 key = ParseStringLiteral(); |
| 8566 } | 8548 } |
| 8567 if (key == NULL) { | 8549 if (key == NULL) { |
| 8568 ErrorMsg("map entry key must be string literal"); | 8550 ErrorMsg("map entry key must be string literal"); |
| 8569 } else if (is_const && !key->IsLiteralNode()) { | 8551 } else if (is_const && !key->IsLiteralNode()) { |
| 8570 ErrorMsg("map entry key must be compile time constant string"); | 8552 ErrorMsg("map entry key must be compile-time constant string"); |
| 8571 } | 8553 } |
| 8572 ExpectToken(Token::kCOLON); | 8554 ExpectToken(Token::kCOLON); |
| 8573 const bool saved_mode = SetAllowFunctionLiterals(true); | 8555 const bool saved_mode = SetAllowFunctionLiterals(true); |
| 8574 const intptr_t value_pos = TokenPos(); | 8556 const intptr_t value_pos = TokenPos(); |
| 8575 AstNode* value = ParseExpr(is_const, kConsumeCascades); | 8557 AstNode* value = ParseExpr(is_const, kConsumeCascades); |
| 8576 SetAllowFunctionLiterals(saved_mode); | 8558 SetAllowFunctionLiterals(saved_mode); |
| 8577 if (FLAG_enable_type_checks && | 8559 if (FLAG_enable_type_checks && |
| 8578 !is_const && | 8560 !is_const && |
| 8579 !value_type.IsDynamicType()) { | 8561 !value_type.IsDynamicType()) { |
| 8580 value = new AssignableNode(value_pos, | 8562 value = new AssignableNode(value_pos, |
| (...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9557 void Parser::SkipQualIdent() { | 9539 void Parser::SkipQualIdent() { |
| 9558 ASSERT(IsIdentifier()); | 9540 ASSERT(IsIdentifier()); |
| 9559 ConsumeToken(); | 9541 ConsumeToken(); |
| 9560 if (CurrentToken() == Token::kPERIOD) { | 9542 if (CurrentToken() == Token::kPERIOD) { |
| 9561 ConsumeToken(); // Consume the kPERIOD token. | 9543 ConsumeToken(); // Consume the kPERIOD token. |
| 9562 ExpectIdentifier("identifier expected after '.'"); | 9544 ExpectIdentifier("identifier expected after '.'"); |
| 9563 } | 9545 } |
| 9564 } | 9546 } |
| 9565 | 9547 |
| 9566 } // namespace dart | 9548 } // namespace dart |
| OLD | NEW |