Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: runtime/vm/parser.cc

Issue 9615035: Generate dynamic type errors according to spec. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 5355 matching lines...) Expand 10 before | Expand all | Expand 10 after
5366 va_list args; 5366 va_list args;
5367 va_start(args, format); 5367 va_start(args, format);
5368 const Error& error = Error::Handle( 5368 const Error& error = Error::Handle(
5369 FormatError(script_, token_index_, "Error", format, args)); 5369 FormatError(script_, token_index_, "Error", format, args));
5370 va_end(args); 5370 va_end(args);
5371 Isolate::Current()->long_jump_base()->Jump(1, error); 5371 Isolate::Current()->long_jump_base()->Jump(1, error);
5372 UNREACHABLE(); 5372 UNREACHABLE();
5373 } 5373 }
5374 5374
5375 5375
5376 void Parser::ErrorMsg(const Error& error) {
5377 Isolate::Current()->long_jump_base()->Jump(1, error);
5378 UNREACHABLE();
5379 }
5380
5381
5376 void Parser::AppendErrorMsg( 5382 void Parser::AppendErrorMsg(
5377 const Error& prev_error, intptr_t token_index, const char* format, ...) { 5383 const Error& prev_error, intptr_t token_index, const char* format, ...) {
5378 va_list args; 5384 va_list args;
5379 va_start(args, format); 5385 va_start(args, format);
5380 const Error& error = Error::Handle(FormatErrorWithAppend( 5386 const Error& error = Error::Handle(FormatErrorWithAppend(
5381 prev_error, script_, token_index, "Error", format, args)); 5387 prev_error, script_, token_index, "Error", format, args));
5382 va_end(args); 5388 va_end(args);
5383 Isolate::Current()->long_jump_base()->Jump(1, error); 5389 Isolate::Current()->long_jump_base()->Jump(1, error);
5384 UNREACHABLE(); 5390 UNREACHABLE();
5385 } 5391 }
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
5546 const intptr_t type_pos = token_index_; 5552 const intptr_t type_pos = token_index_;
5547 const AbstractType& type = 5553 const AbstractType& type =
5548 AbstractType::ZoneHandle(ParseType(ClassFinalizer::kFinalize)); 5554 AbstractType::ZoneHandle(ParseType(ClassFinalizer::kFinalize));
5549 if (!type.IsInstantiated() && 5555 if (!type.IsInstantiated() &&
5550 (current_block_->scope->function_level() > 0)) { 5556 (current_block_->scope->function_level() > 0)) {
5551 // Make sure that the instantiator is captured. 5557 // Make sure that the instantiator is captured.
5552 CaptureReceiver(); 5558 CaptureReceiver();
5553 } 5559 }
5554 right_operand = new TypeNode(type_pos, type); 5560 right_operand = new TypeNode(type_pos, type);
5555 if (type.IsMalformed()) { 5561 if (type.IsMalformed()) {
5562 // Note that a type error is thrown even if the tested value is null.
5556 return ThrowTypeError(type_pos, type); 5563 return ThrowTypeError(type_pos, type);
5557 } 5564 }
5558 } 5565 }
5559 if (Token::IsRelationalOperator(op_kind) 5566 if (Token::IsRelationalOperator(op_kind)
5560 || Token::IsInstanceofOperator(op_kind) 5567 || Token::IsInstanceofOperator(op_kind)
5561 || Token::IsEqualityOperator(op_kind)) { 5568 || Token::IsEqualityOperator(op_kind)) {
5562 left_operand = new ComparisonNode( 5569 left_operand = new ComparisonNode(
5563 op_pos, op_kind, left_operand, right_operand); 5570 op_pos, op_kind, left_operand, right_operand);
5564 break; // Equality and relational operators cannot be chained. 5571 break; // Equality and relational operators cannot be chained.
5565 } else { 5572 } else {
(...skipping 820 matching lines...) Expand 10 before | Expand all | Expand 10 after
6386 // At this point, we can only have a parameterized_type. 6393 // At this point, we can only have a parameterized_type.
6387 Type& parameterized_type = Type::Handle(); 6394 Type& parameterized_type = Type::Handle();
6388 parameterized_type ^= type->raw(); 6395 parameterized_type ^= type->raw();
6389 if (!resolved_type_class.IsNull()) { 6396 if (!resolved_type_class.IsNull()) {
6390 Object& type_class = Object::Handle(resolved_type_class.raw()); 6397 Object& type_class = Object::Handle(resolved_type_class.raw());
6391 // Replace unresolved class with resolved type class. 6398 // Replace unresolved class with resolved type class.
6392 parameterized_type.set_type_class(type_class); 6399 parameterized_type.set_type_class(type_class);
6393 } else if (finalization >= ClassFinalizer::kFinalize) { 6400 } else if (finalization >= ClassFinalizer::kFinalize) {
6394 // The type is malformed. 6401 // The type is malformed.
6395 ClassFinalizer::FinalizeMalformedType( 6402 ClassFinalizer::FinalizeMalformedType(
6403 Error::Handle(), // No previous error.
6396 current_class(), parameterized_type, finalization, 6404 current_class(), parameterized_type, finalization,
6397 "type '%s' is not loaded", 6405 "type '%s' is not loaded",
6398 String::Handle(parameterized_type.Name()).ToCString()); 6406 String::Handle(parameterized_type.Name()).ToCString());
6399 } 6407 }
6400 } 6408 }
6401 // Resolve type arguments, if any. 6409 // Resolve type arguments, if any.
6402 const AbstractTypeArguments& arguments = 6410 const AbstractTypeArguments& arguments =
6403 AbstractTypeArguments::Handle(type->arguments()); 6411 AbstractTypeArguments::Handle(type->arguments());
6404 if (!arguments.IsNull()) { 6412 if (!arguments.IsNull()) {
6405 const intptr_t num_arguments = arguments.Length(); 6413 const intptr_t num_arguments = arguments.Length();
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after
6960 String::NewSymbol("list literal element")); 6968 String::NewSymbol("list literal element"));
6961 while (CurrentToken() != Token::kRBRACK) { 6969 while (CurrentToken() != Token::kRBRACK) {
6962 const intptr_t element_pos = token_index_; 6970 const intptr_t element_pos = token_index_;
6963 AstNode* element = ParseExpr(is_const); 6971 AstNode* element = ParseExpr(is_const);
6964 if (FLAG_enable_type_checks && 6972 if (FLAG_enable_type_checks &&
6965 !is_const && 6973 !is_const &&
6966 !element_type.IsDynamicType()) { 6974 !element_type.IsDynamicType()) {
6967 // The expression needs to be type checked at runtime. 6975 // The expression needs to be type checked at runtime.
6968 // Eliminate the type check if it can be performed at compile time and 6976 // Eliminate the type check if it can be performed at compile time and
6969 // if it succeeds. 6977 // if it succeeds.
6978 Error& malformed_error = Error::Handle();
6970 if (!element_type.IsInstantiated() || 6979 if (!element_type.IsInstantiated() ||
6971 !element->IsLiteralNode() || 6980 !element->IsLiteralNode() ||
6972 !element->AsLiteralNode()->literal(). 6981 !element->AsLiteralNode()->literal().
6973 IsAssignableTo(element_type, TypeArguments::Handle())) { 6982 IsAssignableTo(element_type,
6983 TypeArguments::Handle(),
6984 &malformed_error)) {
6974 element = new AssignableNode(element_pos, 6985 element = new AssignableNode(element_pos,
6975 element, 6986 element,
6976 element_type, 6987 element_type,
6977 dst_name); 6988 dst_name);
6978 } 6989 }
6979 } 6990 }
6980 list->AddElement(element); 6991 list->AddElement(element);
6981 if (CurrentToken() == Token::kCOMMA) { 6992 if (CurrentToken() == Token::kCOMMA) {
6982 ConsumeToken(); 6993 ConsumeToken();
6983 } else if (CurrentToken() != Token::kRBRACK) { 6994 } else if (CurrentToken() != Token::kRBRACK) {
6984 ErrorMsg("comma or ']' expected"); 6995 ErrorMsg("comma or ']' expected");
6985 } 6996 }
6986 } 6997 }
6987 ExpectToken(Token::kRBRACK); 6998 ExpectToken(Token::kRBRACK);
6988 SetAllowFunctionLiterals(saved_mode); 6999 SetAllowFunctionLiterals(saved_mode);
6989 } 7000 }
6990 7001
6991 if (is_const) { 7002 if (is_const) {
6992 // Allocate and initialize the const list at compile time. 7003 // Allocate and initialize the const list at compile time.
6993 Array& const_list = 7004 Array& const_list =
6994 Array::ZoneHandle(Array::New(list->length(), Heap::kOld)); 7005 Array::ZoneHandle(Array::New(list->length(), Heap::kOld));
6995 const_list.SetTypeArguments(type_arguments); 7006 const_list.SetTypeArguments(type_arguments);
6996 7007 Error& malformed_error = Error::Handle();
6997 for (int i = 0; i < list->length(); i++) { 7008 for (int i = 0; i < list->length(); i++) {
6998 AstNode* elem = list->ElementAt(i); 7009 AstNode* elem = list->ElementAt(i);
6999 // Arguments have been evaluated to a literal value already. 7010 // Arguments have been evaluated to a literal value already.
7000 ASSERT(elem->IsLiteralNode()); 7011 ASSERT(elem->IsLiteralNode());
7001 if (FLAG_enable_type_checks && 7012 if (FLAG_enable_type_checks &&
7002 !element_type.IsDynamicType() && 7013 !element_type.IsDynamicType() &&
7003 !elem->AsLiteralNode()->literal(). 7014 !elem->AsLiteralNode()->literal().IsAssignableTo(
7004 IsAssignableTo(element_type, TypeArguments::Handle())) { 7015 element_type, TypeArguments::Handle(), &malformed_error)) {
7005 ErrorMsg(elem->AsLiteralNode()->token_index(), 7016 // If the failure is due to a malformed type error, display it instead.
7006 "list literal element at index %d must be " 7017 if (!malformed_error.IsNull()) {
7007 "a constant of type '%s'", 7018 ErrorMsg(malformed_error);
7008 i, 7019 } else {
7009 String::Handle(element_type.Name()).ToCString()); 7020 ErrorMsg(elem->AsLiteralNode()->token_index(),
7021 "list literal element at index %d must be "
7022 "a constant of type '%s'",
7023 i,
7024 String::Handle(element_type.Name()).ToCString());
7025 }
7010 } 7026 }
7011 const_list.SetAt(i, elem->AsLiteralNode()->literal()); 7027 const_list.SetAt(i, elem->AsLiteralNode()->literal());
7012 } 7028 }
7013 const_list ^= const_list.Canonicalize(); 7029 const_list ^= const_list.Canonicalize();
7014 const_list.MakeImmutable(); 7030 const_list.MakeImmutable();
7015 return new LiteralNode(literal_pos, const_list); 7031 return new LiteralNode(literal_pos, const_list);
7016 } else { 7032 } else {
7017 // Factory call at runtime. 7033 // Factory call at runtime.
7018 String& list_literal_factory_class_name = String::Handle( 7034 String& list_literal_factory_class_name = String::Handle(
7019 String::NewSymbol(kListLiteralFactoryClassName)); 7035 String::NewSymbol(kListLiteralFactoryClassName));
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
7137 const bool saved_mode = SetAllowFunctionLiterals(true); 7153 const bool saved_mode = SetAllowFunctionLiterals(true);
7138 const intptr_t value_pos = token_index_; 7154 const intptr_t value_pos = token_index_;
7139 AstNode* value = ParseExpr(is_const); 7155 AstNode* value = ParseExpr(is_const);
7140 SetAllowFunctionLiterals(saved_mode); 7156 SetAllowFunctionLiterals(saved_mode);
7141 if (FLAG_enable_type_checks && 7157 if (FLAG_enable_type_checks &&
7142 !is_const && 7158 !is_const &&
7143 !value_type.IsDynamicType()) { 7159 !value_type.IsDynamicType()) {
7144 // The expression needs to be type checked at runtime. 7160 // The expression needs to be type checked at runtime.
7145 // Eliminate the type check if it can be performed at compile time and 7161 // Eliminate the type check if it can be performed at compile time and
7146 // if it succeeds. 7162 // if it succeeds.
7163 Error& malformed_error = Error::Handle();
7147 if (!value_type.IsInstantiated() || 7164 if (!value_type.IsInstantiated() ||
7148 !value->IsLiteralNode() || 7165 !value->IsLiteralNode() ||
7149 !value->AsLiteralNode()->literal(). 7166 !value->AsLiteralNode()->literal().IsAssignableTo(
7150 IsAssignableTo(value_type, TypeArguments::Handle())) { 7167 value_type, TypeArguments::Handle(), &malformed_error)) {
7151 value = new AssignableNode(value_pos, 7168 value = new AssignableNode(value_pos,
7152 value, 7169 value,
7153 value_type, 7170 value_type,
7154 dst_name); 7171 dst_name);
7155 } 7172 }
7156 } 7173 }
7157 AddKeyValuePair(kv_pairs, is_const, key, value); 7174 AddKeyValuePair(kv_pairs, is_const, key, value);
7158 7175
7159 if (CurrentToken() == Token::kCOMMA) { 7176 if (CurrentToken() == Token::kCOMMA) {
7160 ConsumeToken(); 7177 ConsumeToken();
7161 } else if (CurrentToken() != Token::kRBRACE) { 7178 } else if (CurrentToken() != Token::kRBRACE) {
7162 ErrorMsg("comma or '}' expected"); 7179 ErrorMsg("comma or '}' expected");
7163 } 7180 }
7164 } 7181 }
7165 ASSERT(kv_pairs->length() % 2 == 0); 7182 ASSERT(kv_pairs->length() % 2 == 0);
7166 ExpectToken(Token::kRBRACE); 7183 ExpectToken(Token::kRBRACE);
7167 7184
7168 if (is_const) { 7185 if (is_const) {
7169 // Create the key-value pair array, canonicalize it and then create 7186 // Create the key-value pair array, canonicalize it and then create
7170 // the immutable map object with it. This all happens at compile time. 7187 // the immutable map object with it. This all happens at compile time.
7171 // The resulting immutable map object is returned as a literal. 7188 // The resulting immutable map object is returned as a literal.
7172 7189
7173 // First, create the canonicalized key-value pair array. 7190 // First, create the canonicalized key-value pair array.
7174 Array& key_value_array = 7191 Array& key_value_array =
7175 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld)); 7192 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld));
7193 Error& malformed_error = Error::Handle();
7176 for (int i = 0; i < kv_pairs->length(); i++) { 7194 for (int i = 0; i < kv_pairs->length(); i++) {
7177 AstNode* arg = kv_pairs->ElementAt(i); 7195 AstNode* arg = kv_pairs->ElementAt(i);
7178 // Arguments have been evaluated to a literal value already. 7196 // Arguments have been evaluated to a literal value already.
7179 ASSERT(arg->IsLiteralNode()); 7197 ASSERT(arg->IsLiteralNode());
7180 if (FLAG_enable_type_checks && 7198 if (FLAG_enable_type_checks &&
7181 ((i % 2) == 1) && // Check values only, not keys. 7199 ((i % 2) == 1) && // Check values only, not keys.
7182 !value_type.IsDynamicType() && 7200 !value_type.IsDynamicType() &&
7183 !arg->AsLiteralNode()->literal(). 7201 !arg->AsLiteralNode()->literal().IsAssignableTo(
7184 IsAssignableTo(value_type, TypeArguments::Handle())) { 7202 value_type, TypeArguments::Handle(), &malformed_error)) {
7185 ErrorMsg(arg->AsLiteralNode()->token_index(), 7203 // If the failure is due to a malformed type error, display it instead.
7186 "map literal value at index %d must be " 7204 if (!malformed_error.IsNull()) {
7187 "a constant of type '%s'", 7205 ErrorMsg(malformed_error);
7188 i >> 1, 7206 } else {
7189 String::Handle(value_type.Name()).ToCString()); 7207 ErrorMsg(arg->AsLiteralNode()->token_index(),
7208 "map literal value at index %d must be "
7209 "a constant of type '%s'",
7210 i >> 1,
7211 String::Handle(value_type.Name()).ToCString());
7212 }
7190 } 7213 }
7191 key_value_array.SetAt(i, arg->AsLiteralNode()->literal()); 7214 key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
7192 } 7215 }
7193 key_value_array ^= key_value_array.Canonicalize(); 7216 key_value_array ^= key_value_array.Canonicalize();
7194 key_value_array.MakeImmutable(); 7217 key_value_array.MakeImmutable();
7195 7218
7196 // Construct the map object. 7219 // Construct the map object.
7197 const String& immutable_map_class_name = 7220 const String& immutable_map_class_name =
7198 String::Handle(String::NewSymbol(kImmutableMapName)); 7221 String::Handle(String::NewSymbol(kImmutableMapName));
7199 const Class& immutable_map_class = 7222 const Class& immutable_map_class =
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
7291 TRACE_PARSER("ParseNewOperator"); 7314 TRACE_PARSER("ParseNewOperator");
7292 const intptr_t new_pos = token_index_; 7315 const intptr_t new_pos = token_index_;
7293 ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST)); 7316 ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST));
7294 bool is_const = (CurrentToken() == Token::kCONST); 7317 bool is_const = (CurrentToken() == Token::kCONST);
7295 ConsumeToken(); 7318 ConsumeToken();
7296 if (!IsIdentifier()) { 7319 if (!IsIdentifier()) {
7297 ErrorMsg("type name expected"); 7320 ErrorMsg("type name expected");
7298 } 7321 }
7299 intptr_t type_pos = token_index_; 7322 intptr_t type_pos = token_index_;
7300 7323
7324 // TODO(regis): Bounds error should not result in a compile time error,
7325 // but in a dynamic type error. Requesting kFinalizeWellFormed below is too
7326 // strict. See co19 issue 96.
7301 const AbstractType& type = AbstractType::Handle( 7327 const AbstractType& type = AbstractType::Handle(
7302 ParseType(ClassFinalizer::kFinalizeWellFormed)); 7328 ParseType(ClassFinalizer::kFinalizeWellFormed));
7303 if (type.IsTypeParameter()) { 7329 if (type.IsTypeParameter()) {
7304 ErrorMsg(type_pos, 7330 ErrorMsg(type_pos,
7305 "type parameter '%s' cannot be instantiated", 7331 "type parameter '%s' cannot be instantiated",
7306 String::Handle(type.Name()).ToCString()); 7332 String::Handle(type.Name()).ToCString());
7307 } 7333 }
7308 Class& type_class = Class::Handle(type.type_class()); 7334 Class& type_class = Class::Handle(type.type_class());
7309 String& type_class_name = String::Handle(type_class.Name()); 7335 String& type_class_name = String::Handle(type_class.Name());
7310 AbstractTypeArguments& type_arguments = 7336 AbstractTypeArguments& type_arguments =
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
7368 if (!type_class.HasResolvedFactoryClass()) { 7394 if (!type_class.HasResolvedFactoryClass()) {
7369 // This error can occur only with bootstrap classes. 7395 // This error can occur only with bootstrap classes.
7370 const UnresolvedClass& unresolved = 7396 const UnresolvedClass& unresolved =
7371 UnresolvedClass::Handle(type_class.UnresolvedFactoryClass()); 7397 UnresolvedClass::Handle(type_class.UnresolvedFactoryClass());
7372 const String& missing_class_name = String::Handle(unresolved.ident()); 7398 const String& missing_class_name = String::Handle(unresolved.ident());
7373 ErrorMsg("unresolved factory class '%s'", missing_class_name.ToCString()); 7399 ErrorMsg("unresolved factory class '%s'", missing_class_name.ToCString());
7374 } 7400 }
7375 // Only change the class of the constructor to the factory class if the 7401 // Only change the class of the constructor to the factory class if the
7376 // factory class implements the interface 'type'. 7402 // factory class implements the interface 'type'.
7377 const Class& factory_class = Class::Handle(type_class.FactoryClass()); 7403 const Class& factory_class = Class::Handle(type_class.FactoryClass());
7404 Error& malformed_error = Error::Handle();
7378 if (factory_class.IsSubtypeOf(TypeArguments::Handle(), 7405 if (factory_class.IsSubtypeOf(TypeArguments::Handle(),
7379 type_class, 7406 type_class,
7380 TypeArguments::Handle())) { 7407 TypeArguments::Handle(),
7408 &malformed_error)) {
7381 // Class finalization verifies that the factory class has identical type 7409 // Class finalization verifies that the factory class has identical type
7382 // parameters as the interface. 7410 // parameters as the interface.
7383 constructor_class_name = factory_class.Name(); 7411 constructor_class_name = factory_class.Name();
7384 } 7412 }
7385 // Always change the result type of the constructor to the factory type. 7413 // Always change the result type of the constructor to the factory type.
7386 constructor_class = factory_class.raw(); 7414 constructor_class = factory_class.raw();
7387 // The finalized type_arguments are still those of the interface type. 7415 // The finalized type_arguments are still those of the interface type.
7388 ASSERT(!constructor_class.is_interface()); 7416 ASSERT(!constructor_class.is_interface());
7389 } 7417 }
7390 7418
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
7474 } 7502 }
7475 } else { 7503 } else {
7476 CheckFunctionIsCallable(new_pos, constructor); 7504 CheckFunctionIsCallable(new_pos, constructor);
7477 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); 7505 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments);
7478 if (!type_arguments.IsNull() && 7506 if (!type_arguments.IsNull() &&
7479 !type_arguments.IsInstantiated() && 7507 !type_arguments.IsInstantiated() &&
7480 (current_block_->scope->function_level() > 0)) { 7508 (current_block_->scope->function_level() > 0)) {
7481 // Make sure that the instantiator is captured. 7509 // Make sure that the instantiator is captured.
7482 CaptureReceiver(); 7510 CaptureReceiver();
7483 } 7511 }
7512 // TODO(regis): If the type argument vector is not instantiated, we need to
7513 // verify in checked mode at runtime that it is within its declared bounds.
7484 new_object = new ConstructorCallNode( 7514 new_object = new ConstructorCallNode(
7485 new_pos, type_arguments, constructor, arguments); 7515 new_pos, type_arguments, constructor, arguments);
7486 } 7516 }
7487 return new_object; 7517 return new_object;
7488 } 7518 }
7489 7519
7490 7520
7491 String& Parser::Interpolate(ArrayNode* values) { 7521 String& Parser::Interpolate(ArrayNode* values) {
7492 const String& class_name = 7522 const String& class_name =
7493 String::Handle(String::NewSymbol(kStringClassName)); 7523 String::Handle(String::NewSymbol(kStringClassName));
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
8054 void Parser::SkipQualIdent() { 8084 void Parser::SkipQualIdent() {
8055 ASSERT(IsIdentifier()); 8085 ASSERT(IsIdentifier());
8056 ConsumeToken(); 8086 ConsumeToken();
8057 if (CurrentToken() == Token::kPERIOD) { 8087 if (CurrentToken() == Token::kPERIOD) {
8058 ConsumeToken(); // Consume the kPERIOD token. 8088 ConsumeToken(); // Consume the kPERIOD token.
8059 ExpectIdentifier("identifier expected after '.'"); 8089 ExpectIdentifier("identifier expected after '.'");
8060 } 8090 }
8061 } 8091 }
8062 8092
8063 } // namespace dart 8093 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698