From 95069f0993d06913d855ad8d6bc4765ca892ca57 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 16:04:32 -0800 Subject: [PATCH 1/2] Implementing += operator for record types. This is per #375. Record types can now get additional fields later via '+='. The added fields must however either be &optional or have a &default value. Example: type Foo: record { a: count; b: count &optional; }; redef record Foo += { c: count &default=42; d: count &optional; }; global f: Foo = [$a=21]; print f; Output: [a=21, b=, c=42, d=] --- src/Type.cc | 20 ++++++++++++++++++++ src/Type.h | 4 ++++ src/parse.y | 22 ++++++++++++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) 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); From 2f30c3d245f75fbe14012e2d3ab480f3556de922 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 16:10:09 -0800 Subject: [PATCH 2/2] Adding some tests for the record-extension feature. These will go somewhere else eventually, just making sure they don't get lost. --- testing/rec.bro | 17 +++++++++++++++++ testing/rec2.bro | 17 +++++++++++++++++ testing/wrong-rec.bro | 13 +++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 testing/rec.bro create mode 100644 testing/rec2.bro create mode 100644 testing/wrong-rec.bro diff --git a/testing/rec.bro b/testing/rec.bro new file mode 100644 index 0000000000..904edd4e8c --- /dev/null +++ b/testing/rec.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: count &optional; +}; + +global f: Foo = [$a=21]; + +print f; + diff --git a/testing/rec2.bro b/testing/rec2.bro new file mode 100644 index 0000000000..c8324ae577 --- /dev/null +++ b/testing/rec2.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: string &optional; +}; + +global f: Foo = [$a=21, $d="XXX"]; + +print f; + diff --git a/testing/wrong-rec.bro b/testing/wrong-rec.bro new file mode 100644 index 0000000000..e5f553bf45 --- /dev/null +++ b/testing/wrong-rec.bro @@ -0,0 +1,13 @@ +# @TEST-EXEC-FAIL: bro %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count; + d: string &optional; +}; +