| 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 2435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2446 } | 2446 } |
| 2447 | 2447 |
| 2448 // Parse redirecting factory constructor. | 2448 // Parse redirecting factory constructor. |
| 2449 Type& redirection_type = Type::Handle(); | 2449 Type& redirection_type = Type::Handle(); |
| 2450 String& redirection_identifier = String::Handle(); | 2450 String& redirection_identifier = String::Handle(); |
| 2451 if (method->IsFactory() && (CurrentToken() == Token::kASSIGN)) { | 2451 if (method->IsFactory() && (CurrentToken() == Token::kASSIGN)) { |
| 2452 ConsumeToken(); | 2452 ConsumeToken(); |
| 2453 const intptr_t type_pos = TokenPos(); | 2453 const intptr_t type_pos = TokenPos(); |
| 2454 const AbstractType& type = AbstractType::Handle( | 2454 const AbstractType& type = AbstractType::Handle( |
| 2455 ParseType(ClassFinalizer::kTryResolve)); | 2455 ParseType(ClassFinalizer::kTryResolve)); |
| 2456 if (type.IsTypeParameter()) { | 2456 if (type.IsTypeParameter() || type.IsDynamicType()) { |
| 2457 // TODO(regis): Spec is not clear. Throw dynamic error or report | 2457 // Replace the type with a malformed type and compile a throw when called. |
| 2458 // compile-time error? Same question for new and const operators. | 2458 redirection_type = ClassFinalizer::NewFinalizedMalformedType( |
| 2459 ErrorMsg(type_pos, "factory may not redirect via a type parameter"); | 2459 current_class(), |
| 2460 type_pos, |
| 2461 "factory '%s' may not redirect to %s'%s'", |
| 2462 method->name->ToCString(), |
| 2463 type.IsTypeParameter() ? "type parameter " : "", |
| 2464 type.IsTypeParameter() ? |
| 2465 String::Handle(type.UserVisibleName()).ToCString() : "dynamic"); |
| 2466 } else { |
| 2467 redirection_type ^= type.raw(); |
| 2460 } | 2468 } |
| 2461 redirection_type ^= type.raw(); | |
| 2462 if (CurrentToken() == Token::kPERIOD) { | 2469 if (CurrentToken() == Token::kPERIOD) { |
| 2463 // Named constructor or factory. | 2470 // Named constructor or factory. |
| 2464 ConsumeToken(); | 2471 ConsumeToken(); |
| 2465 redirection_identifier = ExpectIdentifier("identifier expected")->raw(); | 2472 redirection_identifier = ExpectIdentifier("identifier expected")->raw(); |
| 2466 } | 2473 } |
| 2467 } else if (CurrentToken() == Token::kCOLON) { | 2474 } else if (CurrentToken() == Token::kCOLON) { |
| 2468 // Parse initializers. | 2475 // Parse initializers. |
| 2469 if (!method->IsConstructor()) { | 2476 if (!method->IsConstructor()) { |
| 2470 ErrorMsg("initializers only allowed on constructors"); | 2477 ErrorMsg("initializers only allowed on constructors"); |
| 2471 } | 2478 } |
| (...skipping 6379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8851 const intptr_t new_pos = TokenPos(); | 8858 const intptr_t new_pos = TokenPos(); |
| 8852 ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST)); | 8859 ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST)); |
| 8853 bool is_const = (CurrentToken() == Token::kCONST); | 8860 bool is_const = (CurrentToken() == Token::kCONST); |
| 8854 ConsumeToken(); | 8861 ConsumeToken(); |
| 8855 if (!IsIdentifier()) { | 8862 if (!IsIdentifier()) { |
| 8856 ErrorMsg("type name expected"); | 8863 ErrorMsg("type name expected"); |
| 8857 } | 8864 } |
| 8858 intptr_t type_pos = TokenPos(); | 8865 intptr_t type_pos = TokenPos(); |
| 8859 AbstractType& type = AbstractType::Handle( | 8866 AbstractType& type = AbstractType::Handle( |
| 8860 ParseType(ClassFinalizer::kCanonicalizeWellFormed)); | 8867 ParseType(ClassFinalizer::kCanonicalizeWellFormed)); |
| 8861 // Malformed bounds never result in a compile time error, therefore, the | 8868 // In case the type is malformed, throw a dynamic type error after finishing |
| 8862 // parsed type may be malformed although we requested kCanonicalizeWellFormed. | 8869 // parsing the instance creation expression. |
| 8863 // In that case, we throw a dynamic type error instead of calling the | 8870 if (type.IsTypeParameter() || type.IsDynamicType()) { |
| 8864 // constructor. | 8871 // Replace the type with a malformed type. |
| 8865 if (type.IsTypeParameter()) { | 8872 type = ClassFinalizer::NewFinalizedMalformedType( |
| 8866 ErrorMsg(type_pos, | 8873 current_class(), |
| 8867 "type parameter '%s' cannot be instantiated", | 8874 type_pos, |
| 8868 String::Handle(type.UserVisibleName()).ToCString()); | 8875 "%s'%s' cannot be instantiated", |
| 8876 type.IsTypeParameter() ? "type parameter " : "", |
| 8877 type.IsTypeParameter() ? |
| 8878 String::Handle(type.UserVisibleName()).ToCString() : "dynamic"); |
| 8869 } | 8879 } |
| 8870 if (type.IsDynamicType()) { | |
| 8871 ErrorMsg(type_pos, "Dynamic cannot be instantiated"); | |
| 8872 } | |
| 8873 Class& type_class = Class::Handle(type.type_class()); | |
| 8874 const String& type_class_name = String::Handle(type_class.Name()); | |
| 8875 AbstractTypeArguments& type_arguments = | |
| 8876 AbstractTypeArguments::ZoneHandle(type.arguments()); | |
| 8877 | |
| 8878 // The constructor class and its name are those of the parsed type, unless the | |
| 8879 // parsed type is an interface and a default factory class is specified, in | |
| 8880 // which case constructor_class and constructor_class_name are modified below. | |
| 8881 Class& constructor_class = Class::ZoneHandle(type_class.raw()); | |
| 8882 String& constructor_class_name = String::Handle(type_class_name.raw()); | |
| 8883 | 8880 |
| 8884 // The grammar allows for an optional ('.' identifier)? after the type, which | 8881 // The grammar allows for an optional ('.' identifier)? after the type, which |
| 8885 // is a named constructor. Note that ParseType(kMustResolve) above will not | 8882 // is a named constructor. Note that ParseType(kMustResolve) above will not |
| 8886 // consume it as part of a misinterpreted qualified identifier, because only a | 8883 // consume it as part of a misinterpreted qualified identifier, because only a |
| 8887 // valid library prefix is accepted as qualifier. | 8884 // valid library prefix is accepted as qualifier. |
| 8888 String* named_constructor = NULL; | 8885 String* named_constructor = NULL; |
| 8889 if (CurrentToken() == Token::kPERIOD) { | 8886 if (CurrentToken() == Token::kPERIOD) { |
| 8890 ConsumeToken(); | 8887 ConsumeToken(); |
| 8891 named_constructor = ExpectIdentifier("name of constructor expected"); | 8888 named_constructor = ExpectIdentifier("name of constructor expected"); |
| 8892 } | 8889 } |
| 8893 | 8890 |
| 8894 // Parse constructor parameters. | 8891 // Parse constructor parameters. |
| 8895 if (CurrentToken() != Token::kLPAREN) { | 8892 if (CurrentToken() != Token::kLPAREN) { |
| 8896 ErrorMsg("'(' expected"); | 8893 ErrorMsg("'(' expected"); |
| 8897 } | 8894 } |
| 8898 intptr_t call_pos = TokenPos(); | 8895 intptr_t call_pos = TokenPos(); |
| 8899 ArgumentListNode* arguments = ParseActualParameters(NULL, is_const); | 8896 ArgumentListNode* arguments = ParseActualParameters(NULL, is_const); |
| 8900 | 8897 |
| 8898 // Parsing is complete, so we can return a throw in case of a malformed type. |
| 8899 if (type.IsMalformed()) { |
| 8900 return ThrowTypeError(type_pos, type); |
| 8901 } |
| 8902 |
| 8903 // Resolve the type and optional identifier to a constructor or factory. |
| 8904 Class& type_class = Class::Handle(type.type_class()); |
| 8905 const String& type_class_name = String::Handle(type_class.Name()); |
| 8906 AbstractTypeArguments& type_arguments = |
| 8907 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 8908 |
| 8909 // The constructor class and its name are those of the parsed type, unless the |
| 8910 // parsed type is an interface and a default factory class is specified, in |
| 8911 // which case constructor_class and constructor_class_name are modified below. |
| 8912 Class& constructor_class = Class::ZoneHandle(type_class.raw()); |
| 8913 String& constructor_class_name = String::Handle(type_class_name.raw()); |
| 8914 |
| 8901 // A constructor has an implicit 'this' parameter (instance to construct) | 8915 // A constructor has an implicit 'this' parameter (instance to construct) |
| 8902 // and a factory has an implicit 'this' parameter (type_arguments). | 8916 // and a factory has an implicit 'this' parameter (type_arguments). |
| 8903 // A constructor has a second implicit 'phase' parameter. | 8917 // A constructor has a second implicit 'phase' parameter. |
| 8904 intptr_t arguments_length = arguments->length() + 2; | 8918 intptr_t arguments_length = arguments->length() + 2; |
| 8905 | 8919 |
| 8906 if (type_class.is_interface()) { | 8920 if (type_class.is_interface()) { |
| 8907 // We need to make sure that an appropriate constructor is | 8921 // We need to make sure that an appropriate constructor is |
| 8908 // declared in the interface. | 8922 // declared in the interface. |
| 8909 const String& constructor_name = | 8923 const String& constructor_name = |
| 8910 BuildConstructorName(type_class_name, named_constructor); | 8924 BuildConstructorName(type_class_name, named_constructor); |
| 8911 const String& external_constructor_name = | 8925 const String& external_constructor_name = |
| 8912 (named_constructor ? constructor_name : type_class_name); | 8926 (named_constructor ? constructor_name : type_class_name); |
| 8913 Function& constructor = Function::ZoneHandle( | 8927 Function& constructor = Function::ZoneHandle( |
| 8914 type_class.LookupConstructor(constructor_name)); | 8928 type_class.LookupConstructor(constructor_name)); |
| 8915 if (constructor.IsNull()) { | 8929 if (constructor.IsNull()) { |
| 8916 ErrorMsg(type_pos, | 8930 // Replace the type with a malformed type and compile a throw. |
| 8917 "interface '%s' has no constructor named '%s'", | 8931 type = ClassFinalizer::NewFinalizedMalformedType( |
| 8918 type_class_name.ToCString(), | 8932 current_class(), |
| 8919 external_constructor_name.ToCString()); | 8933 type_pos, |
| 8934 "interface '%s' has no constructor named '%s'", |
| 8935 type_class_name.ToCString(), |
| 8936 external_constructor_name.ToCString()); |
| 8937 return ThrowTypeError(type_pos, type); |
| 8920 } | 8938 } |
| 8939 // TODO(regis): Throw a NoSuchMethodError instead of a TypeError. |
| 8921 String& error_message = String::Handle(); | 8940 String& error_message = String::Handle(); |
| 8922 if (!constructor.AreValidArguments(arguments_length, | 8941 if (!constructor.AreValidArguments(arguments_length, |
| 8923 arguments->names(), | 8942 arguments->names(), |
| 8924 &error_message)) { | 8943 &error_message)) { |
| 8925 ErrorMsg(call_pos, | 8944 // Replace the type with a malformed type and compile a throw. |
| 8926 "invalid arguments passed to constructor '%s' " | 8945 type = ClassFinalizer::NewFinalizedMalformedType( |
| 8927 "for interface '%s': %s", | 8946 current_class(), |
| 8928 external_constructor_name.ToCString(), | 8947 call_pos, |
| 8929 type_class_name.ToCString(), | 8948 "invalid arguments passed to constructor '%s' " |
| 8930 error_message.ToCString()); | 8949 "for interface '%s': %s", |
| 8950 external_constructor_name.ToCString(), |
| 8951 type_class_name.ToCString(), |
| 8952 error_message.ToCString()); |
| 8953 return ThrowTypeError(call_pos, type); |
| 8931 } | 8954 } |
| 8955 // TODO(regis): Remove support for obsolete default factory classes. |
| 8932 if (!type_class.HasFactoryClass()) { | 8956 if (!type_class.HasFactoryClass()) { |
| 8933 ErrorMsg(type_pos, | 8957 ErrorMsg(type_pos, |
| 8934 "cannot allocate interface '%s' without factory class", | 8958 "cannot allocate interface '%s' without factory class", |
| 8935 type_class_name.ToCString()); | 8959 type_class_name.ToCString()); |
| 8936 } | 8960 } |
| 8937 if (!type_class.HasResolvedFactoryClass()) { | 8961 if (!type_class.HasResolvedFactoryClass()) { |
| 8938 // This error can occur only with bootstrap classes. | 8962 // This error can occur only with bootstrap classes. |
| 8939 const UnresolvedClass& unresolved = | 8963 const UnresolvedClass& unresolved = |
| 8940 UnresolvedClass::Handle(type_class.UnresolvedFactoryClass()); | 8964 UnresolvedClass::Handle(type_class.UnresolvedFactoryClass()); |
| 8941 const String& missing_class_name = String::Handle(unresolved.ident()); | 8965 const String& missing_class_name = String::Handle(unresolved.ident()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 8961 // Make sure that an appropriate constructor exists. | 8985 // Make sure that an appropriate constructor exists. |
| 8962 const String& constructor_name = | 8986 const String& constructor_name = |
| 8963 BuildConstructorName(constructor_class_name, named_constructor); | 8987 BuildConstructorName(constructor_class_name, named_constructor); |
| 8964 Function& constructor = Function::ZoneHandle( | 8988 Function& constructor = Function::ZoneHandle( |
| 8965 constructor_class.LookupConstructor(constructor_name)); | 8989 constructor_class.LookupConstructor(constructor_name)); |
| 8966 if (constructor.IsNull()) { | 8990 if (constructor.IsNull()) { |
| 8967 constructor = constructor_class.LookupFactory(constructor_name); | 8991 constructor = constructor_class.LookupFactory(constructor_name); |
| 8968 if (constructor.IsNull()) { | 8992 if (constructor.IsNull()) { |
| 8969 const String& external_constructor_name = | 8993 const String& external_constructor_name = |
| 8970 (named_constructor ? constructor_name : constructor_class_name); | 8994 (named_constructor ? constructor_name : constructor_class_name); |
| 8971 ErrorMsg(type_pos, | 8995 // Replace the type with a malformed type and compile a throw. |
| 8972 "class '%s' has no constructor or factory named '%s'", | 8996 type = ClassFinalizer::NewFinalizedMalformedType( |
| 8973 String::Handle(constructor_class.Name()).ToCString(), | 8997 current_class(), |
| 8974 external_constructor_name.ToCString()); | 8998 type_pos, |
| 8999 "class '%s' has no constructor or factory named '%s'", |
| 9000 String::Handle(constructor_class.Name()).ToCString(), |
| 9001 external_constructor_name.ToCString()); |
| 9002 return ThrowTypeError(type_pos, type); |
| 8975 } else if (constructor.IsRedirectingFactory()) { | 9003 } else if (constructor.IsRedirectingFactory()) { |
| 8976 type = constructor.RedirectionType(); | 9004 type = constructor.RedirectionType(); |
| 9005 if (type.IsMalformed()) { |
| 9006 return ThrowTypeError(type.token_pos(), type); |
| 9007 } |
| 8977 constructor = constructor.RedirectionTarget(); | 9008 constructor = constructor.RedirectionTarget(); |
| 8978 if (constructor.IsNull()) { | 9009 ASSERT(!constructor.IsNull()); |
| 8979 // TODO(regis): We normally report a compile-time error if the | 9010 type_class = type.type_class(); |
| 8980 // constructor is not found. See above. However, we should throw a | 9011 type_arguments = type.arguments(); |
| 8981 // dynamic error instead. We do it here. This is the first step. | 9012 constructor_class = constructor.Owner(); |
| 8982 ASSERT(type.IsMalformed()); | 9013 ASSERT(type_class.raw() == constructor_class.raw()); |
| 8983 } else { | |
| 8984 type_class = type.type_class(); | |
| 8985 type_arguments = type.arguments(); | |
| 8986 constructor_class = constructor.Owner(); | |
| 8987 ASSERT(type_class.raw() == constructor_class.raw()); | |
| 8988 } | |
| 8989 } | 9014 } |
| 8990 if (!constructor.IsNull() && constructor.IsFactory()) { | 9015 if (constructor.IsFactory()) { |
| 8991 // A factory does not have the implicit 'phase' parameter. | 9016 // A factory does not have the implicit 'phase' parameter. |
| 8992 arguments_length -= 1; | 9017 arguments_length -= 1; |
| 8993 } | 9018 } |
| 8994 } | 9019 } |
| 8995 | 9020 |
| 8996 // It is ok to call a factory method of an abstract class, but it is | 9021 // It is ok to call a factory method of an abstract class, but it is |
| 8997 // a dynamic error to instantiate an abstract class. | 9022 // a dynamic error to instantiate an abstract class. |
| 8998 if (!constructor.IsNull() && | 9023 ASSERT(!constructor.IsNull()); |
| 8999 constructor_class.is_abstract() && | 9024 if (constructor_class.is_abstract() && |
| 9000 !constructor.IsFactory()) { | 9025 !constructor.IsFactory()) { |
| 9001 ArgumentListNode* arguments = new ArgumentListNode(type_pos); | 9026 ArgumentListNode* arguments = new ArgumentListNode(type_pos); |
| 9002 arguments->Add(new LiteralNode( | 9027 arguments->Add(new LiteralNode( |
| 9003 TokenPos(), Integer::ZoneHandle(Integer::New(type_pos)))); | 9028 TokenPos(), Integer::ZoneHandle(Integer::New(type_pos)))); |
| 9004 arguments->Add(new LiteralNode( | 9029 arguments->Add(new LiteralNode( |
| 9005 TokenPos(), String::ZoneHandle(constructor_class_name.raw()))); | 9030 TokenPos(), String::ZoneHandle(constructor_class_name.raw()))); |
| 9006 const String& cls_name = | 9031 const String& cls_name = |
| 9007 String::Handle(Symbols::AbstractClassInstantiationError()); | 9032 String::Handle(Symbols::AbstractClassInstantiationError()); |
| 9008 const String& func_name = String::Handle(Symbols::ThrowNew()); | 9033 const String& func_name = String::Handle(Symbols::ThrowNew()); |
| 9009 return MakeStaticCall(cls_name, func_name, arguments); | 9034 return MakeStaticCall(cls_name, func_name, arguments); |
| 9010 } | 9035 } |
| 9011 | 9036 // TODO(regis): Throw a NoSuchMethodError instead of a TypeError. |
| 9012 String& error_message = String::Handle(); | 9037 String& error_message = String::Handle(); |
| 9013 if (!constructor.IsNull() && | 9038 if (!constructor.AreValidArguments(arguments_length, |
| 9014 !constructor.AreValidArguments(arguments_length, | |
| 9015 arguments->names(), | 9039 arguments->names(), |
| 9016 &error_message)) { | 9040 &error_message)) { |
| 9017 const String& external_constructor_name = | 9041 const String& external_constructor_name = |
| 9018 (named_constructor ? constructor_name : constructor_class_name); | 9042 (named_constructor ? constructor_name : constructor_class_name); |
| 9019 ErrorMsg(call_pos, | 9043 // Replace the type with a malformed type and compile a throw when called. |
| 9020 "invalid arguments passed to constructor '%s' for class '%s': %s", | 9044 type = ClassFinalizer::NewFinalizedMalformedType( |
| 9021 external_constructor_name.ToCString(), | 9045 current_class(), |
| 9022 String::Handle(constructor_class.Name()).ToCString(), | 9046 call_pos, |
| 9023 error_message.ToCString()); | 9047 "invalid arguments passed to constructor '%s' for class '%s': %s", |
| 9048 external_constructor_name.ToCString(), |
| 9049 String::Handle(constructor_class.Name()).ToCString(), |
| 9050 error_message.ToCString()); |
| 9051 return ThrowTypeError(call_pos, type); |
| 9024 } | 9052 } |
| 9025 | 9053 |
| 9026 // Now that the constructor to be called is identified, finalize the type | 9054 // Now that the constructor to be called is identified, finalize the type |
| 9027 // argument vector to be passed. | 9055 // argument vector to be passed. |
| 9028 // The type argument vector of the parsed type was finalized in ParseType. | 9056 // The type argument vector of the parsed type was finalized in ParseType. |
| 9029 // If the constructor class was changed from the interface class to the | 9057 // If the constructor class was changed from the interface class to the |
| 9030 // factory class, we need to finalize the type argument vector again, because | 9058 // factory class, we need to finalize the type argument vector again, because |
| 9031 // it may be longer due to the factory class extending a class, or/and because | 9059 // it may be longer due to the factory class extending a class, or/and because |
| 9032 // the bounds on the factory class may be tighter than on the interface. | 9060 // the bounds on the factory class may be tighter than on the interface. |
| 9033 if (!constructor.IsNull() && (constructor_class.raw() != type_class.raw())) { | 9061 if (!constructor.IsNull() && (constructor_class.raw() != type_class.raw())) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 9059 type_arguments = temp_type.arguments(); | 9087 type_arguments = temp_type.arguments(); |
| 9060 // The type parameter bounds of the factory class may be more specific than | 9088 // The type parameter bounds of the factory class may be more specific than |
| 9061 // the type parameter bounds of the interface class. Therefore, although | 9089 // the type parameter bounds of the interface class. Therefore, although |
| 9062 // type was not malformed, temp_type may be malformed. | 9090 // type was not malformed, temp_type may be malformed. |
| 9063 if (!type.IsMalformed() && temp_type.IsMalformed()) { | 9091 if (!type.IsMalformed() && temp_type.IsMalformed()) { |
| 9064 const Error& error = Error::Handle(temp_type.malformed_error()); | 9092 const Error& error = Error::Handle(temp_type.malformed_error()); |
| 9065 type.set_malformed_error(error); | 9093 type.set_malformed_error(error); |
| 9066 } | 9094 } |
| 9067 } | 9095 } |
| 9068 if (type.IsMalformed()) { | 9096 if (type.IsMalformed()) { |
| 9069 // Compile the throw of a dynamic type error due to a bound error or to | 9097 // Return the throw of a dynamic type error if the type is malformed. |
| 9070 // a redirection error. | |
| 9071 return ThrowTypeError(type_pos, type); | 9098 return ThrowTypeError(type_pos, type); |
| 9072 } | 9099 } |
| 9073 type_arguments ^= type_arguments.Canonicalize(); | 9100 type_arguments ^= type_arguments.Canonicalize(); |
| 9074 // Make the constructor call. | 9101 // Make the constructor call. |
| 9075 AstNode* new_object = NULL; | 9102 AstNode* new_object = NULL; |
| 9076 if (is_const) { | 9103 if (is_const) { |
| 9077 if (!constructor.is_const()) { | 9104 if (!constructor.is_const()) { |
| 9078 ErrorMsg("'const' requires const constructor: '%s'", | 9105 ErrorMsg("'const' requires const constructor: '%s'", |
| 9079 String::Handle(constructor.name()).ToCString()); | 9106 String::Handle(constructor.name()).ToCString()); |
| 9080 } | 9107 } |
| (...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9694 void Parser::SkipQualIdent() { | 9721 void Parser::SkipQualIdent() { |
| 9695 ASSERT(IsIdentifier()); | 9722 ASSERT(IsIdentifier()); |
| 9696 ConsumeToken(); | 9723 ConsumeToken(); |
| 9697 if (CurrentToken() == Token::kPERIOD) { | 9724 if (CurrentToken() == Token::kPERIOD) { |
| 9698 ConsumeToken(); // Consume the kPERIOD token. | 9725 ConsumeToken(); // Consume the kPERIOD token. |
| 9699 ExpectIdentifier("identifier expected after '.'"); | 9726 ExpectIdentifier("identifier expected after '.'"); |
| 9700 } | 9727 } |
| 9701 } | 9728 } |
| 9702 | 9729 |
| 9703 } // namespace dart | 9730 } // namespace dart |
| OLD | NEW |