diff --git a/src/Expr.cc b/src/Expr.cc index 997c1509e9..ae46abf213 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -2830,8 +2830,10 @@ ValPtr IndexSliceAssignExpr::Eval(Frame* f) const return nullptr; } -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) +IndexExpr::IndexExpr(ExprPtr arg_op1, ListExprPtr arg_op2, bool 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() ) return; @@ -4467,8 +4469,8 @@ ValPtr InExpr::Fold(Val* v1, Val* v2) const return val_mgr->Bool(res); } -CallExpr::CallExpr(ExprPtr arg_func, ListExprPtr arg_args, bool in_hook) - : Expr(EXPR_CALL), func(std::move(arg_func)), args(std::move(arg_args)) +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)), in_when(_in_when) { if ( func->IsError() || args->IsError() ) { diff --git a/src/Expr.h b/src/Expr.h index a8b90d42dc..3bb9633cb6 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -1005,7 +1005,7 @@ public: class IndexExpr : public BinaryExpr { 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 CanDel() const override; @@ -1021,6 +1021,7 @@ public: ValPtr Eval(Frame* f) const override; bool IsSlice() const { return is_slice; } + bool IsInsideWhen() const { return is_inside_when; } // Optimization-related: ExprPtr Duplicate() override; @@ -1034,6 +1035,7 @@ protected: void ExprDescribe(ODesc* d) const override; bool is_slice; + bool is_inside_when; }; // 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). 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 { public: @@ -1077,7 +1086,7 @@ public: } 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 { 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(); } ListExpr* Args() const { return args.get(); } ListExprPtr ArgsPtr() const { return args; } bool IsPure() const override; + bool IsInWhen() const { return in_when; } ValPtr Eval(Frame* f) const override; @@ -1424,6 +1434,7 @@ protected: ExprPtr func; ListExprPtr args; + bool in_when; }; /** diff --git a/src/parse.y b/src/parse.y index 39046348b1..d2bb078322 100644 --- a/src/parse.y +++ b/src/parse.y @@ -5,7 +5,7 @@ // Switching parser table type fixes ambiguity problems. %define lr.type ielr -%expect 196 +%expect 195 %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %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_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_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_PORT TOK_PRINT TOK_RECORD TOK_REDEF %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. extern bool current_file_has_conditionals; -YYLTYPE GetCurrentLocation(); +extern YYLTYPE GetCurrentLocation(); extern int yyerror(const char[]); extern int brolex(); @@ -133,7 +134,8 @@ extern Expr* g_curr_debug_expr; extern bool in_debug; extern const char* g_curr_debug_error; -static int in_when_cond = 0; +extern int in_when_cond; + static int in_hook = 0; int in_init = 0; int in_record = 0; @@ -618,7 +620,7 @@ expr: $$ = 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); if ( ! locals_at_this_scope.empty() ) @@ -780,7 +782,7 @@ expr: } 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 diff --git a/src/scan.l b/src/scan.l index 52d2896692..cca6ddd0f5 100644 --- a/src/scan.l +++ b/src/scan.l @@ -68,6 +68,10 @@ std::unordered_set files_with_conditionals; 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; const char* filename = 0; // Absolute path of file currently being parsed. const char* last_filename = 0; // Absolute path of last file parsed. @@ -278,7 +282,7 @@ int return TOK_INT; interval return TOK_INTERVAL; is return TOK_IS; list return TOK_LIST; -local return TOK_LOCAL; +local return in_when_cond ? TOK_WHEN_LOCAL : TOK_LOCAL; module return TOK_MODULE; next return TOK_NEXT; of return TOK_OF; @@ -586,10 +590,11 @@ YYLTYPE zeek::detail::GetCurrentLocation() return currloc; } -void zeek::detail::SetCurrentLocation(YYLTYPE currloc) { +void zeek::detail::SetCurrentLocation(YYLTYPE currloc) + { ::filename = currloc.filename; line_number = currloc.first_line; -} + } static int load_files(const char* orig_file) { diff --git a/src/script_opt/Expr.cc b/src/script_opt/Expr.cc index 483b93efe9..b76f4b16bd 100644 --- a/src/script_opt/Expr.cc +++ b/src/script_opt/Expr.cc @@ -1863,7 +1863,7 @@ ExprPtr IndexExpr::Duplicate() { auto op1_d = op1->Duplicate(); 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 diff --git a/src/script_opt/ProfileFunc.cc b/src/script_opt/ProfileFunc.cc index 1b8c31b019..a6057eb4e3 100644 --- a/src/script_opt/ProfileFunc.cc +++ b/src/script_opt/ProfileFunc.cc @@ -129,7 +129,15 @@ TraversalCode ProfileFunc::PreStmt(const Stmt* s) return TC_ABORTSTMT; case STMT_WHEN: + { ++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; case STMT_FOR: