mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
directly construct records of known types, rather than requiring coercion
This commit is contained in:
parent
d165db6909
commit
9a429808ab
6 changed files with 81 additions and 12 deletions
59
src/Expr.cc
59
src/Expr.cc
|
@ -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
|
||||
{
|
||||
|
|
17
src/Expr.h
17
src/Expr.h
|
@ -1062,9 +1062,13 @@ protected:
|
|||
class RecordConstructorExpr final : public Expr {
|
||||
public:
|
||||
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;
|
||||
|
||||
|
@ -1085,6 +1089,7 @@ protected:
|
|||
void ExprDescribe(ODesc* d) const override;
|
||||
|
||||
ListExprPtr op;
|
||||
std::optional<std::vector<int>> map;
|
||||
};
|
||||
|
||||
class TableConstructorExpr final : public UnaryExpr {
|
||||
|
@ -1165,6 +1170,14 @@ public:
|
|||
|
||||
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;
|
||||
bool IsRecordElement(TypeDecl* td) const override;
|
||||
|
||||
|
|
|
@ -683,10 +683,8 @@ expr:
|
|||
switch ( ctor_type->Tag() ) {
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
auto rce = make_intrusive<RecordConstructorExpr>(
|
||||
ListExprPtr{AdoptRef{}, $4});
|
||||
auto rt = cast_intrusive<RecordType>(ctor_type);
|
||||
$$ = new RecordCoerceExpr(std::move(rce), std::move(rt));
|
||||
$$ = new RecordConstructorExpr(rt, ListExprPtr{AdoptRef{}, $4});
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -1827,6 +1827,13 @@ ExprPtr HasFieldExpr::Duplicate()
|
|||
ExprPtr RecordConstructorExpr::Duplicate()
|
||||
{
|
||||
auto op_l = op->Duplicate()->AsListExprPtr();
|
||||
|
||||
if ( map )
|
||||
{
|
||||
auto rt = cast_intrusive<RecordType>(type);
|
||||
return SetSucc(new RecordConstructorExpr(rt, op_l));
|
||||
}
|
||||
else
|
||||
return SetSucc(new RecordConstructorExpr(op_l));
|
||||
}
|
||||
|
||||
|
|
|
@ -1084,7 +1084,7 @@ TraversalCode RD_Decorate::PreExpr(const Expr* e)
|
|||
{
|
||||
auto r = static_cast<const RecordConstructorExpr*>(e);
|
||||
auto l = r->Op();
|
||||
mgr.SetPreFromPre(l, e);
|
||||
mgr.SetPreFromPre(l.get(), e);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,7 +482,7 @@ UDs UseDefs::ExprUDs(const Expr* e)
|
|||
case EXPR_RECORD_CONSTRUCTOR:
|
||||
{
|
||||
auto r = static_cast<const RecordConstructorExpr*>(e);
|
||||
AddInExprUDs(uds, r->Op());
|
||||
AddInExprUDs(uds, r->Op().get());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue