Chromium Code Reviews| 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. |
| + Smi& ordinal_value = Smi::Handle(I, Smi::New(i)); |
|
srdjan
2014/11/18 21:19:18
const Smi&
hausner
2014/11/18 23:14:07
Done.
|
| + 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); |