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.
This commit is contained in:
Robin Sommer 2011-02-18 13:01:34 -08:00
parent ffa494e428
commit 9d407d882c
5 changed files with 119 additions and 40 deletions

View file

@ -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<RecordType*>(t->AsRecordType()));
if ( record_promotion_compatible(t->AsRecordType(), Type()->AsRecordType()) )
{
RecordVal* ar = aggr->AsRecordVal();
RecordType* ar_t = aggr->Type()->AsRecordType();
RecordVal* rv = Eval(0)->AsRecordVal();
RecordType* rv_t = rv->Type()->AsRecordType();
RecordVal* ar = rv->CoerceTo(t->AsRecordType(), aggr);
int i;
for ( i = 0; i < rv_t->NumFields(); ++i )
if ( ar )
{
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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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<RecordType*>(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();

View file

@ -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: