diff --git a/src/Type.cc b/src/Type.cc index ec7c8e510b..cfb7f86c0b 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -898,6 +898,26 @@ void RecordType::Describe(ODesc* d) const } } +const char* RecordType::AddFields(type_decl_list* others) + { + assert(types); + + loop_over_list(*others, i) + { + TypeDecl* td = (*others)[i]; + + if ( ! td->FindAttr(ATTR_DEFAULT) && ! td->FindAttr(ATTR_OPTIONAL) ) + return "extension field must be &optional or have &default"; + + types->append(td); + } + + delete others; + + num_fields = types->length(); + return 0; + } + void RecordType::DescribeFields(ODesc* d) const { if ( d->IsReadable() ) diff --git a/src/Type.h b/src/Type.h index ff4d3df9e6..23cdd0af25 100644 --- a/src/Type.h +++ b/src/Type.h @@ -409,6 +409,10 @@ public: int NumFields() const { return num_fields; } + // Returns 0 if all is ok, otherwise a pointer to an error message. Takes + // ownership of list. + const char* AddFields(type_decl_list* types); + void Describe(ODesc* d) const; void DescribeFields(ODesc* d) const; diff --git a/src/parse.y b/src/parse.y index 3cf2c07b18..b4d01c624c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -799,8 +799,8 @@ decl: | TOK_REDEF global_id opt_type init_class opt_init opt_attr ';' { add_global($2, $3, $4, $5, $6, VAR_REDEF); } - | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO - '{' enum_id_list opt_comma '}' ';' + | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO + '{' enum_id_list opt_comma '}' ';' { if ( ! $3->Type() ) $3->Error("unknown identifier"); @@ -815,6 +815,24 @@ decl: } } + | TOK_REDEF TOK_RECORD global_id TOK_ADD_TO + '{' type_decl_list '}' ';' + { + if ( ! $3->Type() ) + $3->Error("unknown identifier"); + else + { + RecordType* add_to = $3->Type()->AsRecordType(); + if ( ! add_to ) + $3->Error("not a record type"); + else { + const char* error = add_to->AddFields($6); + if ( error ) + $3->Error(error); + } + } + } + | TOK_TYPE global_id ':' refined_type opt_attr ';' { add_type($2, $4, $5, 0);