From 9d407d882c67be22e979f35e9b44efcd609f6153 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 18 Feb 2011 13:01:34 -0800 Subject: [PATCH] Two small infrastructure extensions for passing information into the logging framework. - To enable passing a type into a bif, there's now a new BroType-derived class TypeType and a corresponding TYPE_TYPE tag. With that, a Val can now have a type as its value. This is experimental for now. - RecordVal's get a new method CoerceTo() to coerce their value into a another record type with the usual semantics. Most of the code in there was previously in RecordContructorExpr::InitVal(), which is now calling the new CoerceTo() method. --- src/Expr.cc | 44 ++++------------------------------------- src/Type.cc | 5 +++++ src/Type.h | 28 +++++++++++++++++++++++++++ src/Val.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Val.h | 26 +++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 40 deletions(-) diff --git a/src/Expr.cc b/src/Expr.cc index 5788cdeb7b..0f186b1f99 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -284,7 +284,7 @@ Val* NameExpr::Eval(Frame* f) const Val* v; if ( id->AsType() ) - RunTime("cannot evaluate type name"); + return new Val(id->AsType(), true); if ( id->IsGlobal() ) v = id->ID_Val(); @@ -3309,48 +3309,12 @@ RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list) Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const { - if ( ! aggr ) - aggr = new RecordVal(const_cast(t->AsRecordType())); + RecordVal* rv = Eval(0)->AsRecordVal(); + RecordVal* ar = rv->CoerceTo(t->AsRecordType(), aggr); - if ( record_promotion_compatible(t->AsRecordType(), Type()->AsRecordType()) ) + if ( ar ) { - RecordVal* ar = aggr->AsRecordVal(); - RecordType* ar_t = aggr->Type()->AsRecordType(); - - RecordVal* rv = Eval(0)->AsRecordVal(); - RecordType* rv_t = rv->Type()->AsRecordType(); - - int i; - for ( i = 0; i < rv_t->NumFields(); ++i ) - { - int t_i = ar_t->FieldOffset(rv_t->FieldName(i)); - - if ( t_i < 0 ) - { - char buf[512]; - safe_snprintf(buf, sizeof(buf), - "orphan field \"%s\" in initialization", - rv_t->FieldName(i)); - Error(buf); - break; - } - - else - ar->Assign(t_i, rv->Lookup(i)->Ref()); - } - - for ( i = 0; i < ar_t->NumFields(); ++i ) - if ( ! ar->Lookup(i) && - ! ar_t->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) ) - { - char buf[512]; - safe_snprintf(buf, sizeof(buf), - "non-optional field \"%s\" missing in initialization", ar_t->FieldName(i)); - Error(buf); - } - Unref(rv); - return ar; } diff --git a/src/Type.cc b/src/Type.cc index db74781072..31a04bfeb3 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -95,6 +95,7 @@ BroType::BroType(TypeTag t, bool arg_base_type) case TYPE_FUNC: case TYPE_FILE: case TYPE_VECTOR: + case TYPE_TYPE: internal_tag = TYPE_INTERNAL_OTHER; break; @@ -1426,6 +1427,9 @@ int same_type(const BroType* t1, const BroType* t2, int is_init) case TYPE_FILE: return same_type(t1->YieldType(), t2->YieldType(), is_init); + case TYPE_TYPE: + return same_type(t1, t2, is_init); + case TYPE_UNION: error("union type in same_type()"); } @@ -1514,6 +1518,7 @@ int is_assignable(BroType* t) case TYPE_VECTOR: case TYPE_FILE: case TYPE_TABLE: + case TYPE_TYPE: return 1; case TYPE_VOID: diff --git a/src/Type.h b/src/Type.h index 7e890d9e07..8901380ab7 100644 --- a/src/Type.h +++ b/src/Type.h @@ -31,6 +31,7 @@ typedef enum { TYPE_FUNC, TYPE_FILE, TYPE_VECTOR, + TYPE_TYPE, TYPE_ERROR #define NUM_TYPES (int(TYPE_ERROR) + 1) } TypeTag; @@ -59,6 +60,7 @@ class ListExpr; class EnumType; class Serializer; class VectorType; +class TypeType; const int DOES_NOT_MATCH_INDEX = 0; const int MATCHES_INDEX_SCALAR = 1; @@ -151,6 +153,7 @@ public: CHECK_TYPE_TAG(TYPE_SUBNET, "BroType::AsSubNetType"); return (const SubNetType*) this; } + SubNetType* AsSubNetType() { CHECK_TYPE_TAG(TYPE_SUBNET, "BroType::AsSubNetType"); @@ -192,6 +195,18 @@ public: return (VectorType*) this; } + const TypeType* AsTypeType() const + { + CHECK_TYPE_TAG(TYPE_TYPE, "BroType::AsTypeType"); + return (TypeType*) this; + } + + TypeType* AsTypeType() + { + CHECK_TYPE_TAG(TYPE_TYPE, "BroType::AsTypeType"); + return (TypeType*) this; + } + int IsSet() const { return tag == TYPE_TABLE && (YieldType() == 0); @@ -359,6 +374,19 @@ protected: ID* return_value; }; +class TypeType : public BroType { +public: + TypeType(BroType* t) : BroType(TYPE_TYPE) { type = t->Ref(); } + ~TypeType() { Unref(type); } + + BroType* Type() { return type; } + +protected: + TypeType() {} + + BroType* type; +}; + class TypeDecl { public: TypeDecl(BroType* t, const char* i, attr_list* attrs = 0); diff --git a/src/Val.cc b/src/Val.cc index e7f601210a..dbc55856db 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2892,6 +2892,62 @@ Val* RecordVal::Lookup(int field) const return (*AsRecord())[field]; } +RecordVal* RecordVal::CoerceTo(const RecordType* t, Val* aggr) const + { + if ( ! record_promotion_compatible(t->AsRecordType(), Type()->AsRecordType()) ) + return 0; + + if ( ! aggr ) + aggr = new RecordVal(const_cast(t->AsRecordType())); + + RecordVal* ar = aggr->AsRecordVal(); + RecordType* ar_t = aggr->Type()->AsRecordType(); + + const RecordType* rv_t = Type()->AsRecordType(); + + int i; + for ( i = 0; i < rv_t->NumFields(); ++i ) + { + int t_i = ar_t->FieldOffset(rv_t->FieldName(i)); + + if ( t_i < 0 ) + { + char buf[512]; + safe_snprintf(buf, sizeof(buf), + "orphan field \"%s\" in initialization", + rv_t->FieldName(i)); + Error(buf); + break; + } + + else + ar->Assign(t_i, Lookup(i)->Ref()); + } + + for ( i = 0; i < ar_t->NumFields(); ++i ) + if ( ! ar->Lookup(i) && + ! ar_t->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) ) + { + char buf[512]; + safe_snprintf(buf, sizeof(buf), + "non-optional field \"%s\" missing in initialization", ar_t->FieldName(i)); + Error(buf); + } + + return ar; + } + +RecordVal* RecordVal::CoerceTo(RecordType* t) + { + if ( same_type(Type(), t) ) + { + this->Ref(); + return this; + } + + return CoerceTo(t, 0); + } + void RecordVal::Describe(ODesc* d) const { const val_list* vl = AsRecord(); diff --git a/src/Val.h b/src/Val.h index d21562c907..c056c4e630 100644 --- a/src/Val.h +++ b/src/Val.h @@ -39,6 +39,7 @@ class TableVal; class RecordVal; class ListVal; class StringVal; +class EnumVal; class MutableVal; class StateAccess; @@ -163,6 +164,15 @@ public: // class has ref'd it. Val(BroFile* f); + Val(BroType* t, bool type_type) // Extra arg to differentiate from protected version. + { + type = new TypeType(t->Ref()); + attribs = 0; +#ifdef DEBUG + bound_id = 0; +#endif + } + Val() { val.int_val = 0; @@ -245,6 +255,12 @@ public: return &val.subnet_val; } + const BroType* AsType() const + { + CHECK_TAG(type->Tag(), TYPE_TYPE, "Val::Type", type_name) + return type; + } + // ... in network byte order const addr_type AsAddr() const { @@ -295,6 +311,7 @@ public: CONVERTER(TYPE_LIST, ListVal*, AsListVal) CONVERTER(TYPE_STRING, StringVal*, AsStringVal) CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal) + CONVERTER(TYPE_ENUM, EnumVal*, AsEnumVal) #define CONST_CONVERTER(tag, ctype, name) \ const ctype name() const \ @@ -921,6 +938,15 @@ public: void SetOrigin(BroObj* o) { origin = o; } BroObj* GetOrigin() const { return origin; } + // Returns a new value representing the value coerced to the given type. + // If coercion is not possible, returns 0. The non-const version may + // return the current value ref'ed if its type matches directly. + // + // *aggr* is optional; if non-zero, we add to it. See Expr::InitVal(). We + // leave it out in the non-const version to make the choice unambigious. + RecordVal* CoerceTo(const RecordType* other, Val* aggr) const; + RecordVal* CoerceTo(RecordType* other); + unsigned int MemoryAllocation() const; protected: