Allow named record constructors. Addresses #983.

This commit is contained in:
Jon Siwek 2013-05-29 12:48:15 -05:00
parent d67123d0c3
commit a0ad87b4c2
6 changed files with 105 additions and 7 deletions

View file

@ -3320,12 +3320,20 @@ bool HasFieldExpr::DoUnserialize(UnserialInfo* info)
return UNSERIALIZE(&not_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field); return UNSERIALIZE(&not_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field);
} }
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list) RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list,
BroType* arg_type)
: UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list) : UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list)
{ {
if ( IsError() ) if ( IsError() )
return; return;
if ( arg_type && arg_type->Tag() != TYPE_RECORD )
{
Error("bad record constructor type", arg_type);
SetError();
return;
}
// Spin through the list, which should be comprised of // Spin through the list, which should be comprised of
// either record's or record-field-assign, and build up a // either record's or record-field-assign, and build up a
// record type to associate with this constructor. // record type to associate with this constructor.
@ -3365,7 +3373,17 @@ RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
} }
} }
SetType(new RecordType(record_types)); ctor_type = new RecordType(record_types);
if ( arg_type )
SetType(arg_type->Ref());
else
SetType(ctor_type->Ref());
}
RecordConstructorExpr::~RecordConstructorExpr()
{
Unref(ctor_type);
} }
Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
@ -3391,7 +3409,7 @@ Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
Val* RecordConstructorExpr::Fold(Val* v) const Val* RecordConstructorExpr::Fold(Val* v) const
{ {
ListVal* lv = v->AsListVal(); ListVal* lv = v->AsListVal();
RecordType* rt = type->AsRecordType(); RecordType* rt = ctor_type->AsRecordType();
if ( lv->Length() != rt->NumFields() ) if ( lv->Length() != rt->NumFields() )
Internal("inconsistency evaluating record constructor"); Internal("inconsistency evaluating record constructor");
@ -3401,6 +3419,19 @@ Val* RecordConstructorExpr::Fold(Val* v) const
for ( int i = 0; i < lv->Length(); ++i ) for ( int i = 0; i < lv->Length(); ++i )
rv->Assign(i, lv->Index(i)->Ref()); rv->Assign(i, lv->Index(i)->Ref());
if ( ! same_type(rt, type) )
{
RecordVal* new_val = rv->CoerceTo(type->AsRecordType());
if ( new_val )
{
Unref(rv);
rv = new_val;
}
else
Internal("record constructor coercion failed");
}
return rv; return rv;
} }
@ -3416,12 +3447,16 @@ IMPLEMENT_SERIAL(RecordConstructorExpr, SER_RECORD_CONSTRUCTOR_EXPR);
bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const
{ {
DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr); DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr);
SERIALIZE_OPTIONAL(ctor_type);
return true; return true;
} }
bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info) bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info)
{ {
DO_UNSERIALIZE(UnaryExpr); DO_UNSERIALIZE(UnaryExpr);
BroType* t = 0;
UNSERIALIZE_OPTIONAL(t, RecordType::Unserialize(info));
ctor_type = t->AsRecordType();
return true; return true;
} }

View file

@ -57,6 +57,7 @@ extern const char* expr_name(BroExprTag t);
class Stmt; class Stmt;
class Frame; class Frame;
class ListExpr; class ListExpr;
class NameExpr;
class CallExpr; class CallExpr;
class EventExpr; class EventExpr;
@ -165,6 +166,17 @@ public:
return (ListExpr*) this; return (ListExpr*) this;
} }
const NameExpr* AsNameExpr() const
{
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
return (const NameExpr*) this;
}
NameExpr* AsNameExpr()
{
CHECK_TAG(tag, EXPR_NAME, "ExprVal::AsNameExpr", expr_name)
return (NameExpr*) this;
}
void Describe(ODesc* d) const; void Describe(ODesc* d) const;
bool Serialize(SerialInfo* info) const; bool Serialize(SerialInfo* info) const;
@ -729,7 +741,8 @@ protected:
class RecordConstructorExpr : public UnaryExpr { class RecordConstructorExpr : public UnaryExpr {
public: public:
RecordConstructorExpr(ListExpr* constructor_list); RecordConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0);
~RecordConstructorExpr();
protected: protected:
friend class Expr; friend class Expr;
@ -741,6 +754,8 @@ protected:
void ExprDescribe(ODesc* d) const; void ExprDescribe(ODesc* d) const;
DECLARE_SERIAL(RecordConstructorExpr); DECLARE_SERIAL(RecordConstructorExpr);
RecordType* ctor_type; // type inferred from the ctor expression list args
}; };
class TableConstructorExpr : public UnaryExpr { class TableConstructorExpr : public UnaryExpr {

View file

@ -217,6 +217,11 @@ public:
return tag == TYPE_TABLE && (YieldType() == 0); return tag == TYPE_TABLE && (YieldType() == 0);
} }
int IsTable() const
{
return tag == TYPE_TABLE && (YieldType() != 0);
}
BroType* Ref() { ::Ref(this); return this; } BroType* Ref() { ::Ref(this); return this; }
virtual void Describe(ODesc* d) const; virtual void Describe(ODesc* d) const;

View file

@ -522,10 +522,39 @@ expr:
$$ = new VectorConstructorExpr($3); $$ = new VectorConstructorExpr($3);
} }
| expr '(' opt_expr_list ')' | expr '('
{ {
set_location(@1, @4); if ( $1->Tag() == EXPR_NAME && $1->Type()->IsTable() )
$$ = new CallExpr($1, $3, in_hook > 0); ++in_init;
}
opt_expr_list
{
if ( $1->Tag() == EXPR_NAME && $1->Type()->IsTable() )
--in_init;
}
')'
{
set_location(@1, @6);
BroType* ctor_type = 0;
if ( $1->Tag() == EXPR_NAME &&
(ctor_type = $1->AsNameExpr()->Id()->AsType()) )
{
switch ( ctor_type->Tag() ) {
case TYPE_RECORD:
$$ = new RecordConstructorExpr($4, ctor_type);
break;
case TYPE_TABLE:
case TYPE_VECTOR:
default:
$1->Error("constructor type not implemented");
YYERROR;
}
}
else
$$ = new CallExpr($1, $4, in_hook > 0);
} }
| TOK_HOOK { ++in_hook; } expr | TOK_HOOK { ++in_hook; } expr

View file

@ -0,0 +1,2 @@
[min=<uninitialized>, max=2]
[min=7, max=42]

View file

@ -0,0 +1,12 @@
# @TEST-EXEC: bro -b %INPUT >out
# @TEST-EXEC: btest-diff out
type MyRec: record {
min: count &optional;
max: count;
};
local myrec: MyRec = MyRec($max=2);
print myrec;
myrec = MyRec($min=7, $max=42);
print myrec;