zeek/src/Func.h
Zeke Medley f0798c4b49 Allow serialization of closures over Broker.
anonymous-functions, their closures, can now be sent over broker.
In order to send an anonymous function the receiver must have parsed
a definition of the functon, but it need not to have been evaluated.
See testing/btest/language/closure-sending.zeek for an example of how
this can be done.

This also sends their closures as well as the closures of regular
functions.
2019-07-12 10:31:40 -07:00

212 lines
5 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#ifndef func_h
#define func_h
#include <utility>
#include <memory> // std::shared_ptr, std::unique_ptr
#include <broker/data.hh>
#include <broker/expected.hh>
#include "BroList.h"
#include "Obj.h"
#include "Debug.h"
#include "Frame.h"
class Val;
class ListExpr;
class FuncType;
class Stmt;
class Frame;
class ID;
class CallExpr;
class Func : public BroObj {
public:
enum Kind { BRO_FUNC, BUILTIN_FUNC };
explicit Func(Kind arg_kind);
~Func() override;
virtual int IsPure() const = 0;
function_flavor Flavor() const { return FType()->Flavor(); }
struct Body {
Stmt* stmts;
int priority;
bool operator<(const Body& other) const
{ return priority > other.priority; } // reverse sort
};
const vector<Body>& GetBodies() const { return bodies; }
bool HasBodies() const { return bodies.size(); }
// virtual Val* Call(ListExpr* args) const = 0;
virtual Val* Call(val_list* args, Frame* parent = 0) const = 0;
// Add a new event handler to an existing function (event).
virtual void AddBody(Stmt* new_body, id_list* new_inits,
int new_frame_size, int priority = 0);
virtual void SetScope(Scope* newscope) { scope = newscope; }
virtual Scope* GetScope() const { return scope; }
virtual FuncType* FType() const { return type->AsFuncType(); }
Kind GetKind() const { return kind; }
const char* Name() const { return name.c_str(); }
void SetName(const char* arg_name) { name = arg_name; }
void Describe(ODesc* d) const override = 0;
virtual void DescribeDebug(ODesc* d, const val_list* args) const;
virtual Func* DoClone();
virtual TraversalCode Traverse(TraversalCallback* cb) const;
uint32 GetUniqueFuncID() const { return unique_id; }
static Func* GetFuncPtrByID(uint32 id)
{ return id >= unique_ids.size() ? 0 : unique_ids[id]; }
protected:
Func();
// Copies this functions state into other.
void CopyStateInto(Func* other) const;
// Helper function for handling result of plugin hook.
std::pair<bool, Val*> HandlePluginResult(std::pair<bool, Val*> plugin_result, val_list* args, function_flavor flavor) const;
vector<Body> bodies;
Scope* scope;
Kind kind;
BroType* type;
string name;
uint32 unique_id;
static vector<Func*> unique_ids;
};
class BroFunc : public Func {
public:
BroFunc(ID* id, Stmt* body, id_list* inits, int frame_size, int priority);
~BroFunc() override;
int IsPure() const override;
Val* Call(val_list* args, Frame* parent) const override;
/**
* Adds adds a closure to the function. Closures are cloned and
* future calls to BroFunc will not modify *f*
*
* @param ids IDs that are captured by the closure.
* @param f the closure to be captured.
*/
void AddClosure(std::shared_ptr<id_list> ids, Frame* f);
/**
* Replaces the current closure with one built from *data*
*
* @param data a serialized closure
*/
bool UpdateClosure(const broker::vector& data);
void AddBody(Stmt* new_body, id_list* new_inits, int new_frame_size,
int priority) override;
/**
* Clones this function along with its closures.
*/
Func* DoClone() override;
/**
* Serializes this function's closure.
*
* @return a serialized version of the function's closure.
*/
broker::expected<broker::data> SerializeClosure() const;
/** Sets this function's outer_id list. */
void SetOuterIDs(std::shared_ptr<id_list> ids)
{ outer_ids = std::move(ids); }
void Describe(ODesc* d) const override;
protected:
BroFunc() : Func(BRO_FUNC) {}
Stmt* AddInits(Stmt* body, id_list* inits);
int frame_size;
private:
/**
* Performs a selective clone of *f* using the IDs that were
* captured in the function's closure.
*
* @param f the frame to be cloned.
*/
void SetClosureFrame(Frame* f);
// List of the outer IDs used in the function.
std::shared_ptr<id_list> outer_ids = nullptr;
// The frame the BroFunc was initialized in.
Frame* closure = nullptr;
};
typedef Val* (*built_in_func)(Frame* frame, val_list* args);
class BuiltinFunc : public Func {
public:
BuiltinFunc(built_in_func func, const char* name, int is_pure);
~BuiltinFunc() override;
int IsPure() const override;
Val* Call(val_list* args, Frame* parent) const override;
built_in_func TheFunc() const { return func; }
void Describe(ODesc* d) const override;
protected:
BuiltinFunc() { func = 0; is_pure = 0; }
built_in_func func;
int is_pure;
};
extern void builtin_error(const char* msg, BroObj* arg = 0);
extern void init_builtin_funcs();
extern void init_builtin_funcs_subdirs();
extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call);
struct CallInfo {
const CallExpr* call;
const Func* func;
const val_list* args;
};
// Struct that collects the arguments for a Func.
// Used for BroFuncs with closures.
struct function_ingredients
{
ID* id;
Stmt* body;
id_list* inits;
int frame_size;
int priority;
Scope* scope;
};
extern vector<CallInfo> call_stack;
extern std::string render_call_stack();
// This is set to true after the built-in functions have been initialized.
extern bool did_builtin_init;
#endif