Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 41810) |
+++ runtime/vm/parser.cc (working copy) |
@@ -732,6 +732,14 @@ |
const Library& lib = Library::Handle(isolate, cls.library()); |
Parser parser(script, lib, cls.token_pos()); |
parser.ParseClassDefinition(cls); |
+ } else if (cls.is_enum_class()) { |
+ Isolate* isolate = Isolate::Current(); |
+ TimerScope timer(FLAG_compiler_stats, &CompilerStats::parser_timer); |
+ ASSERT(isolate->long_jump_base()->IsSafeToJump()); |
+ const Script& script = Script::Handle(isolate, cls.script()); |
+ const Library& lib = Library::Handle(isolate, cls.library()); |
+ Parser parser(script, lib, cls.token_pos()); |
+ parser.ParseEnumDefinition(cls); |
} |
} |
@@ -1125,11 +1133,13 @@ |
// Receiver is local 0. |
LocalVariable* receiver = current_block_->scope->VariableAt(0); |
LoadLocalNode* load_receiver = new LoadLocalNode(ident_pos, receiver); |
- ASSERT(IsIdentifier()); |
- const String& field_name = *CurrentLiteral(); |
+ String& field_name = String::Handle(I, func.name()); |
+ field_name = Field::NameFromGetter(field_name); |
+ |
const Class& field_class = Class::Handle(I, func.Owner()); |
const Field& field = |
Field::ZoneHandle(I, field_class.LookupInstanceField(field_name)); |
+ ASSERT(!field.IsNull()); |
LoadInstanceFieldNode* load_field = |
new LoadInstanceFieldNode(ident_pos, load_receiver, field); |
@@ -3051,8 +3061,7 @@ |
intptr_t end_token_pos = 0; |
if (CurrentToken() == Token::kLBRACE) { |
ConsumeToken(); |
- if (String::Handle(I, func.name()).Equals( |
- Symbols::EqualOperator())) { |
+ if (String::Handle(I, func.name()).Equals(Symbols::EqualOperator())) { |
const Class& owner = Class::Handle(I, func.Owner()); |
if (!owner.IsObjectClass()) { |
AddEqualityNullCheck(); |
@@ -4002,6 +4011,54 @@ |
} |
+void Parser::ParseEnumDeclaration(const GrowableObjectArray& pending_classes, |
+ const Class& toplevel_class, |
+ intptr_t metadata_pos) { |
+ TRACE_PARSER("ParseEnumDeclaration"); |
+ ConsumeToken(); |
+ const intptr_t enum_pos = TokenPos(); |
+ String* enum_name = |
+ ExpectUserDefinedTypeIdentifier("enum type name expected"); |
+ if (FLAG_trace_parser) { |
+ OS::Print("TopLevel parsing enum '%s'\n", enum_name->ToCString()); |
+ } |
+ ExpectToken(Token::kLBRACE); |
+ if (!IsIdentifier()) { |
+ ReportError("Enumeration must have at least one name"); |
+ } |
+ while (IsIdentifier()) { |
+ ConsumeToken(); |
+ if (CurrentToken() == Token::kCOMMA) { |
+ ConsumeToken(); |
+ if (CurrentToken() == Token::kRBRACE) { |
+ break; |
+ } |
+ } else if (CurrentToken() == Token::kRBRACE) { |
+ break; |
+ } else { |
+ ReportError(", or } expected"); |
+ } |
+ } |
+ ExpectToken(Token::kRBRACE); |
+ |
+ Object& obj = Object::Handle(I, library_.LookupLocalObject(*enum_name)); |
+ if (!obj.IsNull()) { |
+ ReportError(enum_pos, "'%s' is already defined", enum_name->ToCString()); |
+ } |
+ Class& cls = Class::Handle(I); |
+ cls = Class::New(*enum_name, script_, enum_pos); |
+ cls.set_library(library_); |
+ library_.AddClass(cls); |
+ cls.set_is_synthesized_class(); |
+ cls.set_is_enum_class(); |
+ if (metadata_pos >= 0) { |
+ library_.AddClassMetadata(cls, toplevel_class, metadata_pos); |
+ } |
+ cls.set_super_type(Type::Handle(I, Type::ObjectType())); |
+ pending_classes.Add(cls, Heap::kOld); |
+} |
+ |
+ |
void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes, |
const Class& toplevel_class, |
intptr_t metadata_pos) { |
@@ -4244,6 +4301,168 @@ |
} |
+void Parser::ParseEnumDefinition(const Class& cls) { |
+ TRACE_PARSER("ParseEnumDefinition"); |
+ CompilerStats::num_classes_compiled++; |
+ |
+ const String& enum_name = String::Handle(I, cls.Name()); |
+ ClassDesc enum_members(cls, enum_name, false, cls.token_pos()); |
+ |
+ // Add instance field 'final int index'. |
+ Field& index_field = Field::ZoneHandle(I); |
+ const Type& int_type = Type::Handle(I, Type::IntType()); |
+ const Type& dynamic_type = Type::Handle(Type::DynamicType()); |
+ index_field = Field::New(Symbols::Index(), |
+ false, // Not static. |
+ true, // Field is final. |
+ false, // Not const. |
+ false, // Not synthetic. |
+ cls, |
+ cls.token_pos()); |
+ index_field.set_type(int_type); |
+ enum_members.AddField(index_field); |
+ |
+ // Add implicit getter for index field. |
+ const String& getter_name = |
+ String::Handle(I, Field::GetterSymbol(Symbols::Index())); |
+ Function& getter = Function::Handle(I); |
+ getter = Function::New(getter_name, |
+ RawFunction::kImplicitGetter, |
+ /* is_static = */ false, |
+ /* is_const = */ true, |
+ /* is_abstract = */ false, |
+ /* is_external = */ false, |
+ /* is_native = */ false, |
+ cls, |
+ cls.token_pos()); |
+ getter.set_result_type(int_type); |
+ ParamList params; |
+ params.AddReceiver(&dynamic_type, cls.token_pos()); |
+ AddFormalParamsToFunction(¶ms, getter); |
+ enum_members.AddFunction(getter); |
+ |
+ GrowableObjectArray& enum_names = GrowableObjectArray::Handle(I, |
+ GrowableObjectArray::New(8, Heap::kOld)); |
+ const String& name_prefix = |
+ String::Handle(String::Concat(enum_name, Symbols::Dot())); |
+ |
+ ASSERT(IsIdentifier()); |
+ ASSERT(CurrentLiteral()->raw() == cls.Name()); |
+ |
+ ConsumeToken(); // Enum type name. |
+ ExpectToken(Token::kLBRACE); |
+ Field& enum_value = Field::Handle(I); |
+ String& enum_value_name = String::Handle(I); |
+ intptr_t i = 0; |
+ GrowableArray<String*> declared_names(8); |
+ |
+ while (IsIdentifier()) { |
+ String* enum_ident = CurrentLiteral(); |
+ |
+ // Check for name conflicts. |
+ if (enum_ident->raw() == cls.Name()) { |
+ ReportError("enum identifier '%s' cannot be equal to enum type name", |
+ CurrentLiteral()->ToCString()); |
+ } else if (enum_ident->raw() == Symbols::Index().raw()) { |
+ ReportError("enum identifier conflicts with " |
+ "implicit instance field 'index'"); |
+ } else if (enum_ident->raw() == Symbols::Values().raw()) { |
+ ReportError("enum identifier conflicts with " |
+ "implicit static field 'values'"); |
+ } else if (enum_ident->raw() == Symbols::toString().raw()) { |
+ ReportError("enum identifier conflicts with " |
+ "implicit instance method 'toString()'"); |
+ } |
+ for (intptr_t i = 0; i < declared_names.length(); i++) { |
+ if (enum_ident->Equals(*declared_names[i])) { |
+ ReportError("Duplicate name '%s' in enum definition '%s'", |
+ enum_ident->ToCString(), |
+ enum_name.ToCString()); |
+ } |
+ } |
+ declared_names.Add(enum_ident); |
+ |
+ // Create the static const field for the enumeration value. |
+ enum_value = Field::New(*enum_ident, |
+ /* is_static = */ true, |
+ /* is_final = */ true, |
+ /* is_const = */ true, |
+ /* is_synthetic = */ false, |
+ cls, |
+ cls.token_pos()); |
+ enum_value.set_type(dynamic_type); |
+ enum_value.set_has_initializer(false); |
+ enum_members.AddField(enum_value); |
+ // Initialize the field with the ordinal value. It will be patched |
+ // later with the enum constant instance. |
+ const Smi& ordinal_value = Smi::Handle(I, Smi::New(i)); |
+ enum_value.set_value(ordinal_value); |
+ enum_value.RecordStore(ordinal_value); |
+ i++; |
+ |
+ // For the user-visible name of the enumeration value, we need to |
+ // unmangle private names. |
+ if (enum_ident->CharAt(0) == '_') { |
+ *enum_ident = String::IdentifierPrettyName(*enum_ident); |
+ } |
+ enum_value_name = Symbols::FromConcat(name_prefix, *enum_ident); |
+ enum_names.Add(enum_value_name, Heap::kOld); |
+ |
+ ConsumeToken(); // Enum value name. |
+ if (CurrentToken() == Token::kCOMMA) { |
+ ConsumeToken(); |
+ } |
+ } |
+ ExpectToken(Token::kRBRACE); |
+ |
+ const Class& helper_class = |
+ Class::Handle(I, Library::LookupCoreClass(Symbols::_EnumHelper())); |
+ ASSERT(!helper_class.IsNull()); |
+ |
+ // Add static field 'const List values'. |
+ Field& values_field = Field::ZoneHandle(I); |
+ values_field = Field::New(Symbols::Values(), |
+ /* is_static = */ true, |
+ /* is_final = */ true, |
+ /* is_const = */ true, |
+ /* is_synthetic = */ false, |
+ cls, |
+ cls.token_pos()); |
+ values_field.set_type(Type::Handle(I, Type::ArrayType())); |
+ enum_members.AddField(values_field); |
+ |
+ // Allocate the immutable array containing the enumeration values. |
+ // The actual enum instance values will be patched in later. |
+ const Array& values_array = Array::Handle(I, Array::New(i, Heap::kOld)); |
+ values_field.set_value(values_array); |
+ values_field.RecordStore(values_array); |
+ |
+ // Create a static field that contains the list of enumeration names. |
+ // Clone the _enum_names field from the helper class. |
+ Field& names_field = Field::Handle(I, |
+ helper_class.LookupStaticField(Symbols::_EnumNames())); |
+ ASSERT(!names_field.IsNull()); |
+ names_field = names_field.Clone(cls); |
+ enum_members.AddField(names_field); |
+ const Array& names_array = Array::Handle(Array::MakeArray(enum_names)); |
+ names_field.set_value(names_array); |
+ names_field.RecordStore(names_array); |
+ |
+ // Clone the toString() function from the helper class. |
+ Function& to_string_func = Function::Handle(I, |
+ helper_class.LookupDynamicFunctionAllowPrivate(Symbols::toString())); |
+ ASSERT(!to_string_func.IsNull()); |
+ to_string_func = to_string_func.Clone(cls); |
+ to_string_func.set_is_visible(false); |
+ enum_members.AddFunction(to_string_func); |
+ |
+ cls.AddFields(enum_members.fields()); |
+ const Array& functions = |
+ Array::Handle(I, Array::MakeArray(enum_members.functions())); |
+ cls.SetFunctions(functions); |
+} |
+ |
+ |
// Add an implicit constructor to the given class. |
void Parser::AddImplicitConstructor(const Class& cls) { |
// The implicit constructor is unnamed, has no explicit parameter. |
@@ -5426,6 +5645,8 @@ |
intptr_t metadata_pos = SkipMetadata(); |
if (CurrentToken() == Token::kCLASS) { |
ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos); |
+ } else if (CurrentToken() == Token::kENUM) { |
+ ParseEnumDeclaration(pending_classes, toplevel_class, metadata_pos); |
} else if ((CurrentToken() == Token::kTYPEDEF) && |
(LookaheadToken(1) != Token::kLPAREN)) { |
set_current_class(toplevel_class); |
@@ -10986,6 +11207,12 @@ |
String::Handle(I, type.UserVisibleName()).ToCString() : |
"dynamic"); |
} |
+ // Attempting to instantiate an enum type is a compile-time error. |
+ Class& type_class = Class::Handle(I, type.type_class()); |
+ if (type_class.is_enum_class()) { |
+ ReportError(new_pos, "enum type '%s' can not be instantiated", |
+ String::Handle(I, type_class.Name()).ToCString()); |
+ } |
// The grammar allows for an optional ('.' identifier)? after the type, which |
// is a named constructor. Note that we tell ParseType() above not to |
@@ -11013,7 +11240,6 @@ |
} |
// Resolve the type and optional identifier to a constructor or factory. |
- Class& type_class = Class::Handle(I, type.type_class()); |
String& type_class_name = String::Handle(I, type_class.Name()); |
TypeArguments& type_arguments = |
TypeArguments::ZoneHandle(I, type.arguments()); |