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);
}
RecordConstructorExpr::RecordConstructorExpr(ListExprPtr constructor_list)
: Expr(EXPR_RECORD_CONSTRUCTOR), op(std::move(constructor_list))
: Expr(EXPR_RECORD_CONSTRUCTOR)
{
if ( IsError() )
return;
map = std::nullopt;
op = std::move(constructor_list);
// Spin through the list, which should be comprised only of
// record-field-assign expressions, and build up a
// record type to associate with this constructor.
@ -3248,8 +3252,46 @@ RecordConstructorExpr::RecordConstructorExpr(ListExprPtr constructor_list)
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
@ -3289,13 +3331,16 @@ ValPtr RecordConstructorExpr::Eval(Frame* f) const
const auto& exprs = op->Exprs();
auto rt = cast_intrusive<RecordType>(type);
if ( exprs.length() != rt->NumFields() )
if ( ! map && exprs.length() != rt->NumFields() )
RuntimeErrorWithCallStack("inconsistency evaluating record constructor");
auto rv = make_intrusive<RecordVal>(std::move(rt));
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;
}
@ -3697,6 +3742,12 @@ FieldAssignExpr::FieldAssignExpr(const char* arg_field_name, ExprPtr value)
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)
const
{