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 "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
9 #include "vm/bootstrap.h" | 9 #include "vm/bootstrap.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "vm/tags.h" | 32 #include "vm/tags.h" |
33 #include "vm/timer.h" | 33 #include "vm/timer.h" |
34 #include "vm/zone.h" | 34 #include "vm/zone.h" |
35 | 35 |
36 namespace dart { | 36 namespace dart { |
37 | 37 |
38 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); | 38 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); |
39 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); | 39 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); |
40 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); | 40 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); |
41 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef."); | 41 DEFINE_FLAG(bool, warn_mixin_typedef, true, "Warning on legacy mixin typedef."); |
| 42 DEFINE_FLAG(bool, enable_async, false, "Enable async operations."); |
42 DECLARE_FLAG(bool, error_on_bad_type); | 43 DECLARE_FLAG(bool, error_on_bad_type); |
43 DECLARE_FLAG(bool, throw_on_javascript_int_overflow); | 44 DECLARE_FLAG(bool, throw_on_javascript_int_overflow); |
44 DECLARE_FLAG(bool, warn_on_javascript_compatibility); | 45 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
45 | 46 |
46 static void CheckedModeHandler(bool value) { | 47 static void CheckedModeHandler(bool value) { |
47 FLAG_enable_asserts = value; | 48 FLAG_enable_asserts = value; |
48 FLAG_enable_type_checks = value; | 49 FLAG_enable_type_checks = value; |
49 } | 50 } |
50 | 51 |
51 // --enable-checked-mode and --checked both enable checked mode which is | 52 // --enable-checked-mode and --checked both enable checked mode which is |
(...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 SequenceNode* node_sequence = NULL; | 789 SequenceNode* node_sequence = NULL; |
789 Array& default_parameter_values = Array::ZoneHandle(isolate, Array::null()); | 790 Array& default_parameter_values = Array::ZoneHandle(isolate, Array::null()); |
790 switch (func.kind()) { | 791 switch (func.kind()) { |
791 case RawFunction::kRegularFunction: | 792 case RawFunction::kRegularFunction: |
792 case RawFunction::kClosureFunction: | 793 case RawFunction::kClosureFunction: |
793 case RawFunction::kGetterFunction: | 794 case RawFunction::kGetterFunction: |
794 case RawFunction::kSetterFunction: | 795 case RawFunction::kSetterFunction: |
795 case RawFunction::kConstructor: | 796 case RawFunction::kConstructor: |
796 // The call to a redirecting factory is redirected. | 797 // The call to a redirecting factory is redirected. |
797 ASSERT(!func.IsRedirectingFactory()); | 798 ASSERT(!func.IsRedirectingFactory()); |
798 if (!func.IsImplicitConstructor()) { | 799 if (!func.IsImplicitConstructor() && !func.is_async_closure()) { |
799 parser.SkipFunctionPreamble(); | 800 parser.SkipFunctionPreamble(); |
800 } | 801 } |
801 node_sequence = parser.ParseFunc(func, &default_parameter_values); | 802 node_sequence = parser.ParseFunc(func, &default_parameter_values); |
802 break; | 803 break; |
803 case RawFunction::kImplicitGetter: | 804 case RawFunction::kImplicitGetter: |
804 ASSERT(!func.is_static()); | 805 ASSERT(!func.is_static()); |
805 node_sequence = parser.ParseInstanceGetter(func); | 806 node_sequence = parser.ParseInstanceGetter(func); |
806 break; | 807 break; |
807 case RawFunction::kImplicitSetter: | 808 case RawFunction::kImplicitSetter: |
808 ASSERT(!func.is_static()); | 809 ASSERT(!func.is_static()); |
(...skipping 2082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2891 AstNode* guarded_block_statements = | 2892 AstNode* guarded_block_statements = |
2892 new IfNode(Scanner::kNoSourcePos, comparison, ctor_block, NULL); | 2893 new IfNode(Scanner::kNoSourcePos, comparison, ctor_block, NULL); |
2893 current_block_->statements->Add(guarded_block_statements); | 2894 current_block_->statements->Add(guarded_block_statements); |
2894 } | 2895 } |
2895 current_block_->statements->Add(new ReturnNode(func.end_token_pos())); | 2896 current_block_->statements->Add(new ReturnNode(func.end_token_pos())); |
2896 SequenceNode* statements = CloseBlock(); | 2897 SequenceNode* statements = CloseBlock(); |
2897 return statements; | 2898 return statements; |
2898 } | 2899 } |
2899 | 2900 |
2900 | 2901 |
| 2902 // TODO(mlippautz): Once we know where these classes should come from, adjust |
| 2903 // how we get their definition. |
| 2904 RawClass* Parser::GetClassForAsync(const String& class_name) { |
| 2905 const Class& cls = Class::Handle(library_.LookupClass(class_name)); |
| 2906 if (cls.IsNull()) { |
| 2907 ReportError("async modifier requires dart:async to be imported without " |
| 2908 "prefix"); |
| 2909 } |
| 2910 return cls.raw(); |
| 2911 } |
| 2912 |
| 2913 |
2901 // Parser is at the opening parenthesis of the formal parameter | 2914 // Parser is at the opening parenthesis of the formal parameter |
2902 // declaration of the function or constructor. | 2915 // declaration of the function or constructor. |
2903 // Parse the formal parameters and code. | 2916 // Parse the formal parameters and code. |
2904 SequenceNode* Parser::ParseFunc(const Function& func, | 2917 SequenceNode* Parser::ParseFunc(const Function& func, |
2905 Array* default_parameter_values) { | 2918 Array* default_parameter_values) { |
2906 TRACE_PARSER("ParseFunc"); | 2919 TRACE_PARSER("ParseFunc"); |
2907 Function& saved_innermost_function = | 2920 Function& saved_innermost_function = |
2908 Function::Handle(I, innermost_function().raw()); | 2921 Function::Handle(I, innermost_function().raw()); |
2909 innermost_function_ = func.raw(); | 2922 innermost_function_ = func.raw(); |
2910 | 2923 |
2911 // Save current try index. Try index starts at zero for each function. | 2924 // Save current try index. Try index starts at zero for each function. |
2912 intptr_t saved_try_index = last_used_try_index_; | 2925 intptr_t saved_try_index = last_used_try_index_; |
2913 last_used_try_index_ = 0; | 2926 last_used_try_index_ = 0; |
2914 | 2927 |
| 2928 intptr_t formal_params_pos = TokenPos(); |
2915 // TODO(12455) : Need better validation mechanism. | 2929 // TODO(12455) : Need better validation mechanism. |
2916 | 2930 |
2917 if (func.IsConstructor()) { | 2931 if (func.IsConstructor()) { |
2918 SequenceNode* statements = ParseConstructor(func, default_parameter_values); | 2932 SequenceNode* statements = ParseConstructor(func, default_parameter_values); |
2919 innermost_function_ = saved_innermost_function.raw(); | 2933 innermost_function_ = saved_innermost_function.raw(); |
2920 last_used_try_index_ = saved_try_index; | 2934 last_used_try_index_ = saved_try_index; |
2921 return statements; | 2935 return statements; |
2922 } | 2936 } |
2923 | 2937 |
2924 ASSERT(!func.IsConstructor()); | 2938 ASSERT(!func.IsConstructor()); |
(...skipping 14 matching lines...) Expand all Loading... |
2939 ASSERT(current_class().raw() == func.Owner()); | 2953 ASSERT(current_class().raw() == func.Owner()); |
2940 params.AddReceiver(ReceiverType(current_class()), func.token_pos()); | 2954 params.AddReceiver(ReceiverType(current_class()), func.token_pos()); |
2941 } else if (func.IsFactory()) { | 2955 } else if (func.IsFactory()) { |
2942 // The first parameter of a factory is the TypeArguments vector of | 2956 // The first parameter of a factory is the TypeArguments vector of |
2943 // the type of the instance to be allocated. | 2957 // the type of the instance to be allocated. |
2944 params.AddFinalParameter( | 2958 params.AddFinalParameter( |
2945 TokenPos(), | 2959 TokenPos(), |
2946 &Symbols::TypeArgumentsParameter(), | 2960 &Symbols::TypeArgumentsParameter(), |
2947 &Type::ZoneHandle(I, Type::DynamicType())); | 2961 &Type::ZoneHandle(I, Type::DynamicType())); |
2948 } | 2962 } |
2949 ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction()); | 2963 ASSERT((CurrentToken() == Token::kLPAREN) || |
| 2964 func.IsGetterFunction() || |
| 2965 func.is_async_closure()); |
2950 const bool allow_explicit_default_values = true; | 2966 const bool allow_explicit_default_values = true; |
2951 if (func.IsGetterFunction()) { | 2967 if (func.IsGetterFunction()) { |
2952 // Populate function scope with the formal parameters. Since in this case | 2968 // Populate function scope with the formal parameters. Since in this case |
2953 // we are compiling a getter this will at most populate the receiver. | 2969 // we are compiling a getter this will at most populate the receiver. |
2954 AddFormalParamsToScope(¶ms, current_block_->scope); | 2970 AddFormalParamsToScope(¶ms, current_block_->scope); |
| 2971 } else if (func.is_async_closure()) { |
| 2972 AddFormalParamsToScope(¶ms, current_block_->scope); |
| 2973 ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
| 2974 ASSERT(func.NumParameters() == params.parameters->length()); |
| 2975 if (!Function::Handle(func.parent_function()).IsGetterFunction()) { |
| 2976 // Parse away any formal parameters, as they are accessed as as context |
| 2977 // variables. |
| 2978 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
| 2979 } |
2955 } else { | 2980 } else { |
2956 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); | 2981 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
2957 | 2982 |
2958 // The number of parameters and their type are not yet set in local | 2983 // The number of parameters and their type are not yet set in local |
2959 // functions, since they are not 'top-level' parsed. | 2984 // functions, since they are not 'top-level' parsed. |
2960 if (func.IsLocalFunction()) { | 2985 if (func.IsLocalFunction()) { |
2961 AddFormalParamsToFunction(¶ms, func); | 2986 AddFormalParamsToFunction(¶ms, func); |
2962 } | 2987 } |
2963 SetupDefaultsForOptionalParams(¶ms, default_parameter_values); | 2988 SetupDefaultsForOptionalParams(¶ms, default_parameter_values); |
2964 ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); | 2989 ASSERT(AbstractType::Handle(I, func.result_type()).IsResolved()); |
(...skipping 20 matching lines...) Expand all Loading... |
2985 if (IsInstantiatorRequired()) { | 3010 if (IsInstantiatorRequired()) { |
2986 // Make sure that the receiver of the enclosing instance function | 3011 // Make sure that the receiver of the enclosing instance function |
2987 // (or implicit first parameter of an enclosing factory) is marked as | 3012 // (or implicit first parameter of an enclosing factory) is marked as |
2988 // captured if type checks are enabled, because they may access it to | 3013 // captured if type checks are enabled, because they may access it to |
2989 // instantiate types. | 3014 // instantiate types. |
2990 CaptureInstantiator(); | 3015 CaptureInstantiator(); |
2991 } | 3016 } |
2992 } | 3017 } |
2993 } | 3018 } |
2994 | 3019 |
| 3020 RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
| 3021 func.set_modifier(func_modifier); |
| 3022 |
2995 OpenBlock(); // Open a nested scope for the outermost function block. | 3023 OpenBlock(); // Open a nested scope for the outermost function block. |
| 3024 |
| 3025 Function& async_closure = Function::ZoneHandle(I); |
| 3026 if (func.IsAsyncFunction() && !func.is_async_closure()) { |
| 3027 async_closure = OpenAsyncFunction(formal_params_pos); |
| 3028 } |
| 3029 |
2996 intptr_t end_token_pos = 0; | 3030 intptr_t end_token_pos = 0; |
2997 if (CurrentToken() == Token::kLBRACE) { | 3031 if (CurrentToken() == Token::kLBRACE) { |
2998 ConsumeToken(); | 3032 ConsumeToken(); |
2999 if (String::Handle(I, func.name()).Equals( | 3033 if (String::Handle(I, func.name()).Equals( |
3000 Symbols::EqualOperator())) { | 3034 Symbols::EqualOperator())) { |
3001 const Class& owner = Class::Handle(I, func.Owner()); | 3035 const Class& owner = Class::Handle(I, func.Owner()); |
3002 if (!owner.IsObjectClass()) { | 3036 if (!owner.IsObjectClass()) { |
3003 AddEqualityNullCheck(); | 3037 AddEqualityNullCheck(); |
3004 } | 3038 } |
3005 } | 3039 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3046 &func)); // Unpatched external function. | 3080 &func)); // Unpatched external function. |
3047 end_token_pos = TokenPos(); | 3081 end_token_pos = TokenPos(); |
3048 } else { | 3082 } else { |
3049 UnexpectedToken(); | 3083 UnexpectedToken(); |
3050 } | 3084 } |
3051 | 3085 |
3052 ASSERT(func.end_token_pos() == func.token_pos() || | 3086 ASSERT(func.end_token_pos() == func.token_pos() || |
3053 func.end_token_pos() == end_token_pos); | 3087 func.end_token_pos() == end_token_pos); |
3054 func.set_end_token_pos(end_token_pos); | 3088 func.set_end_token_pos(end_token_pos); |
3055 SequenceNode* body = CloseBlock(); | 3089 SequenceNode* body = CloseBlock(); |
| 3090 if (func.IsAsyncFunction() && !func.is_async_closure()) { |
| 3091 body = CloseAsyncFunction(async_closure, body); |
| 3092 } else if (func.is_async_closure()) { |
| 3093 CloseAsyncClosure(body); |
| 3094 } |
3056 current_block_->statements->Add(body); | 3095 current_block_->statements->Add(body); |
3057 innermost_function_ = saved_innermost_function.raw(); | 3096 innermost_function_ = saved_innermost_function.raw(); |
3058 last_used_try_index_ = saved_try_index; | 3097 last_used_try_index_ = saved_try_index; |
3059 return CloseBlock(); | 3098 return CloseBlock(); |
3060 } | 3099 } |
3061 | 3100 |
3062 | 3101 |
3063 void Parser::AddEqualityNullCheck() { | 3102 void Parser::AddEqualityNullCheck() { |
3064 AstNode* argument = | 3103 AstNode* argument = |
3065 new LoadLocalNode(Scanner::kNoSourcePos, | 3104 new LoadLocalNode(Scanner::kNoSourcePos, |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3359 ASSERT((method->redirect_name == NULL) || method->IsConstructor()); | 3398 ASSERT((method->redirect_name == NULL) || method->IsConstructor()); |
3360 | 3399 |
3361 if (method->IsConstructor() && | 3400 if (method->IsConstructor() && |
3362 method->has_external && | 3401 method->has_external && |
3363 method->params.has_field_initializer) { | 3402 method->params.has_field_initializer) { |
3364 ReportError(method->name_pos, | 3403 ReportError(method->name_pos, |
3365 "external constructor '%s' may not have field initializers", | 3404 "external constructor '%s' may not have field initializers", |
3366 method->name->ToCString()); | 3405 method->name->ToCString()); |
3367 } | 3406 } |
3368 | 3407 |
| 3408 RawFunction::AsyncModifier async_modifier = ParseFunctionModifier(); |
| 3409 if ((method->IsFactoryOrConstructor() || method->IsSetter()) && |
| 3410 async_modifier != RawFunction::kNoModifier) { |
| 3411 ReportError(method->name_pos, |
| 3412 "%s '%s' may not be async", |
| 3413 (method->IsSetter()) ? "setter" : "constructor", |
| 3414 method->name->ToCString()); |
| 3415 } |
| 3416 |
3369 intptr_t method_end_pos = TokenPos(); | 3417 intptr_t method_end_pos = TokenPos(); |
3370 if ((CurrentToken() == Token::kLBRACE) || | 3418 if ((CurrentToken() == Token::kLBRACE) || |
3371 (CurrentToken() == Token::kARROW)) { | 3419 (CurrentToken() == Token::kARROW)) { |
3372 if (method->has_abstract) { | 3420 if (method->has_abstract) { |
3373 ReportError(TokenPos(), | 3421 ReportError(TokenPos(), |
3374 "abstract method '%s' may not have a function body", | 3422 "abstract method '%s' may not have a function body", |
3375 method->name->ToCString()); | 3423 method->name->ToCString()); |
3376 } else if (method->has_external) { | 3424 } else if (method->has_external) { |
3377 ReportError(TokenPos(), | 3425 ReportError(TokenPos(), |
3378 "external %s '%s' may not have a function body", | 3426 "external %s '%s' may not have a function body", |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3473 method->has_static, | 3521 method->has_static, |
3474 method->has_const, | 3522 method->has_const, |
3475 method->has_abstract, | 3523 method->has_abstract, |
3476 method->has_external, | 3524 method->has_external, |
3477 method->has_native, | 3525 method->has_native, |
3478 current_class(), | 3526 current_class(), |
3479 method->decl_begin_pos)); | 3527 method->decl_begin_pos)); |
3480 func.set_result_type(*method->type); | 3528 func.set_result_type(*method->type); |
3481 func.set_end_token_pos(method_end_pos); | 3529 func.set_end_token_pos(method_end_pos); |
3482 func.set_is_redirecting(is_redirecting); | 3530 func.set_is_redirecting(is_redirecting); |
| 3531 func.set_modifier(async_modifier); |
3483 if (method->has_native && library_.is_dart_scheme() && | 3532 if (method->has_native && library_.is_dart_scheme() && |
3484 library_.IsPrivate(*method->name)) { | 3533 library_.IsPrivate(*method->name)) { |
3485 func.set_is_visible(false); | 3534 func.set_is_visible(false); |
3486 } | 3535 } |
3487 if (method->IsFactoryOrConstructor() && library_.is_dart_scheme() && | 3536 if (method->IsFactoryOrConstructor() && library_.is_dart_scheme() && |
3488 library_.IsPrivate(*method->name)) { | 3537 library_.IsPrivate(*method->name)) { |
3489 func.set_is_visible(false); | 3538 func.set_is_visible(false); |
3490 } | 3539 } |
3491 if (method->metadata_pos > 0) { | 3540 if (method->metadata_pos > 0) { |
3492 library_.AddFunctionMetadata(func, method->metadata_pos); | 3541 library_.AddFunctionMetadata(func, method->metadata_pos); |
(...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4793 } else if (CurrentToken() == Token::kSEMICOLON) { | 4842 } else if (CurrentToken() == Token::kSEMICOLON) { |
4794 ConsumeToken(); | 4843 ConsumeToken(); |
4795 break; | 4844 break; |
4796 } else { | 4845 } else { |
4797 ExpectSemicolon(); // Reports error. | 4846 ExpectSemicolon(); // Reports error. |
4798 } | 4847 } |
4799 } | 4848 } |
4800 } | 4849 } |
4801 | 4850 |
4802 | 4851 |
| 4852 RawFunction::AsyncModifier Parser::ParseFunctionModifier() { |
| 4853 if (FLAG_enable_async) { |
| 4854 if (CurrentLiteral()->raw() == Symbols::Async().raw()) { |
| 4855 ConsumeToken(); |
| 4856 return RawFunction::kAsync; |
| 4857 } |
| 4858 } |
| 4859 return RawFunction::kNoModifier; |
| 4860 } |
| 4861 |
| 4862 |
4803 void Parser::ParseTopLevelFunction(TopLevel* top_level, | 4863 void Parser::ParseTopLevelFunction(TopLevel* top_level, |
4804 intptr_t metadata_pos) { | 4864 intptr_t metadata_pos) { |
4805 TRACE_PARSER("ParseTopLevelFunction"); | 4865 TRACE_PARSER("ParseTopLevelFunction"); |
4806 const intptr_t decl_begin_pos = TokenPos(); | 4866 const intptr_t decl_begin_pos = TokenPos(); |
4807 AbstractType& result_type = Type::Handle(I, Type::DynamicType()); | 4867 AbstractType& result_type = Type::Handle(I, Type::DynamicType()); |
4808 const bool is_static = true; | 4868 const bool is_static = true; |
4809 bool is_external = false; | 4869 bool is_external = false; |
4810 bool is_patch = false; | 4870 bool is_patch = false; |
4811 if (is_patch_source() && | 4871 if (is_patch_source() && |
4812 (CurrentToken() == Token::kIDENT) && | 4872 (CurrentToken() == Token::kIDENT) && |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4846 } | 4906 } |
4847 // A setter named x= may co-exist with a function named x, thus we do | 4907 // A setter named x= may co-exist with a function named x, thus we do |
4848 // not need to check setters. | 4908 // not need to check setters. |
4849 | 4909 |
4850 CheckToken(Token::kLPAREN); | 4910 CheckToken(Token::kLPAREN); |
4851 const intptr_t function_pos = TokenPos(); | 4911 const intptr_t function_pos = TokenPos(); |
4852 ParamList params; | 4912 ParamList params; |
4853 const bool allow_explicit_default_values = true; | 4913 const bool allow_explicit_default_values = true; |
4854 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); | 4914 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
4855 | 4915 |
| 4916 RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
| 4917 |
4856 intptr_t function_end_pos = function_pos; | 4918 intptr_t function_end_pos = function_pos; |
4857 bool is_native = false; | 4919 bool is_native = false; |
4858 if (is_external) { | 4920 if (is_external) { |
4859 function_end_pos = TokenPos(); | 4921 function_end_pos = TokenPos(); |
4860 ExpectSemicolon(); | 4922 ExpectSemicolon(); |
4861 } else if (CurrentToken() == Token::kLBRACE) { | 4923 } else if (CurrentToken() == Token::kLBRACE) { |
4862 SkipBlock(); | 4924 SkipBlock(); |
4863 function_end_pos = TokenPos(); | 4925 function_end_pos = TokenPos(); |
4864 ExpectToken(Token::kRBRACE); | 4926 ExpectToken(Token::kRBRACE); |
4865 } else if (CurrentToken() == Token::kARROW) { | 4927 } else if (CurrentToken() == Token::kARROW) { |
(...skipping 14 matching lines...) Expand all Loading... |
4880 RawFunction::kRegularFunction, | 4942 RawFunction::kRegularFunction, |
4881 is_static, | 4943 is_static, |
4882 /* is_const = */ false, | 4944 /* is_const = */ false, |
4883 /* is_abstract = */ false, | 4945 /* is_abstract = */ false, |
4884 is_external, | 4946 is_external, |
4885 is_native, | 4947 is_native, |
4886 current_class(), | 4948 current_class(), |
4887 decl_begin_pos)); | 4949 decl_begin_pos)); |
4888 func.set_result_type(result_type); | 4950 func.set_result_type(result_type); |
4889 func.set_end_token_pos(function_end_pos); | 4951 func.set_end_token_pos(function_end_pos); |
| 4952 func.set_modifier(func_modifier); |
4890 if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) { | 4953 if (is_native && library_.is_dart_scheme() && library_.IsPrivate(func_name)) { |
4891 func.set_is_visible(false); | 4954 func.set_is_visible(false); |
4892 } | 4955 } |
4893 AddFormalParamsToFunction(¶ms, func); | 4956 AddFormalParamsToFunction(¶ms, func); |
4894 top_level->functions.Add(func); | 4957 top_level->functions.Add(func); |
4895 if (!is_patch) { | 4958 if (!is_patch) { |
4896 library_.AddObject(func, func_name); | 4959 library_.AddObject(func, func_name); |
4897 } else { | 4960 } else { |
4898 library_.ReplaceObject(func, func_name); | 4961 library_.ReplaceObject(func, func_name); |
4899 } | 4962 } |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4982 if (found && !is_patch) { | 5045 if (found && !is_patch) { |
4983 ReportError(name_pos, "%s for '%s' is already defined", | 5046 ReportError(name_pos, "%s for '%s' is already defined", |
4984 is_getter ? "getter" : "setter", | 5047 is_getter ? "getter" : "setter", |
4985 field_name->ToCString()); | 5048 field_name->ToCString()); |
4986 } else if (!found && is_patch) { | 5049 } else if (!found && is_patch) { |
4987 ReportError(name_pos, "missing %s for '%s' cannot be patched", | 5050 ReportError(name_pos, "missing %s for '%s' cannot be patched", |
4988 is_getter ? "getter" : "setter", | 5051 is_getter ? "getter" : "setter", |
4989 field_name->ToCString()); | 5052 field_name->ToCString()); |
4990 } | 5053 } |
4991 | 5054 |
| 5055 RawFunction::AsyncModifier func_modifier = ParseFunctionModifier(); |
| 5056 |
4992 intptr_t accessor_end_pos = accessor_pos; | 5057 intptr_t accessor_end_pos = accessor_pos; |
4993 bool is_native = false; | 5058 bool is_native = false; |
4994 if (is_external) { | 5059 if (is_external) { |
4995 accessor_end_pos = TokenPos(); | 5060 accessor_end_pos = TokenPos(); |
4996 ExpectSemicolon(); | 5061 ExpectSemicolon(); |
4997 } else if (CurrentToken() == Token::kLBRACE) { | 5062 } else if (CurrentToken() == Token::kLBRACE) { |
4998 SkipBlock(); | 5063 SkipBlock(); |
4999 accessor_end_pos = TokenPos(); | 5064 accessor_end_pos = TokenPos(); |
5000 ExpectToken(Token::kRBRACE); | 5065 ExpectToken(Token::kRBRACE); |
5001 } else if (CurrentToken() == Token::kARROW) { | 5066 } else if (CurrentToken() == Token::kARROW) { |
(...skipping 15 matching lines...) Expand all Loading... |
5017 RawFunction::kSetterFunction, | 5082 RawFunction::kSetterFunction, |
5018 is_static, | 5083 is_static, |
5019 /* is_const = */ false, | 5084 /* is_const = */ false, |
5020 /* is_abstract = */ false, | 5085 /* is_abstract = */ false, |
5021 is_external, | 5086 is_external, |
5022 is_native, | 5087 is_native, |
5023 current_class(), | 5088 current_class(), |
5024 decl_begin_pos)); | 5089 decl_begin_pos)); |
5025 func.set_result_type(result_type); | 5090 func.set_result_type(result_type); |
5026 func.set_end_token_pos(accessor_end_pos); | 5091 func.set_end_token_pos(accessor_end_pos); |
| 5092 func.set_modifier(func_modifier); |
5027 if (is_native && library_.is_dart_scheme() && | 5093 if (is_native && library_.is_dart_scheme() && |
5028 library_.IsPrivate(accessor_name)) { | 5094 library_.IsPrivate(accessor_name)) { |
5029 func.set_is_visible(false); | 5095 func.set_is_visible(false); |
5030 } | 5096 } |
5031 AddFormalParamsToFunction(¶ms, func); | 5097 AddFormalParamsToFunction(¶ms, func); |
5032 top_level->functions.Add(func); | 5098 top_level->functions.Add(func); |
5033 if (!is_patch) { | 5099 if (!is_patch) { |
5034 library_.AddObject(func, accessor_name); | 5100 library_.AddObject(func, accessor_name); |
5035 } else { | 5101 } else { |
5036 library_.ReplaceObject(func, accessor_name); | 5102 library_.ReplaceObject(func, accessor_name); |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5433 // We are parsing a nested function while compiling the enclosing function. | 5499 // We are parsing a nested function while compiling the enclosing function. |
5434 outer_scope = | 5500 outer_scope = |
5435 new(I) LocalScope(current_block_->scope, | 5501 new(I) LocalScope(current_block_->scope, |
5436 current_block_->scope->function_level() + 1, | 5502 current_block_->scope->function_level() + 1, |
5437 0); | 5503 0); |
5438 } | 5504 } |
5439 ChainNewBlock(outer_scope); | 5505 ChainNewBlock(outer_scope); |
5440 } | 5506 } |
5441 | 5507 |
5442 | 5508 |
| 5509 RawFunction* Parser::OpenAsyncFunction(intptr_t formal_param_pos) { |
| 5510 // Create the closure containing the old body of this function. |
| 5511 Class& sig_cls = Class::ZoneHandle(I); |
| 5512 Type& sig_type = Type::ZoneHandle(I); |
| 5513 Function& closure = Function::ZoneHandle(I); |
| 5514 String& sig = String::ZoneHandle(I); |
| 5515 ParamList closure_params; |
| 5516 closure_params.AddFinalParameter( |
| 5517 formal_param_pos, |
| 5518 &Symbols::ClosureParameter(), |
| 5519 &Type::ZoneHandle(I, Type::DynamicType())); |
| 5520 closure = Function::NewClosureFunction( |
| 5521 Symbols::AnonymousClosure(), |
| 5522 innermost_function(), |
| 5523 formal_param_pos); |
| 5524 AddFormalParamsToFunction(&closure_params, closure); |
| 5525 closure.set_is_async_closure(true); |
| 5526 closure.set_result_type(AbstractType::Handle(Type::DynamicType())); |
| 5527 sig = closure.Signature(); |
| 5528 sig_cls = library_.LookupLocalClass(sig); |
| 5529 if (sig_cls.IsNull()) { |
| 5530 sig_cls = Class::NewSignatureClass(sig, closure, script_, formal_param_pos); |
| 5531 library_.AddClass(sig_cls); |
| 5532 } |
| 5533 closure.set_signature_class(sig_cls); |
| 5534 sig_type = sig_cls.SignatureType(); |
| 5535 if (!sig_type.IsFinalized()) { |
| 5536 ClassFinalizer::FinalizeType( |
| 5537 sig_cls, sig_type, ClassFinalizer::kCanonicalize); |
| 5538 } |
| 5539 ASSERT(AbstractType::Handle(I, closure.result_type()).IsResolved()); |
| 5540 ASSERT(closure.NumParameters() == closure_params.parameters->length()); |
| 5541 OpenFunctionBlock(closure); |
| 5542 AddFormalParamsToScope(&closure_params, current_block_->scope); |
| 5543 OpenBlock(); |
| 5544 return closure.raw(); |
| 5545 } |
| 5546 |
| 5547 |
5443 SequenceNode* Parser::CloseBlock() { | 5548 SequenceNode* Parser::CloseBlock() { |
5444 SequenceNode* statements = current_block_->statements; | 5549 SequenceNode* statements = current_block_->statements; |
5445 if (current_block_->scope != NULL) { | 5550 if (current_block_->scope != NULL) { |
5446 // Record the begin and end token index of the scope. | 5551 // Record the begin and end token index of the scope. |
5447 ASSERT(statements != NULL); | 5552 ASSERT(statements != NULL); |
5448 current_block_->scope->set_begin_token_pos(statements->token_pos()); | 5553 current_block_->scope->set_begin_token_pos(statements->token_pos()); |
5449 current_block_->scope->set_end_token_pos(TokenPos()); | 5554 current_block_->scope->set_end_token_pos(TokenPos()); |
5450 } | 5555 } |
5451 current_block_ = current_block_->parent; | 5556 current_block_ = current_block_->parent; |
5452 return statements; | 5557 return statements; |
5453 } | 5558 } |
5454 | 5559 |
5455 | 5560 |
| 5561 SequenceNode* Parser::CloseAsyncFunction(const Function& closure, |
| 5562 SequenceNode* closure_body) { |
| 5563 ASSERT(!closure.IsNull()); |
| 5564 ASSERT(closure_body != NULL); |
| 5565 // The block for the async closure body has already been closed. Close the |
| 5566 // corresponding function block. |
| 5567 CloseBlock(); |
| 5568 |
| 5569 // Create and return a new future that executes a closure with the current |
| 5570 // body. |
| 5571 |
| 5572 bool found = false; |
| 5573 |
| 5574 // No need to capture parameters or other variables, since they have already |
| 5575 // been captured in the corresponding scope as the body has been parsed within |
| 5576 // a nested block (contained in the async funtion's block). |
| 5577 const Class& future = Class::ZoneHandle(I, |
| 5578 GetClassForAsync(Symbols::Future())); |
| 5579 ASSERT(!future.IsNull()); |
| 5580 const Function& constructor = Function::ZoneHandle(I, |
| 5581 future.LookupFunction(Symbols::FutureConstructor())); |
| 5582 ASSERT(!constructor.IsNull()); |
| 5583 const Class& completer = Class::ZoneHandle(I, |
| 5584 GetClassForAsync(Symbols::Completer())); |
| 5585 ASSERT(!completer.IsNull()); |
| 5586 const Function& completer_constructor = Function::ZoneHandle(I, |
| 5587 completer.LookupFunction(Symbols::CompleterConstructor())); |
| 5588 ASSERT(!completer_constructor.IsNull()); |
| 5589 |
| 5590 // Add to AST: |
| 5591 // var :async_op; |
| 5592 // var :async_completer; |
| 5593 LocalVariable* async_op_var = new (I) LocalVariable( |
| 5594 Scanner::kNoSourcePos, |
| 5595 Symbols::AsyncOperation(), |
| 5596 Type::ZoneHandle(I, Type::DynamicType())); |
| 5597 current_block_->scope->AddVariable(async_op_var); |
| 5598 found = closure_body->scope()->CaptureVariable(Symbols::AsyncOperation()); |
| 5599 ASSERT(found); |
| 5600 LocalVariable* async_completer = new (I) LocalVariable( |
| 5601 Scanner::kNoSourcePos, |
| 5602 Symbols::AsyncCompleter(), |
| 5603 Type::ZoneHandle(I, Type::DynamicType())); |
| 5604 current_block_->scope->AddVariable(async_completer); |
| 5605 found = closure_body->scope()->CaptureVariable(Symbols::AsyncCompleter()); |
| 5606 ASSERT(found); |
| 5607 |
| 5608 // Add to AST: |
| 5609 // :async_completer = new Completer(); |
| 5610 ArgumentListNode* empty_args = new (I) ArgumentListNode( |
| 5611 Scanner::kNoSourcePos); |
| 5612 ConstructorCallNode* completer_constructor_node = new (I) ConstructorCallNode( |
| 5613 Scanner::kNoSourcePos, |
| 5614 TypeArguments::ZoneHandle(I), |
| 5615 completer_constructor, |
| 5616 empty_args); |
| 5617 StoreLocalNode* store_completer = new (I) StoreLocalNode( |
| 5618 Scanner::kNoSourcePos, |
| 5619 async_completer, |
| 5620 completer_constructor_node); |
| 5621 current_block_->statements->Add(store_completer); |
| 5622 |
| 5623 // Add to AST: |
| 5624 // :async_op = <closure>; (containing the original body) |
| 5625 ClosureNode* cn = new(I) ClosureNode( |
| 5626 Scanner::kNoSourcePos, closure, NULL, closure_body->scope()); |
| 5627 StoreLocalNode* store_async_op = new (I) StoreLocalNode( |
| 5628 Scanner::kNoSourcePos, |
| 5629 async_op_var, |
| 5630 cn); |
| 5631 current_block_->statements->Add(store_async_op); |
| 5632 |
| 5633 // Add to AST: |
| 5634 // new Future(:async_op); |
| 5635 ArgumentListNode* arguments = new (I) ArgumentListNode(Scanner::kNoSourcePos); |
| 5636 arguments->Add(new (I) LoadLocalNode( |
| 5637 Scanner::kNoSourcePos, async_op_var)); |
| 5638 ConstructorCallNode* future_node = new (I) ConstructorCallNode( |
| 5639 Scanner::kNoSourcePos, TypeArguments::ZoneHandle(I), constructor, |
| 5640 arguments); |
| 5641 current_block_->statements->Add(future_node); |
| 5642 |
| 5643 // Add to AST: |
| 5644 // return :async_completer.future; |
| 5645 ReturnNode* return_node = new (I) ReturnNode( |
| 5646 Scanner::kNoSourcePos, |
| 5647 new (I) InstanceGetterNode( |
| 5648 Scanner::kNoSourcePos, |
| 5649 new (I) LoadLocalNode( |
| 5650 Scanner::kNoSourcePos, |
| 5651 async_completer), |
| 5652 Symbols::CompleterFuture())); |
| 5653 current_block_->statements->Add(return_node); |
| 5654 return CloseBlock(); |
| 5655 } |
| 5656 |
| 5657 |
| 5658 void Parser::CloseAsyncClosure(SequenceNode* body) { |
| 5659 ASSERT(body != NULL); |
| 5660 // Replace an optional ReturnNode with the appropriate completer calls. |
| 5661 intptr_t last_index = body->length() - 1; |
| 5662 AstNode* last = NULL; |
| 5663 if (last_index >= 0) { |
| 5664 // Non-empty async closure. |
| 5665 last = body->NodeAt(last_index); |
| 5666 } |
| 5667 ArgumentListNode* args = new (I) ArgumentListNode(Scanner::kNoSourcePos); |
| 5668 LocalVariable* completer = body->scope()->LookupVariable( |
| 5669 Symbols::AsyncCompleter(), false); |
| 5670 ASSERT(completer != NULL); |
| 5671 if (last != NULL && last->IsReturnNode()) { |
| 5672 // Replace |
| 5673 // return <expr>; |
| 5674 // with |
| 5675 // completer.complete(<expr>); |
| 5676 args->Add(body->NodeAt(last_index)->AsReturnNode()->value()); |
| 5677 body->ReplaceNodeAt(last_index, |
| 5678 new (I) InstanceCallNode( |
| 5679 Scanner::kNoSourcePos, |
| 5680 new (I) LoadLocalNode(Scanner::kNoSourcePos, completer), |
| 5681 Symbols::CompleterComplete(), |
| 5682 args)); |
| 5683 } else { |
| 5684 // Add to AST: |
| 5685 // completer.complete(); |
| 5686 body->Add( |
| 5687 new (I) InstanceCallNode( |
| 5688 Scanner::kNoSourcePos, |
| 5689 new (I) LoadLocalNode(Scanner::kNoSourcePos, completer), |
| 5690 Symbols::CompleterComplete(), |
| 5691 args)); |
| 5692 } |
| 5693 } |
| 5694 |
| 5695 |
5456 // Set up default values for all optional parameters to the function. | 5696 // Set up default values for all optional parameters to the function. |
5457 void Parser::SetupDefaultsForOptionalParams(const ParamList* params, | 5697 void Parser::SetupDefaultsForOptionalParams(const ParamList* params, |
5458 Array* default_values) { | 5698 Array* default_values) { |
5459 if (params->num_optional_parameters > 0) { | 5699 if (params->num_optional_parameters > 0) { |
5460 // Build array of default parameter values. | 5700 // Build array of default parameter values. |
5461 ParamDesc* param = | 5701 ParamDesc* param = |
5462 params->parameters->data() + params->num_fixed_parameters; | 5702 params->parameters->data() + params->num_fixed_parameters; |
5463 *default_values = Array::New(params->num_optional_parameters); | 5703 *default_values = Array::New(params->num_optional_parameters); |
5464 for (int i = 0; i < params->num_optional_parameters; i++) { | 5704 for (int i = 0; i < params->num_optional_parameters; i++) { |
5465 ASSERT(param->default_value != NULL); | 5705 ASSERT(param->default_value != NULL); |
(...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6221 } else { | 6461 } else { |
6222 SetPosition(saved_pos); | 6462 SetPosition(saved_pos); |
6223 return false; | 6463 return false; |
6224 } | 6464 } |
6225 // Check parameter list and the following token. | 6465 // Check parameter list and the following token. |
6226 if (CurrentToken() == Token::kLPAREN) { | 6466 if (CurrentToken() == Token::kLPAREN) { |
6227 SkipToMatchingParenthesis(); | 6467 SkipToMatchingParenthesis(); |
6228 if ((CurrentToken() == Token::kLBRACE) || | 6468 if ((CurrentToken() == Token::kLBRACE) || |
6229 (CurrentToken() == Token::kARROW) || | 6469 (CurrentToken() == Token::kARROW) || |
6230 (is_top_level_ && IsLiteral("native")) || | 6470 (is_top_level_ && IsLiteral("native")) || |
6231 is_external) { | 6471 is_external || |
| 6472 (FLAG_enable_async && |
| 6473 CurrentLiteral()->raw() == Symbols::Async().raw())) { |
6232 SetPosition(saved_pos); | 6474 SetPosition(saved_pos); |
6233 return true; | 6475 return true; |
6234 } | 6476 } |
6235 } | 6477 } |
6236 SetPosition(saved_pos); | 6478 SetPosition(saved_pos); |
6237 return false; | 6479 return false; |
6238 } | 6480 } |
6239 | 6481 |
6240 | 6482 |
6241 bool Parser::IsTopLevelAccessor() { | 6483 bool Parser::IsTopLevelAccessor() { |
(...skipping 22 matching lines...) Expand all Loading... |
6264 } | 6506 } |
6265 | 6507 |
6266 | 6508 |
6267 bool Parser::IsFunctionLiteral() { | 6509 bool Parser::IsFunctionLiteral() { |
6268 if (CurrentToken() != Token::kLPAREN || !allow_function_literals_) { | 6510 if (CurrentToken() != Token::kLPAREN || !allow_function_literals_) { |
6269 return false; | 6511 return false; |
6270 } | 6512 } |
6271 const intptr_t saved_pos = TokenPos(); | 6513 const intptr_t saved_pos = TokenPos(); |
6272 bool is_function_literal = false; | 6514 bool is_function_literal = false; |
6273 SkipToMatchingParenthesis(); | 6515 SkipToMatchingParenthesis(); |
| 6516 ParseFunctionModifier(); |
6274 if ((CurrentToken() == Token::kLBRACE) || | 6517 if ((CurrentToken() == Token::kLBRACE) || |
6275 (CurrentToken() == Token::kARROW)) { | 6518 (CurrentToken() == Token::kARROW)) { |
6276 is_function_literal = true; | 6519 is_function_literal = true; |
6277 } | 6520 } |
6278 SetPosition(saved_pos); | 6521 SetPosition(saved_pos); |
6279 return is_function_literal; | 6522 return is_function_literal; |
6280 } | 6523 } |
6281 | 6524 |
6282 | 6525 |
6283 // Current token position is the token after the opening ( of the for | 6526 // Current token position is the token after the opening ( of the for |
(...skipping 4476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10760 SkipType(true); | 11003 SkipType(true); |
10761 } | 11004 } |
10762 ExpectIdentifier("function name expected"); | 11005 ExpectIdentifier("function name expected"); |
10763 } | 11006 } |
10764 if (CurrentToken() == Token::kLPAREN) { | 11007 if (CurrentToken() == Token::kLPAREN) { |
10765 const bool allow_explicit_default_values = true; | 11008 const bool allow_explicit_default_values = true; |
10766 ParamList params; | 11009 ParamList params; |
10767 params.skipped = true; | 11010 params.skipped = true; |
10768 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); | 11011 ParseFormalParameterList(allow_explicit_default_values, false, ¶ms); |
10769 } | 11012 } |
| 11013 ParseFunctionModifier(); |
10770 if (CurrentToken() == Token::kLBRACE) { | 11014 if (CurrentToken() == Token::kLBRACE) { |
10771 SkipBlock(); | 11015 SkipBlock(); |
10772 ExpectToken(Token::kRBRACE); | 11016 ExpectToken(Token::kRBRACE); |
10773 } else if (CurrentToken() == Token::kARROW) { | 11017 } else if (CurrentToken() == Token::kARROW) { |
10774 ConsumeToken(); | 11018 ConsumeToken(); |
10775 SkipExpr(); | 11019 SkipExpr(); |
10776 } | 11020 } |
10777 } | 11021 } |
10778 | 11022 |
10779 | 11023 |
10780 // Skips function/method/constructor/getter/setter preambles until the formal | 11024 // Skips function/method/constructor/getter/setter preambles until the formal |
10781 // parameter list. It is enough to skip the tokens, since we have already | 11025 // parameter list. It is enough to skip the tokens, since we have already |
10782 // previously parsed the function. | 11026 // previously parsed the function. |
10783 void Parser::SkipFunctionPreamble() { | 11027 void Parser::SkipFunctionPreamble() { |
10784 while (true) { | 11028 while (true) { |
10785 const Token::Kind token = CurrentToken(); | 11029 const Token::Kind token = CurrentToken(); |
10786 if (token == Token::kLPAREN || | 11030 if (token == Token::kLPAREN) { |
10787 token == Token::kARROW || | |
10788 token == Token::kSEMICOLON || | |
10789 token == Token::kLBRACE) { | |
10790 return; | 11031 return; |
10791 } | 11032 } |
10792 // Case handles "native" keyword, but also return types of form | 11033 if (token == Token::kGET) { |
10793 // native.SomeType where native is the name of a library. | 11034 if (LookaheadToken(1) == Token::kLPAREN) { |
10794 if (token == Token::kIDENT && LookaheadToken(1) != Token::kPERIOD) { | 11035 // Case: Function/method named get. |
10795 if (CurrentLiteral()->raw() == Symbols::Native().raw()) { | 11036 ConsumeToken(); // Parse away 'get' (the function's name). |
10796 return; | 11037 return; |
10797 } | 11038 } |
| 11039 // Case: Getter. |
| 11040 ConsumeToken(); // Parse away 'get'. |
| 11041 ConsumeToken(); // Parse away the getter name. |
| 11042 return; |
10798 } | 11043 } |
10799 ConsumeToken(); | 11044 ConsumeToken(); |
10800 } | 11045 } |
10801 } | 11046 } |
10802 | 11047 |
10803 | 11048 |
10804 void Parser::SkipListLiteral() { | 11049 void Parser::SkipListLiteral() { |
10805 if (CurrentToken() == Token::kINDEX) { | 11050 if (CurrentToken() == Token::kINDEX) { |
10806 // Empty list literal. | 11051 // Empty list literal. |
10807 ConsumeToken(); | 11052 ConsumeToken(); |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11080 void Parser::SkipQualIdent() { | 11325 void Parser::SkipQualIdent() { |
11081 ASSERT(IsIdentifier()); | 11326 ASSERT(IsIdentifier()); |
11082 ConsumeToken(); | 11327 ConsumeToken(); |
11083 if (CurrentToken() == Token::kPERIOD) { | 11328 if (CurrentToken() == Token::kPERIOD) { |
11084 ConsumeToken(); // Consume the kPERIOD token. | 11329 ConsumeToken(); // Consume the kPERIOD token. |
11085 ExpectIdentifier("identifier expected after '.'"); | 11330 ExpectIdentifier("identifier expected after '.'"); |
11086 } | 11331 } |
11087 } | 11332 } |
11088 | 11333 |
11089 } // namespace dart | 11334 } // namespace dart |
OLD | NEW |