zeek/src/Expr.h
Arne Welzel ec1088c3ef Merge remote-tracking branch 'origin/topic/vern/zam-regularization'
* origin/topic/vern/zam-regularization: (33 commits)
  simpler and more robust identification of function parameters for AST profiling
  fixes to limit AST traversal in the face of recursive types
  address some script optimization compiler warnings under Linux
  fix for -O C++ construction of variable names that use multiple module namespaces
  fix for script optimization of "opaque" values that are run-time constants
  fix for script optimization of nested switch statements
  script optimization fix for complex "in" expressions in conditionals
  updates to typos allow-list reflecting ZAM regularization changes
  BTest updates for ZAM regularization changes
  convert new ZAM operations to use typed operands
  complete migration of ZAM to use only public ZVal methods
  "-O validate-ZAM" option to validate generated ZAM instructions
  internal option to suppress control-flow optimization
  exposing some functionality for greater flexibility in structuring run-time execution
  rework ZAM compilation of type switches to leverage value switches
  add tracking of control flow information
  factoring of ZAM operation specifications into separate files
  updates to ZAM operations / gen-zam regularization, other than the operations themselves
  type-checking fix for vector-of-string operations
  ZVal constructor for booleans
  ...
2024-08-16 12:10:33 +02:00

1730 lines
52 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#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 T>
class IntrusivePtr;
namespace detail {
class Frame;
class Scope;
class FunctionIngredients;
class WhenInfo;
using IDPtr = IntrusivePtr<ID>;
using ScopePtr = IntrusivePtr<Scope>;
using ScriptFuncPtr = IntrusivePtr<ScriptFunc>;
using FunctionIngredientsPtr = std::shared_ptr<FunctionIngredients>;
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_REC_ASSIGN_FIELDS,
EXPR_REC_ADD_FIELDS,
EXPR_REC_CONSTRUCT_WITH_REC,
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<CallExpr>;
using ConstExprPtr = IntrusivePtr<ConstExpr>;
using EventExprPtr = IntrusivePtr<EventExpr>;
using ExprPtr = IntrusivePtr<Expr>;
using NameExprPtr = IntrusivePtr<NameExpr>;
using RefExprPtr = IntrusivePtr<RefExpr>;
using LambdaExprPtr = IntrusivePtr<LambdaExpr>;
class Stmt;
using StmtPtr = IntrusivePtr<Stmt>;
class ExprOptInfo;
class Expr : public Obj {
public:
const TypePtr& GetType() const { return type; }
template<class T>
IntrusivePtr<T> GetType() const {
return cast_intrusive<T>(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<ctype> 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 {
if ( type->Tag() == TYPE_OPAQUE )
// Aggressive constant propagation can lead to the appearance of
// opaque "constants". Don't consider these as foldable because
// they're problematic to generate independently.
return nullptr;
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<ValPtr> results = {};
static inline int evaluating = 0;
static void StartEval() { ++evaluating; }
static void EndEval() { --evaluating; }
static std::vector<ValPtr> 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.
// The flag allows skipping of checking for mandatory fields, for
// script optimization that may elide them.
explicit RecordConstructorExpr(RecordTypePtr known_rt, ListExprPtr constructor_list,
bool check_mandatory_fields = true);
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<std::vector<int>> map;
};
class TableConstructorExpr final : public UnaryExpr {
public:
TableConstructorExpr(ListExprPtr constructor_list, std::unique_ptr<std::vector<AttrPtr>> 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<std::vector<AttrPtr>> 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<int>& 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<int> map;
};
extern RecordValPtr coerce_to_record(RecordTypePtr rt, Val* v, const std::vector<int>& 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<FuncType::Capture>;
const std::optional<CaptureList>& 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<CaptureList> 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);
bool IsReduced(Reducer* c) const override;
ExprPtr Reduce(Reducer* c, StmtPtr& red_stmt) override;
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<std::vector<ValPtr>> 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