add/delete expressions working w/ interpreter

This commit is contained in:
Vern Paxson 2024-05-08 12:52:06 -07:00
parent 2c46d3139c
commit 905ed55389
6 changed files with 153 additions and 44 deletions

View file

@ -42,6 +42,8 @@ const char* expr_name(ExprTag t) {
"-", "-",
"+", "+",
"-", "-",
"add",
"delete",
"+=", "+=",
"-=", "-=",
"*", "*",
@ -211,9 +213,13 @@ bool Expr::CanAdd() const { return false; }
bool Expr::CanDel() const { return false; } bool Expr::CanDel() const { return false; }
void Expr::Add(Frame* /* f */) { Internal("Expr::Add called"); } TypePtr Expr::AddType() const { return nullptr; }
void Expr::Delete(Frame* /* f */) { Internal("Expr::Delete called"); } TypePtr Expr::DelType() const { return nullptr; }
ValPtr Expr::Add(Frame* /* f */) { Internal("Expr::Add called"); }
ValPtr Expr::Delete(Frame* /* f */) { Internal("Expr::Delete called"); }
ExprPtr Expr::MakeLvalue() { ExprPtr Expr::MakeLvalue() {
if ( ! IsError() ) if ( ! IsError() )
@ -416,8 +422,11 @@ bool NameExpr::CanDel() const {
return GetType()->Tag() == TYPE_TABLE || GetType()->Tag() == TYPE_VECTOR; return GetType()->Tag() == TYPE_TABLE || GetType()->Tag() == TYPE_VECTOR;
} }
void NameExpr::Delete(Frame* f) { TypePtr NameExpr::DelType() const { return GetType(); }
if ( auto v = Eval(f) ) {
ValPtr NameExpr::Delete(Frame* f) {
auto v = Eval(f);
if ( v ) {
if ( GetType()->Tag() == TYPE_TABLE ) if ( GetType()->Tag() == TYPE_TABLE )
v->AsTableVal()->RemoveAll(); v->AsTableVal()->RemoveAll();
else if ( GetType()->Tag() == TYPE_VECTOR ) else if ( GetType()->Tag() == TYPE_VECTOR )
@ -425,6 +434,7 @@ void NameExpr::Delete(Frame* f) {
else else
RuntimeError("delete unsupported"); RuntimeError("delete unsupported");
} }
return v;
} }
// This isn't in-lined to avoid needing to pull in ID.h. // This isn't in-lined to avoid needing to pull in ID.h.
@ -1393,6 +1403,24 @@ void AddExpr::Canonicalize() {
SwapOps(); SwapOps();
} }
AggrAddExpr::AggrAddExpr(ExprPtr _op) : UnaryExpr(EXPR_AGGR_ADD, std::move(_op)) {
if ( ! op->IsError() && ! op->CanAdd() )
ExprError("illegal add expression");
SetType(op->AddType());
}
ValPtr AggrAddExpr::Eval(Frame* f) const { return op->Add(f); }
AggrDelExpr::AggrDelExpr(ExprPtr _op) : UnaryExpr(EXPR_AGGR_DEL, std::move(_op)) {
if ( ! op->IsError() && ! op->CanDel() )
Error("illegal delete expression");
SetType(op->DelType());
}
ValPtr AggrDelExpr::Eval(Frame* f) const { return op->Delete(f); }
// True if we should treat LHS += RHS as add-every-element-of-RHS-to-LHS. // True if we should treat LHS += RHS as add-every-element-of-RHS-to-LHS.
// False for the alternative, add-RHS-as-one-element-to-LHS. // False for the alternative, add-RHS-as-one-element-to-LHS.
// //
@ -2496,46 +2524,57 @@ bool IndexExpr::CanDel() const {
return op1->GetType()->Tag() == TYPE_TABLE; return op1->GetType()->Tag() == TYPE_TABLE;
} }
void IndexExpr::Add(Frame* f) { TypePtr IndexExpr::AddType() const { return op1->GetType(); }
TypePtr IndexExpr::DelType() const {
auto y = op1->GetType()->Yield();
return y ? y : base_type(TYPE_VOID);
}
ValPtr IndexExpr::Add(Frame* f) {
if ( IsError() ) if ( IsError() )
return; return nullptr;
auto v1 = op1->Eval(f); auto v1 = op1->Eval(f);
if ( ! v1 ) if ( ! v1 )
return; return nullptr;
auto v2 = op2->Eval(f); auto v2 = op2->Eval(f);
if ( ! v2 ) if ( ! v2 )
return; return nullptr;
bool iterators_invalidated = false; bool iterators_invalidated = false;
v1->AsTableVal()->Assign(std::move(v2), nullptr, true, &iterators_invalidated); v1->AsTableVal()->Assign(std::move(v2), nullptr, true, &iterators_invalidated);
if ( iterators_invalidated ) if ( iterators_invalidated )
reporter->ExprRuntimeWarning(this, "possible loop/iterator invalidation"); reporter->ExprRuntimeWarning(this, "possible loop/iterator invalidation");
return v1;
} }
void IndexExpr::Delete(Frame* f) { ValPtr IndexExpr::Delete(Frame* f) {
if ( IsError() ) if ( IsError() )
return; return nullptr;
auto v1 = op1->Eval(f); auto v1 = op1->Eval(f);
if ( ! v1 ) if ( ! v1 )
return; return nullptr;
auto v2 = op2->Eval(f); auto v2 = op2->Eval(f);
if ( ! v2 ) if ( ! v2 )
return; return nullptr;
bool iterators_invalidated = false; bool iterators_invalidated = false;
v1->AsTableVal()->Remove(*v2, true, &iterators_invalidated); auto removed = v1->AsTableVal()->Remove(*v2, true, &iterators_invalidated);
if ( iterators_invalidated ) if ( iterators_invalidated )
reporter->ExprRuntimeWarning(this, "possible loop/iterator invalidation"); reporter->ExprRuntimeWarning(this, "possible loop/iterator invalidation");
return removed;
} }
ExprPtr IndexExpr::MakeLvalue() { ExprPtr IndexExpr::MakeLvalue() {
@ -2752,17 +2791,25 @@ ExprPtr FieldExpr::MakeLvalue() { return with_location_of(make_intrusive<RefExpr
bool FieldExpr::CanDel() const { return td->GetAttr(ATTR_DEFAULT) || td->GetAttr(ATTR_OPTIONAL); } bool FieldExpr::CanDel() const { return td->GetAttr(ATTR_DEFAULT) || td->GetAttr(ATTR_OPTIONAL); }
TypePtr FieldExpr::DelType() const { return GetType(); }
void FieldExpr::Assign(Frame* f, ValPtr v) { void FieldExpr::Assign(Frame* f, ValPtr v) {
if ( IsError() ) if ( IsError() )
return; return;
if ( auto op_v = op->Eval(f) ) { Assign(op->Eval(f), v);
RecordVal* r = op_v->AsRecordVal();
r->Assign(field, std::move(v));
}
} }
void FieldExpr::Delete(Frame* f) { Assign(f, nullptr); } void FieldExpr::Assign(ValPtr lhs, ValPtr rhs) {
if ( lhs )
lhs->AsRecordVal()->Assign(field, std::move(rhs));
}
ValPtr FieldExpr::Delete(Frame* f) {
auto op_v = op->Eval(f);
Assign(op_v, nullptr);
return op_v;
}
ValPtr FieldExpr::Fold(Val* v) const { ValPtr FieldExpr::Fold(Val* v) const {
if ( const auto& result = v->AsRecordVal()->GetField(field) ) if ( const auto& result = v->AsRecordVal()->GetField(field) )

View file

@ -46,6 +46,8 @@ enum ExprTag : int {
EXPR_NEGATE, EXPR_NEGATE,
EXPR_ADD, EXPR_ADD,
EXPR_SUB, EXPR_SUB,
EXPR_AGGR_ADD,
EXPR_AGGR_DEL,
EXPR_ADD_TO, EXPR_ADD_TO,
EXPR_REMOVE_FROM, EXPR_REMOVE_FROM,
EXPR_TIMES, EXPR_TIMES,
@ -204,8 +206,12 @@ public:
virtual bool CanAdd() const; virtual bool CanAdd() const;
virtual bool CanDel() const; virtual bool CanDel() const;
virtual void Add(Frame* f); // perform add operation // The types associated with those operations.
virtual void Delete(Frame* f); // perform delete operation virtual TypePtr AddType() const;
virtual TypePtr DelType() const;
virtual ValPtr Add(Frame* f); // perform add operation
virtual ValPtr Delete(Frame* f); // perform delete operation
// Return the expression converted to L-value form. If expr // Return the expression converted to L-value form. If expr
// cannot be used as an L-value, reports an error and returns // cannot be used as an L-value, reports an error and returns
@ -421,7 +427,8 @@ public:
explicit NameExpr(IDPtr id, bool const_init = false); explicit NameExpr(IDPtr id, bool const_init = false);
bool CanDel() const override; bool CanDel() const override;
void Delete(Frame* f) override; TypePtr DelType() const override;
ValPtr Delete(Frame* f) override;
ID* Id() const { return id.get(); } ID* Id() const { return id.get(); }
const IDPtr& IdPtr() const; const IDPtr& IdPtr() const;
@ -700,6 +707,36 @@ protected:
ExprPtr BuildSub(const ExprPtr& op1, const ExprPtr& op2); ExprPtr BuildSub(const ExprPtr& op1, const ExprPtr& op2);
}; };
class AggrAddExpr final : public UnaryExpr {
public:
explicit AggrAddExpr(ExprPtr e);
bool IsPure() const override { return false; }
// Optimization-related:
ExprPtr Duplicate() override;
bool IsReduced(Reducer* c) const override { return HasReducedOps(c); }
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
protected:
ValPtr Eval(Frame* f) const override;
};
class AggrDelExpr final : public UnaryExpr {
public:
explicit AggrDelExpr(ExprPtr e);
bool IsPure() const override { return false; }
// Optimization-related:
ExprPtr Duplicate() override;
bool IsReduced(Reducer* c) const override { return HasReducedOps(c); }
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
protected:
ValPtr Eval(Frame* f) const override;
};
class AddToExpr final : public BinaryExpr { class AddToExpr final : public BinaryExpr {
public: public:
AddToExpr(ExprPtr op1, ExprPtr op2); AddToExpr(ExprPtr op1, ExprPtr op2);
@ -976,8 +1013,11 @@ public:
bool CanAdd() const override; bool CanAdd() const override;
bool CanDel() const override; bool CanDel() const override;
void Add(Frame* f) override; TypePtr AddType() const override;
void Delete(Frame* f) override; TypePtr DelType() const override;
ValPtr Add(Frame* f) override;
ValPtr Delete(Frame* f) override;
void Assign(Frame* f, ValPtr v) override; void Assign(Frame* f, ValPtr v) override;
ExprPtr MakeLvalue() override; ExprPtr MakeLvalue() override;
@ -1075,9 +1115,10 @@ public:
const char* FieldName() const { return field_name; } const char* FieldName() const { return field_name; }
bool CanDel() const override; bool CanDel() const override;
TypePtr DelType() const override;
void Assign(Frame* f, ValPtr v) override; void Assign(Frame* f, ValPtr v) override;
void Delete(Frame* f) override; ValPtr Delete(Frame* f) override;
ExprPtr MakeLvalue() override; ExprPtr MakeLvalue() override;
@ -1085,6 +1126,7 @@ public:
ExprPtr Duplicate() override; ExprPtr Duplicate() override;
protected: protected:
void Assign(ValPtr lhs, ValPtr rhs);
ValPtr Fold(Val* v) const override; ValPtr Fold(Val* v) const override;
void ExprDescribe(ODesc* d) const override; void ExprDescribe(ODesc* d) const override;

View file

@ -18,8 +18,8 @@ enum StmtTag {
STMT_NEXT, STMT_NEXT,
STMT_BREAK, STMT_BREAK,
STMT_RETURN, STMT_RETURN,
STMT_ADD, STMT_ADD, // ### DELETE
STMT_DELETE, STMT_DELETE, // ### DELETE
STMT_LIST, STMT_LIST,
STMT_EVENT_BODY_LIST, STMT_EVENT_BODY_LIST,
STMT_INIT, STMT_INIT,

View file

@ -37,7 +37,7 @@
%token TOK_NO_TEST %token TOK_NO_TEST
%left ',' %left ','
%right '=' TOK_ADD_TO TOK_REMOVE_FROM %right '=' TOK_ADD_TO TOK_REMOVE_FROM TOK_ADD TOK_DELETE
%right '?' ':' %right '?' ':'
%left TOK_OR_OR %left TOK_OR_OR
%left TOK_AND_AND %left TOK_AND_AND
@ -508,6 +508,18 @@ expr:
$$ = new CloneExpr({AdoptRef{}, $3}); $$ = new CloneExpr({AdoptRef{}, $3});
} }
| TOK_ADD expr
{
set_location(@1, @2);
$$ = new AggrAddExpr({AdoptRef{}, $2});
}
| TOK_DELETE expr
{
set_location(@1, @2);
$$ = new AggrDelExpr({AdoptRef{}, $2});
}
| TOK_INCR expr | TOK_INCR expr
{ {
set_location(@1, @2); set_location(@1, @2);
@ -1934,22 +1946,6 @@ stmt:
script_coverage_mgr.AddStmt($$); script_coverage_mgr.AddStmt($$);
} }
| TOK_ADD expr ';' opt_no_test
{
set_location(@1, @3);
$$ = new AddStmt({AdoptRef{}, $2});
if ( ! $4 )
script_coverage_mgr.AddStmt($$);
}
| TOK_DELETE expr ';' opt_no_test
{
set_location(@1, @3);
$$ = new DelStmt({AdoptRef{}, $2});
if ( ! $4 )
script_coverage_mgr.AddStmt($$);
}
| TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';' opt_no_test | TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';' opt_no_test
{ {
set_location(@1, @7); set_location(@1, @7);

View file

@ -723,6 +723,30 @@ ExprPtr AddExpr::BuildSub(const ExprPtr& op1, const ExprPtr& op2) {
return with_location_of(make_intrusive<SubExpr>(op1, rhs), this); return with_location_of(make_intrusive<SubExpr>(op1, rhs), this);
} }
ExprPtr AggrAddExpr::Duplicate() { return SetSucc(new AggrAddExpr(op->Duplicate())); }
ExprPtr AggrAddExpr::Reduce(Reducer* c, StmtPtr& red_stmt) {
if ( c->Optimizing() ) {
op = c->OptExpr(op);
return ThisPtr();
}
red_stmt = op->ReduceToSingletons(c);
return ThisPtr();
}
ExprPtr AggrDelExpr::Duplicate() { return SetSucc(new AggrDelExpr(op->Duplicate())); }
ExprPtr AggrDelExpr::Reduce(Reducer* c, StmtPtr& red_stmt) {
if ( c->Optimizing() ) {
op = c->OptExpr(op);
return ThisPtr();
}
red_stmt = op->ReduceToSingletons(c);
return ThisPtr();
}
ExprPtr AddToExpr::Duplicate() { ExprPtr AddToExpr::Duplicate() {
auto op1_d = op1->Duplicate(); auto op1_d = op1->Duplicate();
auto op2_d = op2->Duplicate(); auto op2_d = op2->Duplicate();

View file

@ -1,2 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
error in <...>/wrong-delete-field.zeek, line 10: illegal delete statement (delete x$a) error in <...>/wrong-delete-field.zeek, line 10: illegal delete expression (deletex$a)