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

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

Issue 8637018: Implement type checking of map literals (issue 221). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month 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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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"
11 #include "vm/dart_api_impl.h" 11 #include "vm/dart_api_impl.h"
12 #include "vm/dart_entry.h" 12 #include "vm/dart_entry.h"
13 #include "vm/flags.h" 13 #include "vm/flags.h"
14 #include "vm/growable_array.h" 14 #include "vm/growable_array.h"
15 #include "vm/longjump.h" 15 #include "vm/longjump.h"
16 #include "vm/native_entry.h" 16 #include "vm/native_entry.h"
17 #include "vm/object.h" 17 #include "vm/object.h"
18 #include "vm/object_store.h" 18 #include "vm/object_store.h"
19 #include "vm/resolver.h" 19 #include "vm/resolver.h"
20 #include "vm/scopes.h" 20 #include "vm/scopes.h"
21 21
22 namespace dart { 22 namespace dart {
23 23
24 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); 24 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
25 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); 25 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
26 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); 26 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
27 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); 27 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
28 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); 28 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
29 DECLARE_FLAG(bool, expose_core_impl);
srdjan 2011/11/23 03:43:44 Future CL: Since we are using this flag only for d
regis 2011/11/23 15:51:32 Will do.
29 30
30 // All references to Dart names are listed here. 31 // All references to Dart names are listed here.
31 static const char* kAssertionErrorName = "AssertionError"; 32 static const char* kAssertionErrorName = "AssertionError";
32 static const char* kFallThroughErrorName = "FallThroughError"; 33 static const char* kFallThroughErrorName = "FallThroughError";
33 static const char* kThrowNewName = "_throwNew"; 34 static const char* kThrowNewName = "_throwNew";
34 static const char* kGrowableObjectArrayFromArrayName = 35 static const char* kGrowableObjectArrayFromArrayName =
35 "GrowableObjectArray._usingArray"; 36 "GrowableObjectArray._usingArray";
36 static const char* kGrowableObjectArrayName = "GrowableObjectArray"; 37 static const char* kGrowableObjectArrayName = "GrowableObjectArray";
37 static const char* kMutableMapName = "MutableMap"; 38 static const char* kLiteralMapFactoryName = "_LiteralMapFactory";
38 static const char* kMutableMapFromLiteralName = "fromLiteral"; 39 static const char* kLiteralMapFactoryFromLiteralName = "Map.fromLiteral";
39 static const char* kImmutableMapName = "ImmutableMap"; 40 static const char* kImmutableMapName = "ImmutableMap";
40 static const char* kImmutableMapConstructorName = "ImmutableMap."; 41 static const char* kImmutableMapConstructorName = "ImmutableMap.";
41 static const char* kStringClassName = "StringBase"; 42 static const char* kStringClassName = "StringBase";
42 static const char* kInterpolateName = "_interpolate"; 43 static const char* kInterpolateName = "_interpolate";
43 static const char* kThisName = "this"; 44 static const char* kThisName = "this";
44 static const char* kPhaseParameterName = ":phase"; 45 static const char* kPhaseParameterName = ":phase";
45 static const char* kGetIteratorName = "iterator"; 46 static const char* kGetIteratorName = "iterator";
46 47
47 #if defined(DEBUG) 48 #if defined(DEBUG)
48 49
(...skipping 4374 matching lines...) Expand 10 before | Expand all | Expand 10 after
4423 } 4424 }
4424 4425
4425 4426
4426 // Lookup class in the corelib implementation which contains various VM 4427 // Lookup class in the corelib implementation which contains various VM
4427 // helper methods and classes. 4428 // helper methods and classes.
4428 static RawClass* LookupImplClass(const String& class_name) { 4429 static RawClass* LookupImplClass(const String& class_name) {
4429 return Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name); 4430 return Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name);
4430 } 4431 }
4431 4432
4432 4433
4434 // Lookup class in the corelib which also contains various VM
4435 // helper methods and classes. Allow look up of private classes.
4436 static RawClass* LookupCoreClass(const String& class_name) {
4437 const Library& core_lib = Library::Handle(Library::CoreLibrary());
4438 String& name = String::Handle(class_name.raw());
4439 if ((class_name.CharAt(0) == Scanner::kPrivateIdentifierStart) &&
4440 !FLAG_expose_core_impl) {
4441 // Private identifiers are mangled on a per script basis.
4442 name = String::Concat(name, String::Handle(core_lib.private_key()));
4443 name = String::NewSymbol(name);
4444 }
4445 return core_lib.LookupClass(name);
4446 }
4447
4448
4433 RawClass* Parser::LookupClass(const String& class_name) { 4449 RawClass* Parser::LookupClass(const String& class_name) {
4434 return library_.LookupClass(class_name); 4450 return library_.LookupClass(class_name);
4435 } 4451 }
4436 4452
4437 4453
4438 // Calling VM-internal helpers, uses implementation core library. 4454 // Calling VM-internal helpers, uses implementation core library.
4439 AstNode* Parser::MakeStaticCall(const char* class_name, 4455 AstNode* Parser::MakeStaticCall(const char* class_name,
4440 const char* function_name, 4456 const char* function_name,
4441 ArgumentListNode* arguments) { 4457 ArgumentListNode* arguments) {
4442 const String& cls_name = 4458 const String& cls_name =
(...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after
5107 va_start(args, format); 5123 va_start(args, format);
5108 FormatMessage(script_, token_index_, "Error", 5124 FormatMessage(script_, token_index_, "Error",
5109 message_buffer, kMessageBufferSize, 5125 message_buffer, kMessageBufferSize,
5110 format, args); 5126 format, args);
5111 va_end(args); 5127 va_end(args);
5112 Isolate::Current()->long_jump_base()->Jump(1, message_buffer); 5128 Isolate::Current()->long_jump_base()->Jump(1, message_buffer);
5113 UNREACHABLE(); 5129 UNREACHABLE();
5114 } 5130 }
5115 5131
5116 5132
5133 void Parser::Warning(intptr_t token_index, const char* format, ...) {
5134 const intptr_t kMessageBufferSize = 512;
5135 char message_buffer[kMessageBufferSize];
5136 if (FLAG_silent_warnings) return;
5137 va_list args;
5138 va_start(args, format);
5139 FormatMessage(script_, token_index, "Warning",
5140 message_buffer, kMessageBufferSize,
5141 format, args);
5142 va_end(args);
5143 if (FLAG_warning_as_error) {
5144 Isolate::Current()->long_jump_base()->Jump(1, message_buffer);
5145 UNREACHABLE();
5146 } else {
5147 OS::Print(message_buffer);
5148 }
5149 }
5150
5151
5117 void Parser::Warning(const char* format, ...) { 5152 void Parser::Warning(const char* format, ...) {
5118 const intptr_t kMessageBufferSize = 512; 5153 const intptr_t kMessageBufferSize = 512;
5119 char message_buffer[kMessageBufferSize]; 5154 char message_buffer[kMessageBufferSize];
5120 if (FLAG_silent_warnings) return; 5155 if (FLAG_silent_warnings) return;
5121 va_list args; 5156 va_list args;
5122 va_start(args, format); 5157 va_start(args, format);
5123 FormatMessage(script_, token_index_, "Warning", 5158 FormatMessage(script_, token_index_, "Warning",
5124 message_buffer, kMessageBufferSize, 5159 message_buffer, kMessageBufferSize,
5125 format, args); 5160 format, args);
5126 va_end(args); 5161 va_end(args);
(...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after
6657 } 6692 }
6658 pairs->AddElement(key); 6693 pairs->AddElement(key);
6659 pairs->AddElement(value); 6694 pairs->AddElement(value);
6660 } 6695 }
6661 6696
6662 6697
6663 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, 6698 AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
6664 bool is_const, 6699 bool is_const,
6665 const TypeArguments& type_arguments) { 6700 const TypeArguments& type_arguments) {
6666 TRACE_PARSER("ParseMapLiteral"); 6701 TRACE_PARSER("ParseMapLiteral");
6702 ASSERT(type_pos >= 0);
6667 ASSERT(CurrentToken() == Token::kLBRACE); 6703 ASSERT(CurrentToken() == Token::kLBRACE);
6668 const intptr_t literal_pos = token_index_; 6704 const intptr_t literal_pos = token_index_;
6669 ConsumeToken(); 6705 ConsumeToken();
6670 6706
6671 String& map_class_name = String::Handle( 6707 Type& value_type_argument = Type::Handle(Type::DynamicType());
6672 String::NewSymbol(is_const ? kImmutableMapName : kMutableMapName));
6673 const Class& map_class = Class::Handle(LookupImplClass(map_class_name));
6674 ASSERT(!map_class.IsNull());
6675
6676 TypeArguments& map_type_arguments = 6708 TypeArguments& map_type_arguments =
6677 TypeArguments::ZoneHandle(type_arguments.raw()); 6709 TypeArguments::ZoneHandle(type_arguments.raw());
6678 // If no type arguments are provided, leave them as null, which is equivalent 6710 // If no type argument is provided, leave it as null, which is equivalent
6679 // to using Map<Dynamic, Dynamic>. See issue 4966724. 6711 // to using Dynamic as the type argument for the value type.
6680 if (!map_type_arguments.IsNull()) { 6712 if (!map_type_arguments.IsNull()) {
6681 // For now, only check the number of type arguments. See issue 4975876. 6713 // Map literals only take one type argument.
6682 if (map_type_arguments.Length() != 2) { 6714 value_type_argument = map_type_arguments.TypeAt(0);
6683 ASSERT(type_pos >= 0); 6715 if (map_type_arguments.Length() > 1) {
6684 ErrorMsg(type_pos, "wrong number of type arguments for Map literal"); 6716 // We temporarily accept two type arguments, as long as the first one is
6717 // type String.
6718 if (map_type_arguments.Length() != 2) {
6719 ErrorMsg(type_pos,
6720 "a map literal takes one type argument specifying "
6721 "the value type");
6722 }
6723 if (!value_type_argument.IsStringInterface()) {
6724 ErrorMsg(type_pos,
6725 "the key type of a map literal is implicitly 'String'");
6726 }
6727 Warning(type_pos,
6728 "a map literal takes one type argument specifying "
6729 "the value type");
6730 value_type_argument = map_type_arguments.TypeAt(1);
6731 } else {
6732 TypeArray& type_array = TypeArray::Handle(TypeArray::New(2));
6733 type_array.SetTypeAt(0, Type::Handle(Type::StringInterface()));
6734 type_array.SetTypeAt(1, value_type_argument);
6735 map_type_arguments = type_array.raw();
6736 }
6737 if (is_const && !value_type_argument.IsInstantiated()) {
6738 ErrorMsg(type_pos,
6739 "the type argument of a constant map literal cannot include "
6740 "a type variable");
6685 } 6741 }
6686 } 6742 }
6743 ASSERT(map_type_arguments.IsNull() || (map_type_arguments.Length() == 2));
6687 6744
6688 // Parse the map entries. Note: there may be an optional extra 6745 // Parse the map entries. Note: there may be an optional extra
6689 // comma after the last entry. 6746 // comma after the last entry.
6690 ArrayNode* kv_pairs = 6747 ArrayNode* kv_pairs =
6691 new ArrayNode(token_index_, TypeArguments::ZoneHandle()); 6748 new ArrayNode(token_index_, TypeArguments::ZoneHandle());
6692 while (CurrentToken() != Token::kRBRACE) { 6749 while (CurrentToken() != Token::kRBRACE) {
6693 AstNode* key = NULL; 6750 AstNode* key = NULL;
6694 if (CurrentToken() == Token::kSTRING) { 6751 if (CurrentToken() == Token::kSTRING) {
6695 key = ParseStringLiteral(); 6752 key = ParseStringLiteral();
6696 } 6753 }
(...skipping 23 matching lines...) Expand all
6720 // the immutable map object with it. This all happens at compile time. 6777 // the immutable map object with it. This all happens at compile time.
6721 // The resulting immutable map object is returned as a literal. 6778 // The resulting immutable map object is returned as a literal.
6722 6779
6723 // First, create the canonicalized key-value pair array. 6780 // First, create the canonicalized key-value pair array.
6724 Array& key_value_array = 6781 Array& key_value_array =
6725 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld)); 6782 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld));
6726 for (int i = 0; i < kv_pairs->length(); i++) { 6783 for (int i = 0; i < kv_pairs->length(); i++) {
6727 AstNode* arg = kv_pairs->ElementAt(i); 6784 AstNode* arg = kv_pairs->ElementAt(i);
6728 // Arguments have been evaluated to a literal value already. 6785 // Arguments have been evaluated to a literal value already.
6729 ASSERT(arg->IsLiteralNode()); 6786 ASSERT(arg->IsLiteralNode());
6787 if (((i % 2) == 1) && // Check values only, not keys.
6788 !value_type_argument.IsDynamicType() &&
6789 !arg->AsLiteralNode()->literal().Is(value_type_argument)) {
6790 ErrorMsg(arg->AsLiteralNode()->token_index(),
6791 "map literal entry value must be a constant of type '%s'",
6792 String::Handle(value_type_argument.Name()).ToCString());
6793 }
6730 key_value_array.SetAt(i, arg->AsLiteralNode()->literal()); 6794 key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
6731 } 6795 }
6732 key_value_array ^= key_value_array.Canonicalize(); 6796 key_value_array ^= key_value_array.Canonicalize();
6733 key_value_array.MakeImmutable(); 6797 key_value_array.MakeImmutable();
6734 6798
6735 // Construct the map object. 6799 // Construct the map object.
6800 const String& immutable_map_class_name =
6801 String::Handle(String::NewSymbol(kImmutableMapName));
6802 const Class& immutable_map_class =
6803 Class::Handle(LookupImplClass(immutable_map_class_name));
6804 ASSERT(!immutable_map_class.IsNull());
6736 ArgumentListNode* constr_args = new ArgumentListNode(token_index_); 6805 ArgumentListNode* constr_args = new ArgumentListNode(token_index_);
6737 constr_args->Add(new LiteralNode(literal_pos, key_value_array)); 6806 constr_args->Add(new LiteralNode(literal_pos, key_value_array));
6738 const String& constr_name = 6807 const String& constr_name =
6739 String::Handle(String::NewSymbol(kImmutableMapConstructorName)); 6808 String::Handle(String::NewSymbol(kImmutableMapConstructorName));
6740 const Function& map_constr = Function::ZoneHandle( 6809 const Function& map_constr = Function::ZoneHandle(
6741 map_class.LookupConstructor(constr_name)); 6810 immutable_map_class.LookupConstructor(constr_name));
6742 ASSERT(!map_constr.IsNull()); 6811 ASSERT(!map_constr.IsNull());
6743 const Instance& const_instance = Instance::ZoneHandle( 6812 const Instance& const_instance = Instance::ZoneHandle(
6744 EvaluateConstConstructorCall(map_class, 6813 EvaluateConstConstructorCall(immutable_map_class,
6745 map_type_arguments, 6814 map_type_arguments,
6746 map_constr, 6815 map_constr,
6747 constr_args)); 6816 constr_args));
6748 if (const_instance.IsUnhandledException()) { 6817 if (const_instance.IsUnhandledException()) {
6749 return CreateEvalConstConstructorThrow(literal_pos, const_instance); 6818 return CreateEvalConstConstructorThrow(literal_pos, const_instance);
6750 } else { 6819 } else {
6751 return new LiteralNode(literal_pos, const_instance); 6820 return new LiteralNode(literal_pos, const_instance);
6752 } 6821 }
6753 } else { 6822 } else {
6754 // Static call at runtime. 6823 // Factory call at runtime.
6755 const String& static_factory_name = 6824 String& literal_map_factory_class_name = String::Handle(
6756 String::Handle(String::NewSymbol(kMutableMapFromLiteralName)); 6825 String::NewSymbol(kLiteralMapFactoryName));
6757 const Function& static_factory = Function::ZoneHandle( 6826 const Class& literal_map_factory_class =
6758 map_class.LookupStaticFunction(static_factory_name)); 6827 Class::Handle(LookupCoreClass(literal_map_factory_class_name));
6759 ASSERT(!static_factory.IsNull()); 6828 ASSERT(!literal_map_factory_class.IsNull());
6829 const String& literal_map_factory_name =
6830 String::Handle(String::NewSymbol(kLiteralMapFactoryFromLiteralName));
6831 const Function& literal_map_factory = Function::ZoneHandle(
6832 literal_map_factory_class.LookupFactory(literal_map_factory_name));
6833 ASSERT(!literal_map_factory.IsNull());
6760 if (!map_type_arguments.IsNull() && 6834 if (!map_type_arguments.IsNull() &&
6761 !map_type_arguments.IsInstantiated() && 6835 !map_type_arguments.IsInstantiated() &&
6762 (current_block_->scope->function_level() > 0)) { 6836 (current_block_->scope->function_level() > 0)) {
6763 // Make sure that the instantiator is captured. 6837 // Make sure that the instantiator is captured.
6764 CaptureReceiver(); 6838 CaptureReceiver();
6765 } 6839 }
6766 ArgumentListNode* factory_param = new ArgumentListNode(literal_pos); 6840 ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
6841 factory_param->Add(
6842 new LiteralNode(literal_pos, Smi::ZoneHandle(Smi::New(literal_pos))));
6843 factory_param->Add(
6844 new LiteralNode(literal_pos,
6845 String::ZoneHandle(value_type_argument.Name())));
6767 factory_param->Add(kv_pairs); 6846 factory_param->Add(kv_pairs);
6768 return new StaticCallNode( 6847 return new ConstructorCallNode(
6769 literal_pos, static_factory, factory_param); 6848 literal_pos, map_type_arguments, literal_map_factory, factory_param);
6770 } 6849 }
6771 } 6850 }
6772 6851
6773 6852
6774 AstNode* Parser::ParseCompoundLiteral() { 6853 AstNode* Parser::ParseCompoundLiteral() {
6775 bool is_const = false; 6854 bool is_const = false;
6776 if (CurrentToken() == Token::kCONST) { 6855 if (CurrentToken() == Token::kCONST) {
6777 is_const = true; 6856 is_const = true;
6778 ConsumeToken(); 6857 ConsumeToken();
6779 } 6858 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
7436 } 7515 }
7437 7516
7438 7517
7439 void Parser::SkipNestedExpr() { 7518 void Parser::SkipNestedExpr() {
7440 const bool saved_mode = SetAllowFunctionLiterals(true); 7519 const bool saved_mode = SetAllowFunctionLiterals(true);
7441 SkipExpr(); 7520 SkipExpr();
7442 SetAllowFunctionLiterals(saved_mode); 7521 SetAllowFunctionLiterals(saved_mode);
7443 } 7522 }
7444 7523
7445 } // namespace dart 7524 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698