diff --git a/aux/btest b/aux/btest index f9b347738f..539c2d8253 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit f9b347738f1edff486d64fe8c8fdfea2e6c98996 +Subproject commit 539c2d82534345c62ba9a20c2e98ea5cbdea9c7e diff --git a/doc b/doc index d57b3ad38b..69a337c5c7 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit d57b3ad38b2b1ecfd9f1d51699b5fcb785178bf7 +Subproject commit 69a337c5c7958014566f138bfbce9ce95db47b3d diff --git a/src/Expr.cc b/src/Expr.cc index 8bc06960f8..b1865791e6 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -30,7 +30,7 @@ const char* expr_name(BroExprTag t) "=", "~", "[]", "$", "?$", "[=]", "table()", "set()", "vector()", "$=", "in", "<<>>", - "()", "event", "schedule", + "()", "function()", "event", "schedule", "coerce", "record_coerce", "table_coerce", "sizeof", "flatten", "cast", "is", "[:]=" }; @@ -4323,7 +4323,7 @@ void CallExpr::ExprDescribe(ODesc* d) const } LambdaExpr::LambdaExpr(std::unique_ptr ingredients, - std::shared_ptr outer_ids) + std::shared_ptr outer_ids) : Expr(EXPR_LAMBDA) { this->ingredients = std::move(ingredients); this->outer_ids = std::move(outer_ids); @@ -4333,6 +4333,7 @@ LambdaExpr::LambdaExpr(std::unique_ptr ingredients, Val* LambdaExpr::Eval(Frame* f) const { + reporter->Warning("eval lambda"); BroFunc* lamb = new BroFunc( ingredients->id, ingredients->body, @@ -4347,10 +4348,8 @@ Val* LambdaExpr::Eval(Frame* f) const void LambdaExpr::ExprDescribe(ODesc* d) const { - d->Add("Lambda Expression"); - d->Add("{"); - ingredients->body->Describe(d); - d->Add("}"); + d->Add(expr_name(Tag())); + ingredients->body->Describe(d); } TraversalCode LambdaExpr::Traverse(TraversalCallback* cb) const diff --git a/src/Expr.h b/src/Expr.h index 894ce82cbe..53ffbd2e1c 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -43,6 +43,7 @@ typedef enum { EXPR_IN, EXPR_LIST, EXPR_CALL, + EXPR_LAMBDA, EXPR_EVENT, EXPR_SCHEDULE, EXPR_ARITH_COERCE, @@ -952,15 +953,11 @@ protected: }; -// Class to handle the creation of anonymous functions with closures. - -// Facts: -// - LambdaExpr creates a new BroFunc on every call to Eval. -// - LambdaExpr must be given all the information to create a BroFunc on -// construction except for the closure. -// - The closure for created BroFuncs is the frame that the LambdaExpr is -// evaluated in. - +/** + * Class that represents an anonymous function expression in Zeek. + * On evaluation, captures the frame that it is evaluated in. This becomes + * the closure for the instance of the function that it creates. + */ class LambdaExpr : public Expr { public: LambdaExpr(std::unique_ptr ingredients, diff --git a/src/Frame.cc b/src/Frame.cc index 8b2d3ab8e3..d9a4ebdfdb 100644 --- a/src/Frame.cc +++ b/src/Frame.cc @@ -217,7 +217,7 @@ ClosureFrame::~ClosureFrame() Val* ClosureFrame::GetElement(ID* id) const { - if ( ClosureContains(id) ) + if ( CaptureContains(id) ) return ClosureFrame::GatherFromClosure(this, id); return this->NthElement(id->Offset()); @@ -225,7 +225,7 @@ Val* ClosureFrame::GetElement(ID* id) const void ClosureFrame::SetElement(const ID* id, Val* v) { - if ( ClosureContains(id) ) + if ( CaptureContains(id) ) ClosureFrame::SetInClosure(this, id, v); else this->Frame::SetElement(id->Offset(), v); @@ -250,7 +250,7 @@ Frame* ClosureFrame::SelectiveClone(id_list* choose) loop_over_list(*choose, i) { ID* we = (*choose)[i]; - if ( ClosureContains(we) ) + if ( CaptureContains(we) ) us.append(we); else them.append(we); @@ -282,7 +282,7 @@ Val* ClosureFrame::GatherFromClosure(const Frame* start, const ID* id) if ( ! conductor ) return start->NthElement(id->Offset()); - if (conductor->ClosureContains(id)) + if (conductor->CaptureContains(id)) return ClosureFrame::GatherFromClosure(conductor->closure, id); return conductor->NthElement(id->Offset()); @@ -295,14 +295,14 @@ void ClosureFrame::SetInClosure(Frame* start, const ID* id, Val* val) if ( ! conductor ) start->SetElement(id->Offset(), val); - else if (conductor->ClosureContains(id)) + else if (conductor->CaptureContains(id)) ClosureFrame::SetInClosure(conductor->closure, id, val); else conductor->Frame::SetElement(id->Offset(), val); } -bool ClosureFrame::ClosureContains(const ID* i) const +bool ClosureFrame::CaptureContains(const ID* i) const { const char* target = i->Name(); return std::any_of(closure_elements.begin(), closure_elements.end(), diff --git a/src/Frame.h b/src/Frame.h index 37ed7437ba..18df7ac6a9 100644 --- a/src/Frame.h +++ b/src/Frame.h @@ -18,8 +18,9 @@ class Val; class Frame : public BroObj { public: Frame(int size, const BroFunc* func, const val_list *fn_args); - // The constructed frame becomes a view of the input frame. No copying is done. - Frame(const Frame* other, bool is_view = false); + // Constructs a copy or view of other. If a view is constructed the + // destructor will not change other's state on deletion. + Frame(const Frame* other, bool is_view = false); ~Frame() override; Val* NthElement(int n) const { return frame[n]; } @@ -95,19 +96,11 @@ protected: }; -// Class that allows for lookups in both a closure frame and a regular frame -// according to a list of outer IDs passed into the constructor. - -// Facts: -// - A ClosureFrame is created from two frames: a closure and a regular frame. -// - ALL operations except Get/SetElement operations operate on the regular frame. -// - A ClosureFrame requires a list of outside ID's captured by the closure. -// - Get/Set operations on those IDs will be performed on the closure frame. - -// ClosureFrame allows functions that generate functions to be passed between -// different sized frames and still properly capture their closures. It also allows for -// cleaner handling of closures. - +/** + * Class that allows for actions in both a regular frame and a closure frame + * according to a list of outer IDs captured in the closure passed into the + * constructor. + */ class ClosureFrame : public Frame { public: ClosureFrame(Frame* closure, Frame* body, @@ -122,14 +115,12 @@ private: Frame* closure; Frame* body; - // Searches the start frame and all sub-frame's closures for a value corresponding - // to the id. Returns it when its found. Will fail with little grace if the value - // does not actually exist in any of the sub-frames. + // Both of these assume that it has already been verified that id is + // in the start frame. static Val* GatherFromClosure(const Frame* start, const ID* id); - // Moves through the closure frames and associates val with id. static void SetInClosure(Frame* start, const ID* id, Val* val); - bool ClosureContains(const ID* i) const; + bool CaptureContains(const ID* i) const; std::vector closure_elements; }; diff --git a/src/Var.cc b/src/Var.cc index 739b19428a..c86002321e 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -530,7 +530,7 @@ std::unique_ptr gather_function_ingredients(Stmt* body) ingredients->priority = get_func_priotity(attrs); ingredients->body = body; - return std::move(ingredients); + return ingredients; } Val* internal_val(const char* name) @@ -555,7 +555,7 @@ std::shared_ptr gather_outer_ids(Scope* scope, Stmt* body) for ( size_t i = 0; i < cb.outer_id_references.size(); ++i ) idl->append(cb.outer_id_references[i]->Id()); - return std::move(idl); + return idl; } Val* internal_const_val(const char* name) diff --git a/src/Var.h b/src/Var.h index 1c96ff2081..397a8a486e 100644 --- a/src/Var.h +++ b/src/Var.h @@ -26,8 +26,7 @@ extern void add_type(ID* id, BroType* t, attr_list* attr); extern void begin_func(ID* id, const char* module_name, function_flavor flavor, int is_redef, FuncType* t, attr_list* attrs = nullptr); extern void end_func(Stmt* body); -extern std::unique_ptr - gather_function_ingredients(Stmt* body); +extern std::unique_ptr gather_function_ingredients(Stmt* body); extern std::shared_ptr gather_outer_ids(Scope* scope, Stmt* body); extern Val* internal_val(const char* name); diff --git a/testing/btest/Baseline/language.function-closures/out b/testing/btest/Baseline/language.function-closures/out index db8f613344..a58db4552b 100644 --- a/testing/btest/Baseline/language.function-closures/out +++ b/testing/btest/Baseline/language.function-closures/out @@ -31,7 +31,7 @@ expect: client client expect: client client -expect: unknown-22. outside-5 +expect: unknown-33. outside-5 unknown-33. outside-5 expect: unknown-11. outside-4 @@ -42,5 +42,5 @@ expect: client client expect: client client -expect: unknown-22. outside-5 +expect: unknown-33. outside-5 unknown-33. outside-5 diff --git a/testing/btest/language/function-closures.zeek b/testing/btest/language/function-closures.zeek index b314f7e30d..a04c90096d 100644 --- a/testing/btest/language/function-closures.zeek +++ b/testing/btest/language/function-closures.zeek @@ -102,7 +102,7 @@ event zeek_init() print "expect: client"; print dogs[3]; - print "expect: unknown-22. outside-5"; + print "expect: unknown-33. outside-5"; print dogs[33]; print ""; @@ -126,7 +126,7 @@ event zeek_init() print "expect: client"; print dogs_also[3]; - print "expect: unknown-22. outside-5"; + print "expect: unknown-33. outside-5"; print dogs_also[33];