// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include #include #include #include #include #include "zeek/EventHandler.h" #include "zeek/IntrusivePtr.h" #include "zeek/StmtBase.h" #include "zeek/Timer.h" #include "zeek/TraverseTypes.h" #include "zeek/Type.h" #include "zeek/Val.h" #include "zeek/ZeekArgs.h" #include "zeek/ZeekList.h" namespace zeek { template class IntrusivePtr; namespace detail { class Frame; class Scope; class FunctionIngredients; class WhenInfo; using IDPtr = IntrusivePtr; using ScopePtr = IntrusivePtr; using ScriptFuncPtr = IntrusivePtr; using FunctionIngredientsPtr = std::shared_ptr; enum ExprTag : int { EXPR_ANY = -1, EXPR_NAME, EXPR_CONST, EXPR_CLONE, EXPR_INCR, EXPR_DECR, EXPR_NOT, EXPR_COMPLEMENT, EXPR_POSITIVE, EXPR_NEGATE, EXPR_ADD, EXPR_SUB, EXPR_AGGR_ADD, EXPR_AGGR_DEL, EXPR_ADD_TO, EXPR_REMOVE_FROM, EXPR_TIMES, EXPR_DIVIDE, EXPR_MASK, EXPR_MOD, EXPR_AND, EXPR_OR, EXPR_XOR, EXPR_LSHIFT, EXPR_RSHIFT, EXPR_AND_AND, EXPR_OR_OR, EXPR_LT, EXPR_LE, EXPR_EQ, EXPR_NE, EXPR_GE, EXPR_GT, EXPR_COND, EXPR_REF, EXPR_ASSIGN, EXPR_INDEX, EXPR_FIELD, EXPR_HAS_FIELD, EXPR_RECORD_CONSTRUCTOR, EXPR_TABLE_CONSTRUCTOR, EXPR_SET_CONSTRUCTOR, EXPR_VECTOR_CONSTRUCTOR, EXPR_FIELD_ASSIGN, EXPR_IN, EXPR_LIST, EXPR_CALL, EXPR_LAMBDA, EXPR_EVENT, EXPR_SCHEDULE, EXPR_ARITH_COERCE, EXPR_RECORD_COERCE, EXPR_TABLE_COERCE, EXPR_VECTOR_COERCE, EXPR_TO_ANY_COERCE, EXPR_FROM_ANY_COERCE, EXPR_SIZE, EXPR_CAST, EXPR_IS, EXPR_INDEX_SLICE_ASSIGN, // The following types of expressions are only created for ASTs // transformed to reduced form; they aren't germane for ASTs produced // by parsing .zeek script files. See script_opt/Expr.h for the // corresponding definitions. EXPR_INLINE, EXPR_APPEND_TO, EXPR_INDEX_ASSIGN, EXPR_FIELD_LHS_ASSIGN, EXPR_FROM_ANY_VEC_COERCE, EXPR_ANY_INDEX, EXPR_SCRIPT_OPT_BUILTIN, EXPR_NOP, #define NUM_EXPRS (int(EXPR_NOP) + 1) }; extern const char* expr_name(ExprTag t); class AddToExpr; class AssignExpr; class CallExpr; class ConstExpr; class EventExpr; class FieldAssignExpr; class FieldExpr; class ForExpr; class HasFieldExpr; class IndexExpr; class IsExpr; class LambdaExpr; class ListExpr; class NameExpr; class RefExpr; class Expr; using CallExprPtr = IntrusivePtr; using ConstExprPtr = IntrusivePtr; using EventExprPtr = IntrusivePtr; using ExprPtr = IntrusivePtr; using NameExprPtr = IntrusivePtr; using RefExprPtr = IntrusivePtr; using LambdaExprPtr = IntrusivePtr; class Stmt; using StmtPtr = IntrusivePtr; class ExprOptInfo; class Expr : public Obj { public: const TypePtr& GetType() const { return type; } template IntrusivePtr GetType() const { return cast_intrusive(type); } ExprTag Tag() const { return tag; } Expr* Ref() { zeek::Ref(this); return this; } ExprPtr ThisPtr() { return {NewRef{}, this}; } // Evaluates the expression and returns a corresponding Val*, // or nil if the expression's value isn't fixed. virtual ValPtr Eval(Frame* f) const = 0; // Assign to the given value, if appropriate. virtual void Assign(Frame* f, ValPtr v); // Returns the type corresponding to this expression interpreted // as an initialization. Returns nil if the initialization is illegal. virtual TypePtr InitType() const; // Returns true if this expression, interpreted as an initialization, // constitutes a record element, false otherwise. If the TypeDecl* // is non-nil and the expression is a record element, fills in the // TypeDecl with a description of the element. virtual bool IsRecordElement(TypeDecl* td) const; // True if the expression has no side effects, false otherwise. virtual bool IsPure() const { return true; } // True if the expression is a constant, false otherwise. bool IsConst() const { return tag == EXPR_CONST; } // True if the expression is in error (to alleviate error propagation). bool IsError() const; // Mark expression as in error. void SetError(); void SetError(const char* msg); // Returns the expression's constant value, or complains // if it's not a constant. inline Val* ExprVal() const; // True if the expression is a constant zero, false otherwise. bool IsZero() const; // True if the expression is a constant one, false otherwise. bool IsOne() const; // True if the expression supports the "add" or "delete" operations, // false otherwise. virtual bool CanAdd() const; virtual bool CanDel() const; // The types associated with those operations. 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 // cannot be used as an L-value, reports an error and returns // the current value of expr (this is the default method). virtual ExprPtr MakeLvalue(); // Invert the sense of the operation. Returns true if the expression // was invertible (currently only true for relational/equality // expressions), false otherwise. virtual bool InvertSense(); // Marks the expression as one requiring (or at least appearing // with) parentheses. Used for pretty-printing. void MarkParen() { paren = true; } bool IsParen() const { return paren; } // These are used by script optimization for AST analysis. #define ZEEK_EXPR_ACCESSOR_DECLS(ctype) \ const ctype* As##ctype() const; \ ctype* As##ctype(); \ IntrusivePtr As##ctype##Ptr(); ZEEK_EXPR_ACCESSOR_DECLS(AddToExpr) ZEEK_EXPR_ACCESSOR_DECLS(AssignExpr) ZEEK_EXPR_ACCESSOR_DECLS(CallExpr) ZEEK_EXPR_ACCESSOR_DECLS(ConstExpr) ZEEK_EXPR_ACCESSOR_DECLS(EventExpr) ZEEK_EXPR_ACCESSOR_DECLS(FieldAssignExpr) ZEEK_EXPR_ACCESSOR_DECLS(FieldExpr) ZEEK_EXPR_ACCESSOR_DECLS(ForExpr) ZEEK_EXPR_ACCESSOR_DECLS(HasFieldExpr) ZEEK_EXPR_ACCESSOR_DECLS(IndexExpr) ZEEK_EXPR_ACCESSOR_DECLS(IsExpr) ZEEK_EXPR_ACCESSOR_DECLS(LambdaExpr) ZEEK_EXPR_ACCESSOR_DECLS(ListExpr) ZEEK_EXPR_ACCESSOR_DECLS(NameExpr) ZEEK_EXPR_ACCESSOR_DECLS(RefExpr) void Describe(ODesc* d) const override final; virtual TraversalCode Traverse(TraversalCallback* cb) const = 0; // Returns a duplicate of the expression. virtual ExprPtr Duplicate() = 0; // Recursively traverses the AST to inline eligible function calls. virtual ExprPtr Inline(Inliner* inl) { return ThisPtr(); } // True if the expression can serve as an operand to a reduced // expression. bool IsSingleton(Reducer* r) const { return (tag == EXPR_NAME && IsReduced(r)) || tag == EXPR_CONST; } // True if the expression has no side effects, false otherwise. virtual bool HasNoSideEffects() const { return IsPure(); } // True if the expression is in fully reduced form: a singleton // or an assignment to an operator with singleton operands. virtual bool IsReduced(Reducer* c) const; // True if the expression's operands are singletons. virtual bool HasReducedOps(Reducer* c) const; // True if (a) the expression has at least one operand, and (b) all // of its operands are constant. bool HasConstantOps() const { return GetOp1() && GetOp1()->IsConst() && (! GetOp2() || (GetOp2()->IsConst() && (! GetOp3() || GetOp3()->IsConst()))); } // True if the expression is reduced to a form that can be // used in a conditional. bool IsReducedConditional(Reducer* c) const; // True if the expression is reduced to a form that can be // used in a field assignment. bool IsReducedFieldAssignment(Reducer* c) const; // True if this expression can be the RHS for a field assignment. bool IsFieldAssignable(const Expr* e) const; // True if the expression will transform to one of another AST node // (perhaps of the same type) upon reduction, for non-constant // operands. "Transform" means something beyond assignment to a // temporary. Necessary so that we know to fully reduce such // expressions if they're the RHS of an assignment. virtual bool WillTransform(Reducer* c) const { return false; } // The same, but for the expression when used in a conditional context. virtual bool WillTransformInConditional(Reducer* c) const { return false; } // Returns the current expression transformed into "new_me". ExprPtr TransformMe(ExprPtr new_me, Reducer* c, StmtPtr& red_stmt); // Returns a set of predecessor statements in red_stmt (which might // be nil if no reduction necessary), and the reduced version of // the expression, suitable for replacing previous uses. The // second version always yields a singleton suitable for use // as an operand. The first version does this too except // for assignment statements; thus, its form is not guarantee // suitable for use as an operand. virtual ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt); virtual ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) { return Reduce(c, red_stmt); } // Reduces the expression to one whose operands are singletons. // Returns a predecessor statement (which might be a StmtList), if any. virtual StmtPtr ReduceToSingletons(Reducer* c); // Reduces the expression to one that can appear as a conditional. ExprPtr ReduceToConditional(Reducer* c, StmtPtr& red_stmt); // Transforms the expression into its form suitable for use in // a conditional. Only meaningful for expressions that return true // for WillTransformInConditional(). virtual ExprPtr TransformToConditional(Reducer* c, StmtPtr& red_stmt); // Reduces the expression to one that can appear as a field // assignment. ExprPtr ReduceToFieldAssignment(Reducer* c, StmtPtr& red_stmt); // Helper function for factoring out complexities related to // index-based assignment. void AssignToIndex(ValPtr v1, ValPtr v2, ValPtr v3) const; // Returns a new expression corresponding to a temporary // that's been assigned to the given expression via red_stmt. ExprPtr AssignToTemporary(ExprPtr e, Reducer* c, StmtPtr& red_stmt); // Same but for this expression. ExprPtr AssignToTemporary(Reducer* c, StmtPtr& red_stmt) { return AssignToTemporary(ThisPtr(), c, red_stmt); } // If the expression always evaluates to the same value, returns // that value. Otherwise, returns nullptr. virtual ValPtr FoldVal() const { return nullptr; } // Returns a Val or a constant Expr corresponding to zero. ValPtr MakeZero(TypeTag t) const; ConstExprPtr MakeZeroExpr(TypeTag t) const; // Returns the expression's operands, or nil if it doesn't // have the given operand. virtual ExprPtr GetOp1() const; virtual ExprPtr GetOp2() const; virtual ExprPtr GetOp3() const; // Sets the operands to new values. virtual void SetOp1(ExprPtr new_op); virtual void SetOp2(ExprPtr new_op); virtual void SetOp3(ExprPtr new_op); // Helper function to reduce boring code runs. StmtPtr MergeStmts(StmtPtr s1, StmtPtr s2, StmtPtr s3 = nullptr) const; // A convenience function for taking a newly-created Expr, // making it point to us as the successor, and returning it. // // Takes an Expr* rather than a ExprPtr to de-clutter the calling // code, which is always passing in "new XyzExpr(...)". This // call, as a convenient side effect, transforms that bare pointer // into an ExprPtr. virtual ExprPtr SetSucc(Expr* succ) { succ->SetLocationInfo(GetLocationInfo()); if ( IsParen() ) succ->MarkParen(); return {AdoptRef{}, succ}; } // Access script optimization information associated with // this statement. ExprOptInfo* GetOptInfo() const { return opt_info; } // Returns the number of expressions created since the last reset. static int GetNumExprs() { return num_exprs; } // Clears the number of expressions created. static void ResetNumExprs() { num_exprs = 0; } ~Expr() override; protected: Expr() = default; explicit Expr(ExprTag arg_tag); virtual void ExprDescribe(ODesc* d) const = 0; void AddTag(ODesc* d) const; // Puts the expression in canonical form. virtual void Canonicalize(); void SetType(TypePtr t); // Reports the given error and sets the expression's type to // TYPE_ERROR. void ExprError(const char msg[]); // These two functions both call Reporter::RuntimeError or Reporter::ExprRuntimeError, // both of which are marked as [[noreturn]]. [[noreturn]] void RuntimeError(const std::string& msg) const; [[noreturn]] void RuntimeErrorWithCallStack(const std::string& msg) const; ExprTag tag; bool paren; TypePtr type; // Information associated with the Expr for purposes of // script optimization. ExprOptInfo* opt_info; // Number of expressions created thus far. static int num_exprs; }; class NameExpr final : public Expr { public: explicit NameExpr(IDPtr id, bool const_init = false); bool CanDel() const override; ValPtr Delete(Frame* f) override; ID* Id() const { return id.get(); } const IDPtr& IdPtr() const; ValPtr Eval(Frame* f) const override; void Assign(Frame* f, ValPtr v) override; ExprPtr MakeLvalue() override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; bool HasNoSideEffects() const override { return true; } bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override { return IsReduced(c); } bool WillTransform(Reducer* c) const override { return ! IsReduced(c); } ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ValPtr FoldVal() const override; protected: void ExprDescribe(ODesc* d) const override; // Returns true if our identifier is a global with a constant value // that can be propagated; used for optimization. bool FoldableGlobal() const; IDPtr id; bool in_const_init; }; class ConstExpr final : public Expr { public: explicit ConstExpr(ValPtr val); Val* Value() const { return val.get(); } ValPtr ValuePtr() const { return val; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ValPtr FoldVal() const override { return val; } protected: void ExprDescribe(ODesc* d) const override; ValPtr val; }; class UnaryExpr : public Expr { public: Expr* Op() const { return op.get(); } // UnaryExpr::Eval correctly handles vector types. Any child // class that overrides Eval() should be modified to handle // vectors correctly as necessary. ValPtr Eval(Frame* f) const override; bool IsPure() const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Inline(Inliner* inl) override; bool HasNoSideEffects() const override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr GetOp1() const override final { return op; } void SetOp1(ExprPtr _op) override final { op = std::move(_op); } protected: UnaryExpr(ExprTag arg_tag, ExprPtr arg_op); void ExprDescribe(ODesc* d) const override; // Returns the expression folded using the given constant. virtual ValPtr Fold(Val* v) const; ExprPtr op; }; class BinaryExpr : public Expr { public: Expr* Op1() const { return op1.get(); } Expr* Op2() const { return op2.get(); } bool IsPure() const override; // BinaryExpr::Eval correctly handles vector types. Any child // class that overrides Eval() should be modified to handle // vectors correctly as necessary. ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Inline(Inliner* inl) override; bool HasNoSideEffects() const override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr GetOp1() const override final { return op1; } ExprPtr GetOp2() const override final { return op2; } void SetOp1(ExprPtr _op) override final { op1 = std::move(_op); } void SetOp2(ExprPtr _op) override final { op2 = std::move(_op); } protected: BinaryExpr(ExprTag arg_tag, ExprPtr arg_op1, ExprPtr arg_op2) : Expr(arg_tag), op1(std::move(arg_op1)), op2(std::move(arg_op2)) { if ( ! (op1 && op2) ) return; if ( op1->IsError() || op2->IsError() ) SetError(); } // Returns the expression folded using the given constants. virtual ValPtr Fold(Val* v1, Val* v2) const; // Same for when the constants are strings. virtual ValPtr StringFold(Val* v1, Val* v2) const; // Same for when the constants are patterns. virtual ValPtr PatternFold(Val* v1, Val* v2) const; // Same for when the constants are sets. virtual ValPtr SetFold(Val* v1, Val* v2) const; // Same for when the constants are tables. virtual ValPtr TableFold(Val* v1, Val* v2) const; // Same for when the constants are addresses or subnets. virtual ValPtr AddrFold(Val* v1, Val* v2) const; virtual ValPtr SubNetFold(Val* v1, Val* v2) const; bool BothConst() const { return op1->IsConst() && op2->IsConst(); } // Exchange op1 and op2. void SwapOps(); // Promote the operands to the given type tag, if necessary. void PromoteOps(TypeTag t); // Promote the expression to the given type tag (i.e., promote // operands and also set expression's type). void PromoteType(TypeTag t, bool is_vector); // Promote one of the operands to be "double" (if not already), // to make it suitable for combining with the other "interval" // operand, yielding an "interval" type. void PromoteForInterval(ExprPtr& op); void ExprDescribe(ODesc* d) const override; // For assignment operations (=, +=, -=) checks for a valid // expression-list on the RHS (op2), potentially transforming // op2 in the process. Returns true if the list is present // and type-checks correctly, false otherwise. bool CheckForRHSList(); ExprPtr op1; ExprPtr op2; }; class CloneExpr final : public UnaryExpr { public: explicit CloneExpr(ExprPtr op); ValPtr Eval(Frame* f) const override; // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Fold(Val* v) const override; }; class IncrExpr final : public UnaryExpr { public: IncrExpr(ExprTag tag, ExprPtr op); ValPtr Eval(Frame* f) const override; ValPtr DoSingleEval(Frame* f, Val* v) const; bool IsPure() const override { return false; } // Optimization-related: ExprPtr Duplicate() override; bool HasNoSideEffects() const override; bool WillTransform(Reducer* c) const override { return true; } bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override { return false; } ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override; }; class ComplementExpr final : public UnaryExpr { public: explicit ComplementExpr(ExprPtr op); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; }; class NotExpr final : public UnaryExpr { public: explicit NotExpr(ExprPtr op); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; }; class PosExpr final : public UnaryExpr { public: explicit PosExpr(ExprPtr op); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; }; class NegExpr final : public UnaryExpr { public: explicit NegExpr(ExprPtr op); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; }; class SizeExpr final : public UnaryExpr { public: explicit SizeExpr(ExprPtr op); ValPtr Eval(Frame* f) const override; // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Fold(Val* v) const override; }; class AddExpr final : public BinaryExpr { public: AddExpr(ExprPtr op1, ExprPtr op2); void Canonicalize() override; // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ExprPtr BuildSub(const ExprPtr& op1, const ExprPtr& op2); }; // A helper class that enables us to factor some common code. class AggrAddDelExpr : public UnaryExpr { public: explicit AggrAddDelExpr(ExprTag _tag, ExprPtr _e) : UnaryExpr(_tag, std::move(_e)) {} bool IsPure() const override { return false; } // Optimization-related: bool IsReduced(Reducer* c) const override { return HasReducedOps(c); } bool HasReducedOps(Reducer* c) const override { return op->HasReducedOps(c); } ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; }; class AggrAddExpr final : public AggrAddDelExpr { public: explicit AggrAddExpr(ExprPtr e); // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Eval(Frame* f) const override; }; class AggrDelExpr final : public AggrAddDelExpr { public: explicit AggrDelExpr(ExprPtr e); // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Eval(Frame* f) const override; }; class AddToExpr final : public BinaryExpr { public: AddToExpr(ExprPtr op1, ExprPtr op2); ValPtr Eval(Frame* f) const override; bool IsVectorElemAppend() const { return is_vector_elem_append; } // Optimization-related: bool IsPure() const override { return false; } ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override { return false; } bool WillTransform(Reducer* c) const override { return true; } bool IsReduced(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override; private: // Whether this operation is appending a single element to a vector. bool is_vector_elem_append = false; }; class RemoveFromExpr final : public BinaryExpr { public: bool IsPure() const override { return false; } RemoveFromExpr(ExprPtr op1, ExprPtr op2); ValPtr Eval(Frame* f) const override; // Optimization-related: ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override { return false; } bool WillTransform(Reducer* c) const override { return true; } bool IsReduced(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override; }; class SubExpr final : public BinaryExpr { public: SubExpr(ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; }; class TimesExpr final : public BinaryExpr { public: TimesExpr(ExprPtr op1, ExprPtr op2); void Canonicalize() override; // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; }; class DivideExpr final : public BinaryExpr { public: DivideExpr(ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; }; class MaskExpr final : public BinaryExpr { public: MaskExpr(ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr AddrFold(Val* v1, Val* v2) const override; }; class ModExpr final : public BinaryExpr { public: ModExpr(ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; }; class BoolExpr final : public BinaryExpr { public: BoolExpr(ExprTag tag, ExprPtr op1, ExprPtr op2); ValPtr Eval(Frame* f) const override; ValPtr DoSingleEval(Frame* f, ValPtr v1, Expr* op2) const; // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; bool WillTransformInConditional(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr TransformToConditional(Reducer* c, StmtPtr& red_stmt) override; protected: bool IsTrue(const ExprPtr& e) const; bool IsFalse(const ExprPtr& e) const; }; class BitExpr final : public BinaryExpr { public: BitExpr(ExprTag tag, ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; }; // Intermediary class for comparison operators. Not directly instantiated. class CmpExpr : public BinaryExpr { protected: CmpExpr(ExprTag tag, ExprPtr op1, ExprPtr op2); void Canonicalize() override; bool WillTransform(Reducer* c) const override; bool WillTransformInConditional(Reducer* c) const override; bool IsReduced(Reducer* c) const override; ExprPtr TransformToConditional(Reducer* c, StmtPtr& red_stmt) override; bool IsHasElementsTest() const; ExprPtr BuildHasElementsTest() const; }; class EqExpr final : public CmpExpr { public: EqExpr(ExprTag tag, ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; bool InvertSense() override; protected: ValPtr Fold(Val* v1, Val* v2) const override; }; class RelExpr final : public CmpExpr { public: RelExpr(ExprTag tag, ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; bool InvertSense() override; }; class CondExpr final : public Expr { public: CondExpr(ExprPtr op1, ExprPtr op2, ExprPtr op3); const Expr* Op1() const { return op1.get(); } const Expr* Op2() const { return op2.get(); } const Expr* Op3() const { return op3.get(); } ValPtr Eval(Frame* f) const override; bool IsPure() const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool WillTransform(Reducer* c) const override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; ExprPtr GetOp1() const override final { return op1; } ExprPtr GetOp2() const override final { return op2; } ExprPtr GetOp3() const override final { return op3; } void SetOp1(ExprPtr _op) override final { op1 = std::move(_op); } void SetOp2(ExprPtr _op) override final { op2 = std::move(_op); } void SetOp3(ExprPtr _op) override final { op3 = std::move(_op); } protected: void ExprDescribe(ODesc* d) const override; bool IsMinOrMax(Reducer* c) const; ExprPtr TransformToMinOrMax() const; ExprPtr op1; ExprPtr op2; ExprPtr op3; }; class RefExpr final : public UnaryExpr { public: explicit RefExpr(ExprPtr op); void Assign(Frame* f, ValPtr v) override; ExprPtr MakeLvalue() override; // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; // Reduce to simplified LHS form, i.e., a reference to only a name. StmtPtr ReduceToLHS(Reducer* c); }; class AssignExpr : public BinaryExpr { public: // If val is given, evaluating this expression will always yield the val // yet still perform the assignment. Used for triggers. AssignExpr(ExprPtr op1, ExprPtr op2, bool is_init, ValPtr val = nullptr, const AttributesPtr& attrs = nullptr, bool type_check = true); ValPtr Eval(Frame* f) const override; TypePtr InitType() const override; bool IsRecordElement(TypeDecl* td) const override; bool IsPure() const override { return false; } // Optimization-related: ExprPtr Duplicate() override; bool HasNoSideEffects() const override; bool WillTransform(Reducer* c) const override { return true; } bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr ReduceToSingleton(Reducer* c, StmtPtr& red_stmt) override; // Whether this is an assignment to a temporary. bool IsTemp() const { return is_temp; } void SetIsTemp() { is_temp = true; } // The following is a hack that's used in "when" expressions to support // assignments to new locals, like "when ( (local l = foo()) && ...". // These methods return the value to use when evaluating such // assignments. That would normally be the RHS of the assignment, // but to get when's to work in a convenient fashion, for them it's // instead boolean T. ValPtr AssignVal() { return val; } const ValPtr& AssignVal() const { return val; } protected: bool TypeCheck(const AttributesPtr& attrs = nullptr); bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2); bool is_init; bool is_temp = false; // Optimization related ValPtr val; // optional }; class IndexSliceAssignExpr final : public AssignExpr { public: IndexSliceAssignExpr(ExprPtr op1, ExprPtr op2, bool is_init); ValPtr Eval(Frame* f) const override; // Optimization-related: ExprPtr Duplicate() override; }; class IndexExpr : public BinaryExpr { public: IndexExpr(ExprPtr op1, ListExprPtr op2, bool is_slice = false, bool is_inside_when = false); bool CanAdd() const override; bool CanDel() const override; ValPtr Add(Frame* f) override; ValPtr Delete(Frame* f) override; void Assign(Frame* f, ValPtr v) override; ExprPtr MakeLvalue() override; // Need to override Eval since it can take a vector arg but does // not necessarily return a vector. ValPtr Eval(Frame* f) const override; bool IsSlice() const { return is_slice; } bool IsInsideWhen() const { return is_inside_when; } // Optimization-related: ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: ValPtr Fold(Val* v1, Val* v2) const override; void ExprDescribe(ODesc* d) const override; bool is_slice; bool is_inside_when; bool is_pattern_table = false; }; // The following execute the heart of IndexExpr functionality for // vector slices and strings. // Extracts a slice of a vector, where the span of the slice is specified // by a list of (exactly) two values. This is how the interpreter develops // the components of a slice. extern VectorValPtr index_slice(VectorVal* vect, const ListVal* lv); // Lower-level access to the slice, where its span is expressed // directly as integers. extern VectorValPtr index_slice(VectorVal* vect, int first, int last); // Returns a subset of a string, with the span specified by a list of // (exactly) two values. extern StringValPtr index_string(const String* s, const ListVal* lv); // Returns a vector indexed by a boolean vector. extern VectorValPtr vector_bool_select(VectorTypePtr vt, const VectorVal* v1, const VectorVal* v2); // Returns a vector indexed by a numeric vector (which specifies the // 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. // // TODO: One Fine Day we should do the equivalent for accessing fields // in records, too. class IndexExprWhen final : public IndexExpr { public: static inline std::vector results = {}; static inline int evaluating = 0; static void StartEval() { ++evaluating; } static void EndEval() { --evaluating; } static std::vector TakeAllResults() { auto rval = std::move(results); results = {}; return rval; } IndexExprWhen(ExprPtr op1, ListExprPtr op2, bool is_slice = false) : IndexExpr(std::move(op1), std::move(op2), is_slice, true) {} ValPtr Eval(Frame* f) const override { auto v = IndexExpr::Eval(f); if ( v && evaluating > 0 ) results.emplace_back(v); return v; } // Optimization-related: ExprPtr Duplicate() override; }; class FieldExpr final : public UnaryExpr { public: FieldExpr(ExprPtr op, const char* field_name); ~FieldExpr() override; int Field() const { return field; } const char* FieldName() const { return field_name; } bool CanDel() const override; void Assign(Frame* f, ValPtr v) override; ValPtr Delete(Frame* f) override; ExprPtr MakeLvalue() override; // Optimization-related: ExprPtr Duplicate() override; protected: void Assign(ValPtr lhs, ValPtr rhs); ValPtr Fold(Val* v) const override; void ExprDescribe(ODesc* d) const override; const char* field_name; const TypeDecl* td; int field; // -1 = attributes }; // "rec?$fieldname" is true if the value of $fieldname in rec is not nil. // "rec?$$attrname" is true if the attribute attrname is not nil. class HasFieldExpr final : public UnaryExpr { public: HasFieldExpr(ExprPtr op, const char* field_name); ~HasFieldExpr() override; const char* FieldName() const { return field_name; } int Field() const { return field; } // Optimization-related: ExprPtr Duplicate() override; bool IsReduced(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; void ExprDescribe(ODesc* d) const override; const char* field_name; int field; }; class RecordConstructorExpr final : public Expr { public: explicit RecordConstructorExpr(ListExprPtr constructor_list); // This form is used to construct records of a known (ultimate) type. explicit RecordConstructorExpr(RecordTypePtr known_rt, ListExprPtr constructor_list); ListExprPtr Op() const { return op; } const auto& Map() const { return map; } ValPtr Eval(Frame* f) const override; bool IsPure() const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: void ExprDescribe(ODesc* d) const override; ListExprPtr op; std::optional> map; }; class TableConstructorExpr final : public UnaryExpr { public: TableConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> attrs, TypePtr arg_type = nullptr, AttributesPtr arg_attrs = nullptr); void SetAttrs(AttributesPtr _attrs) { attrs = std::move(_attrs); } const AttributesPtr& GetAttrs() const { return attrs; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: void ExprDescribe(ODesc* d) const override; AttributesPtr attrs; }; class SetConstructorExpr final : public UnaryExpr { public: SetConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> attrs, TypePtr arg_type = nullptr, AttributesPtr arg_attrs = nullptr); void SetAttrs(AttributesPtr _attrs) { attrs = std::move(_attrs); } const AttributesPtr& GetAttrs() const { return attrs; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: void ExprDescribe(ODesc* d) const override; AttributesPtr attrs; }; class VectorConstructorExpr final : public UnaryExpr { public: explicit VectorConstructorExpr(ListExprPtr constructor_list, TypePtr arg_type = nullptr); ValPtr Eval(Frame* f) const override; // Optimization-related: ExprPtr Duplicate() override; bool HasReducedOps(Reducer* c) const override; protected: void ExprDescribe(ODesc* d) const override; }; class FieldAssignExpr final : public UnaryExpr { public: FieldAssignExpr(const char* field_name, ExprPtr value); const char* FieldName() const { return field_name.c_str(); } // When these are first constructed, we don't know the type. // The following method coerces/promotes the assignment expression // as needed, once we do know the type. // // Returns true on success, false if the types were incompatible // (in which case an error is reported). bool PromoteTo(TypePtr t); bool IsRecordElement(TypeDecl* td) const override; // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override { return true; } ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: void ExprDescribe(ODesc* d) const override; std::string field_name; }; class ArithCoerceExpr final : public UnaryExpr { public: ArithCoerceExpr(ExprPtr op, TypeTag t); // Optimization-related: ExprPtr Duplicate() override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr FoldSingleVal(ValPtr v, const TypePtr& t) const; ValPtr Fold(Val* v) const override; }; class RecordCoerceExpr final : public UnaryExpr { public: RecordCoerceExpr(ExprPtr op, RecordTypePtr r); // Optimization-related: ExprPtr Duplicate() override; bool IsReduced(Reducer* c) const override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; const std::vector& Map() const { return map; } protected: ValPtr Fold(Val* v) const override; // For each super-record slot, gives subrecord slot with which to // fill it. std::vector map; }; extern RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector& map); class TableCoerceExpr final : public UnaryExpr { public: TableCoerceExpr(ExprPtr op, TableTypePtr r, bool type_check = true); ~TableCoerceExpr() override = default; // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Fold(Val* v) const override; }; class VectorCoerceExpr final : public UnaryExpr { public: VectorCoerceExpr(ExprPtr op, VectorTypePtr v); ~VectorCoerceExpr() override = default; // Optimization-related: ExprPtr Duplicate() override; bool IsReduced(Reducer* c) const override; bool WillTransform(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v) const override; }; class ScheduleTimer final : public Timer { public: ScheduleTimer(const EventHandlerPtr& event, zeek::Args args, double t); ~ScheduleTimer() override = default; void Dispatch(double t, bool is_expire) override; protected: EventHandlerPtr event; zeek::Args args; }; class ScheduleExpr final : public Expr { public: ScheduleExpr(ExprPtr when, EventExprPtr event); bool IsPure() const override { return false; } ValPtr Eval(Frame* f) const override; Expr* When() const { return when.get(); } EventExpr* Event() const { return event.get(); } TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; ExprPtr GetOp1() const override final; ExprPtr GetOp2() const override final; void SetOp1(ExprPtr _op) override final; void SetOp2(ExprPtr _op) override final; protected: void ExprDescribe(ODesc* d) const override; ExprPtr when; EventExprPtr event; }; class InExpr final : public BinaryExpr { public: InExpr(ExprPtr op1, ExprPtr op2); // Optimization-related: ExprPtr Duplicate() override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; protected: ValPtr Fold(Val* v1, Val* v2) const override; }; class CallExpr final : public Expr { public: CallExpr(ExprPtr func, ListExprPtr args, bool in_hook = false, bool in_when = false); Expr* Func() const { return func.get(); } ExprPtr FuncPtr() const { return func; } 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; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool IsReduced(Reducer* c) const override; bool WillTransform(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: void ExprDescribe(ODesc* d) const override; bool IsFoldableBiF() const; bool AllConstArgs() const; bool CheckForBuiltin() const; ExprPtr TransformToBuiltin(); ExprPtr func; ListExprPtr args; bool in_when; }; /** * 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 final : public Expr { public: LambdaExpr(FunctionIngredientsPtr ingredients, IDPList outer_ids, std::string name = "", StmtPtr when_parent = nullptr); const std::string& Name() const { return my_name; } const IDPList& OuterIDs() const { return outer_ids; } // Lambda's potentially have their own private copy of captures, // to enable updates to the set during script optimization. using CaptureList = std::vector; const std::optional& GetCaptures() const { return captures; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; ScopePtr GetScope() const; // Optimization-related: ExprPtr Duplicate() override; const ScriptFuncPtr& PrimaryFunc() const { return primary_func; } const FunctionIngredientsPtr& Ingredients() const { return ingredients; } void ReplaceBody(StmtPtr new_body); bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: // Constructor used for script optimization. LambdaExpr(LambdaExpr* orig); void ExprDescribe(ODesc* d) const override; private: friend class WhenInfo; // "Private" captures are captures that correspond to "when" // condition locals. These aren't true captures in that they // don't come from the outer frame when the lambda is constructed, // but they otherwise behave like captures in that they persist // across function invocations. void SetPrivateCaptures(const IDSet& pcaps) { private_captures = pcaps; } bool CheckCaptures(StmtPtr when_parent); void BuildName(); void UpdateCaptures(Reducer* c); FunctionIngredientsPtr ingredients; ScriptFuncPtr primary_func; IDPtr lambda_id; IDPList outer_ids; std::optional captures; IDSet private_captures; std::string my_name; }; // This comes before EventExpr so that EventExpr::GetOp1 can return its // arguments as convertible to ExprPtr. class ListExpr : public Expr { public: ListExpr(); explicit ListExpr(ExprPtr e); ~ListExpr() override; void Append(ExprPtr e); const ExprPList& Exprs() const { return exprs; } ExprPList& Exprs() { return exprs; } // True if the entire list represents pure values. bool IsPure() const override; // True if the entire list represents constant values. bool HasConstantOps() const; ValPtr Eval(Frame* f) const override; TypePtr InitType() const override; ExprPtr MakeLvalue() override; void Assign(Frame* f, ValPtr v) override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool IsReduced(Reducer* c) const override; bool HasReducedOps(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; protected: void ExprDescribe(ODesc* d) const override; ExprPList exprs; }; class EventExpr final : public Expr { public: EventExpr(const char* name, ListExprPtr args); const char* Name() const { return name.c_str(); } ListExpr* Args() const { return args.get(); } EventHandlerPtr Handler() const { return handler; } ValPtr Eval(Frame* f) const override; TraversalCode Traverse(TraversalCallback* cb) const override; // Optimization-related: ExprPtr Duplicate() override; ExprPtr Inline(Inliner* inl) override; bool IsReduced(Reducer* c) const override; ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override; StmtPtr ReduceToSingletons(Reducer* c) override; ExprPtr GetOp1() const override final { return args; } void SetOp1(ExprPtr _op) override final { args = {NewRef{}, _op->AsListExpr()}; } protected: void ExprDescribe(ODesc* d) const override; std::string name; EventHandlerPtr handler; ListExprPtr args; }; class RecordAssignExpr final : public ListExpr { public: RecordAssignExpr(const ExprPtr& record, const ExprPtr& init_list, bool is_init); }; class CastExpr final : public UnaryExpr { public: CastExpr(ExprPtr op, TypePtr t); // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Fold(Val* v) const override; void ExprDescribe(ODesc* d) const override; }; // Returns the value 'v' cast to type 't'. On an error, returns nil // and populates "error" with an error message. extern ValPtr cast_value(ValPtr v, const TypePtr& t, std::string& error); class IsExpr final : public UnaryExpr { public: IsExpr(ExprPtr op, TypePtr t); const TypePtr& TestType() const { return t; } // Optimization-related: ExprPtr Duplicate() override; protected: ValPtr Fold(Val* v) const override; void ExprDescribe(ODesc* d) const override; private: TypePtr t; }; // Expression to explicitly capture conversion to an "any" type, rather // than it occurring implicitly during script interpretation. class CoerceToAnyExpr : public UnaryExpr { public: CoerceToAnyExpr(ExprPtr op); protected: ValPtr Fold(Val* v) const override; ExprPtr Duplicate() override; }; // Same, but for conversion from an "any" type. class CoerceFromAnyExpr : public UnaryExpr { public: CoerceFromAnyExpr(ExprPtr op, TypePtr to_type); protected: ValPtr Fold(Val* v) const override; ExprPtr Duplicate() override; }; // Assigns v1[v2] = v3. Returns an error message, or nullptr on success. // Factored out so that compiled code can call it as well as the interpreter. extern const char* assign_to_index(ValPtr v1, ValPtr v2, ValPtr v3, bool& iterators_invalidated); inline Val* Expr::ExprVal() const { if ( ! IsConst() ) BadTag("ExprVal::Val", expr_name(tag), expr_name(EXPR_CONST)); return ((ConstExpr*)this)->Value(); } // Decides whether to return an AssignExpr or a RecordAssignExpr. extern ExprPtr get_assign_expr(ExprPtr op1, ExprPtr op2, bool is_init); // Takes a RHS constructor list and returns a version with any embedded // indices within it (used to concisely represent multiple set/table entries) // expanded. // // Second argument gives the type that the list will expand to, if known. extern ListExprPtr expand_op(ListExprPtr op, const TypePtr& t); /** * Type-check the given expression(s) against the given type(s). Complain * if the expression cannot match the given type, returning nullptr; * otherwise, returns an expression reflecting the promotion. * * The second, third, and fourth forms are for promoting a list of * expressions (which is updated in place) to either match a list of * types or a single type. * * Note, the type is not "const" because it can be ref'd. */ extern ExprPtr check_and_promote_expr(ExprPtr e, TypePtr t); extern bool check_and_promote_exprs(ListExpr* elements, const TypeListPtr& types); extern bool check_and_promote_args(ListExpr* args, const RecordType* types); extern bool check_and_promote_exprs_to_type(ListExpr* elements, TypePtr type); // Returns a ListExpr simplified down to a list a values, or nil // if they couldn't all be reduced. extern std::optional> eval_list(Frame* f, const ListExpr* l); // Returns true if e1 is "greater" than e2 - here "greater" is just // a heuristic, used with commutative operators to put them into // a canonical form. extern bool expr_greater(const Expr* e1, const Expr* e2); // True if the given Expr* has a vector type inline bool is_vector(Expr* e) { return e->GetType()->Tag() == TYPE_VECTOR; } inline bool is_vector(const ExprPtr& e) { return is_vector(e.get()); } // True if the given Expr* has a list type inline bool is_list(Expr* e) { return e->GetType()->Tag() == TYPE_LIST; } inline bool is_list(const ExprPtr& e) { return is_list(e.get()); } } // namespace detail } // namespace zeek