tracking of when statements/expressions occur in a "when" context

This commit is contained in:
Vern Paxson 2022-05-12 13:45:45 -07:00
parent 5a32e58e04
commit 9ada7ac4e7
6 changed files with 45 additions and 17 deletions

View file

@ -2830,8 +2830,10 @@ ValPtr IndexSliceAssignExpr::Eval(Frame* f) const
return nullptr; return nullptr;
} }
IndexExpr::IndexExpr(ExprPtr arg_op1, ListExprPtr arg_op2, bool arg_is_slice) IndexExpr::IndexExpr(ExprPtr arg_op1, ListExprPtr arg_op2, bool arg_is_slice,
: BinaryExpr(EXPR_INDEX, std::move(arg_op1), std::move(arg_op2)), is_slice(arg_is_slice) bool arg_is_inside_when)
: BinaryExpr(EXPR_INDEX, std::move(arg_op1), std::move(arg_op2)), is_slice(arg_is_slice),
is_inside_when(arg_is_inside_when)
{ {
if ( IsError() ) if ( IsError() )
return; return;
@ -4467,8 +4469,8 @@ ValPtr InExpr::Fold(Val* v1, Val* v2) const
return val_mgr->Bool(res); return val_mgr->Bool(res);
} }
CallExpr::CallExpr(ExprPtr arg_func, ListExprPtr arg_args, bool in_hook) CallExpr::CallExpr(ExprPtr arg_func, ListExprPtr arg_args, bool in_hook, bool _in_when)
: Expr(EXPR_CALL), func(std::move(arg_func)), args(std::move(arg_args)) : Expr(EXPR_CALL), func(std::move(arg_func)), args(std::move(arg_args)), in_when(_in_when)
{ {
if ( func->IsError() || args->IsError() ) if ( func->IsError() || args->IsError() )
{ {

View file

@ -1005,7 +1005,7 @@ public:
class IndexExpr : public BinaryExpr class IndexExpr : public BinaryExpr
{ {
public: public:
IndexExpr(ExprPtr op1, ListExprPtr op2, bool is_slice = false); IndexExpr(ExprPtr op1, ListExprPtr op2, bool is_slice = false, bool is_inside_when = false);
bool CanAdd() const override; bool CanAdd() const override;
bool CanDel() const override; bool CanDel() const override;
@ -1021,6 +1021,7 @@ public:
ValPtr Eval(Frame* f) const override; ValPtr Eval(Frame* f) const override;
bool IsSlice() const { return is_slice; } bool IsSlice() const { return is_slice; }
bool IsInsideWhen() const { return is_inside_when; }
// Optimization-related: // Optimization-related:
ExprPtr Duplicate() override; ExprPtr Duplicate() override;
@ -1034,6 +1035,7 @@ protected:
void ExprDescribe(ODesc* d) const override; void ExprDescribe(ODesc* d) const override;
bool is_slice; bool is_slice;
bool is_inside_when;
}; };
// The following execute the heart of IndexExpr functionality for // The following execute the heart of IndexExpr functionality for
@ -1059,6 +1061,13 @@ extern VectorValPtr vector_bool_select(VectorTypePtr vt, const VectorVal* v1, co
// indices to select). // indices to select).
extern VectorValPtr vector_int_select(VectorTypePtr vt, const VectorVal* v1, const VectorVal* v2); extern VectorValPtr vector_int_select(VectorTypePtr vt, const VectorVal* v1, const VectorVal* v2);
// The following is used for index expressions that occur inside "when"
// clauses. It tracks all the results produced by evaluating indexing
// aggregates, so that if any of them are Modifiable(), the associated
// Trigger can register interest in changes to them.
//
// One Fine Day we should do the equivalent for accessing fields in records,
// too.
class IndexExprWhen final : public IndexExpr class IndexExprWhen final : public IndexExpr
{ {
public: public:
@ -1077,7 +1086,7 @@ public:
} }
IndexExprWhen(ExprPtr op1, ListExprPtr op2, bool is_slice = false) IndexExprWhen(ExprPtr op1, ListExprPtr op2, bool is_slice = false)
: IndexExpr(std::move(op1), std::move(op2), is_slice) : IndexExpr(std::move(op1), std::move(op2), is_slice, true)
{ {
} }
@ -1398,13 +1407,14 @@ protected:
class CallExpr final : public Expr class CallExpr final : public Expr
{ {
public: public:
CallExpr(ExprPtr func, ListExprPtr args, bool in_hook = false); CallExpr(ExprPtr func, ListExprPtr args, bool in_hook = false, bool in_when = false);
Expr* Func() const { return func.get(); } Expr* Func() const { return func.get(); }
ListExpr* Args() const { return args.get(); } ListExpr* Args() const { return args.get(); }
ListExprPtr ArgsPtr() const { return args; } ListExprPtr ArgsPtr() const { return args; }
bool IsPure() const override; bool IsPure() const override;
bool IsInWhen() const { return in_when; }
ValPtr Eval(Frame* f) const override; ValPtr Eval(Frame* f) const override;
@ -1424,6 +1434,7 @@ protected:
ExprPtr func; ExprPtr func;
ListExprPtr args; ListExprPtr args;
bool in_when;
}; };
/** /**

View file

@ -5,7 +5,7 @@
// Switching parser table type fixes ambiguity problems. // Switching parser table type fixes ambiguity problems.
%define lr.type ielr %define lr.type ielr
%expect 196 %expect 195
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
@ -13,7 +13,8 @@
%token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_DEFAULT TOK_DELETE %token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_DEFAULT TOK_DELETE
%token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FALLTHROUGH %token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FALLTHROUGH
%token TOK_FILE TOK_FOR TOK_FUNCTION TOK_GLOBAL TOK_HOOK TOK_ID TOK_IF TOK_INT %token TOK_FILE TOK_FOR TOK_FUNCTION TOK_GLOBAL TOK_HOOK TOK_ID TOK_IF TOK_INT
%token TOK_INTERVAL TOK_LIST TOK_LOCAL TOK_MODULE %token TOK_INTERVAL TOK_LIST TOK_MODULE
%token TOK_LOCAL TOK_WHEN_LOCAL
%token TOK_NEXT TOK_OF TOK_OPAQUE TOK_PATTERN TOK_PATTERN_END TOK_PATTERN_TEXT %token TOK_NEXT TOK_OF TOK_OPAQUE TOK_PATTERN TOK_PATTERN_END TOK_PATTERN_TEXT
%token TOK_PORT TOK_PRINT TOK_RECORD TOK_REDEF %token TOK_PORT TOK_PRINT TOK_RECORD TOK_REDEF
%token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET %token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET
@ -111,7 +112,7 @@ extern int conditional_epoch; // let's us track embedded conditionals
// Whether the file we're currently parsing includes @if conditionals. // Whether the file we're currently parsing includes @if conditionals.
extern bool current_file_has_conditionals; extern bool current_file_has_conditionals;
YYLTYPE GetCurrentLocation(); extern YYLTYPE GetCurrentLocation();
extern int yyerror(const char[]); extern int yyerror(const char[]);
extern int brolex(); extern int brolex();
@ -133,7 +134,8 @@ extern Expr* g_curr_debug_expr;
extern bool in_debug; extern bool in_debug;
extern const char* g_curr_debug_error; extern const char* g_curr_debug_error;
static int in_when_cond = 0; extern int in_when_cond;
static int in_hook = 0; static int in_hook = 0;
int in_init = 0; int in_init = 0;
int in_record = 0; int in_record = 0;
@ -618,7 +620,7 @@ expr:
$$ = get_assign_expr({AdoptRef{}, $1}, {AdoptRef{}, $3}, in_init).release(); $$ = get_assign_expr({AdoptRef{}, $1}, {AdoptRef{}, $3}, in_init).release();
} }
| TOK_LOCAL local_id '=' rhs | TOK_WHEN_LOCAL local_id '=' rhs
{ {
set_location(@2, @4); set_location(@2, @4);
if ( ! locals_at_this_scope.empty() ) if ( ! locals_at_this_scope.empty() )
@ -780,7 +782,7 @@ expr:
} }
else else
$$ = new CallExpr({AdoptRef{}, $1}, {AdoptRef{}, $4}, in_hook > 0); $$ = new CallExpr({AdoptRef{}, $1}, {AdoptRef{}, $4}, in_hook > 0, in_when_cond);
} }
| TOK_HOOK { ++in_hook; } expr | TOK_HOOK { ++in_hook; } expr

View file

@ -68,6 +68,10 @@ std::unordered_set<std::string> files_with_conditionals;
zeek::detail::int_list if_stack; zeek::detail::int_list if_stack;
// Whether we're parsing a "when" conditional, for which we treat
// the "local" keyword differently.
int in_when_cond = 0;
int line_number = 1; int line_number = 1;
const char* filename = 0; // Absolute path of file currently being parsed. const char* filename = 0; // Absolute path of file currently being parsed.
const char* last_filename = 0; // Absolute path of last file parsed. const char* last_filename = 0; // Absolute path of last file parsed.
@ -278,7 +282,7 @@ int return TOK_INT;
interval return TOK_INTERVAL; interval return TOK_INTERVAL;
is return TOK_IS; is return TOK_IS;
list return TOK_LIST; list return TOK_LIST;
local return TOK_LOCAL; local return in_when_cond ? TOK_WHEN_LOCAL : TOK_LOCAL;
module return TOK_MODULE; module return TOK_MODULE;
next return TOK_NEXT; next return TOK_NEXT;
of return TOK_OF; of return TOK_OF;
@ -586,10 +590,11 @@ YYLTYPE zeek::detail::GetCurrentLocation()
return currloc; return currloc;
} }
void zeek::detail::SetCurrentLocation(YYLTYPE currloc) { void zeek::detail::SetCurrentLocation(YYLTYPE currloc)
{
::filename = currloc.filename; ::filename = currloc.filename;
line_number = currloc.first_line; line_number = currloc.first_line;
} }
static int load_files(const char* orig_file) static int load_files(const char* orig_file)
{ {

View file

@ -1863,7 +1863,7 @@ ExprPtr IndexExpr::Duplicate()
{ {
auto op1_d = op1->Duplicate(); auto op1_d = op1->Duplicate();
auto op2_l = op2->Duplicate()->AsListExprPtr(); auto op2_l = op2->Duplicate()->AsListExprPtr();
return SetSucc(new IndexExpr(op1_d, op2_l, is_slice)); return SetSucc(new IndexExpr(op1_d, op2_l, is_slice, is_inside_when));
} }
bool IndexExpr::HasReducedOps(Reducer* c) const bool IndexExpr::HasReducedOps(Reducer* c) const

View file

@ -129,7 +129,15 @@ TraversalCode ProfileFunc::PreStmt(const Stmt* s)
return TC_ABORTSTMT; return TC_ABORTSTMT;
case STMT_WHEN: case STMT_WHEN:
{
++num_when_stmts; ++num_when_stmts;
auto w = s->AsWhenStmt();
auto wi = w->Info();
auto wl = wi ? wi->Lambda() : nullptr;
if ( wl )
lambdas.push_back(wl.get());
}
break; break;
case STMT_FOR: case STMT_FOR: