directly construct records of known types, rather than requiring coercion

This commit is contained in:
Vern Paxson 2021-05-30 17:47:28 -07:00
parent d165db6909
commit 9a429808ab
6 changed files with 81 additions and 12 deletions

View file

@ -3218,12 +3218,16 @@ void HasFieldExpr::ExprDescribe(ODesc* d) const
d->Add(field); d->Add(field);
} }
RecordConstructorExpr::RecordConstructorExpr(ListExprPtr constructor_list) RecordConstructorExpr::RecordConstructorExpr(ListExprPtr constructor_list)
: Expr(EXPR_RECORD_CONSTRUCTOR), op(std::move(constructor_list)) : Expr(EXPR_RECORD_CONSTRUCTOR)
{ {
if ( IsError() ) if ( IsError() )
return; return;
map = std::nullopt;
op = std::move(constructor_list);
// Spin through the list, which should be comprised only of // Spin through the list, which should be comprised only of
// record-field-assign expressions, and build up a // record-field-assign expressions, and build up a
// record type to associate with this constructor. // record type to associate with this constructor.
@ -3248,8 +3252,46 @@ RecordConstructorExpr::RecordConstructorExpr(ListExprPtr constructor_list)
SetType(make_intrusive<RecordType>(record_types)); SetType(make_intrusive<RecordType>(record_types));
} }
RecordConstructorExpr::~RecordConstructorExpr() RecordConstructorExpr::RecordConstructorExpr(RecordTypePtr known_rt,
ListExprPtr constructor_list)
: Expr(EXPR_RECORD_CONSTRUCTOR)
{ {
if ( IsError() )
return;
SetType(known_rt);
op = std::move(constructor_list);
const auto& exprs = op->AsListExpr()->Exprs();
map = std::vector<int>(exprs.length());
int i = 0;
for ( const auto& e : exprs )
{
if ( e->Tag() != EXPR_FIELD_ASSIGN )
{
Error("bad type in record constructor", e);
SetError();
continue;
}
auto field = e->AsFieldAssignExpr();
int index = known_rt->FieldOffset(field->FieldName());
if ( index < 0 )
{
Error("no such field in record", e);
SetError();
continue;
}
auto known_ft = known_rt->GetFieldType(index);
if ( ! field->PromoteTo(known_ft) )
SetError();
(*map)[i++] = index;
}
} }
ValPtr RecordConstructorExpr::InitVal(const zeek::Type* t, ValPtr aggr) const ValPtr RecordConstructorExpr::InitVal(const zeek::Type* t, ValPtr aggr) const
@ -3289,13 +3331,16 @@ ValPtr RecordConstructorExpr::Eval(Frame* f) const
const auto& exprs = op->Exprs(); const auto& exprs = op->Exprs();
auto rt = cast_intrusive<RecordType>(type); auto rt = cast_intrusive<RecordType>(type);
if ( exprs.length() != rt->NumFields() ) if ( ! map && exprs.length() != rt->NumFields() )
RuntimeErrorWithCallStack("inconsistency evaluating record constructor"); RuntimeErrorWithCallStack("inconsistency evaluating record constructor");
auto rv = make_intrusive<RecordVal>(std::move(rt)); auto rv = make_intrusive<RecordVal>(std::move(rt));
for ( int i = 0; i < exprs.length(); ++i ) for ( int i = 0; i < exprs.length(); ++i )
rv->Assign(i, exprs[i]->Eval(f)); {
int ind = map ? (*map)[i] : i;
rv->Assign(ind, exprs[i]->Eval(f));
}
return rv; return rv;
} }
@ -3697,6 +3742,12 @@ FieldAssignExpr::FieldAssignExpr(const char* arg_field_name, ExprPtr value)
SetType(op->GetType()); SetType(op->GetType());
} }
bool FieldAssignExpr::PromoteTo(TypePtr t)
{
op = check_and_promote_expr(op.get(), t.get());
return op != nullptr;
}
void FieldAssignExpr::EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) void FieldAssignExpr::EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f)
const const
{ {

View file

@ -1062,9 +1062,13 @@ protected:
class RecordConstructorExpr final : public Expr { class RecordConstructorExpr final : public Expr {
public: public:
explicit RecordConstructorExpr(ListExprPtr constructor_list); explicit RecordConstructorExpr(ListExprPtr constructor_list);
~RecordConstructorExpr() override;
ListExpr* Op() const { return op.get(); } // This form is used to construct records of a known (ultimate) type.
explicit RecordConstructorExpr(RecordTypePtr known_rt,
ListExprPtr constructor_list);
ListExprPtr Op() const { return op; }
const auto& Map() const { return map; }
ValPtr Eval(Frame* f) const override; ValPtr Eval(Frame* f) const override;
@ -1085,6 +1089,7 @@ protected:
void ExprDescribe(ODesc* d) const override; void ExprDescribe(ODesc* d) const override;
ListExprPtr op; ListExprPtr op;
std::optional<std::vector<int>> map;
}; };
class TableConstructorExpr final : public UnaryExpr { class TableConstructorExpr final : public UnaryExpr {
@ -1165,6 +1170,14 @@ public:
const char* FieldName() const { return field_name.c_str(); } const char* FieldName() const { return field_name.c_str(); }
// When these are first constructed, we don't know the type.
// The following method coerces/promotes the assignment expression
// as needed, once we do know the type.
//
// Returns true on success, false if the types were incompatible
// (in which case an error is reported).
bool PromoteTo(TypePtr t);
void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override; void EvalIntoAggregate(const zeek::Type* t, Val* aggr, Frame* f) const override;
bool IsRecordElement(TypeDecl* td) const override; bool IsRecordElement(TypeDecl* td) const override;

View file

@ -683,10 +683,8 @@ expr:
switch ( ctor_type->Tag() ) { switch ( ctor_type->Tag() ) {
case TYPE_RECORD: case TYPE_RECORD:
{ {
auto rce = make_intrusive<RecordConstructorExpr>(
ListExprPtr{AdoptRef{}, $4});
auto rt = cast_intrusive<RecordType>(ctor_type); auto rt = cast_intrusive<RecordType>(ctor_type);
$$ = new RecordCoerceExpr(std::move(rce), std::move(rt)); $$ = new RecordConstructorExpr(rt, ListExprPtr{AdoptRef{}, $4});
} }
break; break;

View file

@ -1827,7 +1827,14 @@ ExprPtr HasFieldExpr::Duplicate()
ExprPtr RecordConstructorExpr::Duplicate() ExprPtr RecordConstructorExpr::Duplicate()
{ {
auto op_l = op->Duplicate()->AsListExprPtr(); auto op_l = op->Duplicate()->AsListExprPtr();
return SetSucc(new RecordConstructorExpr(op_l));
if ( map )
{
auto rt = cast_intrusive<RecordType>(type);
return SetSucc(new RecordConstructorExpr(rt, op_l));
}
else
return SetSucc(new RecordConstructorExpr(op_l));
} }
bool RecordConstructorExpr::HasReducedOps(Reducer* c) const bool RecordConstructorExpr::HasReducedOps(Reducer* c) const

View file

@ -1084,7 +1084,7 @@ TraversalCode RD_Decorate::PreExpr(const Expr* e)
{ {
auto r = static_cast<const RecordConstructorExpr*>(e); auto r = static_cast<const RecordConstructorExpr*>(e);
auto l = r->Op(); auto l = r->Op();
mgr.SetPreFromPre(l, e); mgr.SetPreFromPre(l.get(), e);
break; break;
} }

View file

@ -482,7 +482,7 @@ UDs UseDefs::ExprUDs(const Expr* e)
case EXPR_RECORD_CONSTRUCTOR: case EXPR_RECORD_CONSTRUCTOR:
{ {
auto r = static_cast<const RecordConstructorExpr*>(e); auto r = static_cast<const RecordConstructorExpr*>(e);
AddInExprUDs(uds, r->Op()); AddInExprUDs(uds, r->Op().get());
break; break;
} }